SkImageDecoder_libjpeg.cpp revision 58190644c30e1c4aa8e527f3503c58f841e0fcf3
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 onDecodeSubset(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]\n", 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 SrcDepth srcDepth = k32Bit_SrcDepth; 293 /* default format is RGB */ 294 if (cinfo.jpeg_color_space == JCS_CMYK) { 295 // libjpeg cannot convert from CMYK to RGB - here we set up 296 // so libjpeg will give us CMYK samples back and we will 297 // later manually convert them to RGB 298 cinfo.out_color_space = JCS_CMYK; 299 } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { 300 cinfo.out_color_space = JCS_GRAYSCALE; 301 srcDepth = k8BitGray_SrcDepth; 302 } else { 303 cinfo.out_color_space = JCS_RGB; 304 } 305 306 SkBitmap::Config config = this->getPrefConfig(srcDepth, false); 307 // only these make sense for jpegs 308 if (SkBitmap::kA8_Config == config) { 309 if (cinfo.jpeg_color_space != JCS_GRAYSCALE) { 310 // Converting from a non grayscale image to A8 is 311 // not currently supported. 312 config = SkBitmap::kARGB_8888_Config; 313 // Change the output from jpeg back to RGB. 314 cinfo.out_color_space = JCS_RGB; 315 } 316 } else if (config != SkBitmap::kARGB_8888_Config && 317 config != SkBitmap::kARGB_4444_Config && 318 config != SkBitmap::kRGB_565_Config) { 319 config = SkBitmap::kARGB_8888_Config; 320 } 321 322#ifdef ANDROID_RGB 323 cinfo.dither_mode = JDITHER_NONE; 324 if (SkBitmap::kARGB_8888_Config == config && JCS_CMYK != cinfo.out_color_space) { 325 cinfo.out_color_space = JCS_RGBA_8888; 326 } else if (SkBitmap::kRGB_565_Config == config && JCS_CMYK != cinfo.out_color_space) { 327 cinfo.out_color_space = JCS_RGB_565; 328 if (this->getDitherImage()) { 329 cinfo.dither_mode = JDITHER_ORDERED; 330 } 331 } 332#endif 333 334 if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) { 335 bm->setConfig(config, cinfo.image_width, cinfo.image_height); 336 bm->setIsOpaque(config != SkBitmap::kA8_Config); 337 return true; 338 } 339 340 /* image_width and image_height are the original dimensions, available 341 after jpeg_read_header(). To see the scaled dimensions, we have to call 342 jpeg_start_decompress(), and then read output_width and output_height. 343 */ 344 if (!jpeg_start_decompress(&cinfo)) { 345 /* If we failed here, we may still have enough information to return 346 to the caller if they just wanted (subsampled bounds). If sampleSize 347 was 1, then we would have already returned. Thus we just check if 348 we're in kDecodeBounds_Mode, and that we have valid output sizes. 349 350 One reason to fail here is that we have insufficient stream data 351 to complete the setup. However, output dimensions seem to get 352 computed very early, which is why this special check can pay off. 353 */ 354 if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) { 355 SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height, 356 recompute_sampleSize(sampleSize, cinfo)); 357 bm->setConfig(config, smpl.scaledWidth(), smpl.scaledHeight()); 358 bm->setIsOpaque(config != SkBitmap::kA8_Config); 359 return true; 360 } else { 361 return return_false(cinfo, *bm, "start_decompress"); 362 } 363 } 364 sampleSize = recompute_sampleSize(sampleSize, cinfo); 365 366 // should we allow the Chooser (if present) to pick a config for us??? 367 if (!this->chooseFromOneChoice(config, cinfo.output_width, cinfo.output_height)) { 368 return return_false(cinfo, *bm, "chooseFromOneChoice"); 369 } 370 371 SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize); 372 bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 373 bm->setIsOpaque(config != SkBitmap::kA8_Config); 374 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 375 return true; 376 } 377 if (!this->allocPixelRef(bm, NULL)) { 378 return return_false(cinfo, *bm, "allocPixelRef"); 379 } 380 381 SkAutoLockPixels alp(*bm); 382 383#ifdef ANDROID_RGB 384 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 385 a significant performance boost. 386 */ 387 if (sampleSize == 1 && 388 ((config == SkBitmap::kARGB_8888_Config && 389 cinfo.out_color_space == JCS_RGBA_8888) || 390 (config == SkBitmap::kRGB_565_Config && 391 cinfo.out_color_space == JCS_RGB_565))) 392 { 393 JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels(); 394 INT32 const bpr = bm->rowBytes(); 395 396 while (cinfo.output_scanline < cinfo.output_height) { 397 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 398 // if row_count == 0, then we didn't get a scanline, so abort. 399 // if we supported partial images, we might return true in this case 400 if (0 == row_count) { 401 return return_false(cinfo, *bm, "read_scanlines"); 402 } 403 if (this->shouldCancelDecode()) { 404 return return_false(cinfo, *bm, "shouldCancelDecode"); 405 } 406 rowptr += bpr; 407 } 408 jpeg_finish_decompress(&cinfo); 409 return true; 410 } 411#endif 412 413 // check for supported formats 414 SkScaledBitmapSampler::SrcConfig sc; 415 if (JCS_CMYK == cinfo.out_color_space) { 416 // In this case we will manually convert the CMYK values to RGB 417 sc = SkScaledBitmapSampler::kRGBX; 418 } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) { 419 sc = SkScaledBitmapSampler::kRGB; 420#ifdef ANDROID_RGB 421 } else if (JCS_RGBA_8888 == cinfo.out_color_space) { 422 sc = SkScaledBitmapSampler::kRGBX; 423 } else if (JCS_RGB_565 == cinfo.out_color_space) { 424 sc = SkScaledBitmapSampler::kRGB_565; 425#endif 426 } else if (1 == cinfo.out_color_components && 427 JCS_GRAYSCALE == cinfo.out_color_space) { 428 sc = SkScaledBitmapSampler::kGray; 429 } else { 430 return return_false(cinfo, *bm, "jpeg colorspace"); 431 } 432 433 if (!sampler.begin(bm, sc, this->getDitherImage())) { 434 return return_false(cinfo, *bm, "sampler.begin"); 435 } 436 437 // The CMYK work-around relies on 4 components per pixel here 438 SkAutoMalloc srcStorage(cinfo.output_width * 4); 439 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 440 441 // Possibly skip initial rows [sampler.srcY0] 442 if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) { 443 return return_false(cinfo, *bm, "skip rows"); 444 } 445 446 // now loop through scanlines until y == bm->height() - 1 447 for (int y = 0;; y++) { 448 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 449 int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1); 450 if (0 == row_count) { 451 return return_false(cinfo, *bm, "read_scanlines"); 452 } 453 if (this->shouldCancelDecode()) { 454 return return_false(cinfo, *bm, "shouldCancelDecode"); 455 } 456 457 if (JCS_CMYK == cinfo.out_color_space) { 458 convert_CMYK_to_RGB(srcRow, cinfo.output_width); 459 } 460 461 sampler.next(srcRow); 462 if (bm->height() - 1 == y) { 463 // we're done 464 break; 465 } 466 467 if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) { 468 return return_false(cinfo, *bm, "skip rows"); 469 } 470 } 471 472 // we formally skip the rest, so we don't get a complaint from libjpeg 473 if (!skip_src_rows(&cinfo, srcRow, 474 cinfo.output_height - cinfo.output_scanline)) { 475 return return_false(cinfo, *bm, "skip rows"); 476 } 477 jpeg_finish_decompress(&cinfo); 478 479 return true; 480} 481 482#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 483bool SkJPEGImageDecoder::onBuildTileIndex(SkStream* stream, int *width, int *height) { 484 485 SkJPEGImageIndex* imageIndex = SkNEW_ARGS(SkJPEGImageIndex, (stream, this)); 486 jpeg_decompress_struct* cinfo = imageIndex->cinfo(); 487 huffman_index* huffmanIndex = imageIndex->huffmanIndex(); 488 489 skjpeg_error_mgr sk_err; 490 cinfo->err = jpeg_std_error(&sk_err); 491 sk_err.error_exit = skjpeg_error_exit; 492 493 // All objects need to be instantiated before this setjmp call so that 494 // they will be cleaned up properly if an error occurs. 495 if (setjmp(sk_err.fJmpBuf)) { 496 return false; 497 } 498 499 // create the cinfo used to create/build the huffmanIndex 500 imageIndex->initializeInfo(); 501 cinfo->do_fancy_upsampling = 0; 502 cinfo->do_block_smoothing = 0; 503 504 int status = jpeg_read_header(cinfo, true); 505 if (JPEG_HEADER_OK != status) { 506 SkDELETE(imageIndex); 507 return false; 508 } 509 510 jpeg_create_huffman_index(cinfo, huffmanIndex); 511 cinfo->scale_num = 1; 512 cinfo->scale_denom = 1; 513 if (!jpeg_build_huffman_index(cinfo, huffmanIndex)) { 514 SkDELETE(imageIndex); 515 return false; 516 } 517 518 // destroy the cinfo used to create/build the huffman index 519 jpeg_destroy_decompress(cinfo); 520 521 // Init decoder to image decode mode 522 imageIndex->initializeInfo(); 523 524 status = jpeg_read_header(cinfo, true); 525 if (JPEG_HEADER_OK != status) { 526 SkDELETE(imageIndex); 527 return false; 528 } 529 530 cinfo->out_color_space = JCS_RGBA_8888; 531 cinfo->do_fancy_upsampling = 0; 532 cinfo->do_block_smoothing = 0; 533 534 // instead of jpeg_start_decompress() we start a tiled decompress 535 jpeg_start_tile_decompress(cinfo); 536 537 cinfo->scale_num = 1; 538 *height = cinfo->output_height; 539 *width = cinfo->output_width; 540 fImageWidth = *width; 541 fImageHeight = *height; 542 543 SkDELETE(fImageIndex); 544 fImageIndex = imageIndex; 545 546 return true; 547} 548 549bool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 550 if (NULL == fImageIndex) { 551 return false; 552 } 553 jpeg_decompress_struct* cinfo = fImageIndex->cinfo(); 554 555 SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight); 556 if (!rect.intersect(region)) { 557 // If the requested region is entirely outside the image return false 558 return false; 559 } 560 561 562 skjpeg_error_mgr errorManager; 563 cinfo->err = jpeg_std_error(&errorManager); 564 errorManager.error_exit = skjpeg_error_exit; 565 if (setjmp(errorManager.fJmpBuf)) { 566 return false; 567 } 568 569 int requestedSampleSize = this->getSampleSize(); 570 cinfo->scale_denom = requestedSampleSize; 571 572 if (this->getPreferQualityOverSpeed()) { 573 cinfo->dct_method = JDCT_ISLOW; 574 } else { 575 cinfo->dct_method = JDCT_IFAST; 576 } 577 578 SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false); 579 if (config != SkBitmap::kARGB_8888_Config && 580 config != SkBitmap::kARGB_4444_Config && 581 config != SkBitmap::kRGB_565_Config) { 582 config = SkBitmap::kARGB_8888_Config; 583 } 584 585 /* default format is RGB */ 586 cinfo->out_color_space = JCS_RGB; 587 588#ifdef ANDROID_RGB 589 cinfo->dither_mode = JDITHER_NONE; 590 if (SkBitmap::kARGB_8888_Config == config) { 591 cinfo->out_color_space = JCS_RGBA_8888; 592 } else if (SkBitmap::kRGB_565_Config == config) { 593 cinfo->out_color_space = JCS_RGB_565; 594 if (this->getDitherImage()) { 595 cinfo->dither_mode = JDITHER_ORDERED; 596 } 597 } 598#endif 599 600 int startX = rect.fLeft; 601 int startY = rect.fTop; 602 int width = rect.width(); 603 int height = rect.height(); 604 605 jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), 606 &startX, &startY, &width, &height); 607 int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo); 608 int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size); 609 610 SkScaledBitmapSampler sampler(width, height, skiaSampleSize); 611 612 SkBitmap bitmap; 613 bitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 614 bitmap.setIsOpaque(true); 615 616 // Check ahead of time if the swap(dest, src) is possible or not. 617 // If yes, then we will stick to AllocPixelRef since it's cheaper with the 618 // swap happening. If no, then we will use alloc to allocate pixels to 619 // prevent garbage collection. 620 int w = rect.width() / actualSampleSize; 621 int h = rect.height() / actualSampleSize; 622 bool swapOnly = (rect == region) && bm->isNull() && 623 (w == bitmap.width()) && (h == bitmap.height()) && 624 ((startX - rect.x()) / actualSampleSize == 0) && 625 ((startY - rect.y()) / actualSampleSize == 0); 626 if (swapOnly) { 627 if (!this->allocPixelRef(&bitmap, NULL)) { 628 return return_false(*cinfo, bitmap, "allocPixelRef"); 629 } 630 } else { 631 if (!bitmap.allocPixels()) { 632 return return_false(*cinfo, bitmap, "allocPixels"); 633 } 634 } 635 636 SkAutoLockPixels alp(bitmap); 637 638#ifdef ANDROID_RGB 639 /* short-circuit the SkScaledBitmapSampler when possible, as this gives 640 a significant performance boost. 641 */ 642 if (skiaSampleSize == 1 && 643 ((config == SkBitmap::kARGB_8888_Config && 644 cinfo->out_color_space == JCS_RGBA_8888) || 645 (config == SkBitmap::kRGB_565_Config && 646 cinfo->out_color_space == JCS_RGB_565))) 647 { 648 JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels(); 649 INT32 const bpr = bitmap.rowBytes(); 650 int rowTotalCount = 0; 651 652 while (rowTotalCount < height) { 653 int rowCount = jpeg_read_tile_scanline(cinfo, 654 fImageIndex->huffmanIndex(), 655 &rowptr); 656 // if row_count == 0, then we didn't get a scanline, so abort. 657 // if we supported partial images, we might return true in this case 658 if (0 == rowCount) { 659 return return_false(*cinfo, bitmap, "read_scanlines"); 660 } 661 if (this->shouldCancelDecode()) { 662 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 663 } 664 rowTotalCount += rowCount; 665 rowptr += bpr; 666 } 667 668 if (swapOnly) { 669 bm->swap(bitmap); 670 } else { 671 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 672 region.width(), region.height(), startX, startY); 673 } 674 return true; 675 } 676#endif 677 678 // check for supported formats 679 SkScaledBitmapSampler::SrcConfig sc; 680 if (JCS_CMYK == cinfo->out_color_space) { 681 // In this case we will manually convert the CMYK values to RGB 682 sc = SkScaledBitmapSampler::kRGBX; 683 } else if (3 == cinfo->out_color_components && JCS_RGB == cinfo->out_color_space) { 684 sc = SkScaledBitmapSampler::kRGB; 685#ifdef ANDROID_RGB 686 } else if (JCS_RGBA_8888 == cinfo->out_color_space) { 687 sc = SkScaledBitmapSampler::kRGBX; 688 } else if (JCS_RGB_565 == cinfo->out_color_space) { 689 sc = SkScaledBitmapSampler::kRGB_565; 690#endif 691 } else if (1 == cinfo->out_color_components && 692 JCS_GRAYSCALE == cinfo->out_color_space) { 693 sc = SkScaledBitmapSampler::kGray; 694 } else { 695 return return_false(*cinfo, *bm, "jpeg colorspace"); 696 } 697 698 if (!sampler.begin(&bitmap, sc, this->getDitherImage())) { 699 return return_false(*cinfo, bitmap, "sampler.begin"); 700 } 701 702 // The CMYK work-around relies on 4 components per pixel here 703 SkAutoMalloc srcStorage(width * 4); 704 uint8_t* srcRow = (uint8_t*)srcStorage.get(); 705 706 // Possibly skip initial rows [sampler.srcY0] 707 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) { 708 return return_false(*cinfo, bitmap, "skip rows"); 709 } 710 711 // now loop through scanlines until y == bitmap->height() - 1 712 for (int y = 0;; y++) { 713 JSAMPLE* rowptr = (JSAMPLE*)srcRow; 714 int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr); 715 if (0 == row_count) { 716 return return_false(*cinfo, bitmap, "read_scanlines"); 717 } 718 if (this->shouldCancelDecode()) { 719 return return_false(*cinfo, bitmap, "shouldCancelDecode"); 720 } 721 722 if (JCS_CMYK == cinfo->out_color_space) { 723 convert_CMYK_to_RGB(srcRow, width); 724 } 725 726 sampler.next(srcRow); 727 if (bitmap.height() - 1 == y) { 728 // we're done 729 break; 730 } 731 732 if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, 733 sampler.srcDY() - 1)) { 734 return return_false(*cinfo, bitmap, "skip rows"); 735 } 736 } 737 if (swapOnly) { 738 bm->swap(bitmap); 739 } else { 740 cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(), 741 region.width(), region.height(), startX, startY); 742 } 743 return true; 744} 745#endif 746 747/////////////////////////////////////////////////////////////////////////////// 748 749#include "SkColorPriv.h" 750 751// taken from jcolor.c in libjpeg 752#if 0 // 16bit - precise but slow 753 #define CYR 19595 // 0.299 754 #define CYG 38470 // 0.587 755 #define CYB 7471 // 0.114 756 757 #define CUR -11059 // -0.16874 758 #define CUG -21709 // -0.33126 759 #define CUB 32768 // 0.5 760 761 #define CVR 32768 // 0.5 762 #define CVG -27439 // -0.41869 763 #define CVB -5329 // -0.08131 764 765 #define CSHIFT 16 766#else // 8bit - fast, slightly less precise 767 #define CYR 77 // 0.299 768 #define CYG 150 // 0.587 769 #define CYB 29 // 0.114 770 771 #define CUR -43 // -0.16874 772 #define CUG -85 // -0.33126 773 #define CUB 128 // 0.5 774 775 #define CVR 128 // 0.5 776 #define CVG -107 // -0.41869 777 #define CVB -21 // -0.08131 778 779 #define CSHIFT 8 780#endif 781 782static void rgb2yuv_32(uint8_t dst[], SkPMColor c) { 783 int r = SkGetPackedR32(c); 784 int g = SkGetPackedG32(c); 785 int b = SkGetPackedB32(c); 786 787 int y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT; 788 int u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT; 789 int v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT; 790 791 dst[0] = SkToU8(y); 792 dst[1] = SkToU8(u + 128); 793 dst[2] = SkToU8(v + 128); 794} 795 796static void rgb2yuv_4444(uint8_t dst[], U16CPU c) { 797 int r = SkGetPackedR4444(c); 798 int g = SkGetPackedG4444(c); 799 int b = SkGetPackedB4444(c); 800 801 int y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4); 802 int u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4); 803 int v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4); 804 805 dst[0] = SkToU8(y); 806 dst[1] = SkToU8(u + 128); 807 dst[2] = SkToU8(v + 128); 808} 809 810static void rgb2yuv_16(uint8_t dst[], U16CPU c) { 811 int r = SkGetPackedR16(c); 812 int g = SkGetPackedG16(c); 813 int b = SkGetPackedB16(c); 814 815 int y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2); 816 int u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2); 817 int v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2); 818 819 dst[0] = SkToU8(y); 820 dst[1] = SkToU8(u + 128); 821 dst[2] = SkToU8(v + 128); 822} 823 824/////////////////////////////////////////////////////////////////////////////// 825 826typedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst, 827 const void* SK_RESTRICT src, int width, 828 const SkPMColor* SK_RESTRICT ctable); 829 830static void Write_32_YUV(uint8_t* SK_RESTRICT dst, 831 const void* SK_RESTRICT srcRow, int width, 832 const SkPMColor*) { 833 const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow; 834 while (--width >= 0) { 835#ifdef WE_CONVERT_TO_YUV 836 rgb2yuv_32(dst, *src++); 837#else 838 uint32_t c = *src++; 839 dst[0] = SkGetPackedR32(c); 840 dst[1] = SkGetPackedG32(c); 841 dst[2] = SkGetPackedB32(c); 842#endif 843 dst += 3; 844 } 845} 846 847static void Write_4444_YUV(uint8_t* SK_RESTRICT dst, 848 const void* SK_RESTRICT srcRow, int width, 849 const SkPMColor*) { 850 const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow; 851 while (--width >= 0) { 852#ifdef WE_CONVERT_TO_YUV 853 rgb2yuv_4444(dst, *src++); 854#else 855 SkPMColor16 c = *src++; 856 dst[0] = SkPacked4444ToR32(c); 857 dst[1] = SkPacked4444ToG32(c); 858 dst[2] = SkPacked4444ToB32(c); 859#endif 860 dst += 3; 861 } 862} 863 864static void Write_16_YUV(uint8_t* SK_RESTRICT dst, 865 const void* SK_RESTRICT srcRow, int width, 866 const SkPMColor*) { 867 const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow; 868 while (--width >= 0) { 869#ifdef WE_CONVERT_TO_YUV 870 rgb2yuv_16(dst, *src++); 871#else 872 uint16_t c = *src++; 873 dst[0] = SkPacked16ToR32(c); 874 dst[1] = SkPacked16ToG32(c); 875 dst[2] = SkPacked16ToB32(c); 876#endif 877 dst += 3; 878 } 879} 880 881static void Write_Index_YUV(uint8_t* SK_RESTRICT dst, 882 const void* SK_RESTRICT srcRow, int width, 883 const SkPMColor* SK_RESTRICT ctable) { 884 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow; 885 while (--width >= 0) { 886#ifdef WE_CONVERT_TO_YUV 887 rgb2yuv_32(dst, ctable[*src++]); 888#else 889 uint32_t c = ctable[*src++]; 890 dst[0] = SkGetPackedR32(c); 891 dst[1] = SkGetPackedG32(c); 892 dst[2] = SkGetPackedB32(c); 893#endif 894 dst += 3; 895 } 896} 897 898static WriteScanline ChooseWriter(const SkBitmap& bm) { 899 switch (bm.config()) { 900 case SkBitmap::kARGB_8888_Config: 901 return Write_32_YUV; 902 case SkBitmap::kRGB_565_Config: 903 return Write_16_YUV; 904 case SkBitmap::kARGB_4444_Config: 905 return Write_4444_YUV; 906 case SkBitmap::kIndex8_Config: 907 return Write_Index_YUV; 908 default: 909 return NULL; 910 } 911} 912 913class SkJPEGImageEncoder : public SkImageEncoder { 914protected: 915 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) { 916#ifdef TIME_ENCODE 917 SkAutoTime atm("JPEG Encode"); 918#endif 919 920 SkAutoLockPixels alp(bm); 921 if (NULL == bm.getPixels()) { 922 return false; 923 } 924 925 jpeg_compress_struct cinfo; 926 skjpeg_error_mgr sk_err; 927 skjpeg_destination_mgr sk_wstream(stream); 928 929 // allocate these before set call setjmp 930 SkAutoMalloc oneRow; 931 SkAutoLockColors ctLocker; 932 933 cinfo.err = jpeg_std_error(&sk_err); 934 sk_err.error_exit = skjpeg_error_exit; 935 if (setjmp(sk_err.fJmpBuf)) { 936 return false; 937 } 938 939 // Keep after setjmp or mark volatile. 940 const WriteScanline writer = ChooseWriter(bm); 941 if (NULL == writer) { 942 return false; 943 } 944 945 jpeg_create_compress(&cinfo); 946 cinfo.dest = &sk_wstream; 947 cinfo.image_width = bm.width(); 948 cinfo.image_height = bm.height(); 949 cinfo.input_components = 3; 950#ifdef WE_CONVERT_TO_YUV 951 cinfo.in_color_space = JCS_YCbCr; 952#else 953 cinfo.in_color_space = JCS_RGB; 954#endif 955 cinfo.input_gamma = 1; 956 957 jpeg_set_defaults(&cinfo); 958 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); 959#ifdef DCT_IFAST_SUPPORTED 960 cinfo.dct_method = JDCT_IFAST; 961#endif 962 963 jpeg_start_compress(&cinfo, TRUE); 964 965 const int width = bm.width(); 966 uint8_t* oneRowP = (uint8_t*)oneRow.reset(width * 3); 967 968 const SkPMColor* colors = ctLocker.lockColors(bm); 969 const void* srcRow = bm.getPixels(); 970 971 while (cinfo.next_scanline < cinfo.image_height) { 972 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ 973 974 writer(oneRowP, srcRow, width, colors); 975 row_pointer[0] = oneRowP; 976 (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); 977 srcRow = (const void*)((const char*)srcRow + bm.rowBytes()); 978 } 979 980 jpeg_finish_compress(&cinfo); 981 jpeg_destroy_compress(&cinfo); 982 983 return true; 984 } 985}; 986 987/////////////////////////////////////////////////////////////////////////////// 988DEFINE_DECODER_CREATOR(JPEGImageDecoder); 989DEFINE_ENCODER_CREATOR(JPEGImageEncoder); 990/////////////////////////////////////////////////////////////////////////////// 991 992static bool is_jpeg(SkStream* stream) { 993 static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF }; 994 static const size_t HEADER_SIZE = sizeof(gHeader); 995 996 char buffer[HEADER_SIZE]; 997 size_t len = stream->read(buffer, HEADER_SIZE); 998 999 if (len != HEADER_SIZE) { 1000 return false; // can't read enough 1001 } 1002 if (memcmp(buffer, gHeader, HEADER_SIZE)) { 1003 return false; 1004 } 1005 return true; 1006} 1007 1008#include "SkTRegistry.h" 1009 1010static SkImageDecoder* sk_libjpeg_dfactory(SkStream* stream) { 1011 if (is_jpeg(stream)) { 1012 return SkNEW(SkJPEGImageDecoder); 1013 } 1014 return NULL; 1015} 1016 1017static SkImageDecoder::Format get_format_jpeg(SkStream* stream) { 1018 if (is_jpeg(stream)) { 1019 return SkImageDecoder::kJPEG_Format; 1020 } 1021 return SkImageDecoder::kUnknown_Format; 1022} 1023 1024static SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) { 1025 return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL; 1026} 1027 1028 1029static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libjpeg_dfactory); 1030static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_jpeg); 1031static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libjpeg_efactory); 1032