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