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