gfx/skia/trunk/src/images/SkImageDecoder_libjpeg.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2007 The Android Open Source Project
     3  *
     4  * Use of this source code is governed by a BSD-style license that can be
     5  * found in the LICENSE file.
     6  */
     9 #include "SkImageDecoder.h"
    10 #include "SkImageEncoder.h"
    11 #include "SkJpegUtility.h"
    12 #include "SkColorPriv.h"
    13 #include "SkDither.h"
    14 #include "SkScaledBitmapSampler.h"
    15 #include "SkStream.h"
    16 #include "SkTemplates.h"
    17 #include "SkTime.h"
    18 #include "SkUtils.h"
    19 #include "SkRTConf.h"
    20 #include "SkRect.h"
    21 #include "SkCanvas.h"
    24 #include <stdio.h>
    25 extern "C" {
    26     #include "jpeglib.h"
    27     #include "jerror.h"
    28 }
    30 // These enable timing code that report milliseconds for an encoding/decoding
    31 //#define TIME_ENCODE
    32 //#define TIME_DECODE
    34 // this enables our rgb->yuv code, which is faster than libjpeg on ARM
    35 #define WE_CONVERT_TO_YUV
    37 // If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
    38 // support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
    40 #if defined(SK_DEBUG)
    41 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false
    42 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false
    43 #else  // !defined(SK_DEBUG)
    44 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true
    45 #define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true
    46 #endif  // defined(SK_DEBUG)
    47 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings,
    48                 "images.jpeg.suppressDecoderWarnings",
    49                 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS,
    50                 "Suppress most JPG warnings when calling decode functions.");
    51 SK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors,
    52                 "images.jpeg.suppressDecoderErrors",
    53                 DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS,
    54                 "Suppress most JPG error messages when decode "
    55                 "function fails.");
    57 //////////////////////////////////////////////////////////////////////////
    58 //////////////////////////////////////////////////////////////////////////
    60 static void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) {
    61 #ifdef SK_BUILD_FOR_ANDROID
    62     /* Check if the device indicates that it has a large amount of system memory
    63      * if so, increase the memory allocation to 30MB instead of the default 5MB.
    64      */
    65 #ifdef ANDROID_LARGE_MEMORY_DEVICE
    66     cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
    67 #else
    68     cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
    69 #endif
    70 #endif // SK_BUILD_FOR_ANDROID
    71 }
    73 //////////////////////////////////////////////////////////////////////////
    74 //////////////////////////////////////////////////////////////////////////
    76 static void do_nothing_emit_message(jpeg_common_struct*, int) {
    77     /* do nothing */
    78 }
    79 static void do_nothing_output_message(j_common_ptr) {
    80     /* do nothing */
    81 }
    83 static void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) {
    84     SkASSERT(cinfo != NULL);
    85     SkASSERT(src_mgr != NULL);
    86     jpeg_create_decompress(cinfo);
    87     overwrite_mem_buffer_size(cinfo);
    88     cinfo->src = src_mgr;
    89     /* To suppress warnings with a SK_DEBUG binary, set the
    90      * environment variable "skia_images_jpeg_suppressDecoderWarnings"
    91      * to "true".  Inside a program that links to skia:
    92      * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */
    93     if (c_suppressJPEGImageDecoderWarnings) {
    94         cinfo->err->emit_message = &do_nothing_emit_message;
    95     }
    96     /* To suppress error messages with a SK_DEBUG binary, set the
    97      * environment variable "skia_images_jpeg_suppressDecoderErrors"
    98      * to "true".  Inside a program that links to skia:
    99      * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */
   100     if (c_suppressJPEGImageDecoderErrors) {
   101         cinfo->err->output_message = &do_nothing_output_message;
   102     }
   103 }
   105 #ifdef SK_BUILD_FOR_ANDROID
   106 class SkJPEGImageIndex {
   107 public:
   108     SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
   109         : fSrcMgr(stream, decoder)
   110         , fInfoInitialized(false)
   111         , fHuffmanCreated(false)
   112         , fDecompressStarted(false)
   113         {
   114             SkDEBUGCODE(fReadHeaderSucceeded = false;)
   115         }
   117     ~SkJPEGImageIndex() {
   118         if (fHuffmanCreated) {
   119             // Set to false before calling the libjpeg function, in case
   120             // the libjpeg function calls longjmp. Our setjmp handler may
   121             // attempt to delete this SkJPEGImageIndex, thus entering this
   122             // destructor again. Setting fHuffmanCreated to false first
   123             // prevents an infinite loop.
   124             fHuffmanCreated = false;
   125             jpeg_destroy_huffman_index(&fHuffmanIndex);
   126         }
   127         if (fDecompressStarted) {
   128             // Like fHuffmanCreated, set to false before calling libjpeg
   129             // function to prevent potential infinite loop.
   130             fDecompressStarted = false;
   131             jpeg_finish_decompress(&fCInfo);
   132         }
   133         if (fInfoInitialized) {
   134             this->destroyInfo();
   135         }
   136     }
   138     /**
   139      *  Destroy the cinfo struct.
   140      *  After this call, if a huffman index was already built, it
   141      *  can be used after calling initializeInfoAndReadHeader
   142      *  again. Must not be called after startTileDecompress except
   143      *  in the destructor.
   144      */
   145     void destroyInfo() {
   146         SkASSERT(fInfoInitialized);
   147         SkASSERT(!fDecompressStarted);
   148         // Like fHuffmanCreated, set to false before calling libjpeg
   149         // function to prevent potential infinite loop.
   150         fInfoInitialized = false;
   151         jpeg_destroy_decompress(&fCInfo);
   152         SkDEBUGCODE(fReadHeaderSucceeded = false;)
   153     }
   155     /**
   156      *  Initialize the cinfo struct.
   157      *  Calls jpeg_create_decompress, makes customizations, and
   158      *  finally calls jpeg_read_header. Returns true if jpeg_read_header
   159      *  returns JPEG_HEADER_OK.
   160      *  If cinfo was already initialized, destroyInfo must be called to
   161      *  destroy the old one. Must not be called after startTileDecompress.
   162      */
   163     bool initializeInfoAndReadHeader() {
   164         SkASSERT(!fInfoInitialized && !fDecompressStarted);
   165         initialize_info(&fCInfo, &fSrcMgr);
   166         fInfoInitialized = true;
   167         const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
   168         SkDEBUGCODE(fReadHeaderSucceeded = success;)
   169         return success;
   170     }
   172     jpeg_decompress_struct* cinfo() { return &fCInfo; }
   174     huffman_index* huffmanIndex() { return &fHuffmanIndex; }
   176     /**
   177      *  Build the index to be used for tile based decoding.
   178      *  Must only be called after a successful call to
   179      *  initializeInfoAndReadHeader and must not be called more
   180      *  than once.
   181      */
   182     bool buildHuffmanIndex() {
   183         SkASSERT(fReadHeaderSucceeded);
   184         SkASSERT(!fHuffmanCreated);
   185         jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
   186         SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
   187         fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
   188         return fHuffmanCreated;
   189     }
   191     /**
   192      *  Start tile based decoding. Must only be called after a
   193      *  successful call to buildHuffmanIndex, and must only be
   194      *  called once.
   195      */
   196     bool startTileDecompress() {
   197         SkASSERT(fHuffmanCreated);
   198         SkASSERT(fReadHeaderSucceeded);
   199         SkASSERT(!fDecompressStarted);
   200         if (jpeg_start_tile_decompress(&fCInfo)) {
   201             fDecompressStarted = true;
   202             return true;
   203         }
   204         return false;
   205     }
   207 private:
   208     skjpeg_source_mgr  fSrcMgr;
   209     jpeg_decompress_struct fCInfo;
   210     huffman_index fHuffmanIndex;
   211     bool fInfoInitialized;
   212     bool fHuffmanCreated;
   213     bool fDecompressStarted;
   214     SkDEBUGCODE(bool fReadHeaderSucceeded;)
   215 };
   216 #endif
   218 class SkJPEGImageDecoder : public SkImageDecoder {
   219 public:
   220 #ifdef SK_BUILD_FOR_ANDROID
   221     SkJPEGImageDecoder() {
   222         fImageIndex = NULL;
   223         fImageWidth = 0;
   224         fImageHeight = 0;
   225     }
   227     virtual ~SkJPEGImageDecoder() {
   228         SkDELETE(fImageIndex);
   229     }
   230 #endif
   232     virtual Format getFormat() const {
   233         return kJPEG_Format;
   234     }
   236 protected:
   237 #ifdef SK_BUILD_FOR_ANDROID
   238     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
   239     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
   240 #endif
   241     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
   243 private:
   244 #ifdef SK_BUILD_FOR_ANDROID
   245     SkJPEGImageIndex* fImageIndex;
   246     int fImageWidth;
   247     int fImageHeight;
   248 #endif
   250     /**
   251      *  Determine the appropriate bitmap config and out_color_space based on
   252      *  both the preference of the caller and the jpeg_color_space on the
   253      *  jpeg_decompress_struct passed in.
   254      *  Must be called after jpeg_read_header.
   255      */
   256     SkBitmap::Config getBitmapConfig(jpeg_decompress_struct*);
   258     typedef SkImageDecoder INHERITED;
   259 };
   261 //////////////////////////////////////////////////////////////////////////
   263 /* Automatically clean up after throwing an exception */
   264 class JPEGAutoClean {
   265 public:
   266     JPEGAutoClean(): cinfo_ptr(NULL) {}
   267     ~JPEGAutoClean() {
   268         if (cinfo_ptr) {
   269             jpeg_destroy_decompress(cinfo_ptr);
   270         }
   271     }
   272     void set(jpeg_decompress_struct* info) {
   273         cinfo_ptr = info;
   274     }
   275 private:
   276     jpeg_decompress_struct* cinfo_ptr;
   277 };
   279 ///////////////////////////////////////////////////////////////////////////////
   281 /*  If we need to better match the request, we might examine the image and
   282      output dimensions, and determine if the downsampling jpeg provided is
   283      not sufficient. If so, we can recompute a modified sampleSize value to
   284      make up the difference.
   286      To skip this additional scaling, just set sampleSize = 1; below.
   287  */
   288 static int recompute_sampleSize(int sampleSize,
   289                                 const jpeg_decompress_struct& cinfo) {
   290     return sampleSize * cinfo.output_width / cinfo.image_width;
   291 }
   293 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
   294     /* These are initialized to 0, so if they have non-zero values, we assume
   295        they are "valid" (i.e. have been computed by libjpeg)
   296      */
   297     return 0 != cinfo.output_width && 0 != cinfo.output_height;
   298 }
   300 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
   301     for (int i = 0; i < count; i++) {
   302         JSAMPLE* rowptr = (JSAMPLE*)buffer;
   303         int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
   304         if (1 != row_count) {
   305             return false;
   306         }
   307     }
   308     return true;
   309 }
   311 #ifdef SK_BUILD_FOR_ANDROID
   312 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
   313                                huffman_index *index, void* buffer, int count) {
   314     for (int i = 0; i < count; i++) {
   315         JSAMPLE* rowptr = (JSAMPLE*)buffer;
   316         int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
   317         if (1 != row_count) {
   318             return false;
   319         }
   320     }
   321     return true;
   322 }
   323 #endif
   325 // This guy exists just to aid in debugging, as it allows debuggers to just
   326 // set a break-point in one place to see all error exists.
   327 static bool return_false(const jpeg_decompress_struct& cinfo,
   328                          const SkBitmap& bm, const char caller[]) {
   329     if (!(c_suppressJPEGImageDecoderErrors)) {
   330         char buffer[JMSG_LENGTH_MAX];
   331         cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
   332         SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
   333                  cinfo.err->msg_code, buffer, caller, bm.width(), bm.height());
   334     }
   335     return false;   // must always return false
   336 }
   338 // Convert a scanline of CMYK samples to RGBX in place. Note that this
   339 // method moves the "scanline" pointer in its processing
   340 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
   341     // At this point we've received CMYK pixels from libjpeg. We
   342     // perform a crude conversion to RGB (based on the formulae
   343     // from easyrgb.com):
   344     //  CMYK -> CMY
   345     //    C = ( C * (1 - K) + K )      // for each CMY component
   346     //  CMY -> RGB
   347     //    R = ( 1 - C ) * 255          // for each RGB component
   348     // Unfortunately we are seeing inverted CMYK so all the original terms
   349     // are 1-. This yields:
   350     //  CMYK -> CMY
   351     //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
   352     // The conversion from CMY->RGB remains the same
   353     for (unsigned int x = 0; x < width; ++x, scanline += 4) {
   354         scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
   355         scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
   356         scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
   357         scanline[3] = 255;
   358     }
   359 }
   361 /**
   362  *  Common code for setting the error manager.
   363  */
   364 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
   365     SkASSERT(cinfo != NULL);
   366     SkASSERT(errorManager != NULL);
   367     cinfo->err = jpeg_std_error(errorManager);
   368     errorManager->error_exit = skjpeg_error_exit;
   369 }
   371 /**
   372  *  Common code for turning off upsampling and smoothing. Turning these
   373  *  off helps performance without showing noticable differences in the
   374  *  resulting bitmap.
   375  */
   376 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) {
   377     SkASSERT(cinfo != NULL);
   378     /* this gives about 30% performance improvement. In theory it may
   379        reduce the visual quality, in practice I'm not seeing a difference
   380      */
   381     cinfo->do_fancy_upsampling = 0;
   383     /* this gives another few percents */
   384     cinfo->do_block_smoothing = 0;
   385 }
   387 /**
   388  * Common code for setting the dct method.
   389  */
   390 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
   391     SkASSERT(cinfo != NULL);
   392 #ifdef DCT_IFAST_SUPPORTED
   393     if (decoder.getPreferQualityOverSpeed()) {
   394         cinfo->dct_method = JDCT_ISLOW;
   395     } else {
   396         cinfo->dct_method = JDCT_IFAST;
   397     }
   398 #else
   399     cinfo->dct_method = JDCT_ISLOW;
   400 #endif
   401 }
   403 SkBitmap::Config SkJPEGImageDecoder::getBitmapConfig(jpeg_decompress_struct* cinfo) {
   404     SkASSERT(cinfo != NULL);
   406     SrcDepth srcDepth = k32Bit_SrcDepth;
   407     if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
   408         srcDepth = k8BitGray_SrcDepth;
   409     }
   411     SkBitmap::Config config = this->getPrefConfig(srcDepth, /*hasAlpha*/ false);
   412     switch (config) {
   413         case SkBitmap::kA8_Config:
   414             // Only respect A8 config if the original is grayscale,
   415             // in which case we will treat the grayscale as alpha
   416             // values.
   417             if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
   418                 config = SkBitmap::kARGB_8888_Config;
   419             }
   420             break;
   421         case SkBitmap::kARGB_8888_Config:
   422             // Fall through.
   423         case SkBitmap::kARGB_4444_Config:
   424             // Fall through.
   425         case SkBitmap::kRGB_565_Config:
   426             // These are acceptable destination configs.
   427             break;
   428         default:
   429             // Force all other configs to 8888.
   430             config = SkBitmap::kARGB_8888_Config;
   431             break;
   432     }
   434     switch (cinfo->jpeg_color_space) {
   435         case JCS_CMYK:
   436             // Fall through.
   437         case JCS_YCCK:
   438             // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
   439             // so libjpeg will give us CMYK samples back and we will later
   440             // manually convert them to RGB
   441             cinfo->out_color_space = JCS_CMYK;
   442             break;
   443         case JCS_GRAYSCALE:
   444             if (SkBitmap::kA8_Config == config) {
   445                 cinfo->out_color_space = JCS_GRAYSCALE;
   446                 break;
   447             }
   448             // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
   449             // config. Fall through to set to the default.
   450         default:
   451             cinfo->out_color_space = JCS_RGB;
   452             break;
   453     }
   454     return config;
   455 }
   457 #ifdef ANDROID_RGB
   458 /**
   459  *  Based on the config and dither mode, adjust out_color_space and
   460  *  dither_mode of cinfo.
   461  */
   462 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
   463                                               SkBitmap::Config config,
   464                                               const SkImageDecoder& decoder) {
   465     SkASSERT(cinfo != NULL);
   466     cinfo->dither_mode = JDITHER_NONE;
   467     if (JCS_CMYK == cinfo->out_color_space) {
   468         return;
   469     }
   470     switch(config) {
   471         case SkBitmap::kARGB_8888_Config:
   472             cinfo->out_color_space = JCS_RGBA_8888;
   473             break;
   474         case SkBitmap::kRGB_565_Config:
   475             cinfo->out_color_space = JCS_RGB_565;
   476             if (decoder.getDitherImage()) {
   477                 cinfo->dither_mode = JDITHER_ORDERED;
   478             }
   479             break;
   480         default:
   481             break;
   482     }
   483 }
   484 #endif
   487 /**
   488    Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
   489    Used when decoding fails partway through reading scanlines to fill
   490    remaining lines. */
   491 static void fill_below_level(int y, SkBitmap* bitmap) {
   492     SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
   493     SkCanvas canvas(*bitmap);
   494     canvas.clipRect(SkRect::Make(rect));
   495     canvas.drawColor(SK_ColorWHITE);
   496 }
   498 /**
   499  *  Get the config and bytes per pixel of the source data. Return
   500  *  whether the data is supported.
   501  */
   502 static bool get_src_config(const jpeg_decompress_struct& cinfo,
   503                            SkScaledBitmapSampler::SrcConfig* sc,
   504                            int* srcBytesPerPixel) {
   505     SkASSERT(sc != NULL && srcBytesPerPixel != NULL);
   506     if (JCS_CMYK == cinfo.out_color_space) {
   507         // In this case we will manually convert the CMYK values to RGB
   508         *sc = SkScaledBitmapSampler::kRGBX;
   509         // The CMYK work-around relies on 4 components per pixel here
   510         *srcBytesPerPixel = 4;
   511     } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
   512         *sc = SkScaledBitmapSampler::kRGB;
   513         *srcBytesPerPixel = 3;
   514 #ifdef ANDROID_RGB
   515     } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
   516         *sc = SkScaledBitmapSampler::kRGBX;
   517         *srcBytesPerPixel = 4;
   518     } else if (JCS_RGB_565 == cinfo.out_color_space) {
   519         *sc = SkScaledBitmapSampler::kRGB_565;
   520         *srcBytesPerPixel = 2;
   521 #endif
   522     } else if (1 == cinfo.out_color_components &&
   523                JCS_GRAYSCALE == cinfo.out_color_space) {
   524         *sc = SkScaledBitmapSampler::kGray;
   525         *srcBytesPerPixel = 1;
   526     } else {
   527         return false;
   528     }
   529     return true;
   530 }
   532 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
   533 #ifdef TIME_DECODE
   534     SkAutoTime atm("JPEG Decode");
   535 #endif
   537     JPEGAutoClean autoClean;
   539     jpeg_decompress_struct  cinfo;
   540     skjpeg_source_mgr       srcManager(stream, this);
   542     skjpeg_error_mgr errorManager;
   543     set_error_mgr(&cinfo, &errorManager);
   545     // All objects need to be instantiated before this setjmp call so that
   546     // they will be cleaned up properly if an error occurs.
   547     if (setjmp(errorManager.fJmpBuf)) {
   548         return return_false(cinfo, *bm, "setjmp");
   549     }
   551     initialize_info(&cinfo, &srcManager);
   552     autoClean.set(&cinfo);
   554     int status = jpeg_read_header(&cinfo, true);
   555     if (status != JPEG_HEADER_OK) {
   556         return return_false(cinfo, *bm, "read_header");
   557     }
   559     /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
   560         can) much faster that we, just use their num/denom api to approximate
   561         the size.
   562     */
   563     int sampleSize = this->getSampleSize();
   565     set_dct_method(*this, &cinfo);
   567     SkASSERT(1 == cinfo.scale_num);
   568     cinfo.scale_denom = sampleSize;
   570     turn_off_visual_optimizations(&cinfo);
   572     const SkBitmap::Config config = this->getBitmapConfig(&cinfo);
   574 #ifdef ANDROID_RGB
   575     adjust_out_color_space_and_dither(&cinfo, config, *this);
   576 #endif
   578     if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
   579         // Assume an A8 bitmap is not opaque to avoid the check of each
   580         // individual pixel. It is very unlikely to be opaque, since
   581         // an opaque A8 bitmap would not be very interesting.
   582         // Otherwise, a jpeg image is opaque.
   583         return bm->setConfig(config, cinfo.image_width, cinfo.image_height, 0,
   584                              SkBitmap::kA8_Config == config ?
   585                                 kPremul_SkAlphaType : kOpaque_SkAlphaType);
   586     }
   588     /*  image_width and image_height are the original dimensions, available
   589         after jpeg_read_header(). To see the scaled dimensions, we have to call
   590         jpeg_start_decompress(), and then read output_width and output_height.
   591     */
   592     if (!jpeg_start_decompress(&cinfo)) {
   593         /*  If we failed here, we may still have enough information to return
   594             to the caller if they just wanted (subsampled bounds). If sampleSize
   595             was 1, then we would have already returned. Thus we just check if
   596             we're in kDecodeBounds_Mode, and that we have valid output sizes.
   598             One reason to fail here is that we have insufficient stream data
   599             to complete the setup. However, output dimensions seem to get
   600             computed very early, which is why this special check can pay off.
   601          */
   602         if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
   603             SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
   604                                        recompute_sampleSize(sampleSize, cinfo));
   605             // Assume an A8 bitmap is not opaque to avoid the check of each
   606             // individual pixel. It is very unlikely to be opaque, since
   607             // an opaque A8 bitmap would not be very interesting.
   608             // Otherwise, a jpeg image is opaque.
   609             return bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight(),
   610                                  0, SkBitmap::kA8_Config == config ?
   611                                     kPremul_SkAlphaType : kOpaque_SkAlphaType);
   612         } else {
   613             return return_false(cinfo, *bm, "start_decompress");
   614         }
   615     }
   616     sampleSize = recompute_sampleSize(sampleSize, cinfo);
   618     // should we allow the Chooser (if present) to pick a config for us???
   619     if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) {
   620         return return_false(cinfo, *bm, "chooseFromOneChoice");
   621     }
   623     SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
   624     // Assume an A8 bitmap is not opaque to avoid the check of each
   625     // individual pixel. It is very unlikely to be opaque, since
   626     // an opaque A8 bitmap would not be very interesting.
   627     // Otherwise, a jpeg image is opaque.
   628     bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
   629                   SkBitmap::kA8_Config != config ? kOpaque_SkAlphaType : kPremul_SkAlphaType);
   630     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
   631         return true;
   632     }
   633     if (!this->allocPixelRef(bm, NULL)) {
   634         return return_false(cinfo, *bm, "allocPixelRef");
   635     }
   637     SkAutoLockPixels alp(*bm);
   639 #ifdef ANDROID_RGB
   640     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
   641        a significant performance boost.
   642     */
   643     if (sampleSize == 1 &&
   644         ((config == SkBitmap::kARGB_8888_Config &&
   645                 cinfo.out_color_space == JCS_RGBA_8888) ||
   646         (config == SkBitmap::kRGB_565_Config &&
   647                 cinfo.out_color_space == JCS_RGB_565)))
   648     {
   649         JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
   650         INT32 const bpr =  bm->rowBytes();
   652         while (cinfo.output_scanline < cinfo.output_height) {
   653             int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
   654             if (0 == row_count) {
   655                 // if row_count == 0, then we didn't get a scanline,
   656                 // so return early.  We will return a partial image.
   657                 fill_below_level(cinfo.output_scanline, bm);
   658                 cinfo.output_scanline = cinfo.output_height;
   659                 break;  // Skip to jpeg_finish_decompress()
   660             }
   661             if (this->shouldCancelDecode()) {
   662                 return return_false(cinfo, *bm, "shouldCancelDecode");
   663             }
   664             rowptr += bpr;
   665         }
   666         jpeg_finish_decompress(&cinfo);
   667         return true;
   668     }
   669 #endif
   671     // check for supported formats
   672     SkScaledBitmapSampler::SrcConfig sc;
   673     int srcBytesPerPixel;
   675     if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
   676         return return_false(cinfo, *bm, "jpeg colorspace");
   677     }
   679     if (!sampler.begin(bm, sc, *this)) {
   680         return return_false(cinfo, *bm, "sampler.begin");
   681     }
   683     SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
   684     uint8_t* srcRow = (uint8_t*)srcStorage.get();
   686     //  Possibly skip initial rows [sampler.srcY0]
   687     if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
   688         return return_false(cinfo, *bm, "skip rows");
   689     }
   691     // now loop through scanlines until y == bm->height() - 1
   692     for (int y = 0;; y++) {
   693         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
   694         int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
   695         if (0 == row_count) {
   696             // if row_count == 0, then we didn't get a scanline,
   697             // so return early.  We will return a partial image.
   698             fill_below_level(y, bm);
   699             cinfo.output_scanline = cinfo.output_height;
   700             break;  // Skip to jpeg_finish_decompress()
   701         }
   702         if (this->shouldCancelDecode()) {
   703             return return_false(cinfo, *bm, "shouldCancelDecode");
   704         }
   706         if (JCS_CMYK == cinfo.out_color_space) {
   707             convert_CMYK_to_RGB(srcRow, cinfo.output_width);
   708         }
   710         sampler.next(srcRow);
   711         if (bm->height() - 1 == y) {
   712             // we're done
   713             break;
   714         }
   716         if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
   717             return return_false(cinfo, *bm, "skip rows");
   718         }
   719     }
   721     // we formally skip the rest, so we don't get a complaint from libjpeg
   722     if (!skip_src_rows(&cinfo, srcRow,
   723                        cinfo.output_height - cinfo.output_scanline)) {
   724         return return_false(cinfo, *bm, "skip rows");
   725     }
   726     jpeg_finish_decompress(&cinfo);
   728     return true;
   729 }
   731 #ifdef SK_BUILD_FOR_ANDROID
   732 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
   734     SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
   735     jpeg_decompress_struct* cinfo = imageIndex->cinfo();
   737     skjpeg_error_mgr sk_err;
   738     set_error_mgr(cinfo, &sk_err);
   740     // All objects need to be instantiated before this setjmp call so that
   741     // they will be cleaned up properly if an error occurs.
   742     if (setjmp(sk_err.fJmpBuf)) {
   743         return false;
   744     }
   746     // create the cinfo used to create/build the huffmanIndex
   747     if (!imageIndex->initializeInfoAndReadHeader()) {
   748         return false;
   749     }
   751     if (!imageIndex->buildHuffmanIndex()) {
   752         return false;
   753     }
   755     // destroy the cinfo used to create/build the huffman index
   756     imageIndex->destroyInfo();
   758     // Init decoder to image decode mode
   759     if (!imageIndex->initializeInfoAndReadHeader()) {
   760         return false;
   761     }
   763     // FIXME: This sets cinfo->out_color_space, which we may change later
   764     // based on the config in onDecodeSubset. This should be fine, since
   765     // jpeg_init_read_tile_scanline will check out_color_space again after
   766     // that change (when it calls jinit_color_deconverter).
   767     (void) this->getBitmapConfig(cinfo);
   769     turn_off_visual_optimizations(cinfo);
   771     // instead of jpeg_start_decompress() we start a tiled decompress
   772     if (!imageIndex->startTileDecompress()) {
   773         return false;
   774     }
   776     SkASSERT(1 == cinfo->scale_num);
   777     fImageWidth = cinfo->output_width;
   778     fImageHeight = cinfo->output_height;
   780     if (width) {
   781         *width = fImageWidth;
   782     }
   783     if (height) {
   784         *height = fImageHeight;
   785     }
   787     SkDELETE(fImageIndex);
   788     fImageIndex = imageIndex.detach();
   790     return true;
   791 }
   793 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
   794     if (NULL == fImageIndex) {
   795         return false;
   796     }
   797     jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
   799     SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
   800     if (!rect.intersect(region)) {
   801         // If the requested region is entirely outside the image return false
   802         return false;
   803     }
   806     skjpeg_error_mgr errorManager;
   807     set_error_mgr(cinfo, &errorManager);
   809     if (setjmp(errorManager.fJmpBuf)) {
   810         return false;
   811     }
   813     int requestedSampleSize = this->getSampleSize();
   814     cinfo->scale_denom = requestedSampleSize;
   816     set_dct_method(*this, cinfo);
   818     const SkBitmap::Config config = this->getBitmapConfig(cinfo);
   819 #ifdef ANDROID_RGB
   820     adjust_out_color_space_and_dither(cinfo, config, *this);
   821 #endif
   823     int startX = rect.fLeft;
   824     int startY = rect.fTop;
   825     int width = rect.width();
   826     int height = rect.height();
   828     jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
   829                                  &startX, &startY, &width, &height);
   830     int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
   831     int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
   833     SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
   835     SkBitmap bitmap;
   836     bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
   837     // Assume an A8 bitmap is not opaque to avoid the check of each
   838     // individual pixel. It is very unlikely to be opaque, since
   839     // an opaque A8 bitmap would not be very interesting.
   840     // Otherwise, a jpeg image is opaque.
   841     bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
   842                      config == SkBitmap::kA8_Config ? kPremul_SkAlphaType :
   843                      kOpaque_SkAlphaType);
   845     // Check ahead of time if the swap(dest, src) is possible or not.
   846     // If yes, then we will stick to AllocPixelRef since it's cheaper with the
   847     // swap happening. If no, then we will use alloc to allocate pixels to
   848     // prevent garbage collection.
   849     int w = rect.width() / actualSampleSize;
   850     int h = rect.height() / actualSampleSize;
   851     bool swapOnly = (rect == region) && bm->isNull() &&
   852                     (w == bitmap.width()) && (h == bitmap.height()) &&
   853                     ((startX - rect.x()) / actualSampleSize == 0) &&
   854                     ((startY - rect.y()) / actualSampleSize == 0);
   855     if (swapOnly) {
   856         if (!this->allocPixelRef(&bitmap, NULL)) {
   857             return return_false(*cinfo, bitmap, "allocPixelRef");
   858         }
   859     } else {
   860         if (!bitmap.allocPixels()) {
   861             return return_false(*cinfo, bitmap, "allocPixels");
   862         }
   863     }
   865     SkAutoLockPixels alp(bitmap);
   867 #ifdef ANDROID_RGB
   868     /* short-circuit the SkScaledBitmapSampler when possible, as this gives
   869        a significant performance boost.
   870     */
   871     if (skiaSampleSize == 1 &&
   872         ((config == SkBitmap::kARGB_8888_Config &&
   873                 cinfo->out_color_space == JCS_RGBA_8888) ||
   874         (config == SkBitmap::kRGB_565_Config &&
   875                 cinfo->out_color_space == JCS_RGB_565)))
   876     {
   877         JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
   878         INT32 const bpr = bitmap.rowBytes();
   879         int rowTotalCount = 0;
   881         while (rowTotalCount < height) {
   882             int rowCount = jpeg_read_tile_scanline(cinfo,
   883                                                    fImageIndex->huffmanIndex(),
   884                                                    &rowptr);
   885             // if rowCount == 0, then we didn't get a scanline, so abort.
   886             // onDecodeSubset() relies on onBuildTileIndex(), which
   887             // needs a complete image to succeed.
   888             if (0 == rowCount) {
   889                 return return_false(*cinfo, bitmap, "read_scanlines");
   890             }
   891             if (this->shouldCancelDecode()) {
   892                 return return_false(*cinfo, bitmap, "shouldCancelDecode");
   893             }
   894             rowTotalCount += rowCount;
   895             rowptr += bpr;
   896         }
   898         if (swapOnly) {
   899             bm->swap(bitmap);
   900         } else {
   901             cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
   902                        region.width(), region.height(), startX, startY);
   903         }
   904         return true;
   905     }
   906 #endif
   908     // check for supported formats
   909     SkScaledBitmapSampler::SrcConfig sc;
   910     int srcBytesPerPixel;
   912     if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
   913         return return_false(*cinfo, *bm, "jpeg colorspace");
   914     }
   916     if (!sampler.begin(&bitmap, sc, *this)) {
   917         return return_false(*cinfo, bitmap, "sampler.begin");
   918     }
   920     SkAutoMalloc  srcStorage(width * srcBytesPerPixel);
   921     uint8_t* srcRow = (uint8_t*)srcStorage.get();
   923     //  Possibly skip initial rows [sampler.srcY0]
   924     if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
   925         return return_false(*cinfo, bitmap, "skip rows");
   926     }
   928     // now loop through scanlines until y == bitmap->height() - 1
   929     for (int y = 0;; y++) {
   930         JSAMPLE* rowptr = (JSAMPLE*)srcRow;
   931         int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
   932         // if row_count == 0, then we didn't get a scanline, so abort.
   933         // onDecodeSubset() relies on onBuildTileIndex(), which
   934         // needs a complete image to succeed.
   935         if (0 == row_count) {
   936             return return_false(*cinfo, bitmap, "read_scanlines");
   937         }
   938         if (this->shouldCancelDecode()) {
   939             return return_false(*cinfo, bitmap, "shouldCancelDecode");
   940         }
   942         if (JCS_CMYK == cinfo->out_color_space) {
   943             convert_CMYK_to_RGB(srcRow, width);
   944         }
   946         sampler.next(srcRow);
   947         if (bitmap.height() - 1 == y) {
   948             // we're done
   949             break;
   950         }
   952         if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
   953                                 sampler.srcDY() - 1)) {
   954             return return_false(*cinfo, bitmap, "skip rows");
   955         }
   956     }
   957     if (swapOnly) {
   958         bm->swap(bitmap);
   959     } else {
   960         cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
   961                    region.width(), region.height(), startX, startY);
   962     }
   963     return true;
   964 }
   965 #endif
   967 ///////////////////////////////////////////////////////////////////////////////
   969 #include "SkColorPriv.h"
   971 // taken from jcolor.c in libjpeg
   972 #if 0   // 16bit - precise but slow
   973     #define CYR     19595   // 0.299
   974     #define CYG     38470   // 0.587
   975     #define CYB      7471   // 0.114
   977     #define CUR    -11059   // -0.16874
   978     #define CUG    -21709   // -0.33126
   979     #define CUB     32768   // 0.5
   981     #define CVR     32768   // 0.5
   982     #define CVG    -27439   // -0.41869
   983     #define CVB     -5329   // -0.08131
   985     #define CSHIFT  16
   986 #else      // 8bit - fast, slightly less precise
   987     #define CYR     77    // 0.299
   988     #define CYG     150    // 0.587
   989     #define CYB      29    // 0.114
   991     #define CUR     -43    // -0.16874
   992     #define CUG    -85    // -0.33126
   993     #define CUB     128    // 0.5
   995     #define CVR      128   // 0.5
   996     #define CVG     -107   // -0.41869
   997     #define CVB      -21   // -0.08131
   999     #define CSHIFT  8
  1000 #endif
  1002 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
  1003     int r = SkGetPackedR32(c);
  1004     int g = SkGetPackedG32(c);
  1005     int b = SkGetPackedB32(c);
  1007     int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
  1008     int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
  1009     int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
  1011     dst[0] = SkToU8(y);
  1012     dst[1] = SkToU8(u + 128);
  1013     dst[2] = SkToU8(v + 128);
  1016 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
  1017     int r = SkGetPackedR4444(c);
  1018     int g = SkGetPackedG4444(c);
  1019     int b = SkGetPackedB4444(c);
  1021     int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
  1022     int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
  1023     int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
  1025     dst[0] = SkToU8(y);
  1026     dst[1] = SkToU8(u + 128);
  1027     dst[2] = SkToU8(v + 128);
  1030 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
  1031     int r = SkGetPackedR16(c);
  1032     int g = SkGetPackedG16(c);
  1033     int b = SkGetPackedB16(c);
  1035     int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
  1036     int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
  1037     int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
  1039     dst[0] = SkToU8(y);
  1040     dst[1] = SkToU8(u + 128);
  1041     dst[2] = SkToU8(v + 128);
  1044 ///////////////////////////////////////////////////////////////////////////////
  1046 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
  1047                               const void* SK_RESTRICT src, int width,
  1048                               const SkPMColor* SK_RESTRICT ctable);
  1050 static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
  1051                          const void* SK_RESTRICT srcRow, int width,
  1052                          const SkPMColor*) {
  1053     const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
  1054     while (--width >= 0) {
  1055 #ifdef WE_CONVERT_TO_YUV
  1056         rgb2yuv_32(dst, *src++);
  1057 #else
  1058         uint32_t c = *src++;
  1059         dst[0] = SkGetPackedR32(c);
  1060         dst[1] = SkGetPackedG32(c);
  1061         dst[2] = SkGetPackedB32(c);
  1062 #endif
  1063         dst += 3;
  1067 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
  1068                            const void* SK_RESTRICT srcRow, int width,
  1069                            const SkPMColor*) {
  1070     const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
  1071     while (--width >= 0) {
  1072 #ifdef WE_CONVERT_TO_YUV
  1073         rgb2yuv_4444(dst, *src++);
  1074 #else
  1075         SkPMColor16 c = *src++;
  1076         dst[0] = SkPacked4444ToR32(c);
  1077         dst[1] = SkPacked4444ToG32(c);
  1078         dst[2] = SkPacked4444ToB32(c);
  1079 #endif
  1080         dst += 3;
  1084 static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
  1085                          const void* SK_RESTRICT srcRow, int width,
  1086                          const SkPMColor*) {
  1087     const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
  1088     while (--width >= 0) {
  1089 #ifdef WE_CONVERT_TO_YUV
  1090         rgb2yuv_16(dst, *src++);
  1091 #else
  1092         uint16_t c = *src++;
  1093         dst[0] = SkPacked16ToR32(c);
  1094         dst[1] = SkPacked16ToG32(c);
  1095         dst[2] = SkPacked16ToB32(c);
  1096 #endif
  1097         dst += 3;
  1101 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
  1102                             const void* SK_RESTRICT srcRow, int width,
  1103                             const SkPMColor* SK_RESTRICT ctable) {
  1104     const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
  1105     while (--width >= 0) {
  1106 #ifdef WE_CONVERT_TO_YUV
  1107         rgb2yuv_32(dst, ctable[*src++]);
  1108 #else
  1109         uint32_t c = ctable[*src++];
  1110         dst[0] = SkGetPackedR32(c);
  1111         dst[1] = SkGetPackedG32(c);
  1112         dst[2] = SkGetPackedB32(c);
  1113 #endif
  1114         dst += 3;
  1118 static WriteScanline ChooseWriter(const SkBitmap& bm) {
  1119     switch (bm.config()) {
  1120         case SkBitmap::kARGB_8888_Config:
  1121             return Write_32_YUV;
  1122         case SkBitmap::kRGB_565_Config:
  1123             return Write_16_YUV;
  1124         case SkBitmap::kARGB_4444_Config:
  1125             return Write_4444_YUV;
  1126         case SkBitmap::kIndex8_Config:
  1127             return Write_Index_YUV;
  1128         default:
  1129             return NULL;
  1133 class SkJPEGImageEncoder : public SkImageEncoder {
  1134 protected:
  1135     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
  1136 #ifdef TIME_ENCODE
  1137         SkAutoTime atm("JPEG Encode");
  1138 #endif
  1140         SkAutoLockPixels alp(bm);
  1141         if (NULL == bm.getPixels()) {
  1142             return false;
  1145         jpeg_compress_struct    cinfo;
  1146         skjpeg_error_mgr        sk_err;
  1147         skjpeg_destination_mgr  sk_wstream(stream);
  1149         // allocate these before set call setjmp
  1150         SkAutoMalloc    oneRow;
  1151         SkAutoLockColors ctLocker;
  1153         cinfo.err = jpeg_std_error(&sk_err);
  1154         sk_err.error_exit = skjpeg_error_exit;
  1155         if (setjmp(sk_err.fJmpBuf)) {
  1156             return false;
  1159         // Keep after setjmp or mark volatile.
  1160         const WriteScanline writer = ChooseWriter(bm);
  1161         if (NULL == writer) {
  1162             return false;
  1165         jpeg_create_compress(&cinfo);
  1166         cinfo.dest = &sk_wstream;
  1167         cinfo.image_width = bm.width();
  1168         cinfo.image_height = bm.height();
  1169         cinfo.input_components = 3;
  1170 #ifdef WE_CONVERT_TO_YUV
  1171         cinfo.in_color_space = JCS_YCbCr;
  1172 #else
  1173         cinfo.in_color_space = JCS_RGB;
  1174 #endif
  1175         cinfo.input_gamma = 1;
  1177         jpeg_set_defaults(&cinfo);
  1178         jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
  1179 #ifdef DCT_IFAST_SUPPORTED
  1180         cinfo.dct_method = JDCT_IFAST;
  1181 #endif
  1183         jpeg_start_compress(&cinfo, TRUE);
  1185         const int       width = bm.width();
  1186         uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
  1188         const SkPMColor* colors = ctLocker.lockColors(bm);
  1189         const void*      srcRow = bm.getPixels();
  1191         while (cinfo.next_scanline < cinfo.image_height) {
  1192             JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
  1194             writer(oneRowP, srcRow, width, colors);
  1195             row_pointer[0] = oneRowP;
  1196             (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
  1197             srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
  1200         jpeg_finish_compress(&cinfo);
  1201         jpeg_destroy_compress(&cinfo);
  1203         return true;
  1205 };
  1207 ///////////////////////////////////////////////////////////////////////////////
  1208 DEFINE_DECODER_CREATOR(JPEGImageDecoder);
  1209 DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
  1210 ///////////////////////////////////////////////////////////////////////////////
  1212 static bool is_jpeg(SkStreamRewindable* stream) {
  1213     static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
  1214     static const size_t HEADER_SIZE = sizeof(gHeader);
  1216     char buffer[HEADER_SIZE];
  1217     size_t len = stream->read(buffer, HEADER_SIZE);
  1219     if (len != HEADER_SIZE) {
  1220         return false;   // can't read enough
  1222     if (memcmp(buffer, gHeader, HEADER_SIZE)) {
  1223         return false;
  1225     return true;
  1229 static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
  1230     if (is_jpeg(stream)) {
  1231         return SkNEW(SkJPEGImageDecoder);
  1233     return NULL;
  1236 static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
  1237     if (is_jpeg(stream)) {
  1238         return SkImageDecoder::kJPEG_Format;
  1240     return SkImageDecoder::kUnknown_Format;
  1243 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
  1244     return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
  1247 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
  1248 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
  1249 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);

mercurial