| OLD | NEW | 
|---|
| 1 /* | 1 /* | 
| 2  * Copyright 2007 The Android Open Source Project | 2  * Copyright 2007 The Android Open Source Project | 
| 3  * | 3  * | 
| 4  * Use of this source code is governed by a BSD-style license that can be | 4  * Use of this source code is governed by a BSD-style license that can be | 
| 5  * found in the LICENSE file. | 5  * found in the LICENSE file. | 
| 6  */ | 6  */ | 
| 7 | 7 | 
| 8 | 8 | 
| 9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" | 
| 10 #include "SkImageEncoder.h" | 10 #include "SkImageEncoder.h" | 
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 78     } | 78     } | 
| 79     /* To suppress error messages with a SK_DEBUG binary, set the | 79     /* To suppress error messages with a SK_DEBUG binary, set the | 
| 80      * environment variable "skia_images_jpeg_suppressDecoderErrors" | 80      * environment variable "skia_images_jpeg_suppressDecoderErrors" | 
| 81      * to "true".  Inside a program that links to skia: | 81      * to "true".  Inside a program that links to skia: | 
| 82      * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ | 82      * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */ | 
| 83     if (c_suppressJPEGImageDecoderErrors) { | 83     if (c_suppressJPEGImageDecoderErrors) { | 
| 84         cinfo->err->output_message = &do_nothing_output_message; | 84         cinfo->err->output_message = &do_nothing_output_message; | 
| 85     } | 85     } | 
| 86 } | 86 } | 
| 87 | 87 | 
| 88 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 89 class SkJPEGImageIndex { |  | 
| 90 public: |  | 
| 91     // Takes ownership of stream. |  | 
| 92     SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder) |  | 
| 93         : fSrcMgr(stream, decoder) |  | 
| 94         , fStream(stream) |  | 
| 95         , fInfoInitialized(false) |  | 
| 96         , fHuffmanCreated(false) |  | 
| 97         , fDecompressStarted(false) |  | 
| 98         { |  | 
| 99             SkDEBUGCODE(fReadHeaderSucceeded = false;) |  | 
| 100         } |  | 
| 101 |  | 
| 102     ~SkJPEGImageIndex() { |  | 
| 103         if (fHuffmanCreated) { |  | 
| 104             // Set to false before calling the libjpeg function, in case |  | 
| 105             // the libjpeg function calls longjmp. Our setjmp handler may |  | 
| 106             // attempt to delete this SkJPEGImageIndex, thus entering this |  | 
| 107             // destructor again. Setting fHuffmanCreated to false first |  | 
| 108             // prevents an infinite loop. |  | 
| 109             fHuffmanCreated = false; |  | 
| 110             jpeg_destroy_huffman_index(&fHuffmanIndex); |  | 
| 111         } |  | 
| 112         if (fDecompressStarted) { |  | 
| 113             // Like fHuffmanCreated, set to false before calling libjpeg |  | 
| 114             // function to prevent potential infinite loop. |  | 
| 115             fDecompressStarted = false; |  | 
| 116             jpeg_finish_decompress(&fCInfo); |  | 
| 117         } |  | 
| 118         if (fInfoInitialized) { |  | 
| 119             this->destroyInfo(); |  | 
| 120         } |  | 
| 121     } |  | 
| 122 |  | 
| 123     /** |  | 
| 124      *  Destroy the cinfo struct. |  | 
| 125      *  After this call, if a huffman index was already built, it |  | 
| 126      *  can be used after calling initializeInfoAndReadHeader |  | 
| 127      *  again. Must not be called after startTileDecompress except |  | 
| 128      *  in the destructor. |  | 
| 129      */ |  | 
| 130     void destroyInfo() { |  | 
| 131         SkASSERT(fInfoInitialized); |  | 
| 132         SkASSERT(!fDecompressStarted); |  | 
| 133         // Like fHuffmanCreated, set to false before calling libjpeg |  | 
| 134         // function to prevent potential infinite loop. |  | 
| 135         fInfoInitialized = false; |  | 
| 136         jpeg_destroy_decompress(&fCInfo); |  | 
| 137         SkDEBUGCODE(fReadHeaderSucceeded = false;) |  | 
| 138     } |  | 
| 139 |  | 
| 140     /** |  | 
| 141      *  Initialize the cinfo struct. |  | 
| 142      *  Calls jpeg_create_decompress, makes customizations, and |  | 
| 143      *  finally calls jpeg_read_header. Returns true if jpeg_read_header |  | 
| 144      *  returns JPEG_HEADER_OK. |  | 
| 145      *  If cinfo was already initialized, destroyInfo must be called to |  | 
| 146      *  destroy the old one. Must not be called after startTileDecompress. |  | 
| 147      */ |  | 
| 148     bool initializeInfoAndReadHeader() { |  | 
| 149         SkASSERT(!fInfoInitialized && !fDecompressStarted); |  | 
| 150         initialize_info(&fCInfo, &fSrcMgr); |  | 
| 151         fInfoInitialized = true; |  | 
| 152         const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true))
      ; |  | 
| 153         SkDEBUGCODE(fReadHeaderSucceeded = success;) |  | 
| 154         return success; |  | 
| 155     } |  | 
| 156 |  | 
| 157     jpeg_decompress_struct* cinfo() { return &fCInfo; } |  | 
| 158 |  | 
| 159     huffman_index* huffmanIndex() { return &fHuffmanIndex; } |  | 
| 160 |  | 
| 161     /** |  | 
| 162      *  Build the index to be used for tile based decoding. |  | 
| 163      *  Must only be called after a successful call to |  | 
| 164      *  initializeInfoAndReadHeader and must not be called more |  | 
| 165      *  than once. |  | 
| 166      */ |  | 
| 167     bool buildHuffmanIndex() { |  | 
| 168         SkASSERT(fReadHeaderSucceeded); |  | 
| 169         SkASSERT(!fHuffmanCreated); |  | 
| 170         jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex); |  | 
| 171         SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom); |  | 
| 172         fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex); |  | 
| 173         return fHuffmanCreated; |  | 
| 174     } |  | 
| 175 |  | 
| 176     /** |  | 
| 177      *  Start tile based decoding. Must only be called after a |  | 
| 178      *  successful call to buildHuffmanIndex, and must only be |  | 
| 179      *  called once. |  | 
| 180      */ |  | 
| 181     bool startTileDecompress() { |  | 
| 182         SkASSERT(fHuffmanCreated); |  | 
| 183         SkASSERT(fReadHeaderSucceeded); |  | 
| 184         SkASSERT(!fDecompressStarted); |  | 
| 185         if (jpeg_start_tile_decompress(&fCInfo)) { |  | 
| 186             fDecompressStarted = true; |  | 
| 187             return true; |  | 
| 188         } |  | 
| 189         return false; |  | 
| 190     } |  | 
| 191 |  | 
| 192 private: |  | 
| 193     skjpeg_source_mgr  fSrcMgr; |  | 
| 194     SkAutoTDelete<SkStream> fStream; |  | 
| 195     jpeg_decompress_struct fCInfo; |  | 
| 196     huffman_index fHuffmanIndex; |  | 
| 197     bool fInfoInitialized; |  | 
| 198     bool fHuffmanCreated; |  | 
| 199     bool fDecompressStarted; |  | 
| 200     SkDEBUGCODE(bool fReadHeaderSucceeded;) |  | 
| 201 }; |  | 
| 202 #endif |  | 
| 203 |  | 
| 204 class SkJPEGImageDecoder : public SkImageDecoder { | 88 class SkJPEGImageDecoder : public SkImageDecoder { | 
| 205 public: | 89 public: | 
| 206 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 207     SkJPEGImageDecoder() { |  | 
| 208         fImageIndex = nullptr; |  | 
| 209         fImageWidth = 0; |  | 
| 210         fImageHeight = 0; |  | 
| 211     } |  | 
| 212 |  | 
| 213     virtual ~SkJPEGImageDecoder() { delete fImageIndex; } |  | 
| 214 #endif |  | 
| 215 | 90 | 
| 216     Format getFormat() const override { | 91     Format getFormat() const override { | 
| 217         return kJPEG_Format; | 92         return kJPEG_Format; | 
| 218     } | 93     } | 
| 219 | 94 | 
| 220 protected: | 95 protected: | 
| 221 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 222     bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) o
      verride; |  | 
| 223     bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override; |  | 
| 224 #endif |  | 
| 225     Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; | 96     Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; | 
| 226     bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], | 97     bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], | 
| 227                             void* planes[3], size_t rowBytes[3], | 98                             void* planes[3], size_t rowBytes[3], | 
| 228                             SkYUVColorSpace* colorSpace) override; | 99                             SkYUVColorSpace* colorSpace) override; | 
| 229 | 100 | 
| 230 private: | 101 private: | 
| 231 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 232     SkJPEGImageIndex* fImageIndex; |  | 
| 233     int fImageWidth; |  | 
| 234     int fImageHeight; |  | 
| 235 #endif |  | 
| 236 | 102 | 
| 237     /** | 103     /** | 
| 238      *  Determine the appropriate bitmap colortype and out_color_space based on | 104      *  Determine the appropriate bitmap colortype and out_color_space based on | 
| 239      *  both the preference of the caller and the jpeg_color_space on the | 105      *  both the preference of the caller and the jpeg_color_space on the | 
| 240      *  jpeg_decompress_struct passed in. | 106      *  jpeg_decompress_struct passed in. | 
| 241      *  Must be called after jpeg_read_header. | 107      *  Must be called after jpeg_read_header. | 
| 242      */ | 108      */ | 
| 243     SkColorType getBitmapColorType(jpeg_decompress_struct*); | 109     SkColorType getBitmapColorType(jpeg_decompress_struct*); | 
| 244 | 110 | 
| 245     typedef SkImageDecoder INHERITED; | 111     typedef SkImageDecoder INHERITED; | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 288     for (int i = 0; i < count; i++) { | 154     for (int i = 0; i < count; i++) { | 
| 289         JSAMPLE* rowptr = (JSAMPLE*)buffer; | 155         JSAMPLE* rowptr = (JSAMPLE*)buffer; | 
| 290         int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); | 156         int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); | 
| 291         if (1 != row_count) { | 157         if (1 != row_count) { | 
| 292             return false; | 158             return false; | 
| 293         } | 159         } | 
| 294     } | 160     } | 
| 295     return true; | 161     return true; | 
| 296 } | 162 } | 
| 297 | 163 | 
| 298 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 299 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, |  | 
| 300                                huffman_index *index, void* buffer, int count) { |  | 
| 301     for (int i = 0; i < count; i++) { |  | 
| 302         JSAMPLE* rowptr = (JSAMPLE*)buffer; |  | 
| 303         int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); |  | 
| 304         if (1 != row_count) { |  | 
| 305             return false; |  | 
| 306         } |  | 
| 307     } |  | 
| 308     return true; |  | 
| 309 } |  | 
| 310 #endif |  | 
| 311 |  | 
| 312 /////////////////////////////////////////////////////////////////////////////// | 164 /////////////////////////////////////////////////////////////////////////////// | 
| 313 | 165 | 
| 314 // This guy exists just to aid in debugging, as it allows debuggers to just | 166 // This guy exists just to aid in debugging, as it allows debuggers to just | 
| 315 // set a break-point in one place to see all error exists. | 167 // set a break-point in one place to see all error exists. | 
| 316 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, | 168 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, | 
| 317                          int width, int height, const char caller[]) { | 169                          int width, int height, const char caller[]) { | 
| 318     if (!(c_suppressJPEGImageDecoderErrors)) { | 170     if (!(c_suppressJPEGImageDecoderErrors)) { | 
| 319         char buffer[JMSG_LENGTH_MAX]; | 171         char buffer[JMSG_LENGTH_MAX]; | 
| 320         cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); | 172         cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); | 
| 321         SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", | 173         SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", | 
| 322                  cinfo.err->msg_code, buffer, caller, width, height); | 174                  cinfo.err->msg_code, buffer, caller, width, height); | 
| 323     } | 175     } | 
| 324 } | 176 } | 
| 325 | 177 | 
| 326 static bool return_false(const jpeg_decompress_struct& cinfo, | 178 static bool return_false(const jpeg_decompress_struct& cinfo, | 
| 327                          const char caller[]) { | 179                          const char caller[]) { | 
| 328     print_jpeg_decoder_errors(cinfo, 0, 0, caller); | 180     print_jpeg_decoder_errors(cinfo, 0, 0, caller); | 
| 329     return false; | 181     return false; | 
| 330 } | 182 } | 
| 331 | 183 | 
| 332 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 333 static bool return_false(const jpeg_decompress_struct& cinfo, |  | 
| 334                          const SkBitmap& bm, const char caller[]) { |  | 
| 335     print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); |  | 
| 336     return false; |  | 
| 337 } |  | 
| 338 #endif |  | 
| 339 |  | 
| 340 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo
      , | 184 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo
      , | 
| 341                                              const SkBitmap& bm, const char call
      er[]) { | 185                                              const SkBitmap& bm, const char call
      er[]) { | 
| 342     print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); | 186     print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); | 
| 343     return SkImageDecoder::kFailure; | 187     return SkImageDecoder::kFailure; | 
| 344 } | 188 } | 
| 345 | 189 | 
| 346 /////////////////////////////////////////////////////////////////////////////// | 190 /////////////////////////////////////////////////////////////////////////////// | 
| 347 | 191 | 
| 348 // Convert a scanline of CMYK samples to RGBX in place. Note that this | 192 // Convert a scanline of CMYK samples to RGBX in place. Note that this | 
| 349 // method moves the "scanline" pointer in its processing | 193 // method moves the "scanline" pointer in its processing | 
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 932 | 776 | 
| 933     if (nullptr != colorSpace) { | 777     if (nullptr != colorSpace) { | 
| 934         *colorSpace = kJPEG_SkYUVColorSpace; | 778         *colorSpace = kJPEG_SkYUVColorSpace; | 
| 935     } | 779     } | 
| 936 | 780 | 
| 937     return true; | 781     return true; | 
| 938 } | 782 } | 
| 939 | 783 | 
| 940 /////////////////////////////////////////////////////////////////////////////// | 784 /////////////////////////////////////////////////////////////////////////////// | 
| 941 | 785 | 
| 942 #ifdef SK_JPEG_INDEX_SUPPORTED |  | 
| 943 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width
      , int *height) { |  | 
| 944     SkAutoTDelete<SkJPEGImageIndex> imageIndex(new SkJPEGImageIndex(stream, this
      )); |  | 
| 945 |  | 
| 946     skjpeg_error_mgr sk_err; |  | 
| 947     set_error_mgr(imageIndex->cinfo(), &sk_err); |  | 
| 948 |  | 
| 949     // All objects need to be instantiated before this setjmp call so that |  | 
| 950     // they will be cleaned up properly if an error occurs. |  | 
| 951     if (setjmp(sk_err.fJmpBuf)) { |  | 
| 952         return false; |  | 
| 953     } |  | 
| 954 |  | 
| 955     // create the cinfo used to create/build the huffmanIndex |  | 
| 956     if (!imageIndex->initializeInfoAndReadHeader()) { |  | 
| 957         return false; |  | 
| 958     } |  | 
| 959 |  | 
| 960     if (!imageIndex->buildHuffmanIndex()) { |  | 
| 961         return false; |  | 
| 962     } |  | 
| 963 |  | 
| 964     // destroy the cinfo used to create/build the huffman index |  | 
| 965     imageIndex->destroyInfo(); |  | 
| 966 |  | 
| 967     // Init decoder to image decode mode |  | 
| 968     if (!imageIndex->initializeInfoAndReadHeader()) { |  | 
| 969         return false; |  | 
| 970     } |  | 
| 971 |  | 
| 972     jpeg_decompress_struct* cinfo = imageIndex->cinfo(); |  | 
| 973     // We have a new cinfo, so set the error mgr again. |  | 
| 974     set_error_mgr(cinfo, &sk_err); |  | 
| 975 |  | 
| 976     // FIXME: This sets cinfo->out_color_space, which we may change later |  | 
| 977     // based on the config in onDecodeSubset. This should be fine, since |  | 
| 978     // jpeg_init_read_tile_scanline will check out_color_space again after |  | 
| 979     // that change (when it calls jinit_color_deconverter). |  | 
| 980     (void) this->getBitmapColorType(cinfo); |  | 
| 981 |  | 
| 982     turn_off_visual_optimizations(cinfo); |  | 
| 983 |  | 
| 984     // instead of jpeg_start_decompress() we start a tiled decompress |  | 
| 985     if (!imageIndex->startTileDecompress()) { |  | 
| 986         return false; |  | 
| 987     } |  | 
| 988 |  | 
| 989     SkASSERT(1 == cinfo->scale_num); |  | 
| 990     fImageWidth = cinfo->output_width; |  | 
| 991     fImageHeight = cinfo->output_height; |  | 
| 992 |  | 
| 993     if (width) { |  | 
| 994         *width = fImageWidth; |  | 
| 995     } |  | 
| 996     if (height) { |  | 
| 997         *height = fImageHeight; |  | 
| 998     } |  | 
| 999 |  | 
| 1000     delete fImageIndex; |  | 
| 1001     fImageIndex = imageIndex.detach(); |  | 
| 1002 |  | 
| 1003     return true; |  | 
| 1004 } |  | 
| 1005 |  | 
| 1006 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { |  | 
| 1007     if (nullptr == fImageIndex) { |  | 
| 1008         return false; |  | 
| 1009     } |  | 
| 1010     jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); |  | 
| 1011 |  | 
| 1012     SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); |  | 
| 1013     if (!rect.intersect(region)) { |  | 
| 1014         // If the requested region is entirely outside the image return false |  | 
| 1015         return false; |  | 
| 1016     } |  | 
| 1017 |  | 
| 1018 |  | 
| 1019     skjpeg_error_mgr errorManager; |  | 
| 1020     set_error_mgr(cinfo, &errorManager); |  | 
| 1021 |  | 
| 1022     if (setjmp(errorManager.fJmpBuf)) { |  | 
| 1023         return false; |  | 
| 1024     } |  | 
| 1025 |  | 
| 1026     int requestedSampleSize = this->getSampleSize(); |  | 
| 1027     cinfo->scale_denom = requestedSampleSize; |  | 
| 1028 |  | 
| 1029     set_dct_method(*this, cinfo); |  | 
| 1030 |  | 
| 1031     const SkColorType colorType = this->getBitmapColorType(cinfo); |  | 
| 1032     adjust_out_color_space_and_dither(cinfo, colorType, *this); |  | 
| 1033 |  | 
| 1034     int startX = rect.fLeft; |  | 
| 1035     int startY = rect.fTop; |  | 
| 1036     int width = rect.width(); |  | 
| 1037     int height = rect.height(); |  | 
| 1038 |  | 
| 1039     jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), |  | 
| 1040                                  &startX, &startY, &width, &height); |  | 
| 1041     int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); |  | 
| 1042     int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_siz
      e); |  | 
| 1043 |  | 
| 1044     SkScaledBitmapSampler sampler(width, height, skiaSampleSize); |  | 
| 1045 |  | 
| 1046     SkBitmap bitmap; |  | 
| 1047     // Assume an A8 bitmap is not opaque to avoid the check of each |  | 
| 1048     // individual pixel. It is very unlikely to be opaque, since |  | 
| 1049     // an opaque A8 bitmap would not be very interesting. |  | 
| 1050     // Otherwise, a jpeg image is opaque. |  | 
| 1051     bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight
      (), colorType, |  | 
| 1052                                      kAlpha_8_SkColorType == colorType ? |  | 
| 1053                                          kPremul_SkAlphaType : kOpaque_SkAlphaTy
      pe)); |  | 
| 1054 |  | 
| 1055     // Check ahead of time if the swap(dest, src) is possible or not. |  | 
| 1056     // If yes, then we will stick to AllocPixelRef since it's cheaper with the |  | 
| 1057     // swap happening. If no, then we will use alloc to allocate pixels to |  | 
| 1058     // prevent garbage collection. |  | 
| 1059     int w = rect.width() / actualSampleSize; |  | 
| 1060     int h = rect.height() / actualSampleSize; |  | 
| 1061     bool swapOnly = (rect == region) && bm->isNull() && |  | 
| 1062                     (w == bitmap.width()) && (h == bitmap.height()) && |  | 
| 1063                     ((startX - rect.x()) / actualSampleSize == 0) && |  | 
| 1064                     ((startY - rect.y()) / actualSampleSize == 0); |  | 
| 1065     if (swapOnly) { |  | 
| 1066         if (!this->allocPixelRef(&bitmap, nullptr)) { |  | 
| 1067             return return_false(*cinfo, bitmap, "allocPixelRef"); |  | 
| 1068         } |  | 
| 1069     } else { |  | 
| 1070         if (!bitmap.tryAllocPixels()) { |  | 
| 1071             return return_false(*cinfo, bitmap, "allocPixels"); |  | 
| 1072         } |  | 
| 1073     } |  | 
| 1074 |  | 
| 1075     SkAutoLockPixels alp(bitmap); |  | 
| 1076 |  | 
| 1077 #ifdef ANDROID_RGB |  | 
| 1078     /* short-circuit the SkScaledBitmapSampler when possible, as this gives |  | 
| 1079        a significant performance boost. |  | 
| 1080     */ |  | 
| 1081     if (skiaSampleSize == 1 && |  | 
| 1082         ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_88
      88) || |  | 
| 1083          (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB
      _565))) |  | 
| 1084     { |  | 
| 1085         JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); |  | 
| 1086         INT32 const bpr = bitmap.rowBytes(); |  | 
| 1087         int rowTotalCount = 0; |  | 
| 1088 |  | 
| 1089         while (rowTotalCount < height) { |  | 
| 1090             int rowCount = jpeg_read_tile_scanline(cinfo, |  | 
| 1091                                                    fImageIndex->huffmanIndex(), |  | 
| 1092                                                    &rowptr); |  | 
| 1093             // if rowCount == 0, then we didn't get a scanline, so abort. |  | 
| 1094             // onDecodeSubset() relies on onBuildTileIndex(), which |  | 
| 1095             // needs a complete image to succeed. |  | 
| 1096             if (0 == rowCount) { |  | 
| 1097                 return return_false(*cinfo, bitmap, "read_scanlines"); |  | 
| 1098             } |  | 
| 1099             if (this->shouldCancelDecode()) { |  | 
| 1100                 return return_false(*cinfo, bitmap, "shouldCancelDecode"); |  | 
| 1101             } |  | 
| 1102             rowTotalCount += rowCount; |  | 
| 1103             rowptr += bpr; |  | 
| 1104         } |  | 
| 1105 |  | 
| 1106         if (swapOnly) { |  | 
| 1107             bm->swap(bitmap); |  | 
| 1108             return true; |  | 
| 1109         } |  | 
| 1110 |  | 
| 1111         return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |  | 
| 1112                           region.width(), region.height(), startX, startY); |  | 
| 1113     } |  | 
| 1114 #endif |  | 
| 1115 |  | 
| 1116     // check for supported formats |  | 
| 1117     SkScaledBitmapSampler::SrcConfig sc; |  | 
| 1118     int srcBytesPerPixel; |  | 
| 1119 |  | 
| 1120     if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { |  | 
| 1121         return return_false(*cinfo, *bm, "jpeg colorspace"); |  | 
| 1122     } |  | 
| 1123 |  | 
| 1124     if (!sampler.begin(&bitmap, sc, *this)) { |  | 
| 1125         return return_false(*cinfo, bitmap, "sampler.begin"); |  | 
| 1126     } |  | 
| 1127 |  | 
| 1128     SkAutoMalloc  srcStorage(width * srcBytesPerPixel); |  | 
| 1129     uint8_t* srcRow = (uint8_t*)srcStorage.get(); |  | 
| 1130 |  | 
| 1131     //  Possibly skip initial rows [sampler.srcY0] |  | 
| 1132     if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.
      srcY0())) { |  | 
| 1133         return return_false(*cinfo, bitmap, "skip rows"); |  | 
| 1134     } |  | 
| 1135 |  | 
| 1136     // now loop through scanlines until y == bitmap->height() - 1 |  | 
| 1137     for (int y = 0;; y++) { |  | 
| 1138         JSAMPLE* rowptr = (JSAMPLE*)srcRow; |  | 
| 1139         int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex
      (), &rowptr); |  | 
| 1140         // if row_count == 0, then we didn't get a scanline, so abort. |  | 
| 1141         // onDecodeSubset() relies on onBuildTileIndex(), which |  | 
| 1142         // needs a complete image to succeed. |  | 
| 1143         if (0 == row_count) { |  | 
| 1144             return return_false(*cinfo, bitmap, "read_scanlines"); |  | 
| 1145         } |  | 
| 1146         if (this->shouldCancelDecode()) { |  | 
| 1147             return return_false(*cinfo, bitmap, "shouldCancelDecode"); |  | 
| 1148         } |  | 
| 1149 |  | 
| 1150         if (JCS_CMYK == cinfo->out_color_space) { |  | 
| 1151             convert_CMYK_to_RGB(srcRow, width); |  | 
| 1152         } |  | 
| 1153 |  | 
| 1154         sampler.next(srcRow); |  | 
| 1155         if (bitmap.height() - 1 == y) { |  | 
| 1156             // we're done |  | 
| 1157             break; |  | 
| 1158         } |  | 
| 1159 |  | 
| 1160         if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, |  | 
| 1161                                 sampler.srcDY() - 1)) { |  | 
| 1162             return return_false(*cinfo, bitmap, "skip rows"); |  | 
| 1163         } |  | 
| 1164     } |  | 
| 1165     if (swapOnly) { |  | 
| 1166         bm->swap(bitmap); |  | 
| 1167         return true; |  | 
| 1168     } |  | 
| 1169     return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), |  | 
| 1170                       region.width(), region.height(), startX, startY); |  | 
| 1171 } |  | 
| 1172 #endif |  | 
| 1173 |  | 
| 1174 /////////////////////////////////////////////////////////////////////////////// |  | 
| 1175 |  | 
| 1176 #include "SkColorPriv.h" | 786 #include "SkColorPriv.h" | 
| 1177 | 787 | 
| 1178 // taken from jcolor.c in libjpeg | 788 // taken from jcolor.c in libjpeg | 
| 1179 #if 0   // 16bit - precise but slow | 789 #if 0   // 16bit - precise but slow | 
| 1180     #define CYR     19595   // 0.299 | 790     #define CYR     19595   // 0.299 | 
| 1181     #define CYG     38470   // 0.587 | 791     #define CYG     38470   // 0.587 | 
| 1182     #define CYB      7471   // 0.114 | 792     #define CYB      7471   // 0.114 | 
| 1183 | 793 | 
| 1184     #define CUR    -11059   // -0.16874 | 794     #define CUR    -11059   // -0.16874 | 
| 1185     #define CUG    -21709   // -0.33126 | 795     #define CUG    -21709   // -0.33126 | 
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1446     return SkImageDecoder::kUnknown_Format; | 1056     return SkImageDecoder::kUnknown_Format; | 
| 1447 } | 1057 } | 
| 1448 | 1058 | 
| 1449 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 1059 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { | 
| 1450     return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; | 1060     return (SkImageEncoder::kJPEG_Type == t) ? new SkJPEGImageEncoder : nullptr; | 
| 1451 } | 1061 } | 
| 1452 | 1062 | 
| 1453 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 1063 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); | 
| 1454 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 1064 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); | 
| 1455 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 1065 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); | 
| OLD | NEW | 
|---|