SkImageDecoder_libjpeg.cpp revision 39edf4cd94e6fbeb8c1187a588b314e9795c81e4
1 2/* 3 * Copyright 2007 The Android Open Source Project 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkImageDecoder.h" 11#include "SkImageEncoder.h" 12#include "SkJpegUtility.h" 13#include "SkColorPriv.h" 14#include "SkDither.h" 15#include "SkScaledBitmapSampler.h" 16#include "SkStream.h" 17#include "SkTemplates.h" 18#include "SkTime.h" 19#include "SkUtils.h" 20#include "SkRect.h" 21#include "SkCanvas.h" 22 23#include <stdio.h> 24extern "C" { 25 #include "jpeglib.h" 26 #include "jerror.h" 27} 28 29// Uncomment to enable the code path used by the Android framework with their 30// custom image decoders. 31//#if defined(SK_BUILD_FOR_ANDROID) && defined(SK_DEBUG) 32// #define SK_BUILD_FOR_ANDROID_FRAMEWORK 33//#endif 34 35// These enable timing code that report milliseconds for an encoding/decoding 36//#define TIME_ENCODE 37//#define TIME_DECODE 38 39// this enables our rgb->yuv code, which is faster than libjpeg on ARM 40// disable for the moment, as we have some glitches when width != multiple of 4 41#define WE_CONVERT_TO_YUV 42 43// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers 44// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565. 45 46////////////////////////////////////////////////////////////////////////// 47////////////////////////////////////////////////////////////////////////// 48 49static void overwrite_mem_buffer_size(j_decompress_ptr cinfo) { 50#ifdef SK_BUILD_FOR_ANDROID 51 /* Check if the device indicates that it has a large amount of system memory 52 * if so, increase the memory allocation to 30MB instead of the default 5MB. 53 */ 54#ifdef ANDROID_LARGE_MEMORY_DEVICE 55 cinfo->mem->max_memory_to_use = 30 * 1024 * 1024; 56#else 57 cinfo->mem->max_memory_to_use = 5 * 1024 * 1024; 58#endif 59#endif // SK_BUILD_FOR_ANDROID 60} 61 62////////////////////////////////////////////////////////////////////////// 63////////////////////////////////////////////////////////////////////////// 64 65class SkJPEGImageIndex { 66public: 67 SkJPEGImageIndex(SkStream* stream, SkImageDecoder* decoder) 68 : fSrcMgr(stream, decoder, true) {} 69 70 ~SkJPEGImageIndex() { 71#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 72 jpeg_destroy_huffman_index(&fHuffmanIndex); 73#endif 74 jpeg_finish_decompress(&fCInfo); 75 jpeg_destroy_decompress(&fCInfo); 76 } 77 78 /** 79 * Init the cinfo struct using libjpeg and apply any necessary 80 * customizations. 81 */ 82 void initializeInfo() { 83 jpeg_create_decompress(&fCInfo); 84 overwrite_mem_buffer_size(&fCInfo); 85 fCInfo.src = &fSrcMgr; 86 } 87 88 jpeg_decompress_struct* cinfo() { return &fCInfo; } 89 90#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 91 huffman_index* huffmanIndex() { return &fHuffmanIndex; } 92#endif 93 94private: 95 skjpeg_source_mgr fSrcMgr; 96 jpeg_decompress_struct fCInfo; 97#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 98 huffman_index fHuffmanIndex; 99#endif 100}; 101 102class SkJPEGImageDecoder : public SkImageDecoder { 103public: 104 SkJPEGImageDecoder() { 105 fImageIndex = NULL; 106 fImageWidth = 0; 107 fImageHeight = 0; 108 } 109 110 virtual ~SkJPEGImageDecoder() { 111 SkDELETE(fImageIndex); 112 } 113 114 virtual Format getFormat() const { 115 return kJPEG_Format; 116 } 117 118protected: 119#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 120 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE; 121 virtual bool onDecodeRegion(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE; 122#endif 123 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 124 125private: 126 SkJPEGImageIndex* fImageIndex; 127 int fImageWidth; 128 int fImageHeight; 129 130 typedef SkImageDecoder INHERITED; 131}; 132 133////////////////////////////////////////////////////////////////////////// 134 135/* Automatically clean up after throwing an exception */ 136class JPEGAutoClean { 137public: 138 JPEGAutoClean(): cinfo_ptr(NULL) {} 139 ~JPEGAutoClean() { 140 if (cinfo_ptr) { 141 jpeg_destroy_decompress(cinfo_ptr); 142 } 143 } 144 void set(jpeg_decompress_struct* info) { 145 cinfo_ptr = info; 146 } 147private: 148 jpeg_decompress_struct* cinfo_ptr; 149}; 150 151/////////////////////////////////////////////////////////////////////////////// 152 153/* If we need to better match the request, we might examine the image and 154 output dimensions, and determine if the downsampling jpeg provided is 155 not sufficient. If so, we can recompute a modified sampleSize value to 156 make up the difference. 157 158 To skip this additional scaling, just set sampleSize = 1; below. 159 */ 160static int recompute_sampleSize(int sampleSize, 161 const jpeg_decompress_struct& cinfo) { 162 return sampleSize * cinfo.output_width / cinfo.image_width; 163} 164 165static bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) { 166 /* These are initialized to 0, so if they have non-zero values, we assume 167 they are "valid" (i.e. have been computed by libjpeg) 168 */ 169 return 0 != cinfo.output_width && 0 != cinfo.output_height; 170} 171 172static bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) { 173 for (int i = 0; i < count; i++) { 174 JSAMPLE* rowptr = (JSAMPLE*)buffer; 175 int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1); 176 if (1 != row_count) { 177 return false; 178 } 179 } 180 return true; 181} 182 183#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 184static bool skip_src_rows_tile(jpeg_decompress_struct* cinfo, 185 huffman_index *index, void* buffer, int count) { 186 for (int i = 0; i < count; i++) { 187 JSAMPLE* rowptr = (JSAMPLE*)buffer; 188 int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr); 189 if (1 != row_count) { 190 return false; 191 } 192 } 193 return true; 194} 195#endif 196 197// This guy exists just to aid in debugging, as it allows debuggers to just 198// set a break-point in one place to see all error exists. 199static bool return_false(const jpeg_decompress_struct& cinfo, 200 const SkBitmap& bm, const char msg[]) { 201#ifdef SK_DEBUG 202 SkDebugf("libjpeg error %d <%s> from %s [%d %d]", cinfo.err->msg_code, 203 cinfo.err->jpeg_message_table[cinfo.err->msg_code], msg, 204 bm.width(), bm.height()); 205#endif 206 return false; // must always return false 207} 208 209// Convert a scanline of CMYK samples to RGBX in place. Note that this 210// method moves the "scanline" pointer in its processing 211static void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) { 212 // At this point we've received CMYK pixels from libjpeg. We 213 // perform a crude conversion to RGB (based on the formulae 214 // from easyrgb.com): 215 // CMYK -> CMY 216 // C = ( C * (1 - K) + K ) // for each CMY component 217 // CMY -> RGB 218 // R = ( 1 - C ) * 255 // for each RGB component 219 // Unfortunately we are seeing inverted CMYK so all the original terms 220 // are 1-. This yields: 221 // CMYK -> CMY 222 // C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K 223 // The conversion from CMY->RGB remains the same 224 for (unsigned int x = 0; x < width; ++x, scanline += 4) { 225 scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]); 226 scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]); 227 scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]); 228 scanline[3] = 255; 229 } 230} 231 232bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 233#ifdef TIME_DECODE 234 SkAutoTime atm("JPEG Decode"); 235#endif 236 237 JPEGAutoClean autoClean; 238 239 jpeg_decompress_struct cinfo; 240 skjpeg_error_mgr errorManager; 241 skjpeg_source_mgr srcManager(stream, this, false); 242 243 cinfo.err = jpeg_std_error(&errorManager); 244 errorManager.error_exit = skjpeg_error_exit; 245 246 // All objects need to be instantiated before this setjmp call so that 247 // they will be cleaned up properly if an error occurs. 248 if (setjmp(errorManager.fJmpBuf)) { 249 return return_false(cinfo, *bm, "setjmp"); 250 } 251 252 jpeg_create_decompress(&cinfo); 253 autoClean.set(&cinfo); 254 255 overwrite_mem_buffer_size(&cinfo); 256 257 //jpeg_stdio_src(&cinfo, file); 258 cinfo.src = &srcManager; 259 260 int status = jpeg_read_header(&cinfo, true); 261 if (status != JPEG_HEADER_OK) { 262 return return_false(cinfo, *bm, "read_header"); 263 } 264 265 /* Try to fulfill the requested sampleSize. Since jpeg can do it (when it 266 can) much faster that we, just use their num/denom api to approximate 267 the size. 268 */ 269 int sampleSize = this->getSampleSize(); 270 271#ifdef DCT_IFAST_SUPPORTED 272 if (this->getPreferQualityOverSpeed()) { 273 cinfo.dct_method = JDCT_ISLOW; 274 } else { 275 cinfo.dct_method = JDCT_IFAST; 276 } 277#else 278 cinfo.dct_method = JDCT_ISLOW; 279#endif 280 281 cinfo.scale_num = 1; 282 cinfo.scale_denom = sampleSize; 283 284 /* this gives about 30% performance improvement. In theory it may 285 reduce the visual quality, in practice I'm not seeing a difference 286 */ 287 cinfo.do_fancy_upsampling = 0; 288 289 /* this gives another few percents */ 290 cinfo.do_block_smoothing = 0; 291 292 /* default format is RGB */ 293 if (cinfo.jpeg_color_space == JCS_CMYK) { 294 // libjpeg cannot convert from CMYK to RGB - here we set up 295 // so libjpeg will give us CMYK samples back and we will 296 // later manually convert them to RGB 297 cinfo.out_color_space = JCS_CMYK; 298 } else { 299 cinfo.out_color_space = JCS_RGB; 300 } 301 302 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); 303 // only these make sense for jpegs 304 if (config != SkBitmap::kARGB_8888_Config && 305 config != SkBitmap::kARGB_4444_Config && 306 config != SkBitmap::kRGB_565_Config) { 307 config = SkBitmap::kARGB_8888_Config; 308 } 309 310#ifdef ANDROID_RGB 311 cinfo.dither_mode = JDITHER_NONE; 312 if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) { 313 cinfo.out_color_space = JCS_RGBA_8888; 314 } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) { 315 cinfo.out_color_space = JCS_RGB_565; 316 if (this->getDitherImage()) { 317 cinfo.dither_mode = JDITHER_ORDERED; 318 } 319 } 320#endif 321 322 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 323 bm->setConfig(config, cinfo.image_width, cinfo.image_height); 324 bm->setIsOpaque(true); 325 return true; 326 } 327 328 /* image_width and image_height are the original dimensions, available 329 after jpeg_read_header(). To see the scaled dimensions, we have to call 330 jpeg_start_decompress(), and then read output_width and output_height. 331 */ 332 if (!jpeg_start_decompress(&cinfo)) { 333 /* If we failed here, we may still have enough information to return 334 to the caller if they just wanted (subsampled bounds). If sampleSize 335 was 1, then we would have already returned. Thus we just check if 336 we're in kDecodeBounds_Mode, and that we have valid output sizes. 337 338 One reason to fail here is that we have insufficient stream data 339 to complete the setup. However, output dimensions seem to get 340 computed very early, which is why this special check can pay off. 341 */ 342 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 343 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 344 recompute_sampleSize(sampleSize, cinfo)); 345 bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight()); 346 bm->setIsOpaque(true); 347 return true; 348 } else { 349 return return_false(cinfo, *bm, "start_decompress"); 350 } 351 } 352 sampleSize = recompute_sampleSize(sampleSize, cinfo); 353 354 // should we allow the Chooser (if present) to pick a config for us??? 355 if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) { 356 return return_false(cinfo, *bm, "chooseFromOneChoice"); 357 } 358 359 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 360 361 bm->lockPixels(); 362 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 363 bm->unlockPixels(); 364 bool reuseBitmap = (rowptr != NULL); 365 366 if (reuseBitmap) { 367 if (sampler.scaledWidth() != bm->width() || 368 sampler.scaledHeight() != bm->height()) { 369 // Dimensions must match 370 return false; 371 } else if (SkImageDecoder::kDecodeBounds_Mode == mode) { 372 return true; 373 } 374 } else { 375 bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 376 bm->setIsOpaque(true); 377 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 378 return true; 379 } 380 if (!this->allocPixelRef(bm, NULL)) { 381 return return_false(cinfo, *bm, "allocPixelRef"); 382 } 383 } 384 385 SkAutoLockPixels alp(*bm); 386 387#ifdef ANDROID_RGB 388 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 389 a significant performance boost. 390 */ 391 if (sampleSize == 1 && 392 ((config == SkBitmap::kARGB_8888_Config && 393 cinfo.out_color_space == JCS_RGBA_8888) || 394 (config == SkBitmap::kRGB_565_Config && 395 cinfo.out_color_space == JCS_RGB_565))) 396 { 397 rowptr = (JSAMPLE*)bm->getPixels(); 398 INT32 const bpr = bm->rowBytes(); 399 400 while (cinfo.output_scanline < cinfo.output_height) { 401 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 402 // if row_count == 0, then we didn't get a scanline, so abort. 403 // if we supported partial images, we might return true in this case 404 if (0 == row_count) { 405 return return_false(cinfo, *bm, "read_scanlines"); 406 } 407 if (this->shouldCancelDecode()) { 408 return return_false(cinfo, *bm, "shouldCancelDecode"); 409 } 410 rowptr += bpr; 411 } 412 if (reuseBitmap) { 413 bm->notifyPixelsChanged(); 414 } 415 jpeg_finish_decompress(&cinfo); 416 return true; 417 } 418#endif 419 420 // check for supported formats 421 SkScaledBitmapSampler::SrcConfig sc; 422 if (JCS_CMYK == cinfo.out_color_space) { 423 // In this case we will manually convert the CMYK values to RGB 424 sc = SkScaledBitmapSampler::kRGBX; 425 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 426 sc = SkScaledBitmapSampler::kRGB; 427#ifdef ANDROID_RGB 428 } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 429 sc = SkScaledBitmapSampler::kRGBX; 430 } else if (JCS_RGB_565 == cinfo.out_color_space) { 431 sc = SkScaledBitmapSampler::kRGB_565; 432#endif 433 } else if (1 == cinfo.out_color_components && 434 JCS_GRAYSCALE == cinfo.out_color_space) { 435 sc = SkScaledBitmapSampler::kGray; 436 } else { 437 return return_false(cinfo, *bm, "jpeg colorspace"); 438 } 439 440 if (!sampler.begin(bm, sc, this->getDitherImage())) { 441 return return_false(cinfo, *bm, "sampler.begin"); 442 } 443 444 // The CMYK work-around relies on 4 components per pixel here 445 SkAutoMalloc srcStorage(cinfo.output_width * 4); 446 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 447 448 // Possibly skip initial rows [sampler.srcY0] 449 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 450 return return_false(cinfo, *bm, "skip rows"); 451 } 452 453 // now loop through scanlines until y == bm->height() - 1 454 for (int y = 0;; y++) { 455 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 456 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 457 if (0 == row_count) { 458 return return_false(cinfo, *bm, "read_scanlines"); 459 } 460 if (this->shouldCancelDecode()) { 461 return return_false(cinfo, *bm, "shouldCancelDecode"); 462 } 463 464 if (JCS_CMYK == cinfo.out_color_space) { 465 convert_CMYK_to_RGB(srcRow, cinfo.output_width); 466 } 467 468 sampler.next(srcRow); 469 if (bm->height() - 1 == y) { 470 // we're done 471 break; 472 } 473 474 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 475 return return_false(cinfo, *bm, "skip rows"); 476 } 477 } 478 479 // we formally skip the rest, so we don't get a complaint from libjpeg 480 if (!skip_src_rows(&cinfo, srcRow, 481 cinfo.output_height - cinfo.output_scanline)) { 482 return return_false(cinfo, *bm, "skip rows"); 483 } 484 if (reuseBitmap) { 485 bm->notifyPixelsChanged(); 486 } 487 jpeg_finish_decompress(&cinfo); 488 489 return true; 490} 491 492#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 493bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) { 494 495 SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this)); 496 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 497 huffman_index* huffmanIndex = imageIndex->huffmanIndex(); 498 499 skjpeg_error_mgr sk_err; 500 cinfo->err = jpeg_std_error(&sk_err); 501 sk_err.error_exit = skjpeg_error_exit; 502 503 // All objects need to be instantiated before this setjmp call so that 504 // they will be cleaned up properly if an error occurs. 505 if (setjmp(sk_err.fJmpBuf)) { 506 return false; 507 } 508 509 // create the cinfo used to create/build the huffmanIndex 510 imageIndex->initializeInfo(); 511 cinfo->do_fancy_upsampling = 0; 512 cinfo->do_block_smoothing = 0; 513 514 int status = jpeg_read_header(cinfo, true); 515 if (JPEG_HEADER_OK != status) { 516 SkDELETE(imageIndex); 517 return false; 518 } 519 520 jpeg_create_huffman_index(cinfo, huffmanIndex); 521 cinfo->scale_num = 1; 522 cinfo->scale_denom = 1; 523 if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { 524 SkDELETE(imageIndex); 525 return false; 526 } 527 528 // destroy the cinfo used to create/build the huffman index 529 jpeg_destroy_decompress(cinfo); 530 531 // Init decoder to image decode mode 532 imageIndex->initializeInfo(); 533 534 status = jpeg_read_header(cinfo, true); 535 if (JPEG_HEADER_OK != status) { 536 SkDELETE(imageIndex); 537 return false; 538 } 539 540 cinfo->out_color_space = JCS_RGBA_8888; 541 cinfo->do_fancy_upsampling = 0; 542 cinfo->do_block_smoothing = 0; 543 544 // instead of jpeg_start_decompress() we start a tiled decompress 545 jpeg_start_tile_decompress(cinfo); 546 547 cinfo->scale_num = 1; 548 *height = cinfo->output_height; 549 *width = cinfo->output_width; 550 fImageWidth = *width; 551 fImageHeight = *height; 552 553 SkDELETE(fImageIndex); 554 fImageIndex = imageIndex; 555 556 return true; 557} 558 559bool SkJPEGImageDecoder::onDecodeRegion(SkBitmap* bm, const SkIRect& region) { 560 if (NULL == fImageIndex) { 561 return false; 562 } 563 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 564 565 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 566 if (!rect.intersect(region)) { 567 // If the requested region is entirely outside the image return false 568 return false; 569 } 570 571 572 skjpeg_error_mgr errorManager; 573 cinfo->err = jpeg_std_error(&errorManager); 574 errorManager.error_exit = skjpeg_error_exit; 575 if (setjmp(errorManager.fJmpBuf)) { 576 return false; 577 } 578 579 int requestedSampleSize = this->getSampleSize(); 580 cinfo->scale_denom = requestedSampleSize; 581 582 if (this->getPreferQualityOverSpeed()) { 583 cinfo->dct_method = JDCT_ISLOW; 584 } else { 585 cinfo->dct_method = JDCT_IFAST; 586 } 587 588 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); 589 if (config != SkBitmap::kARGB_8888_Config && 590 config != SkBitmap::kARGB_4444_Config && 591 config != SkBitmap::kRGB_565_Config) { 592 config = SkBitmap::kARGB_8888_Config; 593 } 594 595 /* default format is RGB */ 596 cinfo->out_color_space = JCS_RGB; 597 598#ifdef ANDROID_RGB 599 cinfo->dither_mode = JDITHER_NONE; 600 if (SkBitmap::kARGB_8888_Config == config) { 601 cinfo->out_color_space = JCS_RGBA_8888; 602 } else if (SkBitmap::kRGB_565_Config == config) { 603 cinfo->out_color_space = JCS_RGB_565; 604 if (this->getDitherImage()) { 605 cinfo->dither_mode = JDITHER_ORDERED; 606 } 607 } 608#endif 609 610 int startX = rect.fLeft; 611 int startY = rect.fTop; 612 int width = rect.width(); 613 int height = rect.height(); 614 615 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 616 &startX, &startY, &width, &height); 617 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 618 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 619 620 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 621 622 SkBitmap bitmap; 623 bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 624 bitmap.setIsOpaque(true); 625 626 // Check ahead of time if the swap(dest, src) is possible or not. 627 // If yes, then we will stick to AllocPixelRef since it's cheaper with the 628 // swap happening. If no, then we will use alloc to allocate pixels to 629 // prevent garbage collection. 630 int w = rect.width() / actualSampleSize; 631 int h = rect.height() / actualSampleSize; 632 bool swapOnly = (rect == region) && bm->isNull() && 633 (w == bitmap.width()) && (h == bitmap.height()) && 634 ((startX - rect.x()) / actualSampleSize == 0) && 635 ((startY - rect.y()) / actualSampleSize == 0); 636 if (swapOnly) { 637 if (!this->allocPixelRef(&bitmap, NULL)) { 638 return return_false(*cinfo, bitmap, "allocPixelRef"); 639 } 640 } else { 641 if (!bitmap.allocPixels()) { 642 return return_false(*cinfo, bitmap, "allocPixels"); 643 } 644 } 645 646 SkAutoLockPixels alp(bitmap); 647 648#ifdef ANDROID_RGB 649 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 650 a significant performance boost. 651 */ 652 if (skiaSampleSize == 1 && 653 ((config == SkBitmap::kARGB_8888_Config && 654 cinfo->out_color_space == JCS_RGBA_8888) || 655 (config == SkBitmap::kRGB_565_Config && 656 cinfo->out_color_space == JCS_RGB_565))) 657 { 658 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 659 INT32 const bpr = bitmap.rowBytes(); 660 int rowTotalCount = 0; 661 662 while (rowTotalCount < height) { 663 int rowCount = jpeg_read_tile_scanline(cinfo, 664 fImageIndex->huffmanIndex(), 665 &rowptr); 666 // if row_count == 0, then we didn't get a scanline, so abort. 667 // if we supported partial images, we might return true in this case 668 if (0 == rowCount) { 669 return return_false(*cinfo, bitmap, "read_scanlines"); 670 } 671 if (this->shouldCancelDecode()) { 672 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 673 } 674 rowTotalCount += rowCount; 675 rowptr += bpr; 676 } 677 678 if (swapOnly) { 679 bm->swap(bitmap); 680 } else { 681 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 682 region.width(), region.height(), startX, startY); 683 } 684 return true; 685 } 686#endif 687 688 // check for supported formats 689 SkScaledBitmapSampler::SrcConfig sc; 690 if (JCS_CMYK == cinfo->out_color_space) { 691 // In this case we will manually convert the CMYK values to RGB 692 sc = SkScaledBitmapSampler::kRGBX; 693 } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) { 694 sc = SkScaledBitmapSampler::kRGB; 695#ifdef ANDROID_RGB 696 } else if (JCS_RGBA_8888 == cinfo->out_color_space) { 697 sc = SkScaledBitmapSampler::kRGBX; 698 } else if (JCS_RGB_565 == cinfo->out_color_space) { 699 sc = SkScaledBitmapSampler::kRGB_565; 700#endif 701 } else if (1 == cinfo->out_color_components && 702 JCS_GRAYSCALE == cinfo->out_color_space) { 703 sc = SkScaledBitmapSampler::kGray; 704 } else { 705 return return_false(*cinfo, *bm, "jpeg colorspace"); 706 } 707 708 if (!sampler.begin(&bitmap, sc, this->getDitherImage())) { 709 return return_false(*cinfo, bitmap, "sampler.begin"); 710 } 711 712 // The CMYK work-around relies on 4 components per pixel here 713 SkAutoMalloc srcStorage(width * 4); 714 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 715 716 // Possibly skip initial rows [sampler.srcY0] 717 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 718 return return_false(*cinfo, bitmap, "skip rows"); 719 } 720 721 // now loop through scanlines until y == bitmap->height() - 1 722 for (int y = 0;; y++) { 723 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 724 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 725 if (0 == row_count) { 726 return return_false(*cinfo, bitmap, "read_scanlines"); 727 } 728 if (this->shouldCancelDecode()) { 729 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 730 } 731 732 if (JCS_CMYK == cinfo->out_color_space) { 733 convert_CMYK_to_RGB(srcRow, width); 734 } 735 736 sampler.next(srcRow); 737 if (bitmap.height() - 1 == y) { 738 // we're done 739 break; 740 } 741 742 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 743 sampler.srcDY() - 1)) { 744 return return_false(*cinfo, bitmap, "skip rows"); 745 } 746 } 747 if (swapOnly) { 748 bm->swap(bitmap); 749 } else { 750 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 751 region.width(), region.height(), startX, startY); 752 } 753 return true; 754} 755#endif 756 757/////////////////////////////////////////////////////////////////////////////// 758 759#include "SkColorPriv.h" 760 761// taken from jcolor.c in libjpeg 762#if 0 // 16bit - precise but slow 763 #define CYR 19595 // 0.299 764 #define CYG 38470 // 0.587 765 #define CYB 7471 // 0.114 766 767 #define CUR -11059 // -0.16874 768 #define CUG -21709 // -0.33126 769 #define CUB 32768 // 0.5 770 771 #define CVR 32768 // 0.5 772 #define CVG -27439 // -0.41869 773 #define CVB -5329 // -0.08131 774 775 #define CSHIFT 16 776#else // 8bit - fast, slightly less precise 777 #define CYR 77 // 0.299 778 #define CYG 150 // 0.587 779 #define CYB 29 // 0.114 780 781 #define CUR -43 // -0.16874 782 #define CUG -85 // -0.33126 783 #define CUB 128 // 0.5 784 785 #define CVR 128 // 0.5 786 #define CVG -107 // -0.41869 787 #define CVB -21 // -0.08131 788 789 #define CSHIFT 8 790#endif 791 792static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 793 int r = SkGetPackedR32(c); 794 int g = SkGetPackedG32(c); 795 int b = SkGetPackedB32(c); 796 797 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 798 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 799 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 800 801 dst[0] = SkToU8(y); 802 dst[1] = SkToU8(u + 128); 803 dst[2] = SkToU8(v + 128); 804} 805 806static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 807 int r = SkGetPackedR4444(c); 808 int g = SkGetPackedG4444(c); 809 int b = SkGetPackedB4444(c); 810 811 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 812 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 813 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 814 815 dst[0] = SkToU8(y); 816 dst[1] = SkToU8(u + 128); 817 dst[2] = SkToU8(v + 128); 818} 819 820static void rgb2yuv_16(uint8_t dst[], U16CPU c) { 821 int r = SkGetPackedR16(c); 822 int g = SkGetPackedG16(c); 823 int b = SkGetPackedB16(c); 824 825 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 826 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 827 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 828 829 dst[0] = SkToU8(y); 830 dst[1] = SkToU8(u + 128); 831 dst[2] = SkToU8(v + 128); 832} 833 834/////////////////////////////////////////////////////////////////////////////// 835 836typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 837 const void* SK_RESTRICT src, int width, 838 const SkPMColor* SK_RESTRICT ctable); 839 840static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 841 const void* SK_RESTRICT srcRow, int width, 842 const SkPMColor*) { 843 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 844 while (--width >= 0) { 845#ifdef WE_CONVERT_TO_YUV 846 rgb2yuv_32(dst, *src++); 847#else 848 uint32_t c = *src++; 849 dst[0] = SkGetPackedR32(c); 850 dst[1] = SkGetPackedG32(c); 851 dst[2] = SkGetPackedB32(c); 852#endif 853 dst += 3; 854 } 855} 856 857static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 858 const void* SK_RESTRICT srcRow, int width, 859 const SkPMColor*) { 860 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 861 while (--width >= 0) { 862#ifdef WE_CONVERT_TO_YUV 863 rgb2yuv_4444(dst, *src++); 864#else 865 SkPMColor16 c = *src++; 866 dst[0] = SkPacked4444ToR32(c); 867 dst[1] = SkPacked4444ToG32(c); 868 dst[2] = SkPacked4444ToB32(c); 869#endif 870 dst += 3; 871 } 872} 873 874static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 875 const void* SK_RESTRICT srcRow, int width, 876 const SkPMColor*) { 877 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 878 while (--width >= 0) { 879#ifdef WE_CONVERT_TO_YUV 880 rgb2yuv_16(dst, *src++); 881#else 882 uint16_t c = *src++; 883 dst[0] = SkPacked16ToR32(c); 884 dst[1] = SkPacked16ToG32(c); 885 dst[2] = SkPacked16ToB32(c); 886#endif 887 dst += 3; 888 } 889} 890 891static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 892 const void* SK_RESTRICT srcRow, int width, 893 const SkPMColor* SK_RESTRICT ctable) { 894 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 895 while (--width >= 0) { 896#ifdef WE_CONVERT_TO_YUV 897 rgb2yuv_32(dst, ctable[*src++]); 898#else 899 uint32_t c = ctable[*src++]; 900 dst[0] = SkGetPackedR32(c); 901 dst[1] = SkGetPackedG32(c); 902 dst[2] = SkGetPackedB32(c); 903#endif 904 dst += 3; 905 } 906} 907 908static WriteScanline ChooseWriter(const SkBitmap& bm) { 909 switch (bm.config()) { 910 case SkBitmap::kARGB_8888_Config: 911 return Write_32_YUV; 912 case SkBitmap::kRGB_565_Config: 913 return Write_16_YUV; 914 case SkBitmap::kARGB_4444_Config: 915 return Write_4444_YUV; 916 case SkBitmap::kIndex8_Config: 917 return Write_Index_YUV; 918 default: 919 return NULL; 920 } 921} 922 923class SkJPEGImageEncoder : public SkImageEncoder { 924protected: 925 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 926#ifdef TIME_ENCODE 927 SkAutoTime atm("JPEG Encode"); 928#endif 929 930 const WriteScanline writer = ChooseWriter(bm); 931 if (NULL == writer) { 932 return false; 933 } 934 935 SkAutoLockPixels alp(bm); 936 if (NULL == bm.getPixels()) { 937 return false; 938 } 939 940 jpeg_compress_struct cinfo; 941 skjpeg_error_mgr sk_err; 942 skjpeg_destination_mgr sk_wstream(stream); 943 944 // allocate these before set call setjmp 945 SkAutoMalloc oneRow; 946 SkAutoLockColors ctLocker; 947 948 cinfo.err = jpeg_std_error(&sk_err); 949 sk_err.error_exit = skjpeg_error_exit; 950 if (setjmp(sk_err.fJmpBuf)) { 951 return false; 952 } 953 jpeg_create_compress(&cinfo); 954 955 cinfo.dest = &sk_wstream; 956 cinfo.image_width = bm.width(); 957 cinfo.image_height = bm.height(); 958 cinfo.input_components = 3; 959#ifdef WE_CONVERT_TO_YUV 960 cinfo.in_color_space = JCS_YCbCr; 961#else 962 cinfo.in_color_space = JCS_RGB; 963#endif 964 cinfo.input_gamma = 1; 965 966 jpeg_set_defaults(&cinfo); 967 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 968#ifdef DCT_IFAST_SUPPORTED 969 cinfo.dct_method = JDCT_IFAST; 970#endif 971 972 jpeg_start_compress(&cinfo, TRUE); 973 974 const int width = bm.width(); 975 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 976 977 const SkPMColor* colors = ctLocker.lockColors(bm); 978 const void* srcRow = bm.getPixels(); 979 980 while (cinfo.next_scanline < cinfo.image_height) { 981 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 982 983 writer(oneRowP, srcRow, width, colors); 984 row_pointer[0] = oneRowP; 985 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 986 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 987 } 988 989 jpeg_finish_compress(&cinfo); 990 jpeg_destroy_compress(&cinfo); 991 992 return true; 993 } 994}; 995 996/////////////////////////////////////////////////////////////////////////////// 997DEFINE_DECODER_CREATOR(JPEGImageDecoder); 998DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 999/////////////////////////////////////////////////////////////////////////////// 1000 1001static bool is_jpeg(SkStream* stream) { 1002 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 1003 static const size_t HEADER_SIZE = sizeof(gHeader); 1004 1005 char buffer[HEADER_SIZE]; 1006 size_t len = stream->read(buffer, HEADER_SIZE); 1007 1008 if (len != HEADER_SIZE) { 1009 return false; // can't read enough 1010 } 1011 if (memcmp(buffer, gHeader, HEADER_SIZE)) { 1012 return false; 1013 } 1014 return true; 1015} 1016 1017#include "SkTRegistry.h" 1018 1019static SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) { 1020 if (is_jpeg(stream)) { 1021 return SkNEW(SkJPEGImageDecoder); 1022 } 1023 return NULL; 1024} 1025 1026static SkImageDecoder::Format get_format_jpeg(SkStream* stream) { 1027 if (is_jpeg(stream)) { 1028 return SkImageDecoder::kJPEG_Format; 1029 } 1030 return SkImageDecoder::kUnknown_Format; 1031} 1032 1033static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1034 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1035} 1036 1037 1038static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); 1039static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg); 1040static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory); 1041