2 * Copyright 2007 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "SkImageDecoder.h"
10 #include "SkImageEncoder.h"
11 #include "SkJpegUtility.h"
12 #include "SkColorPriv.h"
14 #include "SkScaledBitmapSampler.h"
16 #include "SkTemplates.h"
30 // These enable timing code that report milliseconds for an encoding/decoding
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.
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 "
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.
65 #ifdef ANDROID_LARGE_MEMORY_DEVICE
66 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
68 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
70 #endif // SK_BUILD_FOR_ANDROID
73 //////////////////////////////////////////////////////////////////////////
74 //////////////////////////////////////////////////////////////////////////
76 static void do_nothing_emit_message(jpeg_common_struct*, int) {
79 static void do_nothing_output_message(j_common_ptr) {
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);
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;
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;
105 #ifdef SK_BUILD_FOR_ANDROID
106 class SkJPEGImageIndex {
108 SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
109 : fSrcMgr(stream, decoder)
110 , fInfoInitialized(false)
111 , fHuffmanCreated(false)
112 , fDecompressStarted(false)
114 SkDEBUGCODE(fReadHeaderSucceeded = false;)
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);
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);
133 if (fInfoInitialized) {
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
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;)
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.
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;)
172 jpeg_decompress_struct* cinfo() { return &fCInfo; }
174 huffman_index* huffmanIndex() { return &fHuffmanIndex; }
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
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;
192 * Start tile based decoding. Must only be called after a
193 * successful call to buildHuffmanIndex, and must only be
196 bool startTileDecompress() {
197 SkASSERT(fHuffmanCreated);
198 SkASSERT(fReadHeaderSucceeded);
199 SkASSERT(!fDecompressStarted);
200 if (jpeg_start_tile_decompress(&fCInfo)) {
201 fDecompressStarted = true;
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;)
218 class SkJPEGImageDecoder : public SkImageDecoder {
220 #ifdef SK_BUILD_FOR_ANDROID
221 SkJPEGImageDecoder() {
227 virtual ~SkJPEGImageDecoder() {
228 SkDELETE(fImageIndex);
232 virtual Format getFormat() const {
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;
241 virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
242 virtual bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
243 void* planes[3], size_t rowBytes[3],
244 SkYUVColorSpace* colorSpace) SK_OVERRIDE;
247 #ifdef SK_BUILD_FOR_ANDROID
248 SkJPEGImageIndex* fImageIndex;
254 * Determine the appropriate bitmap colortype and out_color_space based on
255 * both the preference of the caller and the jpeg_color_space on the
256 * jpeg_decompress_struct passed in.
257 * Must be called after jpeg_read_header.
259 SkColorType getBitmapColorType(jpeg_decompress_struct*);
261 typedef SkImageDecoder INHERITED;
264 //////////////////////////////////////////////////////////////////////////
266 /* Automatically clean up after throwing an exception */
267 class JPEGAutoClean {
269 JPEGAutoClean(): cinfo_ptr(NULL) {}
272 jpeg_destroy_decompress(cinfo_ptr);
275 void set(jpeg_decompress_struct* info) {
279 jpeg_decompress_struct* cinfo_ptr;
282 ///////////////////////////////////////////////////////////////////////////////
284 /* If we need to better match the request, we might examine the image and
285 output dimensions, and determine if the downsampling jpeg provided is
286 not sufficient. If so, we can recompute a modified sampleSize value to
287 make up the difference.
289 To skip this additional scaling, just set sampleSize = 1; below.
291 static int recompute_sampleSize(int sampleSize,
292 const jpeg_decompress_struct& cinfo) {
293 return sampleSize * cinfo.output_width / cinfo.image_width;
296 static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
297 /* These are initialized to 0, so if they have non-zero values, we assume
298 they are "valid" (i.e. have been computed by libjpeg)
300 return 0 != cinfo.output_width && 0 != cinfo.output_height;
303 static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
304 for (int i = 0; i < count; i++) {
305 JSAMPLE* rowptr = (JSAMPLE*)buffer;
306 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
307 if (1 != row_count) {
314 #ifdef SK_BUILD_FOR_ANDROID
315 static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
316 huffman_index *index, void* buffer, int count) {
317 for (int i = 0; i < count; i++) {
318 JSAMPLE* rowptr = (JSAMPLE*)buffer;
319 int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
320 if (1 != row_count) {
328 ///////////////////////////////////////////////////////////////////////////////
330 // This guy exists just to aid in debugging, as it allows debuggers to just
331 // set a break-point in one place to see all error exists.
332 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo,
333 int width, int height, const char caller[]) {
334 if (!(c_suppressJPEGImageDecoderErrors)) {
335 char buffer[JMSG_LENGTH_MAX];
336 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
337 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
338 cinfo.err->msg_code, buffer, caller, width, height);
342 static bool return_false(const jpeg_decompress_struct& cinfo,
343 const char caller[]) {
344 print_jpeg_decoder_errors(cinfo, 0, 0, caller);
348 #ifdef SK_BUILD_FOR_ANDROID
349 static bool return_false(const jpeg_decompress_struct& cinfo,
350 const SkBitmap& bm, const char caller[]) {
351 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
356 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo,
357 const SkBitmap& bm, const char caller[]) {
358 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
359 return SkImageDecoder::kFailure;
362 ///////////////////////////////////////////////////////////////////////////////
364 // Convert a scanline of CMYK samples to RGBX in place. Note that this
365 // method moves the "scanline" pointer in its processing
366 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
367 // At this point we've received CMYK pixels from libjpeg. We
368 // perform a crude conversion to RGB (based on the formulae
369 // from easyrgb.com):
371 // C = ( C * (1 - K) + K ) // for each CMY component
373 // R = ( 1 - C ) * 255 // for each RGB component
374 // Unfortunately we are seeing inverted CMYK so all the original terms
375 // are 1-. This yields:
377 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
378 // The conversion from CMY->RGB remains the same
379 for (unsigned int x = 0; x < width; ++x, scanline += 4) {
380 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
381 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
382 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
388 * Common code for setting the error manager.
390 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
391 SkASSERT(cinfo != NULL);
392 SkASSERT(errorManager != NULL);
393 cinfo->err = jpeg_std_error(errorManager);
394 errorManager->error_exit = skjpeg_error_exit;
398 * Common code for turning off upsampling and smoothing. Turning these
399 * off helps performance without showing noticable differences in the
402 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) {
403 SkASSERT(cinfo != NULL);
404 /* this gives about 30% performance improvement. In theory it may
405 reduce the visual quality, in practice I'm not seeing a difference
407 cinfo->do_fancy_upsampling = 0;
409 /* this gives another few percents */
410 cinfo->do_block_smoothing = 0;
414 * Common code for setting the dct method.
416 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
417 SkASSERT(cinfo != NULL);
418 #ifdef DCT_IFAST_SUPPORTED
419 if (decoder.getPreferQualityOverSpeed()) {
420 cinfo->dct_method = JDCT_ISLOW;
422 cinfo->dct_method = JDCT_IFAST;
425 cinfo->dct_method = JDCT_ISLOW;
429 SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
430 SkASSERT(cinfo != NULL);
432 SrcDepth srcDepth = k32Bit_SrcDepth;
433 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
434 srcDepth = k8BitGray_SrcDepth;
437 SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
439 case kAlpha_8_SkColorType:
440 // Only respect A8 colortype if the original is grayscale,
441 // in which case we will treat the grayscale as alpha
443 if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
444 colorType = kN32_SkColorType;
447 case kN32_SkColorType:
449 case kARGB_4444_SkColorType:
451 case kRGB_565_SkColorType:
452 // These are acceptable destination colortypes.
455 // Force all other colortypes to 8888.
456 colorType = kN32_SkColorType;
460 switch (cinfo->jpeg_color_space) {
464 // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
465 // so libjpeg will give us CMYK samples back and we will later
466 // manually convert them to RGB
467 cinfo->out_color_space = JCS_CMYK;
470 if (kAlpha_8_SkColorType == colorType) {
471 cinfo->out_color_space = JCS_GRAYSCALE;
474 // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
475 // colortype. Fall through to set to the default.
477 cinfo->out_color_space = JCS_RGB;
484 * Based on the colortype and dither mode, adjust out_color_space and
485 * dither_mode of cinfo. Only does work in ANDROID_RGB
487 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
488 SkColorType colorType,
489 const SkImageDecoder& decoder) {
490 SkASSERT(cinfo != NULL);
492 cinfo->dither_mode = JDITHER_NONE;
493 if (JCS_CMYK == cinfo->out_color_space) {
497 case kN32_SkColorType:
498 cinfo->out_color_space = JCS_RGBA_8888;
500 case kRGB_565_SkColorType:
501 cinfo->out_color_space = JCS_RGB_565;
502 if (decoder.getDitherImage()) {
503 cinfo->dither_mode = JDITHER_ORDERED;
513 Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
514 Used when decoding fails partway through reading scanlines to fill
516 static void fill_below_level(int y, SkBitmap* bitmap) {
517 SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
518 SkCanvas canvas(*bitmap);
519 canvas.clipRect(SkRect::Make(rect));
520 canvas.drawColor(SK_ColorWHITE);
524 * Get the config and bytes per pixel of the source data. Return
525 * whether the data is supported.
527 static bool get_src_config(const jpeg_decompress_struct& cinfo,
528 SkScaledBitmapSampler::SrcConfig* sc,
529 int* srcBytesPerPixel) {
530 SkASSERT(sc != NULL && srcBytesPerPixel != NULL);
531 if (JCS_CMYK == cinfo.out_color_space) {
532 // In this case we will manually convert the CMYK values to RGB
533 *sc = SkScaledBitmapSampler::kRGBX;
534 // The CMYK work-around relies on 4 components per pixel here
535 *srcBytesPerPixel = 4;
536 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
537 *sc = SkScaledBitmapSampler::kRGB;
538 *srcBytesPerPixel = 3;
540 } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
541 *sc = SkScaledBitmapSampler::kRGBX;
542 *srcBytesPerPixel = 4;
543 } else if (JCS_RGB_565 == cinfo.out_color_space) {
544 *sc = SkScaledBitmapSampler::kRGB_565;
545 *srcBytesPerPixel = 2;
547 } else if (1 == cinfo.out_color_components &&
548 JCS_GRAYSCALE == cinfo.out_color_space) {
549 *sc = SkScaledBitmapSampler::kGray;
550 *srcBytesPerPixel = 1;
557 SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
559 SkAutoTime atm("JPEG Decode");
562 JPEGAutoClean autoClean;
564 jpeg_decompress_struct cinfo;
565 skjpeg_source_mgr srcManager(stream, this);
567 skjpeg_error_mgr errorManager;
568 set_error_mgr(&cinfo, &errorManager);
570 // All objects need to be instantiated before this setjmp call so that
571 // they will be cleaned up properly if an error occurs.
572 if (setjmp(errorManager.fJmpBuf)) {
573 return return_failure(cinfo, *bm, "setjmp");
576 initialize_info(&cinfo, &srcManager);
577 autoClean.set(&cinfo);
579 int status = jpeg_read_header(&cinfo, true);
580 if (status != JPEG_HEADER_OK) {
581 return return_failure(cinfo, *bm, "read_header");
584 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it
585 can) much faster that we, just use their num/denom api to approximate
588 int sampleSize = this->getSampleSize();
590 set_dct_method(*this, &cinfo);
592 SkASSERT(1 == cinfo.scale_num);
593 cinfo.scale_denom = sampleSize;
595 turn_off_visual_optimizations(&cinfo);
597 const SkColorType colorType = this->getBitmapColorType(&cinfo);
598 const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
599 kPremul_SkAlphaType : kOpaque_SkAlphaType;
601 adjust_out_color_space_and_dither(&cinfo, colorType, *this);
603 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
604 // Assume an A8 bitmap is not opaque to avoid the check of each
605 // individual pixel. It is very unlikely to be opaque, since
606 // an opaque A8 bitmap would not be very interesting.
607 // Otherwise, a jpeg image is opaque.
608 bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
609 colorType, alphaType));
610 return success ? kSuccess : kFailure;
613 /* image_width and image_height are the original dimensions, available
614 after jpeg_read_header(). To see the scaled dimensions, we have to call
615 jpeg_start_decompress(), and then read output_width and output_height.
617 if (!jpeg_start_decompress(&cinfo)) {
618 /* If we failed here, we may still have enough information to return
619 to the caller if they just wanted (subsampled bounds). If sampleSize
620 was 1, then we would have already returned. Thus we just check if
621 we're in kDecodeBounds_Mode, and that we have valid output sizes.
623 One reason to fail here is that we have insufficient stream data
624 to complete the setup. However, output dimensions seem to get
625 computed very early, which is why this special check can pay off.
627 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
628 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
629 recompute_sampleSize(sampleSize, cinfo));
630 // Assume an A8 bitmap is not opaque to avoid the check of each
631 // individual pixel. It is very unlikely to be opaque, since
632 // an opaque A8 bitmap would not be very interesting.
633 // Otherwise, a jpeg image is opaque.
634 bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
635 colorType, alphaType));
636 return success ? kSuccess : kFailure;
638 return return_failure(cinfo, *bm, "start_decompress");
641 sampleSize = recompute_sampleSize(sampleSize, cinfo);
643 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
644 // should we allow the Chooser (if present) to pick a colortype for us???
645 if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) {
646 return return_failure(cinfo, *bm, "chooseFromOneChoice");
650 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
651 // Assume an A8 bitmap is not opaque to avoid the check of each
652 // individual pixel. It is very unlikely to be opaque, since
653 // an opaque A8 bitmap would not be very interesting.
654 // Otherwise, a jpeg image is opaque.
655 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
656 colorType, alphaType));
657 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
660 if (!this->allocPixelRef(bm, NULL)) {
661 return return_failure(cinfo, *bm, "allocPixelRef");
664 SkAutoLockPixels alp(*bm);
667 /* short-circuit the SkScaledBitmapSampler when possible, as this gives
668 a significant performance boost.
670 if (sampleSize == 1 &&
671 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
672 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
674 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
675 INT32 const bpr = bm->rowBytes();
677 while (cinfo.output_scanline < cinfo.output_height) {
678 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
679 if (0 == row_count) {
680 // if row_count == 0, then we didn't get a scanline,
681 // so return early. We will return a partial image.
682 fill_below_level(cinfo.output_scanline, bm);
683 cinfo.output_scanline = cinfo.output_height;
684 jpeg_finish_decompress(&cinfo);
685 return kPartialSuccess;
687 if (this->shouldCancelDecode()) {
688 return return_failure(cinfo, *bm, "shouldCancelDecode");
692 jpeg_finish_decompress(&cinfo);
697 // check for supported formats
698 SkScaledBitmapSampler::SrcConfig sc;
699 int srcBytesPerPixel;
701 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
702 return return_failure(cinfo, *bm, "jpeg colorspace");
705 if (!sampler.begin(bm, sc, *this)) {
706 return return_failure(cinfo, *bm, "sampler.begin");
709 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
710 uint8_t* srcRow = (uint8_t*)srcStorage.get();
712 // Possibly skip initial rows [sampler.srcY0]
713 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
714 return return_failure(cinfo, *bm, "skip rows");
717 // now loop through scanlines until y == bm->height() - 1
718 for (int y = 0;; y++) {
719 JSAMPLE* rowptr = (JSAMPLE*)srcRow;
720 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
721 if (0 == row_count) {
722 // if row_count == 0, then we didn't get a scanline,
723 // so return early. We will return a partial image.
724 fill_below_level(y, bm);
725 cinfo.output_scanline = cinfo.output_height;
726 jpeg_finish_decompress(&cinfo);
729 if (this->shouldCancelDecode()) {
730 return return_failure(cinfo, *bm, "shouldCancelDecode");
733 if (JCS_CMYK == cinfo.out_color_space) {
734 convert_CMYK_to_RGB(srcRow, cinfo.output_width);
737 sampler.next(srcRow);
738 if (bm->height() - 1 == y) {
743 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
744 return return_failure(cinfo, *bm, "skip rows");
748 // we formally skip the rest, so we don't get a complaint from libjpeg
749 if (!skip_src_rows(&cinfo, srcRow,
750 cinfo.output_height - cinfo.output_scanline)) {
751 return return_failure(cinfo, *bm, "skip rows");
753 jpeg_finish_decompress(&cinfo);
758 ///////////////////////////////////////////////////////////////////////////////
761 kSizeForMemoryAllocation_SizeType,
765 static SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
767 if (sizeType == kSizeForMemoryAllocation_SizeType) {
768 return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
769 info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
771 return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
772 info.cur_comp_info[component]->downsampled_height);
775 static void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
777 for (int i = 0; i < 3; ++i) {
778 componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
782 static bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
783 // U size and V size have to be the same if we're calling output_raw_data()
784 SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
785 SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
787 JSAMPARRAY bufferraw[3];
788 JSAMPROW bufferraw2[32];
789 bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
790 bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
791 bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
792 int yWidth = cinfo.output_width;
793 int yHeight = cinfo.output_height;
794 int yMaxH = yHeight - 1;
795 int v = cinfo.cur_comp_info[0]->v_samp_factor;
796 int uvMaxH = uvSize.height() - 1;
797 JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
798 JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
799 JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
800 size_t rowBytesY = rowBytes[0];
801 size_t rowBytesU = rowBytes[1];
802 size_t rowBytesV = rowBytes[2];
804 int yScanlinesToRead = DCTSIZE * v;
805 SkAutoMalloc lastRowStorage(yWidth * 8);
806 JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
807 JSAMPROW uLastRow = yLastRow + 2 * yWidth;
808 JSAMPROW vLastRow = uLastRow + 2 * yWidth;
809 JSAMPROW dummyRow = vLastRow + 2 * yWidth;
811 while (cinfo.output_scanline < cinfo.output_height) {
812 // Request 8 or 16 scanlines: returns 0 or more scanlines.
813 bool hasYLastRow(false), hasUVLastRow(false);
814 // Assign 8 or 16 rows of memory to read the Y channel.
815 for (int i = 0; i < yScanlinesToRead; ++i) {
816 int scanline = (cinfo.output_scanline + i);
817 if (scanline < yMaxH) {
818 bufferraw2[i] = &outputY[scanline * rowBytesY];
819 } else if (scanline == yMaxH) {
820 bufferraw2[i] = yLastRow;
823 bufferraw2[i] = dummyRow;
826 int scaledScanline = cinfo.output_scanline / v;
827 // Assign 8 rows of memory to read the U and V channels.
828 for (int i = 0; i < 8; ++i) {
829 int scanline = (scaledScanline + i);
830 if (scanline < uvMaxH) {
831 bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
832 bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
833 } else if (scanline == uvMaxH) {
834 bufferraw2[16 + i] = uLastRow;
835 bufferraw2[24 + i] = vLastRow;
838 bufferraw2[16 + i] = dummyRow;
839 bufferraw2[24 + i] = dummyRow;
842 JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
844 if (scanlinesRead == 0) {
849 memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
852 memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
853 memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
857 cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
862 bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
863 void* planes[3], size_t rowBytes[3],
864 SkYUVColorSpace* colorSpace) {
866 SkAutoTime atm("JPEG YUV8 Decode");
869 if (this->getSampleSize() != 1) {
870 return false; // Resizing not supported
873 JPEGAutoClean autoClean;
875 jpeg_decompress_struct cinfo;
876 skjpeg_source_mgr srcManager(stream, this);
878 skjpeg_error_mgr errorManager;
879 set_error_mgr(&cinfo, &errorManager);
881 // All objects need to be instantiated before this setjmp call so that
882 // they will be cleaned up properly if an error occurs.
883 if (setjmp(errorManager.fJmpBuf)) {
884 return return_false(cinfo, "setjmp YUV8");
887 initialize_info(&cinfo, &srcManager);
888 autoClean.set(&cinfo);
890 int status = jpeg_read_header(&cinfo, true);
891 if (status != JPEG_HEADER_OK) {
892 return return_false(cinfo, "read_header YUV8");
895 if (cinfo.jpeg_color_space != JCS_YCbCr) {
896 // It's not an error to not be encoded in YUV, so no need to use return_false()
900 cinfo.out_color_space = JCS_YCbCr;
901 cinfo.raw_data_out = TRUE;
903 if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
904 update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
908 set_dct_method(*this, &cinfo);
910 SkASSERT(1 == cinfo.scale_num);
911 cinfo.scale_denom = 1;
913 turn_off_visual_optimizations(&cinfo);
916 cinfo.dither_mode = JDITHER_NONE;
919 /* image_width and image_height are the original dimensions, available
920 after jpeg_read_header(). To see the scaled dimensions, we have to call
921 jpeg_start_decompress(), and then read output_width and output_height.
923 if (!jpeg_start_decompress(&cinfo)) {
924 return return_false(cinfo, "start_decompress YUV8");
927 if (!output_raw_data(cinfo, planes, rowBytes)) {
928 return return_false(cinfo, "output_raw_data");
931 update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
932 jpeg_finish_decompress(&cinfo);
934 if (NULL != colorSpace) {
935 *colorSpace = kJPEG_SkYUVColorSpace;
941 ///////////////////////////////////////////////////////////////////////////////
943 #ifdef SK_BUILD_FOR_ANDROID
944 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
946 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
947 jpeg_decompress_struct* cinfo = imageIndex->cinfo();
949 skjpeg_error_mgr sk_err;
950 set_error_mgr(cinfo, &sk_err);
952 // All objects need to be instantiated before this setjmp call so that
953 // they will be cleaned up properly if an error occurs.
954 if (setjmp(sk_err.fJmpBuf)) {
958 // create the cinfo used to create/build the huffmanIndex
959 if (!imageIndex->initializeInfoAndReadHeader()) {
963 if (!imageIndex->buildHuffmanIndex()) {
967 // destroy the cinfo used to create/build the huffman index
968 imageIndex->destroyInfo();
970 // Init decoder to image decode mode
971 if (!imageIndex->initializeInfoAndReadHeader()) {
975 // FIXME: This sets cinfo->out_color_space, which we may change later
976 // based on the config in onDecodeSubset. This should be fine, since
977 // jpeg_init_read_tile_scanline will check out_color_space again after
978 // that change (when it calls jinit_color_deconverter).
979 (void) this->getBitmapColorType(cinfo);
981 turn_off_visual_optimizations(cinfo);
983 // instead of jpeg_start_decompress() we start a tiled decompress
984 if (!imageIndex->startTileDecompress()) {
988 SkASSERT(1 == cinfo->scale_num);
989 fImageWidth = cinfo->output_width;
990 fImageHeight = cinfo->output_height;
993 *width = fImageWidth;
996 *height = fImageHeight;
999 SkDELETE(fImageIndex);
1000 fImageIndex = imageIndex.detach();
1005 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
1006 if (NULL == fImageIndex) {
1009 jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
1011 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
1012 if (!rect.intersect(region)) {
1013 // If the requested region is entirely outside the image return false
1018 skjpeg_error_mgr errorManager;
1019 set_error_mgr(cinfo, &errorManager);
1021 if (setjmp(errorManager.fJmpBuf)) {
1025 int requestedSampleSize = this->getSampleSize();
1026 cinfo->scale_denom = requestedSampleSize;
1028 set_dct_method(*this, cinfo);
1030 const SkColorType colorType = this->getBitmapColorType(cinfo);
1031 adjust_out_color_space_and_dither(cinfo, colorType, *this);
1033 int startX = rect.fLeft;
1034 int startY = rect.fTop;
1035 int width = rect.width();
1036 int height = rect.height();
1038 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
1039 &startX, &startY, &width, &height);
1040 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
1041 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
1043 SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
1046 // Assume an A8 bitmap is not opaque to avoid the check of each
1047 // individual pixel. It is very unlikely to be opaque, since
1048 // an opaque A8 bitmap would not be very interesting.
1049 // Otherwise, a jpeg image is opaque.
1050 bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType,
1051 kAlpha_8_SkColorType == colorType ?
1052 kPremul_SkAlphaType : kOpaque_SkAlphaType));
1054 // Check ahead of time if the swap(dest, src) is possible or not.
1055 // If yes, then we will stick to AllocPixelRef since it's cheaper with the
1056 // swap happening. If no, then we will use alloc to allocate pixels to
1057 // prevent garbage collection.
1058 int w = rect.width() / actualSampleSize;
1059 int h = rect.height() / actualSampleSize;
1060 bool swapOnly = (rect == region) && bm->isNull() &&
1061 (w == bitmap.width()) && (h == bitmap.height()) &&
1062 ((startX - rect.x()) / actualSampleSize == 0) &&
1063 ((startY - rect.y()) / actualSampleSize == 0);
1065 if (!this->allocPixelRef(&bitmap, NULL)) {
1066 return return_false(*cinfo, bitmap, "allocPixelRef");
1069 if (!bitmap.tryAllocPixels()) {
1070 return return_false(*cinfo, bitmap, "allocPixels");
1074 SkAutoLockPixels alp(bitmap);
1077 /* short-circuit the SkScaledBitmapSampler when possible, as this gives
1078 a significant performance boost.
1080 if (skiaSampleSize == 1 &&
1081 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) ||
1082 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565)))
1084 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
1085 INT32 const bpr = bitmap.rowBytes();
1086 int rowTotalCount = 0;
1088 while (rowTotalCount < height) {
1089 int rowCount = jpeg_read_tile_scanline(cinfo,
1090 fImageIndex->huffmanIndex(),
1092 // if rowCount == 0, then we didn't get a scanline, so abort.
1093 // onDecodeSubset() relies on onBuildTileIndex(), which
1094 // needs a complete image to succeed.
1095 if (0 == rowCount) {
1096 return return_false(*cinfo, bitmap, "read_scanlines");
1098 if (this->shouldCancelDecode()) {
1099 return return_false(*cinfo, bitmap, "shouldCancelDecode");
1101 rowTotalCount += rowCount;
1108 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
1109 region.width(), region.height(), startX, startY);
1115 // check for supported formats
1116 SkScaledBitmapSampler::SrcConfig sc;
1117 int srcBytesPerPixel;
1119 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
1120 return return_false(*cinfo, *bm, "jpeg colorspace");
1123 if (!sampler.begin(&bitmap, sc, *this)) {
1124 return return_false(*cinfo, bitmap, "sampler.begin");
1127 SkAutoMalloc srcStorage(width * srcBytesPerPixel);
1128 uint8_t* srcRow = (uint8_t*)srcStorage.get();
1130 // Possibly skip initial rows [sampler.srcY0]
1131 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
1132 return return_false(*cinfo, bitmap, "skip rows");
1135 // now loop through scanlines until y == bitmap->height() - 1
1136 for (int y = 0;; y++) {
1137 JSAMPLE* rowptr = (JSAMPLE*)srcRow;
1138 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
1139 // if row_count == 0, then we didn't get a scanline, so abort.
1140 // onDecodeSubset() relies on onBuildTileIndex(), which
1141 // needs a complete image to succeed.
1142 if (0 == row_count) {
1143 return return_false(*cinfo, bitmap, "read_scanlines");
1145 if (this->shouldCancelDecode()) {
1146 return return_false(*cinfo, bitmap, "shouldCancelDecode");
1149 if (JCS_CMYK == cinfo->out_color_space) {
1150 convert_CMYK_to_RGB(srcRow, width);
1153 sampler.next(srcRow);
1154 if (bitmap.height() - 1 == y) {
1159 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
1160 sampler.srcDY() - 1)) {
1161 return return_false(*cinfo, bitmap, "skip rows");
1167 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
1168 region.width(), region.height(), startX, startY);
1174 ///////////////////////////////////////////////////////////////////////////////
1176 #include "SkColorPriv.h"
1178 // taken from jcolor.c in libjpeg
1179 #if 0 // 16bit - precise but slow
1180 #define CYR 19595 // 0.299
1181 #define CYG 38470 // 0.587
1182 #define CYB 7471 // 0.114
1184 #define CUR -11059 // -0.16874
1185 #define CUG -21709 // -0.33126
1186 #define CUB 32768 // 0.5
1188 #define CVR 32768 // 0.5
1189 #define CVG -27439 // -0.41869
1190 #define CVB -5329 // -0.08131
1193 #else // 8bit - fast, slightly less precise
1194 #define CYR 77 // 0.299
1195 #define CYG 150 // 0.587
1196 #define CYB 29 // 0.114
1198 #define CUR -43 // -0.16874
1199 #define CUG -85 // -0.33126
1200 #define CUB 128 // 0.5
1202 #define CVR 128 // 0.5
1203 #define CVG -107 // -0.41869
1204 #define CVB -21 // -0.08131
1209 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
1210 int r = SkGetPackedR32(c);
1211 int g = SkGetPackedG32(c);
1212 int b = SkGetPackedB32(c);
1214 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
1215 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
1216 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
1219 dst[1] = SkToU8(u + 128);
1220 dst[2] = SkToU8(v + 128);
1223 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
1224 int r = SkGetPackedR4444(c);
1225 int g = SkGetPackedG4444(c);
1226 int b = SkGetPackedB4444(c);
1228 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
1229 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
1230 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
1233 dst[1] = SkToU8(u + 128);
1234 dst[2] = SkToU8(v + 128);
1237 static void rgb2yuv_16(uint8_t dst[], U16CPU c) {
1238 int r = SkGetPackedR16(c);
1239 int g = SkGetPackedG16(c);
1240 int b = SkGetPackedB16(c);
1242 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
1243 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
1244 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
1247 dst[1] = SkToU8(u + 128);
1248 dst[2] = SkToU8(v + 128);
1251 ///////////////////////////////////////////////////////////////////////////////
1253 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
1254 const void* SK_RESTRICT src, int width,
1255 const SkPMColor* SK_RESTRICT ctable);
1257 static void Write_32_YUV(uint8_t* SK_RESTRICT dst,
1258 const void* SK_RESTRICT srcRow, int width,
1260 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
1261 while (--width >= 0) {
1262 #ifdef WE_CONVERT_TO_YUV
1263 rgb2yuv_32(dst, *src++);
1265 uint32_t c = *src++;
1266 dst[0] = SkGetPackedR32(c);
1267 dst[1] = SkGetPackedG32(c);
1268 dst[2] = SkGetPackedB32(c);
1274 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
1275 const void* SK_RESTRICT srcRow, int width,
1277 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
1278 while (--width >= 0) {
1279 #ifdef WE_CONVERT_TO_YUV
1280 rgb2yuv_4444(dst, *src++);
1282 SkPMColor16 c = *src++;
1283 dst[0] = SkPacked4444ToR32(c);
1284 dst[1] = SkPacked4444ToG32(c);
1285 dst[2] = SkPacked4444ToB32(c);
1291 static void Write_16_YUV(uint8_t* SK_RESTRICT dst,
1292 const void* SK_RESTRICT srcRow, int width,
1294 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
1295 while (--width >= 0) {
1296 #ifdef WE_CONVERT_TO_YUV
1297 rgb2yuv_16(dst, *src++);
1299 uint16_t c = *src++;
1300 dst[0] = SkPacked16ToR32(c);
1301 dst[1] = SkPacked16ToG32(c);
1302 dst[2] = SkPacked16ToB32(c);
1308 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
1309 const void* SK_RESTRICT srcRow, int width,
1310 const SkPMColor* SK_RESTRICT ctable) {
1311 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
1312 while (--width >= 0) {
1313 #ifdef WE_CONVERT_TO_YUV
1314 rgb2yuv_32(dst, ctable[*src++]);
1316 uint32_t c = ctable[*src++];
1317 dst[0] = SkGetPackedR32(c);
1318 dst[1] = SkGetPackedG32(c);
1319 dst[2] = SkGetPackedB32(c);
1325 static WriteScanline ChooseWriter(const SkBitmap& bm) {
1326 switch (bm.colorType()) {
1327 case kN32_SkColorType:
1328 return Write_32_YUV;
1329 case kRGB_565_SkColorType:
1330 return Write_16_YUV;
1331 case kARGB_4444_SkColorType:
1332 return Write_4444_YUV;
1333 case kIndex_8_SkColorType:
1334 return Write_Index_YUV;
1340 class SkJPEGImageEncoder : public SkImageEncoder {
1342 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
1344 SkAutoTime atm("JPEG Encode");
1347 SkAutoLockPixels alp(bm);
1348 if (NULL == bm.getPixels()) {
1352 jpeg_compress_struct cinfo;
1353 skjpeg_error_mgr sk_err;
1354 skjpeg_destination_mgr sk_wstream(stream);
1356 // allocate these before set call setjmp
1357 SkAutoMalloc oneRow;
1358 SkAutoLockColors ctLocker;
1360 cinfo.err = jpeg_std_error(&sk_err);
1361 sk_err.error_exit = skjpeg_error_exit;
1362 if (setjmp(sk_err.fJmpBuf)) {
1366 // Keep after setjmp or mark volatile.
1367 const WriteScanline writer = ChooseWriter(bm);
1368 if (NULL == writer) {
1372 jpeg_create_compress(&cinfo);
1373 cinfo.dest = &sk_wstream;
1374 cinfo.image_width = bm.width();
1375 cinfo.image_height = bm.height();
1376 cinfo.input_components = 3;
1377 #ifdef WE_CONVERT_TO_YUV
1378 cinfo.in_color_space = JCS_YCbCr;
1380 cinfo.in_color_space = JCS_RGB;
1382 cinfo.input_gamma = 1;
1384 jpeg_set_defaults(&cinfo);
1385 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
1386 #ifdef DCT_IFAST_SUPPORTED
1387 cinfo.dct_method = JDCT_IFAST;
1390 jpeg_start_compress(&cinfo, TRUE);
1392 const int width = bm.width();
1393 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3);
1395 const SkPMColor* colors = ctLocker.lockColors(bm);
1396 const void* srcRow = bm.getPixels();
1398 while (cinfo.next_scanline < cinfo.image_height) {
1399 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
1401 writer(oneRowP, srcRow, width, colors);
1402 row_pointer[0] = oneRowP;
1403 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1404 srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
1407 jpeg_finish_compress(&cinfo);
1408 jpeg_destroy_compress(&cinfo);
1414 ///////////////////////////////////////////////////////////////////////////////
1415 DEFINE_DECODER_CREATOR(JPEGImageDecoder);
1416 DEFINE_ENCODER_CREATOR(JPEGImageEncoder);
1417 ///////////////////////////////////////////////////////////////////////////////
1419 static bool is_jpeg(SkStreamRewindable* stream) {
1420 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
1421 static const size_t HEADER_SIZE = sizeof(gHeader);
1423 char buffer[HEADER_SIZE];
1424 size_t len = stream->read(buffer, HEADER_SIZE);
1426 if (len != HEADER_SIZE) {
1427 return false; // can't read enough
1429 if (memcmp(buffer, gHeader, HEADER_SIZE)) {
1436 static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
1437 if (is_jpeg(stream)) {
1438 return SkNEW(SkJPEGImageDecoder);
1443 static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
1444 if (is_jpeg(stream)) {
1445 return SkImageDecoder::kJPEG_Format;
1447 return SkImageDecoder::kUnknown_Format;
1450 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1451 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1454 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
1455 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
1456 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);