| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkImageDecoder.h" | 10 #include "SkImageDecoder.h" |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 #ifdef SK_BUILD_FOR_ANDROID | 73 #ifdef SK_BUILD_FOR_ANDROID |
| 74 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_
OVERRIDE; | 74 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_
OVERRIDE; |
| 75 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVER
RIDE; | 75 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVER
RIDE; |
| 76 #endif | 76 #endif |
| 77 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | 77 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; |
| 78 | 78 |
| 79 private: | 79 private: |
| 80 SkPNGImageIndex* fImageIndex; | 80 SkPNGImageIndex* fImageIndex; |
| 81 | 81 |
| 82 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p
trp); | 82 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p
trp); |
| 83 bool decodePalette(png_structp png_ptr, png_infop info_ptr, bool *hasAlphap, | 83 bool decodePalette(png_structp png_ptr, png_infop info_ptr, |
| 84 bool *reallyHasAlphap, SkColorTable **colorTablep); | 84 bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap, |
| 85 SkColorTable **colorTablep); |
| 85 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 86 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, |
| 86 SkBitmap::Config *config, bool *hasAlpha, | 87 SkBitmap::Config *config, bool *hasAlpha, |
| 87 bool *doDither, SkPMColor *theTranspColor); | 88 bool *doDither, SkPMColor *theTranspColor); |
| 88 | 89 |
| 89 typedef SkImageDecoder INHERITED; | 90 typedef SkImageDecoder INHERITED; |
| 90 }; | 91 }; |
| 91 | 92 |
| 92 #ifndef png_jmpbuf | 93 #ifndef png_jmpbuf |
| 93 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 94 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
| 94 #endif | 95 #endif |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 bool reuseBitmap = (rowptr != NULL); | 305 bool reuseBitmap = (rowptr != NULL); |
| 305 decodedBitmap->unlockPixels(); | 306 decodedBitmap->unlockPixels(); |
| 306 if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() || | 307 if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() || |
| 307 sampler.scaledHeight() != decodedBitmap->height())) { | 308 sampler.scaledHeight() != decodedBitmap->height())) { |
| 308 // Dimensions must match | 309 // Dimensions must match |
| 309 return false; | 310 return false; |
| 310 } | 311 } |
| 311 | 312 |
| 312 if (!reuseBitmap) { | 313 if (!reuseBitmap) { |
| 313 decodedBitmap->setConfig(config, sampler.scaledWidth(), | 314 decodedBitmap->setConfig(config, sampler.scaledWidth(), |
| 314 sampler.scaledHeight(), 0); | 315 sampler.scaledHeight()); |
| 315 } | 316 } |
| 316 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | 317 if (SkImageDecoder::kDecodeBounds_Mode == mode) { |
| 317 return true; | 318 return true; |
| 318 } | 319 } |
| 319 | 320 |
| 320 // from here down we are concerned with colortables and pixels | 321 // from here down we are concerned with colortables and pixels |
| 321 | 322 |
| 322 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype | 323 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype |
| 323 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we | 324 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we |
| 324 // draw lots faster if we can flag the bitmap has being opaque | 325 // draw lots faster if we can flag the bitmap has being opaque |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 skip_src_rows(png_ptr, srcRow, origHeight - read); | 429 skip_src_rows(png_ptr, srcRow, origHeight - read); |
| 429 } | 430 } |
| 430 } | 431 } |
| 431 | 432 |
| 432 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 433 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
| 433 png_read_end(png_ptr, info_ptr); | 434 png_read_end(png_ptr, info_ptr); |
| 434 | 435 |
| 435 if (0 != theTranspColor) { | 436 if (0 != theTranspColor) { |
| 436 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); | 437 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); |
| 437 } | 438 } |
| 439 if (reallyHasAlpha && this->getRequireUnpremultipliedColors() && |
| 440 SkBitmap::kARGB_8888_Config != decodedBitmap->config()) { |
| 441 // If the caller wants an unpremultiplied bitmap, and we let them get |
| 442 // away with a config other than 8888, and it has alpha after all, |
| 443 // return false, since the result will have premultiplied colors. |
| 444 return false; |
| 445 } |
| 438 decodedBitmap->setIsOpaque(!reallyHasAlpha); | 446 decodedBitmap->setIsOpaque(!reallyHasAlpha); |
| 439 if (reuseBitmap) { | 447 if (reuseBitmap) { |
| 440 decodedBitmap->notifyPixelsChanged(); | 448 decodedBitmap->notifyPixelsChanged(); |
| 441 } | 449 } |
| 442 return true; | 450 return true; |
| 443 } | 451 } |
| 444 | 452 |
| 445 | 453 |
| 446 | 454 |
| 447 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 455 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, |
| 448 SkBitmap::Config *configp, bool *hasAlph
ap, | 456 SkBitmap::Config *configp, bool * SK_RES
TRICT hasAlphap, |
| 449 bool *doDitherp, SkPMColor *theTranspCol
orp) { | 457 bool *doDitherp, SkPMColor *theTranspCol
orp) { |
| 450 png_uint_32 origWidth, origHeight; | 458 png_uint_32 origWidth, origHeight; |
| 451 int bitDepth, colorType; | 459 int bitDepth, colorType; |
| 452 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 460 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
| 453 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 461 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
| 454 | 462 |
| 455 // check for sBIT chunk data, in case we should disable dithering because | 463 // check for sBIT chunk data, in case we should disable dithering because |
| 456 // our data is not truely 8bits per component | 464 // our data is not truely 8bits per component |
| 457 png_color_8p sig_bit; | 465 png_color_8p sig_bit; |
| 458 if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { | 466 if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 size.setMul(origWidth, origHeight); | 547 size.setMul(origWidth, origHeight); |
| 540 if (size.isNeg() || !size.is32()) { | 548 if (size.isNeg() || !size.is32()) { |
| 541 return false; | 549 return false; |
| 542 } | 550 } |
| 543 // now check that if we are 4-bytes per pixel, we also don't overflow | 551 // now check that if we are 4-bytes per pixel, we also don't overflow |
| 544 if (size.get32() > (0x7FFFFFFF >> 2)) { | 552 if (size.get32() > (0x7FFFFFFF >> 2)) { |
| 545 return false; | 553 return false; |
| 546 } | 554 } |
| 547 } | 555 } |
| 548 | 556 |
| 549 return this->chooseFromOneChoice(*configp, origWidth, origHeight); | 557 if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) { |
| 558 return false; |
| 559 } |
| 560 |
| 561 // If the image has alpha and the decoder wants unpremultiplied |
| 562 // colors, the only supported config is 8888. |
| 563 if (this->getRequireUnpremultipliedColors() && *hasAlphap) { |
| 564 *configp = SkBitmap::kARGB_8888_Config; |
| 565 } |
| 566 return true; |
| 550 } | 567 } |
| 551 | 568 |
| 569 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
| 570 |
| 552 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, | 571 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, |
| 553 bool *hasAlphap, bool *reallyHasAlphap, | 572 bool *hasAlphap, bool *reallyHasAlphap, |
| 554 SkColorTable **colorTablep) { | 573 SkColorTable **colorTablep) { |
| 555 int numPalette; | 574 int numPalette; |
| 556 png_colorp palette; | 575 png_colorp palette; |
| 557 png_bytep trans; | 576 png_bytep trans; |
| 558 int numTrans; | 577 int numTrans; |
| 559 bool reallyHasAlpha = false; | 578 bool reallyHasAlpha = false; |
| 560 SkColorTable* colorTable = NULL; | 579 SkColorTable* colorTable = NULL; |
| 561 | 580 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 580 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOp
aque_Flag); | 599 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOp
aque_Flag); |
| 581 } | 600 } |
| 582 // check for bad images that might make us crash | 601 // check for bad images that might make us crash |
| 583 if (numTrans > numPalette) { | 602 if (numTrans > numPalette) { |
| 584 numTrans = numPalette; | 603 numTrans = numPalette; |
| 585 } | 604 } |
| 586 | 605 |
| 587 int index = 0; | 606 int index = 0; |
| 588 int transLessThanFF = 0; | 607 int transLessThanFF = 0; |
| 589 | 608 |
| 609 // Choose which function to use to create the color table. If the final dest
ination's |
| 610 // config is unpremultiplied, the color table will store unpremultiplied col
ors. |
| 611 PackColorProc proc; |
| 612 if (this->getRequireUnpremultipliedColors()) { |
| 613 proc = &SkPackARGB32NoCheck; |
| 614 } else { |
| 615 proc = &SkPreMultiplyARGB; |
| 616 } |
| 590 for (; index < numTrans; index++) { | 617 for (; index < numTrans; index++) { |
| 591 transLessThanFF |= (int)*trans - 0xFF; | 618 transLessThanFF |= (int)*trans - 0xFF; |
| 592 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green,
palette->blue); | 619 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue
); |
| 593 palette++; | 620 palette++; |
| 594 } | 621 } |
| 595 reallyHasAlpha |= (transLessThanFF < 0); | 622 reallyHasAlpha |= (transLessThanFF < 0); |
| 596 | 623 |
| 597 for (; index < numPalette; index++) { | 624 for (; index < numPalette; index++) { |
| 598 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); | 625 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->
blue); |
| 599 palette++; | 626 palette++; |
| 600 } | 627 } |
| 601 | 628 |
| 602 // see BUGGY IMAGE WORKAROUND comment above | 629 // see BUGGY IMAGE WORKAROUND comment above |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 SkPMColor theTranspColor = 0; // 0 tells us not to try to match | 699 SkPMColor theTranspColor = 0; // 0 tells us not to try to match |
| 673 | 700 |
| 674 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT
ranspColor)) { | 701 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT
ranspColor)) { |
| 675 return false; | 702 return false; |
| 676 } | 703 } |
| 677 | 704 |
| 678 const int sampleSize = this->getSampleSize(); | 705 const int sampleSize = this->getSampleSize(); |
| 679 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); | 706 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); |
| 680 | 707 |
| 681 SkBitmap decodedBitmap; | 708 SkBitmap decodedBitmap; |
| 682 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(
), 0); | 709 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(
)); |
| 683 | 710 |
| 684 // from here down we are concerned with colortables and pixels | 711 // from here down we are concerned with colortables and pixels |
| 685 | 712 |
| 686 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype | 713 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype |
| 687 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we | 714 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we |
| 688 // draw lots faster if we can flag the bitmap has being opaque | 715 // draw lots faster if we can flag the bitmap has being opaque |
| 689 bool reallyHasAlpha = false; | 716 bool reallyHasAlpha = false; |
| 690 SkColorTable* colorTable = NULL; | 717 SkColorTable* colorTable = NULL; |
| 691 | 718 |
| 692 if (colorType == PNG_COLOR_TYPE_PALETTE) { | 719 if (colorType == PNG_COLOR_TYPE_PALETTE) { |
| 693 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable
); | 720 decodePalette(png_ptr, info_ptr, config, &hasAlpha, &reallyHasAlpha, &co
lorTable); |
| 694 } | 721 } |
| 695 | 722 |
| 696 SkAutoUnref aur(colorTable); | 723 SkAutoUnref aur(colorTable); |
| 697 | 724 |
| 698 // Check ahead of time if the swap(dest, src) is possible. | 725 // Check ahead of time if the swap(dest, src) is possible. |
| 699 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s
wap happening. | 726 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s
wap happening. |
| 700 // If no, then we will use alloc to allocate pixels to prevent garbage colle
ction. | 727 // If no, then we will use alloc to allocate pixels to prevent garbage colle
ction. |
| 701 int w = rect.width() / sampleSize; | 728 int w = rect.width() / sampleSize; |
| 702 int h = rect.height() / sampleSize; | 729 int h = rect.height() / sampleSize; |
| 703 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) && | 730 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) && |
| (...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1137 return SkImageDecoder::kUnknown_Format; | 1164 return SkImageDecoder::kUnknown_Format; |
| 1138 } | 1165 } |
| 1139 | 1166 |
| 1140 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 1167 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
| 1141 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; | 1168 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; |
| 1142 } | 1169 } |
| 1143 | 1170 |
| 1144 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto
ry); | 1171 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto
ry); |
| 1145 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png)
; | 1172 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png)
; |
| 1146 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); | 1173 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); |
| OLD | NEW |