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 Result 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 /////////////////////////////////////////////////////////////////////////////// 326 327 // This guy exists just to aid in debugging, as it allows debuggers to just 328 // set a break-point in one place to see all error exists. 329 static void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo, 330 int width, int height, const char caller[]) { 331 if (!(c_suppressJPEGImageDecoderErrors)) { 332 char buffer[JMSG_LENGTH_MAX]; 333 cinfo.err->format_message((const j_common_ptr)&cinfo, buffer); 334 SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n", 335 cinfo.err->msg_code, buffer, caller, width, height); 336 } 337 } 338 339 static bool return_false(const jpeg_decompress_struct& cinfo, 340 const SkBitmap& bm, const char caller[]) { 341 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); 342 return false; 343 } 344 345 static SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo, 346 const SkBitmap& bm, const char caller[]) { 347 print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller); 348 return SkImageDecoder::kFailure; 349 } 350 351 /////////////////////////////////////////////////////////////////////////////// 352 353 // Convert a scanline of CMYK samples to RGBX in place. Note that this 354 // method moves the "scanline" pointer in its processing 355 static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 356 // At this point we've received CMYK pixels from libjpeg. We 357 // perform a crude conversion to RGB (based on the formulae 358 // from easyrgb.com): 359 // CMYK -> CMY 360 // C = ( C * (1 - K) + K ) // for each CMY component 361 // CMY -> RGB 362 // R = ( 1 - C ) * 255 // for each RGB component 363 // Unfortunately we are seeing inverted CMYK so all the original terms 364 // are 1-. This yields: 365 // CMYK -> CMY 366 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 367 // The conversion from CMY->RGB remains the same 368 for (unsigned int x = 0; x < width; ++x, scanline += 4) { 369 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 370 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 371 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 372 scanline[3] = 255; 373 } 374 } 375 376 /** 377 * Common code for setting the error manager. 378 */ 379 static void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) { 380 SkASSERT(cinfo != NULL); 381 SkASSERT(errorManager != NULL); 382 cinfo->err = jpeg_std_error(errorManager); 383 errorManager->error_exit = skjpeg_error_exit; 384 } 385 386 /** 387 * Common code for turning off upsampling and smoothing. Turning these 388 * off helps performance without showing noticable differences in the 389 * resulting bitmap. 390 */ 391 static void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) { 392 SkASSERT(cinfo != NULL); 393 /* this gives about 30% performance improvement. In theory it may 394 reduce the visual quality, in practice I'm not seeing a difference 395 */ 396 cinfo->do_fancy_upsampling = 0; 397 398 /* this gives another few percents */ 399 cinfo->do_block_smoothing = 0; 400 } 401 402 /** 403 * Common code for setting the dct method. 404 */ 405 static void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) { 406 SkASSERT(cinfo != NULL); 407 #ifdef DCT_IFAST_SUPPORTED 408 if (decoder.getPreferQualityOverSpeed()) { 409 cinfo->dct_method = JDCT_ISLOW; 410 } else { 411 cinfo->dct_method = JDCT_IFAST; 412 } 413 #else 414 cinfo->dct_method = JDCT_ISLOW; 415 #endif 416 } 417 418 SkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) { 419 SkASSERT(cinfo != NULL); 420 421 SrcDepth srcDepth = k32Bit_SrcDepth; 422 if (JCS_GRAYSCALE == cinfo->jpeg_color_space) { 423 srcDepth = k8BitGray_SrcDepth; 424 } 425 426 SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false); 427 switch (colorType) { 428 case kAlpha_8_SkColorType: 429 // Only respect A8 colortype if the original is grayscale, 430 // in which case we will treat the grayscale as alpha 431 // values. 432 if (cinfo->jpeg_color_space != JCS_GRAYSCALE) { 433 colorType = kN32_SkColorType; 434 } 435 break; 436 case kN32_SkColorType: 437 // Fall through. 438 case kARGB_4444_SkColorType: 439 // Fall through. 440 case kRGB_565_SkColorType: 441 // These are acceptable destination colortypes. 442 break; 443 default: 444 // Force all other colortypes to 8888. 445 colorType = kN32_SkColorType; 446 break; 447 } 448 449 switch (cinfo->jpeg_color_space) { 450 case JCS_CMYK: 451 // Fall through. 452 case JCS_YCCK: 453 // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up 454 // so libjpeg will give us CMYK samples back and we will later 455 // manually convert them to RGB 456 cinfo->out_color_space = JCS_CMYK; 457 break; 458 case JCS_GRAYSCALE: 459 if (kAlpha_8_SkColorType == colorType) { 460 cinfo->out_color_space = JCS_GRAYSCALE; 461 break; 462 } 463 // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB 464 // colortype. Fall through to set to the default. 465 default: 466 cinfo->out_color_space = JCS_RGB; 467 break; 468 } 469 return colorType; 470 } 471 472 /** 473 * Based on the colortype and dither mode, adjust out_color_space and 474 * dither_mode of cinfo. Only does work in ANDROID_RGB 475 */ 476 static void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo, 477 SkColorType colorType, 478 const SkImageDecoder& decoder) { 479 SkASSERT(cinfo != NULL); 480 #ifdef ANDROID_RGB 481 cinfo->dither_mode = JDITHER_NONE; 482 if (JCS_CMYK == cinfo->out_color_space) { 483 return; 484 } 485 switch (colorType) { 486 case kN32_SkColorType: 487 cinfo->out_color_space = JCS_RGBA_8888; 488 break; 489 case kRGB_565_SkColorType: 490 cinfo->out_color_space = JCS_RGB_565; 491 if (decoder.getDitherImage()) { 492 cinfo->dither_mode = JDITHER_ORDERED; 493 } 494 break; 495 default: 496 break; 497 } 498 #endif 499 } 500 501 /** 502 Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y. 503 Used when decoding fails partway through reading scanlines to fill 504 remaining lines. */ 505 static void fill_below_level(int y, SkBitmap* bitmap) { 506 SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height()); 507 SkCanvas canvas(*bitmap); 508 canvas.clipRect(SkRect::Make(rect)); 509 canvas.drawColor(SK_ColorWHITE); 510 } 511 512 /** 513 * Get the config and bytes per pixel of the source data. Return 514 * whether the data is supported. 515 */ 516 static bool get_src_config(const jpeg_decompress_struct& cinfo, 517 SkScaledBitmapSampler::SrcConfig* sc, 518 int* srcBytesPerPixel) { 519 SkASSERT(sc != NULL && srcBytesPerPixel != NULL); 520 if (JCS_CMYK == cinfo.out_color_space) { 521 // In this case we will manually convert the CMYK values to RGB 522 *sc = SkScaledBitmapSampler::kRGBX; 523 // The CMYK work-around relies on 4 components per pixel here 524 *srcBytesPerPixel = 4; 525 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 526 *sc = SkScaledBitmapSampler::kRGB; 527 *srcBytesPerPixel = 3; 528 #ifdef ANDROID_RGB 529 } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 530 *sc = SkScaledBitmapSampler::kRGBX; 531 *srcBytesPerPixel = 4; 532 } else if (JCS_RGB_565 == cinfo.out_color_space) { 533 *sc = SkScaledBitmapSampler::kRGB_565; 534 *srcBytesPerPixel = 2; 535 #endif 536 } else if (1 == cinfo.out_color_components && 537 JCS_GRAYSCALE == cinfo.out_color_space) { 538 *sc = SkScaledBitmapSampler::kGray; 539 *srcBytesPerPixel = 1; 540 } else { 541 return false; 542 } 543 return true; 544 } 545 546 SkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 547 #ifdef TIME_DECODE 548 SkAutoTime atm("JPEG Decode"); 549 #endif 550 551 JPEGAutoClean autoClean; 552 553 jpeg_decompress_struct cinfo; 554 skjpeg_source_mgr srcManager(stream, this); 555 556 skjpeg_error_mgr errorManager; 557 set_error_mgr(&cinfo, &errorManager); 558 559 // All objects need to be instantiated before this setjmp call so that 560 // they will be cleaned up properly if an error occurs. 561 if (setjmp(errorManager.fJmpBuf)) { 562 return return_failure(cinfo, *bm, "setjmp"); 563 } 564 565 initialize_info(&cinfo, &srcManager); 566 autoClean.set(&cinfo); 567 568 int status = jpeg_read_header(&cinfo, true); 569 if (status != JPEG_HEADER_OK) { 570 return return_failure(cinfo, *bm, "read_header"); 571 } 572 573 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 574 can) much faster that we, just use their num/denom api to approximate 575 the size. 576 */ 577 int sampleSize = this->getSampleSize(); 578 579 set_dct_method(*this, &cinfo); 580 581 SkASSERT(1 == cinfo.scale_num); 582 cinfo.scale_denom = sampleSize; 583 584 turn_off_visual_optimizations(&cinfo); 585 586 const SkColorType colorType = this->getBitmapColorType(&cinfo); 587 const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ? 588 kPremul_SkAlphaType : kOpaque_SkAlphaType; 589 590 adjust_out_color_space_and_dither(&cinfo, colorType, *this); 591 592 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 593 // Assume an A8 bitmap is not opaque to avoid the check of each 594 // individual pixel. It is very unlikely to be opaque, since 595 // an opaque A8 bitmap would not be very interesting. 596 // Otherwise, a jpeg image is opaque. 597 bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height, 598 colorType, alphaType)); 599 return success ? kSuccess : kFailure; 600 } 601 602 /* image_width and image_height are the original dimensions, available 603 after jpeg_read_header(). To see the scaled dimensions, we have to call 604 jpeg_start_decompress(), and then read output_width and output_height. 605 */ 606 if (!jpeg_start_decompress(&cinfo)) { 607 /* If we failed here, we may still have enough information to return 608 to the caller if they just wanted (subsampled bounds). If sampleSize 609 was 1, then we would have already returned. Thus we just check if 610 we're in kDecodeBounds_Mode, and that we have valid output sizes. 611 612 One reason to fail here is that we have insufficient stream data 613 to complete the setup. However, output dimensions seem to get 614 computed very early, which is why this special check can pay off. 615 */ 616 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 617 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 618 recompute_sampleSize(sampleSize, cinfo)); 619 // Assume an A8 bitmap is not opaque to avoid the check of each 620 // individual pixel. It is very unlikely to be opaque, since 621 // an opaque A8 bitmap would not be very interesting. 622 // Otherwise, a jpeg image is opaque. 623 bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(), 624 colorType, alphaType)); 625 return success ? kSuccess : kFailure; 626 } else { 627 return return_failure(cinfo, *bm, "start_decompress"); 628 } 629 } 630 sampleSize = recompute_sampleSize(sampleSize, cinfo); 631 632 #ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER 633 // should we allow the Chooser (if present) to pick a colortype for us??? 634 if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) { 635 return return_failure(cinfo, *bm, "chooseFromOneChoice"); 636 } 637 #endif 638 639 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 640 // Assume an A8 bitmap is not opaque to avoid the check of each 641 // individual pixel. It is very unlikely to be opaque, since 642 // an opaque A8 bitmap would not be very interesting. 643 // Otherwise, a jpeg image is opaque. 644 bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), 645 colorType, alphaType)); 646 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 647 return kSuccess; 648 } 649 if (!this->allocPixelRef(bm, NULL)) { 650 return return_failure(cinfo, *bm, "allocPixelRef"); 651 } 652 653 SkAutoLockPixels alp(*bm); 654 655 #ifdef ANDROID_RGB 656 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 657 a significant performance boost. 658 */ 659 if (sampleSize == 1 && 660 ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) || 661 (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565))) 662 { 663 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 664 INT32 const bpr = bm->rowBytes(); 665 666 while (cinfo.output_scanline < cinfo.output_height) { 667 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 668 if (0 == row_count) { 669 // if row_count == 0, then we didn't get a scanline, 670 // so return early. We will return a partial image. 671 fill_below_level(cinfo.output_scanline, bm); 672 cinfo.output_scanline = cinfo.output_height; 673 jpeg_finish_decompress(&cinfo); 674 return kPartialSuccess; 675 } 676 if (this->shouldCancelDecode()) { 677 return return_failure(cinfo, *bm, "shouldCancelDecode"); 678 } 679 rowptr += bpr; 680 } 681 jpeg_finish_decompress(&cinfo); 682 return kSuccess; 683 } 684 #endif 685 686 // check for supported formats 687 SkScaledBitmapSampler::SrcConfig sc; 688 int srcBytesPerPixel; 689 690 if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) { 691 return return_failure(cinfo, *bm, "jpeg colorspace"); 692 } 693 694 if (!sampler.begin(bm, sc, *this)) { 695 return return_failure(cinfo, *bm, "sampler.begin"); 696 } 697 698 SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel); 699 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 700 701 // Possibly skip initial rows [sampler.srcY0] 702 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 703 return return_failure(cinfo, *bm, "skip rows"); 704 } 705 706 // now loop through scanlines until y == bm->height() - 1 707 for (int y = 0;; y++) { 708 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 709 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 710 if (0 == row_count) { 711 // if row_count == 0, then we didn't get a scanline, 712 // so return early. We will return a partial image. 713 fill_below_level(y, bm); 714 cinfo.output_scanline = cinfo.output_height; 715 jpeg_finish_decompress(&cinfo); 716 return kSuccess; 717 } 718 if (this->shouldCancelDecode()) { 719 return return_failure(cinfo, *bm, "shouldCancelDecode"); 720 } 721 722 if (JCS_CMYK == cinfo.out_color_space) { 723 convert_CMYK_to_RGB(srcRow, cinfo.output_width); 724 } 725 726 sampler.next(srcRow); 727 if (bm->height() - 1 == y) { 728 // we're done 729 break; 730 } 731 732 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 733 return return_failure(cinfo, *bm, "skip rows"); 734 } 735 } 736 737 // we formally skip the rest, so we don't get a complaint from libjpeg 738 if (!skip_src_rows(&cinfo, srcRow, 739 cinfo.output_height - cinfo.output_scanline)) { 740 return return_failure(cinfo, *bm, "skip rows"); 741 } 742 jpeg_finish_decompress(&cinfo); 743 744 return kSuccess; 745 } 746 747 #ifdef SK_BUILD_FOR_ANDROID 748 bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) { 749 750 SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this))); 751 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 752 753 skjpeg_error_mgr sk_err; 754 set_error_mgr(cinfo, &sk_err); 755 756 // All objects need to be instantiated before this setjmp call so that 757 // they will be cleaned up properly if an error occurs. 758 if (setjmp(sk_err.fJmpBuf)) { 759 return false; 760 } 761 762 // create the cinfo used to create/build the huffmanIndex 763 if (!imageIndex->initializeInfoAndReadHeader()) { 764 return false; 765 } 766 767 if (!imageIndex->buildHuffmanIndex()) { 768 return false; 769 } 770 771 // destroy the cinfo used to create/build the huffman index 772 imageIndex->destroyInfo(); 773 774 // Init decoder to image decode mode 775 if (!imageIndex->initializeInfoAndReadHeader()) { 776 return false; 777 } 778 779 // FIXME: This sets cinfo->out_color_space, which we may change later 780 // based on the config in onDecodeSubset. This should be fine, since 781 // jpeg_init_read_tile_scanline will check out_color_space again after 782 // that change (when it calls jinit_color_deconverter). 783 (void) this->getBitmapColorType(cinfo); 784 785 turn_off_visual_optimizations(cinfo); 786 787 // instead of jpeg_start_decompress() we start a tiled decompress 788 if (!imageIndex->startTileDecompress()) { 789 return false; 790 } 791 792 SkASSERT(1 == cinfo->scale_num); 793 fImageWidth = cinfo->output_width; 794 fImageHeight = cinfo->output_height; 795 796 if (width) { 797 *width = fImageWidth; 798 } 799 if (height) { 800 *height = fImageHeight; 801 } 802 803 SkDELETE(fImageIndex); 804 fImageIndex = imageIndex.detach(); 805 806 return true; 807 } 808 809 bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 810 if (NULL == fImageIndex) { 811 return false; 812 } 813 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 814 815 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 816 if (!rect.intersect(region)) { 817 // If the requested region is entirely outside the image return false 818 return false; 819 } 820 821 822 skjpeg_error_mgr errorManager; 823 set_error_mgr(cinfo, &errorManager); 824 825 if (setjmp(errorManager.fJmpBuf)) { 826 return false; 827 } 828 829 int requestedSampleSize = this->getSampleSize(); 830 cinfo->scale_denom = requestedSampleSize; 831 832 set_dct_method(*this, cinfo); 833 834 const SkColorType colorType = this->getBitmapColorType(cinfo); 835 adjust_out_color_space_and_dither(cinfo, colorType, *this); 836 837 int startX = rect.fLeft; 838 int startY = rect.fTop; 839 int width = rect.width(); 840 int height = rect.height(); 841 842 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 843 &startX, &startY, &width, &height); 844 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 845 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 846 847 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 848 849 SkBitmap bitmap; 850 // Assume an A8 bitmap is not opaque to avoid the check of each 851 // individual pixel. It is very unlikely to be opaque, since 852 // an opaque A8 bitmap would not be very interesting. 853 // Otherwise, a jpeg image is opaque. 854 bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType, 855 kAlpha_8_SkColorType == colorType ? 856 kPremul_SkAlphaType : kOpaque_SkAlphaType)); 857 858 // Check ahead of time if the swap(dest, src) is possible or not. 859 // If yes, then we will stick to AllocPixelRef since it's cheaper with the 860 // swap happening. If no, then we will use alloc to allocate pixels to 861 // prevent garbage collection. 862 int w = rect.width() / actualSampleSize; 863 int h = rect.height() / actualSampleSize; 864 bool swapOnly = (rect == region) && bm->isNull() && 865 (w == bitmap.width()) && (h == bitmap.height()) && 866 ((startX - rect.x()) / actualSampleSize == 0) && 867 ((startY - rect.y()) / actualSampleSize == 0); 868 if (swapOnly) { 869 if (!this->allocPixelRef(&bitmap, NULL)) { 870 return return_false(*cinfo, bitmap, "allocPixelRef"); 871 } 872 } else { 873 if (!bitmap.allocPixels()) { 874 return return_false(*cinfo, bitmap, "allocPixels"); 875 } 876 } 877 878 SkAutoLockPixels alp(bitmap); 879 880 #ifdef ANDROID_RGB 881 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 882 a significant performance boost. 883 */ 884 if (skiaSampleSize == 1 && 885 ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) || 886 (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565))) 887 { 888 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 889 INT32 const bpr = bitmap.rowBytes(); 890 int rowTotalCount = 0; 891 892 while (rowTotalCount < height) { 893 int rowCount = jpeg_read_tile_scanline(cinfo, 894 fImageIndex->huffmanIndex(), 895 &rowptr); 896 // if rowCount == 0, then we didn't get a scanline, so abort. 897 // onDecodeSubset() relies on onBuildTileIndex(), which 898 // needs a complete image to succeed. 899 if (0 == rowCount) { 900 return return_false(*cinfo, bitmap, "read_scanlines"); 901 } 902 if (this->shouldCancelDecode()) { 903 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 904 } 905 rowTotalCount += rowCount; 906 rowptr += bpr; 907 } 908 909 if (swapOnly) { 910 bm->swap(bitmap); 911 } else { 912 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 913 region.width(), region.height(), startX, startY); 914 } 915 return true; 916 } 917 #endif 918 919 // check for supported formats 920 SkScaledBitmapSampler::SrcConfig sc; 921 int srcBytesPerPixel; 922 923 if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) { 924 return return_false(*cinfo, *bm, "jpeg colorspace"); 925 } 926 927 if (!sampler.begin(&bitmap, sc, *this)) { 928 return return_false(*cinfo, bitmap, "sampler.begin"); 929 } 930 931 SkAutoMalloc srcStorage(width * srcBytesPerPixel); 932 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 933 934 // Possibly skip initial rows [sampler.srcY0] 935 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 936 return return_false(*cinfo, bitmap, "skip rows"); 937 } 938 939 // now loop through scanlines until y == bitmap->height() - 1 940 for (int y = 0;; y++) { 941 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 942 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 943 // if row_count == 0, then we didn't get a scanline, so abort. 944 // onDecodeSubset() relies on onBuildTileIndex(), which 945 // needs a complete image to succeed. 946 if (0 == row_count) { 947 return return_false(*cinfo, bitmap, "read_scanlines"); 948 } 949 if (this->shouldCancelDecode()) { 950 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 951 } 952 953 if (JCS_CMYK == cinfo->out_color_space) { 954 convert_CMYK_to_RGB(srcRow, width); 955 } 956 957 sampler.next(srcRow); 958 if (bitmap.height() - 1 == y) { 959 // we're done 960 break; 961 } 962 963 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 964 sampler.srcDY() - 1)) { 965 return return_false(*cinfo, bitmap, "skip rows"); 966 } 967 } 968 if (swapOnly) { 969 bm->swap(bitmap); 970 } else { 971 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 972 region.width(), region.height(), startX, startY); 973 } 974 return true; 975 } 976 #endif 977 978 /////////////////////////////////////////////////////////////////////////////// 979 980 #include "SkColorPriv.h" 981 982 // taken from jcolor.c in libjpeg 983 #if 0 // 16bit - precise but slow 984 #define CYR 19595 // 0.299 985 #define CYG 38470 // 0.587 986 #define CYB 7471 // 0.114 987 988 #define CUR -11059 // -0.16874 989 #define CUG -21709 // -0.33126 990 #define CUB 32768 // 0.5 991 992 #define CVR 32768 // 0.5 993 #define CVG -27439 // -0.41869 994 #define CVB -5329 // -0.08131 995 996 #define CSHIFT 16 997 #else // 8bit - fast, slightly less precise 998 #define CYR 77 // 0.299 999 #define CYG 150 // 0.587 1000 #define CYB 29 // 0.114 1001 1002 #define CUR -43 // -0.16874 1003 #define CUG -85 // -0.33126 1004 #define CUB 128 // 0.5 1005 1006 #define CVR 128 // 0.5 1007 #define CVG -107 // -0.41869 1008 #define CVB -21 // -0.08131 1009 1010 #define CSHIFT 8 1011 #endif 1012 1013 static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 1014 int r = SkGetPackedR32(c); 1015 int g = SkGetPackedG32(c); 1016 int b = SkGetPackedB32(c); 1017 1018 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 1019 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 1020 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 1021 1022 dst[0] = SkToU8(y); 1023 dst[1] = SkToU8(u + 128); 1024 dst[2] = SkToU8(v + 128); 1025 } 1026 1027 static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 1028 int r = SkGetPackedR4444(c); 1029 int g = SkGetPackedG4444(c); 1030 int b = SkGetPackedB4444(c); 1031 1032 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 1033 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 1034 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 1035 1036 dst[0] = SkToU8(y); 1037 dst[1] = SkToU8(u + 128); 1038 dst[2] = SkToU8(v + 128); 1039 } 1040 1041 static void rgb2yuv_16(uint8_t dst[], U16CPU c) { 1042 int r = SkGetPackedR16(c); 1043 int g = SkGetPackedG16(c); 1044 int b = SkGetPackedB16(c); 1045 1046 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 1047 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 1048 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 1049 1050 dst[0] = SkToU8(y); 1051 dst[1] = SkToU8(u + 128); 1052 dst[2] = SkToU8(v + 128); 1053 } 1054 1055 /////////////////////////////////////////////////////////////////////////////// 1056 1057 typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 1058 const void* SK_RESTRICT src, int width, 1059 const SkPMColor* SK_RESTRICT ctable); 1060 1061 static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 1062 const void* SK_RESTRICT srcRow, int width, 1063 const SkPMColor*) { 1064 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 1065 while (--width >= 0) { 1066 #ifdef WE_CONVERT_TO_YUV 1067 rgb2yuv_32(dst, *src++); 1068 #else 1069 uint32_t c = *src++; 1070 dst[0] = SkGetPackedR32(c); 1071 dst[1] = SkGetPackedG32(c); 1072 dst[2] = SkGetPackedB32(c); 1073 #endif 1074 dst += 3; 1075 } 1076 } 1077 1078 static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 1079 const void* SK_RESTRICT srcRow, int width, 1080 const SkPMColor*) { 1081 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 1082 while (--width >= 0) { 1083 #ifdef WE_CONVERT_TO_YUV 1084 rgb2yuv_4444(dst, *src++); 1085 #else 1086 SkPMColor16 c = *src++; 1087 dst[0] = SkPacked4444ToR32(c); 1088 dst[1] = SkPacked4444ToG32(c); 1089 dst[2] = SkPacked4444ToB32(c); 1090 #endif 1091 dst += 3; 1092 } 1093 } 1094 1095 static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 1096 const void* SK_RESTRICT srcRow, int width, 1097 const SkPMColor*) { 1098 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 1099 while (--width >= 0) { 1100 #ifdef WE_CONVERT_TO_YUV 1101 rgb2yuv_16(dst, *src++); 1102 #else 1103 uint16_t c = *src++; 1104 dst[0] = SkPacked16ToR32(c); 1105 dst[1] = SkPacked16ToG32(c); 1106 dst[2] = SkPacked16ToB32(c); 1107 #endif 1108 dst += 3; 1109 } 1110 } 1111 1112 static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 1113 const void* SK_RESTRICT srcRow, int width, 1114 const SkPMColor* SK_RESTRICT ctable) { 1115 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 1116 while (--width >= 0) { 1117 #ifdef WE_CONVERT_TO_YUV 1118 rgb2yuv_32(dst, ctable[*src++]); 1119 #else 1120 uint32_t c = ctable[*src++]; 1121 dst[0] = SkGetPackedR32(c); 1122 dst[1] = SkGetPackedG32(c); 1123 dst[2] = SkGetPackedB32(c); 1124 #endif 1125 dst += 3; 1126 } 1127 } 1128 1129 static WriteScanline ChooseWriter(const SkBitmap& bm) { 1130 switch (bm.colorType()) { 1131 case kN32_SkColorType: 1132 return Write_32_YUV; 1133 case kRGB_565_SkColorType: 1134 return Write_16_YUV; 1135 case kARGB_4444_SkColorType: 1136 return Write_4444_YUV; 1137 case kIndex_8_SkColorType: 1138 return Write_Index_YUV; 1139 default: 1140 return NULL; 1141 } 1142 } 1143 1144 class SkJPEGImageEncoder : public SkImageEncoder { 1145 protected: 1146 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 1147 #ifdef TIME_ENCODE 1148 SkAutoTime atm("JPEG Encode"); 1149 #endif 1150 1151 SkAutoLockPixels alp(bm); 1152 if (NULL == bm.getPixels()) { 1153 return false; 1154 } 1155 1156 jpeg_compress_struct cinfo; 1157 skjpeg_error_mgr sk_err; 1158 skjpeg_destination_mgr sk_wstream(stream); 1159 1160 // allocate these before set call setjmp 1161 SkAutoMalloc oneRow; 1162 SkAutoLockColors ctLocker; 1163 1164 cinfo.err = jpeg_std_error(&sk_err); 1165 sk_err.error_exit = skjpeg_error_exit; 1166 if (setjmp(sk_err.fJmpBuf)) { 1167 return false; 1168 } 1169 1170 // Keep after setjmp or mark volatile. 1171 const WriteScanline writer = ChooseWriter(bm); 1172 if (NULL == writer) { 1173 return false; 1174 } 1175 1176 jpeg_create_compress(&cinfo); 1177 cinfo.dest = &sk_wstream; 1178 cinfo.image_width = bm.width(); 1179 cinfo.image_height = bm.height(); 1180 cinfo.input_components = 3; 1181 #ifdef WE_CONVERT_TO_YUV 1182 cinfo.in_color_space = JCS_YCbCr; 1183 #else 1184 cinfo.in_color_space = JCS_RGB; 1185 #endif 1186 cinfo.input_gamma = 1; 1187 1188 jpeg_set_defaults(&cinfo); 1189 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 1190 #ifdef DCT_IFAST_SUPPORTED 1191 cinfo.dct_method = JDCT_IFAST; 1192 #endif 1193 1194 jpeg_start_compress(&cinfo, TRUE); 1195 1196 const int width = bm.width(); 1197 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 1198 1199 const SkPMColor* colors = ctLocker.lockColors(bm); 1200 const void* srcRow = bm.getPixels(); 1201 1202 while (cinfo.next_scanline < cinfo.image_height) { 1203 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 1204 1205 writer(oneRowP, srcRow, width, colors); 1206 row_pointer[0] = oneRowP; 1207 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 1208 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 1209 } 1210 1211 jpeg_finish_compress(&cinfo); 1212 jpeg_destroy_compress(&cinfo); 1213 1214 return true; 1215 } 1216 }; 1217 1218 /////////////////////////////////////////////////////////////////////////////// 1219 DEFINE_DECODER_CREATOR(JPEGImageDecoder); 1220 DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 1221 /////////////////////////////////////////////////////////////////////////////// 1222 1223 static bool is_jpeg(SkStreamRewindable* stream) { 1224 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1225 static const size_t HEADER_SIZE = sizeof(gHeader); 1226 1227 char buffer[HEADER_SIZE]; 1228 size_t len = stream->read(buffer, HEADER_SIZE); 1229 1230 if (len != HEADER_SIZE) { 1231 return false; // can't read enough 1232 } 1233 if (memcmp(buffer, gHeader, HEADER_SIZE)) { 1234 return false; 1235 } 1236 return true; 1237 } 1238 1239 1240 static SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) { 1241 if (is_jpeg(stream)) { 1242 return SkNEW(SkJPEGImageDecoder); 1243 } 1244 return NULL; 1245 } 1246 1247 static SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) { 1248 if (is_jpeg(stream)) { 1249 return SkImageDecoder::kJPEG_Format; 1250 } 1251 return SkImageDecoder::kUnknown_Format; 1252 } 1253 1254 static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1255 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1256 } 1257 1258 static SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory); 1259 static SkImageDecoder_FormatReg gFormatReg(get_format_jpeg); 1260 static SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory); 1261