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 */ 7 8 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" 22 23 24 #include <stdio.h> 25 extern "C" { 26 #include "jpeglib.h" 27 #include "jerror.h" 28 } 29 30 // These enable timing code that report milliseconds for an encoding/decoding 31 //#define TIME_ENCODE 32 //#define TIME_DECODE 33 34 // this enables our rgb->yuv code, which is faster than libjpeg on ARM 35 #define WE_CONVERT_TO_YUV 36 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. 39 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."); 56 57 ////////////////////////////////////////////////////////////////////////// 58 ////////////////////////////////////////////////////////////////////////// 59 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 } 72 73 ////////////////////////////////////////////////////////////////////////// 74 ////////////////////////////////////////////////////////////////////////// 75 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 } 82 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 } 104 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 } 116 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 } 137 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 } 154 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 } 171 172 jpeg_decompress_struct* cinfo() { return &fCInfo; } 173 174 huffman_index* huffmanIndex() { return &fHuffmanIndex; } 175 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 } 190 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 } 206 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 217 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 } 226 227 virtual ~SkJPEGImageDecoder() { 228 SkDELETE(fImageIndex); 229 } 230 #endif 231 232 virtual Format getFormat() const { 233 return kJPEG_Format; 234 } 235 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; 242 243 private: 244 #ifdef SK_BUILD_FOR_ANDROID 245 SkJPEGImageIndex* fImageIndex; 246 int fImageWidth; 247 int fImageHeight; 248 #endif 249 250 /** 251 * Determine the appropriate bitmap colortype 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 SkColorType getBitmapColorType(jpeg_decompress_struct*); 257 258 typedef SkImageDecoder INHERITED; 259 }; 260 261 ////////////////////////////////////////////////////////////////////////// 262 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 }; 278 279 /////////////////////////////////////////////////////////////////////////////// 280 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. 285 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 } 292 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 } 299 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 } 310 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 324 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 } 337 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 } 360 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 } 370 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; 382 383 /* this gives another few percents */ 384 cinfo->do_block_smoothing = 0; 385 } 386 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 } 402 403 SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) { 404 SkASSERT(cinfo != NULL); 405 406 SrcDepth srcDepth = k32Bit_SrcDepth; 407 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { 408 srcDepth = k8BitGray_SrcDepth; 409 } 410 411 SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false); 412 switch (colorType) { 413 case kAlpha_8_SkColorType: 414 // Only respect A8 colortype 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 colorType = kN32_SkColorType; 419 } 420 break; 421 case kN32_SkColorType: 422 // Fall through. 423 case kARGB_4444_SkColorType: 424 // Fall through. 425 case kRGB_565_SkColorType: 426 // These are acceptable destination colortypes. 427 break; 428 default: 429 // Force all other colortypes to 8888. 430 colorType = kN32_SkColorType; 431 break; 432 } 433 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 (kAlpha_8_SkColorType == colorType) { 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 // colortype. Fall through to set to the default. 450 default: 451 cinfo->out_color_space = JCS_RGB; 452 break; 453 } 454 return colorType; 455 } 456 457 /** 458 * Based on the colortype and dither mode, adjust out_color_space and 459 * dither_mode of cinfo. Only does work in ANDROID_RGB 460 */ 461 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, 462 SkColorType colorType, 463 const SkImageDecoder& decoder) { 464 SkASSERT(cinfo != NULL); 465 #ifdef ANDROID_RGB 466 cinfo->dither_mode = JDITHER_NONE; 467 if (JCS_CMYK == cinfo->out_color_space) { 468 return; 469 } 470 switch (colorType) { 471 case kN32_SkColorType: 472 cinfo->out_color_space = JCS_RGBA_8888; 473 break; 474 case kRGB_565_SkColorType: 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 #endif 484 } 485 486 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 } 497 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 } 531 532 bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 533 #ifdef TIME_DECODE 534 SkAutoTime atm("JPEG Decode"); 535 #endif 536 537 JPEGAutoClean autoClean; 538 539 jpeg_decompress_struct cinfo; 540 skjpeg_source_mgr srcManager(stream, this); 541 542 skjpeg_error_mgr errorManager; 543 set_error_mgr(&cinfo, &errorManager); 544 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 } 550 551 initialize_info(&cinfo, &srcManager); 552 autoClean.set(&cinfo); 553 554 int status = jpeg_read_header(&cinfo, true); 555 if (status != JPEG_HEADER_OK) { 556 return return_false(cinfo, *bm, "read_header"); 557 } 558 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(); 564 565 set_dct_method(*this, &cinfo); 566 567 SkASSERT(1 == cinfo.scale_num); 568 cinfo.scale_denom = sampleSize; 569 570 turn_off_visual_optimizations(&cinfo); 571 572 const SkColorType colorType = this->getBitmapColorType(&cinfo); 573 const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ? 574 kPremul_SkAlphaType : kOpaque_SkAlphaType; 575 576 adjust_out_color_space_and_dither(&cinfo, colorType, *this); 577 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->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, 584 colorType, alphaType)); 585 } 586 587 /* image_width and image_height are the original dimensions, available 588 after jpeg_read_header(). To see the scaled dimensions, we have to call 589 jpeg_start_decompress(), and then read output_width and output_height. 590 */ 591 if (!jpeg_start_decompress(&cinfo)) { 592 /* If we failed here, we may still have enough information to return 593 to the caller if they just wanted (subsampled bounds). If sampleSize 594 was 1, then we would have already returned. Thus we just check if 595 we're in kDecodeBounds_Mode, and that we have valid output sizes. 596 597 One reason to fail here is that we have insufficient stream data 598 to complete the setup. However, output dimensions seem to get 599 computed very early, which is why this special check can pay off. 600 */ 601 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 602 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 603 recompute_sampleSize(sampleSize, cinfo)); 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 return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), 609 colorType, alphaType)); 610 } else { 611 return return_false(cinfo, *bm, "start_decompress"); 612 } 613 } 614 sampleSize = recompute_sampleSize(sampleSize, cinfo); 615 616 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER 617 // should we allow the Chooser (if present) to pick a colortype for us??? 618 if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) { 619 return return_false(cinfo, *bm, "chooseFromOneChoice"); 620 } 621 #endif 622 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->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), 629 colorType, alphaType)); 630 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 631 return true; 632 } 633 if (!this->allocPixelRef(bm, NULL)) { 634 return return_false(cinfo, *bm, "allocPixelRef"); 635 } 636 637 SkAutoLockPixels alp(*bm); 638 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 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) || 645 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565))) 646 { 647 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 648 INT32 const bpr = bm->rowBytes(); 649 650 while (cinfo.output_scanline < cinfo.output_height) { 651 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 652 if (0 == row_count) { 653 // if row_count == 0, then we didn't get a scanline, 654 // so return early. We will return a partial image. 655 fill_below_level(cinfo.output_scanline, bm); 656 cinfo.output_scanline = cinfo.output_height; 657 break; // Skip to jpeg_finish_decompress() 658 } 659 if (this->shouldCancelDecode()) { 660 return return_false(cinfo, *bm, "shouldCancelDecode"); 661 } 662 rowptr += bpr; 663 } 664 jpeg_finish_decompress(&cinfo); 665 return true; 666 } 667 #endif 668 669 // check for supported formats 670 SkScaledBitmapSampler::SrcConfig sc; 671 int srcBytesPerPixel; 672 673 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { 674 return return_false(cinfo, *bm, "jpeg colorspace"); 675 } 676 677 if (!sampler.begin(bm, sc, *this)) { 678 return return_false(cinfo, *bm, "sampler.begin"); 679 } 680 681 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); 682 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 683 684 // Possibly skip initial rows [sampler.srcY0] 685 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 686 return return_false(cinfo, *bm, "skip rows"); 687 } 688 689 // now loop through scanlines until y == bm->height() - 1 690 for (int y = 0;; y++) { 691 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 692 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 693 if (0 == row_count) { 694 // if row_count == 0, then we didn't get a scanline, 695 // so return early. We will return a partial image. 696 fill_below_level(y, bm); 697 cinfo.output_scanline = cinfo.output_height; 698 break; // Skip to jpeg_finish_decompress() 699 } 700 if (this->shouldCancelDecode()) { 701 return return_false(cinfo, *bm, "shouldCancelDecode"); 702 } 703 704 if (JCS_CMYK == cinfo.out_color_space) { 705 convert_CMYK_to_RGB(srcRow, cinfo.output_width); 706 } 707 708 sampler.next(srcRow); 709 if (bm->height() - 1 == y) { 710 // we're done 711 break; 712 } 713 714 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 715 return return_false(cinfo, *bm, "skip rows"); 716 } 717 } 718 719 // we formally skip the rest, so we don't get a complaint from libjpeg 720 if (!skip_src_rows(&cinfo, srcRow, 721 cinfo.output_height - cinfo.output_scanline)) { 722 return return_false(cinfo, *bm, "skip rows"); 723 } 724 jpeg_finish_decompress(&cinfo); 725 726 return true; 727 } 728 729 #ifdef SK_BUILD_FOR_ANDROID 730 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { 731 732 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); 733 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 734 735 skjpeg_error_mgr sk_err; 736 set_error_mgr(cinfo, &sk_err); 737 738 // All objects need to be instantiated before this setjmp call so that 739 // they will be cleaned up properly if an error occurs. 740 if (setjmp(sk_err.fJmpBuf)) { 741 return false; 742 } 743 744 // create the cinfo used to create/build the huffmanIndex 745 if (!imageIndex->initializeInfoAndReadHeader()) { 746 return false; 747 } 748 749 if (!imageIndex->buildHuffmanIndex()) { 750 return false; 751 } 752 753 // destroy the cinfo used to create/build the huffman index 754 imageIndex->destroyInfo(); 755 756 // Init decoder to image decode mode 757 if (!imageIndex->initializeInfoAndReadHeader()) { 758 return false; 759 } 760 761 // FIXME: This sets cinfo->out_color_space, which we may change later 762 // based on the config in onDecodeSubset. This should be fine, since 763 // jpeg_init_read_tile_scanline will check out_color_space again after 764 // that change (when it calls jinit_color_deconverter). 765 (void) this->getBitmapColorType(cinfo); 766 767 turn_off_visual_optimizations(cinfo); 768 769 // instead of jpeg_start_decompress() we start a tiled decompress 770 if (!imageIndex->startTileDecompress()) { 771 return false; 772 } 773 774 SkASSERT(1 == cinfo->scale_num); 775 fImageWidth = cinfo->output_width; 776 fImageHeight = cinfo->output_height; 777 778 if (width) { 779 *width = fImageWidth; 780 } 781 if (height) { 782 *height = fImageHeight; 783 } 784 785 SkDELETE(fImageIndex); 786 fImageIndex = imageIndex.detach(); 787 788 return true; 789 } 790 791 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 792 if (NULL == fImageIndex) { 793 return false; 794 } 795 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 796 797 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 798 if (!rect.intersect(region)) { 799 // If the requested region is entirely outside the image return false 800 return false; 801 } 802 803 804 skjpeg_error_mgr errorManager; 805 set_error_mgr(cinfo, &errorManager); 806 807 if (setjmp(errorManager.fJmpBuf)) { 808 return false; 809 } 810 811 int requestedSampleSize = this->getSampleSize(); 812 cinfo->scale_denom = requestedSampleSize; 813 814 set_dct_method(*this, cinfo); 815 816 const SkColorType colorType = this->getBitmapColorType(cinfo); 817 adjust_out_color_space_and_dither(cinfo, colorType, *this); 818 819 int startX = rect.fLeft; 820 int startY = rect.fTop; 821 int width = rect.width(); 822 int height = rect.height(); 823 824 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 825 &startX, &startY, &width, &height); 826 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 827 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 828 829 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 830 831 SkBitmap bitmap; 832 // Assume an A8 bitmap is not opaque to avoid the check of each 833 // individual pixel. It is very unlikely to be opaque, since 834 // an opaque A8 bitmap would not be very interesting. 835 // Otherwise, a jpeg image is opaque. 836 bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, 837 kAlpha_8_SkColorType == colorType ? 838 kPremul_SkAlphaType : kOpaque_SkAlphaType)); 839 840 // Check ahead of time if the swap(dest, src) is possible or not. 841 // If yes, then we will stick to AllocPixelRef since it's cheaper with the 842 // swap happening. If no, then we will use alloc to allocate pixels to 843 // prevent garbage collection. 844 int w = rect.width() / actualSampleSize; 845 int h = rect.height() / actualSampleSize; 846 bool swapOnly = (rect == region) && bm->isNull() && 847 (w == bitmap.width()) && (h == bitmap.height()) && 848 ((startX - rect.x()) / actualSampleSize == 0) && 849 ((startY - rect.y()) / actualSampleSize == 0); 850 if (swapOnly) { 851 if (!this->allocPixelRef(&bitmap, NULL)) { 852 return return_false(*cinfo, bitmap, "allocPixelRef"); 853 } 854 } else { 855 if (!bitmap.allocPixels()) { 856 return return_false(*cinfo, bitmap, "allocPixels"); 857 } 858 } 859 860 SkAutoLockPixels alp(bitmap); 861 862 #ifdef ANDROID_RGB 863 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 864 a significant performance boost. 865 */ 866 if (skiaSampleSize == 1 && 867 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) || 868 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565))) 869 { 870 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 871 INT32 const bpr = bitmap.rowBytes(); 872 int rowTotalCount = 0; 873 874 while (rowTotalCount < height) { 875 int rowCount = jpeg_read_tile_scanline(cinfo, 876 fImageIndex->huffmanIndex(), 877 &rowptr); 878 // if rowCount == 0, then we didn't get a scanline, so abort. 879 // onDecodeSubset() relies on onBuildTileIndex(), which 880 // needs a complete image to succeed. 881 if (0 == rowCount) { 882 return return_false(*cinfo, bitmap, "read_scanlines"); 883 } 884 if (this->shouldCancelDecode()) { 885 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 886 } 887 rowTotalCount += rowCount; 888 rowptr += bpr; 889 } 890 891 if (swapOnly) { 892 bm->swap(bitmap); 893 } else { 894 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 895 region.width(), region.height(), startX, startY); 896 } 897 return true; 898 } 899 #endif 900 901 // check for supported formats 902 SkScaledBitmapSampler::SrcConfig sc; 903 int srcBytesPerPixel; 904 905 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { 906 return return_false(*cinfo, *bm, "jpeg colorspace"); 907 } 908 909 if (!sampler.begin(&bitmap, sc, *this)) { 910 return return_false(*cinfo, bitmap, "sampler.begin"); 911 } 912 913 SkAutoMalloc srcStorage(width * srcBytesPerPixel); 914 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 915 916 // Possibly skip initial rows [sampler.srcY0] 917 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 918 return return_false(*cinfo, bitmap, "skip rows"); 919 } 920 921 // now loop through scanlines until y == bitmap->height() - 1 922 for (int y = 0;; y++) { 923 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 924 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 925 // if row_count == 0, then we didn't get a scanline, so abort. 926 // onDecodeSubset() relies on onBuildTileIndex(), which 927 // needs a complete image to succeed. 928 if (0 == row_count) { 929 return return_false(*cinfo, bitmap, "read_scanlines"); 930 } 931 if (this->shouldCancelDecode()) { 932 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 933 } 934 935 if (JCS_CMYK == cinfo->out_color_space) { 936 convert_CMYK_to_RGB(srcRow, width); 937 } 938 939 sampler.next(srcRow); 940 if (bitmap.height() - 1 == y) { 941 // we're done 942 break; 943 } 944 945 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 946 sampler.srcDY() - 1)) { 947 return return_false(*cinfo, bitmap, "skip rows"); 948 } 949 } 950 if (swapOnly) { 951 bm->swap(bitmap); 952 } else { 953 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 954 region.width(), region.height(), startX, startY); 955 } 956 return true; 957 } 958 #endif 959 960 /////////////////////////////////////////////////////////////////////////////// 961 962 #include "SkColorPriv.h" 963 964 // taken from jcolor.c in libjpeg 965 #if 0 // 16bit - precise but slow 966 #define CYR 19595 // 0.299 967 #define CYG 38470 // 0.587 968 #define CYB 7471 // 0.114 969 970 #define CUR -11059 // -0.16874 971 #define CUG -21709 // -0.33126 972 #define CUB 32768 // 0.5 973 974 #define CVR 32768 // 0.5 975 #define CVG -27439 // -0.41869 976 #define CVB -5329 // -0.08131 977 978 #define CSHIFT 16 979 #else // 8bit - fast, slightly less precise 980 #define CYR 77 // 0.299 981 #define CYG 150 // 0.587 982 #define CYB 29 // 0.114 983 984 #define CUR -43 // -0.16874 985 #define CUG -85 // -0.33126 986 #define CUB 128 // 0.5 987 988 #define CVR 128 // 0.5 989 #define CVG -107 // -0.41869 990 #define CVB -21 // -0.08131 991 992 #define CSHIFT 8 993 #endif 994 995 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 996 int r = SkGetPackedR32(c); 997 int g = SkGetPackedG32(c); 998 int b = SkGetPackedB32(c); 999 1000 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 1001 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 1002 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 1003 1004 dst[0] = SkToU8(y); 1005 dst[1] = SkToU8(u + 128); 1006 dst[2] = SkToU8(v + 128); 1007 } 1008 1009 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 1010 int r = SkGetPackedR4444(c); 1011 int g = SkGetPackedG4444(c); 1012 int b = SkGetPackedB4444(c); 1013 1014 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 1015 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 1016 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 1017 1018 dst[0] = SkToU8(y); 1019 dst[1] = SkToU8(u + 128); 1020 dst[2] = SkToU8(v + 128); 1021 } 1022 1023 static void rgb2yuv_16(uint8_t dst[], U16CPU c) { 1024 int r = SkGetPackedR16(c); 1025 int g = SkGetPackedG16(c); 1026 int b = SkGetPackedB16(c); 1027 1028 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 1029 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 1030 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 1031 1032 dst[0] = SkToU8(y); 1033 dst[1] = SkToU8(u + 128); 1034 dst[2] = SkToU8(v + 128); 1035 } 1036 1037 /////////////////////////////////////////////////////////////////////////////// 1038 1039 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 1040 const void* SK_RESTRICT src, int width, 1041 const SkPMColor* SK_RESTRICT ctable); 1042 1043 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 1044 const void* SK_RESTRICT srcRow, int width, 1045 const SkPMColor*) { 1046 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 1047 while (--width >= 0) { 1048 #ifdef WE_CONVERT_TO_YUV 1049 rgb2yuv_32(dst, *src++); 1050 #else 1051 uint32_t c = *src++; 1052 dst[0] = SkGetPackedR32(c); 1053 dst[1] = SkGetPackedG32(c); 1054 dst[2] = SkGetPackedB32(c); 1055 #endif 1056 dst += 3; 1057 } 1058 } 1059 1060 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 1061 const void* SK_RESTRICT srcRow, int width, 1062 const SkPMColor*) { 1063 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 1064 while (--width >= 0) { 1065 #ifdef WE_CONVERT_TO_YUV 1066 rgb2yuv_4444(dst, *src++); 1067 #else 1068 SkPMColor16 c = *src++; 1069 dst[0] = SkPacked4444ToR32(c); 1070 dst[1] = SkPacked4444ToG32(c); 1071 dst[2] = SkPacked4444ToB32(c); 1072 #endif 1073 dst += 3; 1074 } 1075 } 1076 1077 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 1078 const void* SK_RESTRICT srcRow, int width, 1079 const SkPMColor*) { 1080 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 1081 while (--width >= 0) { 1082 #ifdef WE_CONVERT_TO_YUV 1083 rgb2yuv_16(dst, *src++); 1084 #else 1085 uint16_t c = *src++; 1086 dst[0] = SkPacked16ToR32(c); 1087 dst[1] = SkPacked16ToG32(c); 1088 dst[2] = SkPacked16ToB32(c); 1089 #endif 1090 dst += 3; 1091 } 1092 } 1093 1094 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 1095 const void* SK_RESTRICT srcRow, int width, 1096 const SkPMColor* SK_RESTRICT ctable) { 1097 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 1098 while (--width >= 0) { 1099 #ifdef WE_CONVERT_TO_YUV 1100 rgb2yuv_32(dst, ctable[*src++]); 1101 #else 1102 uint32_t c = ctable[*src++]; 1103 dst[0] = SkGetPackedR32(c); 1104 dst[1] = SkGetPackedG32(c); 1105 dst[2] = SkGetPackedB32(c); 1106 #endif 1107 dst += 3; 1108 } 1109 } 1110 1111 static WriteScanline ChooseWriter(const SkBitmap& bm) { 1112 switch (bm.colorType()) { 1113 case kN32_SkColorType: 1114 return Write_32_YUV; 1115 case kRGB_565_SkColorType: 1116 return Write_16_YUV; 1117 case kARGB_4444_SkColorType: 1118 return Write_4444_YUV; 1119 case kIndex_8_SkColorType: 1120 return Write_Index_YUV; 1121 default: 1122 return NULL; 1123 } 1124 } 1125 1126 class SkJPEGImageEncoder : public SkImageEncoder { 1127 protected: 1128 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 1129 #ifdef TIME_ENCODE 1130 SkAutoTime atm("JPEG Encode"); 1131 #endif 1132 1133 SkAutoLockPixels alp(bm); 1134 if (NULL == bm.getPixels()) { 1135 return false; 1136 } 1137 1138 jpeg_compress_struct cinfo; 1139 skjpeg_error_mgr sk_err; 1140 skjpeg_destination_mgr sk_wstream(stream); 1141 1142 // allocate these before set call setjmp 1143 SkAutoMalloc oneRow; 1144 SkAutoLockColors ctLocker; 1145 1146 cinfo.err = jpeg_std_error(&sk_err); 1147 sk_err.error_exit = skjpeg_error_exit; 1148 if (setjmp(sk_err.fJmpBuf)) { 1149 return false; 1150 } 1151 1152 // Keep after setjmp or mark volatile. 1153 const WriteScanline writer = ChooseWriter(bm); 1154 if (NULL == writer) { 1155 return false; 1156 } 1157 1158 jpeg_create_compress(&cinfo); 1159 cinfo.dest = &sk_wstream; 1160 cinfo.image_width = bm.width(); 1161 cinfo.image_height = bm.height(); 1162 cinfo.input_components = 3; 1163 #ifdef WE_CONVERT_TO_YUV 1164 cinfo.in_color_space = JCS_YCbCr; 1165 #else 1166 cinfo.in_color_space = JCS_RGB; 1167 #endif 1168 cinfo.input_gamma = 1; 1169 1170 jpeg_set_defaults(&cinfo); 1171 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 1172 #ifdef DCT_IFAST_SUPPORTED 1173 cinfo.dct_method = JDCT_IFAST; 1174 #endif 1175 1176 jpeg_start_compress(&cinfo, TRUE); 1177 1178 const int width = bm.width(); 1179 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 1180 1181 const SkPMColor* colors = ctLocker.lockColors(bm); 1182 const void* srcRow = bm.getPixels(); 1183 1184 while (cinfo.next_scanline < cinfo.image_height) { 1185 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 1186 1187 writer(oneRowP, srcRow, width, colors); 1188 row_pointer[0] = oneRowP; 1189 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 1190 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 1191 } 1192 1193 jpeg_finish_compress(&cinfo); 1194 jpeg_destroy_compress(&cinfo); 1195 1196 return true; 1197 } 1198 }; 1199 1200 /////////////////////////////////////////////////////////////////////////////// 1201 DEFINE_DECODER_CREATOR(JPEGImageDecoder); 1202 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 1203 /////////////////////////////////////////////////////////////////////////////// 1204 1205 static bool is_jpeg(SkStreamRewindable* stream) { 1206 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1207 static const size_t HEADER_SIZE = sizeof(gHeader); 1208 1209 char buffer[HEADER_SIZE]; 1210 size_t len = stream->read(buffer, HEADER_SIZE); 1211 1212 if (len != HEADER_SIZE) { 1213 return false; // can't read enough 1214 } 1215 if (memcmp(buffer, gHeader, HEADER_SIZE)) { 1216 return false; 1217 } 1218 return true; 1219 } 1220 1221 1222 static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { 1223 if (is_jpeg(stream)) { 1224 return SkNEW(SkJPEGImageDecoder); 1225 } 1226 return NULL; 1227 } 1228 1229 static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { 1230 if (is_jpeg(stream)) { 1231 return SkImageDecoder::kJPEG_Format; 1232 } 1233 return SkImageDecoder::kUnknown_Format; 1234 } 1235 1236 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1237 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1238 } 1239 1240 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); 1241 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); 1242 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 1243