1 2 /* 3 * Copyright 2006 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 "SkColor.h" 13 #include "SkColorPriv.h" 14 #include "SkDither.h" 15 #include "SkMath.h" 16 #include "SkScaledBitmapSampler.h" 17 #include "SkStream.h" 18 #include "SkTemplates.h" 19 #include "SkUtils.h" 20 #include "transform_scanline.h" 21 22 extern "C" { 23 #include "png.h" 24 } 25 26 /* These were dropped in libpng >= 1.4 */ 27 #ifndef png_infopp_NULL 28 #define png_infopp_NULL NULL 29 #endif 30 31 #ifndef png_bytepp_NULL 32 #define png_bytepp_NULL NULL 33 #endif 34 35 #ifndef int_p_NULL 36 #define int_p_NULL NULL 37 #endif 38 39 #ifndef png_flush_ptr_NULL 40 #define png_flush_ptr_NULL NULL 41 #endif 42 43 class SkPNGImageIndex { 44 public: 45 SkPNGImageIndex(SkStream* stream, png_structp png_ptr, png_infop info_ptr) 46 : fStream(stream) 47 , fPng_ptr(png_ptr) 48 , fInfo_ptr(info_ptr) 49 , fConfig(SkBitmap::kNo_Config) { 50 SkASSERT(stream != NULL); 51 stream->ref(); 52 } 53 ~SkPNGImageIndex() { 54 if (NULL != fPng_ptr) { 55 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); 56 } 57 } 58 59 SkAutoTUnref<SkStream> fStream; 60 png_structp fPng_ptr; 61 png_infop fInfo_ptr; 62 SkBitmap::Config fConfig; 63 }; 64 65 class SkPNGImageDecoder : public SkImageDecoder { 66 public: 67 SkPNGImageDecoder() { 68 fImageIndex = NULL; 69 } 70 virtual Format getFormat() const SK_OVERRIDE { 71 return kPNG_Format; 72 } 73 74 virtual ~SkPNGImageDecoder() { 75 SkDELETE(fImageIndex); 76 } 77 78 protected: 79 #ifdef SK_BUILD_FOR_ANDROID 80 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE; 81 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE; 82 #endif 83 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 84 85 private: 86 SkPNGImageIndex* fImageIndex; 87 88 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_ptrp); 89 bool decodePalette(png_structp png_ptr, png_infop info_ptr, 90 bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap, 91 SkColorTable **colorTablep); 92 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 93 SkBitmap::Config *config, bool *hasAlpha, 94 SkPMColor *theTranspColor); 95 96 typedef SkImageDecoder INHERITED; 97 }; 98 99 #ifndef png_jmpbuf 100 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 101 #endif 102 103 #define PNG_BYTES_TO_CHECK 4 104 105 /* Automatically clean up after throwing an exception */ 106 struct PNGAutoClean { 107 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 108 ~PNGAutoClean() { 109 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 110 } 111 private: 112 png_structp png_ptr; 113 png_infop info_ptr; 114 }; 115 116 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 117 SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr); 118 size_t bytes = sk_stream->read(data, length); 119 if (bytes != length) { 120 png_error(png_ptr, "Read Error!"); 121 } 122 } 123 124 #ifdef SK_BUILD_FOR_ANDROID 125 static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) { 126 SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr); 127 if (!sk_stream->rewind()) { 128 png_error(png_ptr, "Failed to rewind stream!"); 129 } 130 (void)sk_stream->skip(offset); 131 } 132 #endif 133 134 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 135 SkImageDecoder::Peeker* peeker = 136 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 137 // peek() returning true means continue decoding 138 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 139 1 : -1; 140 } 141 142 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 143 SkDEBUGF(("------ png error %s\n", msg)); 144 longjmp(png_jmpbuf(png_ptr), 1); 145 } 146 147 static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 148 for (int i = 0; i < count; i++) { 149 uint8_t* tmp = storage; 150 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 151 } 152 } 153 154 static bool pos_le(int value, int max) { 155 return value > 0 && value <= max; 156 } 157 158 static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 159 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 160 161 bool reallyHasAlpha = false; 162 163 for (int y = bm->height() - 1; y >= 0; --y) { 164 SkPMColor* p = bm->getAddr32(0, y); 165 for (int x = bm->width() - 1; x >= 0; --x) { 166 if (match == *p) { 167 *p = 0; 168 reallyHasAlpha = true; 169 } 170 p += 1; 171 } 172 } 173 return reallyHasAlpha; 174 } 175 176 static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig, 177 bool srcHasAlpha) { 178 switch (dstConfig) { 179 case SkBitmap::kARGB_8888_Config: 180 case SkBitmap::kARGB_4444_Config: 181 return true; 182 case SkBitmap::kRGB_565_Config: 183 // only return true if the src is opaque (since 565 is opaque) 184 return !srcHasAlpha; 185 default: 186 return false; 187 } 188 } 189 190 // call only if color_type is PALETTE. Returns true if the ctable has alpha 191 static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { 192 png_bytep trans; 193 int num_trans; 194 195 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 196 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 197 return num_trans > 0; 198 } 199 return false; 200 } 201 202 bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp, 203 png_infop *info_ptrp) { 204 /* Create and initialize the png_struct with the desired error handler 205 * functions. If you want to use the default stderr and longjump method, 206 * you can supply NULL for the last three parameters. We also supply the 207 * the compiler header file version, so that we know if the application 208 * was compiled with a compatible version of the library. */ 209 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 210 NULL, sk_error_fn, NULL); 211 // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 212 if (png_ptr == NULL) { 213 return false; 214 } 215 *png_ptrp = png_ptr; 216 217 /* Allocate/initialize the memory for image information. */ 218 png_infop info_ptr = png_create_info_struct(png_ptr); 219 if (info_ptr == NULL) { 220 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); 221 return false; 222 } 223 *info_ptrp = info_ptr; 224 225 /* Set error handling if you are using the setjmp/longjmp method (this is 226 * the normal method of doing things with libpng). REQUIRED unless you 227 * set up your own error handlers in the png_create_read_struct() earlier. 228 */ 229 if (setjmp(png_jmpbuf(png_ptr))) { 230 return false; 231 } 232 233 /* If you are using replacement read functions, instead of calling 234 * png_init_io() here you would call: 235 */ 236 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 237 #ifdef SK_BUILD_FOR_ANDROID 238 png_set_seek_fn(png_ptr, sk_seek_fn); 239 #endif 240 /* where user_io_ptr is a structure you want available to the callbacks */ 241 /* If we have already read some of the signature */ 242 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 243 244 // hookup our peeker so we can see any user-chunks the caller may be interested in 245 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 246 if (this->getPeeker()) { 247 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); 248 } 249 250 /* The call to png_read_info() gives us all of the information from the 251 * PNG file before the first IDAT (image data chunk). */ 252 png_read_info(png_ptr, info_ptr); 253 png_uint_32 origWidth, origHeight; 254 int bitDepth, colorType; 255 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 256 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 257 258 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 259 if (bitDepth == 16) { 260 png_set_strip_16(png_ptr); 261 } 262 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 263 * byte into separate bytes (useful for paletted and grayscale images). */ 264 if (bitDepth < 8) { 265 png_set_packing(png_ptr); 266 } 267 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 268 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { 269 png_set_expand_gray_1_2_4_to_8(png_ptr); 270 } 271 272 return true; 273 } 274 275 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 276 Mode mode) { 277 png_structp png_ptr; 278 png_infop info_ptr; 279 280 if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) { 281 return false; 282 } 283 284 if (setjmp(png_jmpbuf(png_ptr))) { 285 return false; 286 } 287 288 PNGAutoClean autoClean(png_ptr, info_ptr); 289 290 png_uint_32 origWidth, origHeight; 291 int bitDepth, colorType, interlaceType; 292 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 293 &colorType, &interlaceType, int_p_NULL, int_p_NULL); 294 295 SkBitmap::Config config; 296 bool hasAlpha = false; 297 SkPMColor theTranspColor = 0; // 0 tells us not to try to match 298 299 if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) { 300 return false; 301 } 302 303 const int sampleSize = this->getSampleSize(); 304 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 305 decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 306 307 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 308 return true; 309 } 310 311 // from here down we are concerned with colortables and pixels 312 313 // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 314 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 315 // draw lots faster if we can flag the bitmap has being opaque 316 bool reallyHasAlpha = false; 317 SkColorTable* colorTable = NULL; 318 319 if (colorType == PNG_COLOR_TYPE_PALETTE) { 320 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable); 321 } 322 323 SkAutoUnref aur(colorTable); 324 325 if (!this->allocPixelRef(decodedBitmap, 326 SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { 327 return false; 328 } 329 330 SkAutoLockPixels alp(*decodedBitmap); 331 332 /* Turn on interlace handling. REQUIRED if you are not using 333 * png_read_image(). To see how to handle interlacing passes, 334 * see the png_read_row() method below: 335 */ 336 const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ? 337 png_set_interlace_handling(png_ptr) : 1; 338 339 /* Optional call to gamma correct and add the background to the palette 340 * and update info structure. REQUIRED if you are expecting libpng to 341 * update the palette for you (ie you selected such a transform above). 342 */ 343 png_read_update_info(png_ptr, info_ptr); 344 345 if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config) 346 && 1 == sampleSize) { 347 // A8 is only allowed if the original was GRAY. 348 SkASSERT(config != SkBitmap::kA8_Config 349 || PNG_COLOR_TYPE_GRAY == colorType); 350 for (int i = 0; i < number_passes; i++) { 351 for (png_uint_32 y = 0; y < origHeight; y++) { 352 uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 353 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 354 } 355 } 356 } else { 357 SkScaledBitmapSampler::SrcConfig sc; 358 int srcBytesPerPixel = 4; 359 360 if (colorTable != NULL) { 361 sc = SkScaledBitmapSampler::kIndex; 362 srcBytesPerPixel = 1; 363 } else if (SkBitmap::kA8_Config == config) { 364 // A8 is only allowed if the original was GRAY. 365 SkASSERT(PNG_COLOR_TYPE_GRAY == colorType); 366 sc = SkScaledBitmapSampler::kGray; 367 srcBytesPerPixel = 1; 368 } else if (hasAlpha) { 369 sc = SkScaledBitmapSampler::kRGBA; 370 } else { 371 sc = SkScaledBitmapSampler::kRGBX; 372 } 373 374 /* We have to pass the colortable explicitly, since we may have one 375 even if our decodedBitmap doesn't, due to the request that we 376 upscale png's palette to a direct model 377 */ 378 SkAutoLockColors ctLock(colorTable); 379 if (!sampler.begin(decodedBitmap, sc, *this, ctLock.colors())) { 380 return false; 381 } 382 const int height = decodedBitmap->height(); 383 384 if (number_passes > 1) { 385 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 386 uint8_t* base = (uint8_t*)storage.get(); 387 size_t rowBytes = origWidth * srcBytesPerPixel; 388 389 for (int i = 0; i < number_passes; i++) { 390 uint8_t* row = base; 391 for (png_uint_32 y = 0; y < origHeight; y++) { 392 uint8_t* bmRow = row; 393 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 394 row += rowBytes; 395 } 396 } 397 // now sample it 398 base += sampler.srcY0() * rowBytes; 399 for (int y = 0; y < height; y++) { 400 reallyHasAlpha |= sampler.next(base); 401 base += sampler.srcDY() * rowBytes; 402 } 403 } else { 404 SkAutoMalloc storage(origWidth * srcBytesPerPixel); 405 uint8_t* srcRow = (uint8_t*)storage.get(); 406 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 407 408 for (int y = 0; y < height; y++) { 409 uint8_t* tmp = srcRow; 410 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 411 reallyHasAlpha |= sampler.next(srcRow); 412 if (y < height - 1) { 413 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 414 } 415 } 416 417 // skip the rest of the rows (if any) 418 png_uint_32 read = (height - 1) * sampler.srcDY() + 419 sampler.srcY0() + 1; 420 SkASSERT(read <= origHeight); 421 skip_src_rows(png_ptr, srcRow, origHeight - read); 422 } 423 } 424 425 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 426 png_read_end(png_ptr, info_ptr); 427 428 if (0 != theTranspColor) { 429 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 430 } 431 if (reallyHasAlpha && this->getRequireUnpremultipliedColors() && 432 SkBitmap::kARGB_8888_Config != decodedBitmap->config()) { 433 // If the caller wants an unpremultiplied bitmap, and we let them get 434 // away with a config other than 8888, and it has alpha after all, 435 // return false, since the result will have premultiplied colors. 436 return false; 437 } 438 if (SkBitmap::kA8_Config == decodedBitmap->config()) { 439 reallyHasAlpha = true; 440 } 441 decodedBitmap->setIsOpaque(!reallyHasAlpha); 442 return true; 443 } 444 445 446 447 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 448 SkBitmap::Config* SK_RESTRICT configp, 449 bool* SK_RESTRICT hasAlphap, 450 SkPMColor* SK_RESTRICT theTranspColorp) { 451 png_uint_32 origWidth, origHeight; 452 int bitDepth, colorType; 453 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 454 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 455 456 // check for sBIT chunk data, in case we should disable dithering because 457 // our data is not truely 8bits per component 458 png_color_8p sig_bit; 459 if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { 460 #if 0 461 SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green, 462 sig_bit->blue, sig_bit->alpha); 463 #endif 464 // 0 seems to indicate no information available 465 if (pos_le(sig_bit->red, SK_R16_BITS) && 466 pos_le(sig_bit->green, SK_G16_BITS) && 467 pos_le(sig_bit->blue, SK_B16_BITS)) { 468 this->setDitherImage(false); 469 } 470 } 471 472 if (colorType == PNG_COLOR_TYPE_PALETTE) { 473 bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 474 *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 475 // now see if we can upscale to their requested config 476 if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) { 477 *configp = SkBitmap::kIndex8_Config; 478 } 479 } else { 480 png_color_16p transpColor = NULL; 481 int numTransp = 0; 482 483 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 484 485 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 486 487 if (valid && numTransp == 1 && transpColor != NULL) { 488 /* Compute our transparent color, which we'll match against later. 489 We don't really handle 16bit components properly here, since we 490 do our compare *after* the values have been knocked down to 8bit 491 which means we will find more matches than we should. The real 492 fix seems to be to see the actual 16bit components, do the 493 compare, and then knock it down to 8bits ourselves. 494 */ 495 if (colorType & PNG_COLOR_MASK_COLOR) { 496 if (16 == bitDepth) { 497 *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8, 498 transpColor->green >> 8, 499 transpColor->blue >> 8); 500 } else { 501 *theTranspColorp = SkPackARGB32(0xFF, transpColor->red, 502 transpColor->green, 503 transpColor->blue); 504 } 505 } else { // gray 506 if (16 == bitDepth) { 507 *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8, 508 transpColor->gray >> 8, 509 transpColor->gray >> 8); 510 } else { 511 *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray, 512 transpColor->gray, 513 transpColor->gray); 514 } 515 } 516 } 517 518 if (valid || 519 PNG_COLOR_TYPE_RGB_ALPHA == colorType || 520 PNG_COLOR_TYPE_GRAY_ALPHA == colorType) { 521 *hasAlphap = true; 522 } 523 524 SrcDepth srcDepth = k32Bit_SrcDepth; 525 if (PNG_COLOR_TYPE_GRAY == colorType) { 526 srcDepth = k8BitGray_SrcDepth; 527 // Remove this assert, which fails on desk_pokemonwiki.skp 528 //SkASSERT(!*hasAlphap); 529 } 530 531 *configp = this->getPrefConfig(srcDepth, *hasAlphap); 532 // now match the request against our capabilities 533 if (*hasAlphap) { 534 if (*configp != SkBitmap::kARGB_4444_Config) { 535 *configp = SkBitmap::kARGB_8888_Config; 536 } 537 } else { 538 if (SkBitmap::kA8_Config == *configp) { 539 if (k8BitGray_SrcDepth != srcDepth) { 540 // Converting a non grayscale image to A8 is not currently supported. 541 *configp = SkBitmap::kARGB_8888_Config; 542 } 543 } else if (*configp != SkBitmap::kRGB_565_Config && 544 *configp != SkBitmap::kARGB_4444_Config) { 545 *configp = SkBitmap::kARGB_8888_Config; 546 } 547 } 548 } 549 550 // sanity check for size 551 { 552 Sk64 size; 553 size.setMul(origWidth, origHeight); 554 if (size.isNeg() || !size.is32()) { 555 return false; 556 } 557 // now check that if we are 4-bytes per pixel, we also don't overflow 558 if (size.get32() > (0x7FFFFFFF >> 2)) { 559 return false; 560 } 561 } 562 563 if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) { 564 return false; 565 } 566 567 // If the image has alpha and the decoder wants unpremultiplied 568 // colors, the only supported config is 8888. 569 if (this->getRequireUnpremultipliedColors() && *hasAlphap) { 570 *configp = SkBitmap::kARGB_8888_Config; 571 } 572 573 if (fImageIndex != NULL) { 574 if (SkBitmap::kNo_Config == fImageIndex->fConfig) { 575 // This is the first time for this subset decode. From now on, 576 // all decodes must be in the same config. 577 fImageIndex->fConfig = *configp; 578 } else if (fImageIndex->fConfig != *configp) { 579 // Requesting a different config for a subsequent decode is not 580 // supported. Report failure before we make changes to png_ptr. 581 return false; 582 } 583 } 584 585 bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType 586 && *configp != SkBitmap::kA8_Config; 587 588 // Unless the user is requesting A8, convert a grayscale image into RGB. 589 // GRAY_ALPHA will always be converted to RGB 590 if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { 591 png_set_gray_to_rgb(png_ptr); 592 } 593 594 // Add filler (or alpha) byte (after each RGB triplet) if necessary. 595 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { 596 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 597 } 598 599 return true; 600 } 601 602 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); 603 604 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, 605 bool *hasAlphap, bool *reallyHasAlphap, 606 SkColorTable **colorTablep) { 607 int numPalette; 608 png_colorp palette; 609 png_bytep trans; 610 int numTrans; 611 bool reallyHasAlpha = false; 612 SkColorTable* colorTable = NULL; 613 614 png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); 615 616 /* BUGGY IMAGE WORKAROUND 617 618 We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count 619 which is a problem since we use the byte as an index. To work around this we grow 620 the colortable by 1 (if its < 256) and duplicate the last color into that slot. 621 */ 622 int colorCount = numPalette + (numPalette < 256); 623 624 colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); 625 626 SkPMColor* colorPtr = colorTable->lockColors(); 627 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 628 png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL); 629 *hasAlphap = (numTrans > 0); 630 } else { 631 numTrans = 0; 632 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); 633 } 634 // check for bad images that might make us crash 635 if (numTrans > numPalette) { 636 numTrans = numPalette; 637 } 638 639 int index = 0; 640 int transLessThanFF = 0; 641 642 // Choose which function to use to create the color table. If the final destination's 643 // config is unpremultiplied, the color table will store unpremultiplied colors. 644 PackColorProc proc; 645 if (this->getRequireUnpremultipliedColors()) { 646 proc = &SkPackARGB32NoCheck; 647 } else { 648 proc = &SkPreMultiplyARGB; 649 } 650 for (; index < numTrans; index++) { 651 transLessThanFF |= (int)*trans - 0xFF; 652 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue); 653 palette++; 654 } 655 reallyHasAlpha |= (transLessThanFF < 0); 656 657 for (; index < numPalette; index++) { 658 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); 659 palette++; 660 } 661 662 // see BUGGY IMAGE WORKAROUND comment above 663 if (numPalette < 256) { 664 *colorPtr = colorPtr[-1]; 665 } 666 colorTable->unlockColors(true); 667 *colorTablep = colorTable; 668 *reallyHasAlphap = reallyHasAlpha; 669 return true; 670 } 671 672 #ifdef SK_BUILD_FOR_ANDROID 673 674 bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *height) { 675 png_structp png_ptr; 676 png_infop info_ptr; 677 678 if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) { 679 return false; 680 } 681 682 if (setjmp(png_jmpbuf(png_ptr)) != 0) { 683 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 684 return false; 685 } 686 687 png_uint_32 origWidth, origHeight; 688 int bitDepth, colorType; 689 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 690 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 691 692 *width = origWidth; 693 *height = origHeight; 694 695 png_build_index(png_ptr); 696 697 if (fImageIndex) { 698 SkDELETE(fImageIndex); 699 } 700 fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (sk_stream, png_ptr, info_ptr)); 701 702 return true; 703 } 704 705 bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { 706 if (NULL == fImageIndex) { 707 return false; 708 } 709 710 png_structp png_ptr = fImageIndex->fPng_ptr; 711 png_infop info_ptr = fImageIndex->fInfo_ptr; 712 if (setjmp(png_jmpbuf(png_ptr))) { 713 return false; 714 } 715 716 png_uint_32 origWidth, origHeight; 717 int bitDepth, colorType, interlaceType; 718 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 719 &colorType, &interlaceType, int_p_NULL, int_p_NULL); 720 721 SkIRect rect = SkIRect::MakeWH(origWidth, origHeight); 722 723 if (!rect.intersect(region)) { 724 // If the requested region is entirely outside the image, just 725 // returns false 726 return false; 727 } 728 729 SkBitmap::Config config; 730 bool hasAlpha = false; 731 SkPMColor theTranspColor = 0; // 0 tells us not to try to match 732 733 if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) { 734 return false; 735 } 736 737 const int sampleSize = this->getSampleSize(); 738 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); 739 740 SkBitmap decodedBitmap; 741 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight()); 742 743 // from here down we are concerned with colortables and pixels 744 745 // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 746 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 747 // draw lots faster if we can flag the bitmap has being opaque 748 bool reallyHasAlpha = false; 749 SkColorTable* colorTable = NULL; 750 751 if (colorType == PNG_COLOR_TYPE_PALETTE) { 752 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable); 753 } 754 755 SkAutoUnref aur(colorTable); 756 757 // Check ahead of time if the swap(dest, src) is possible. 758 // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening. 759 // If no, then we will use alloc to allocate pixels to prevent garbage collection. 760 int w = rect.width() / sampleSize; 761 int h = rect.height() / sampleSize; 762 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) && 763 (h == decodedBitmap.height()) && bm->isNull(); 764 const bool needColorTable = SkBitmap::kIndex8_Config == config; 765 if (swapOnly) { 766 if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : NULL)) { 767 return false; 768 } 769 } else { 770 if (!decodedBitmap.allocPixels(NULL, needColorTable ? colorTable : NULL)) { 771 return false; 772 } 773 } 774 SkAutoLockPixels alp(decodedBitmap); 775 776 /* Turn on interlace handling. REQUIRED if you are not using 777 * png_read_image(). To see how to handle interlacing passes, 778 * see the png_read_row() method below: 779 */ 780 const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ? 781 png_set_interlace_handling(png_ptr) : 1; 782 783 /* Optional call to gamma correct and add the background to the palette 784 * and update info structure. REQUIRED if you are expecting libpng to 785 * update the palette for you (ie you selected such a transform above). 786 */ 787 788 // Direct access to png_ptr fields is deprecated in libpng > 1.2. 789 #if defined(PNG_1_0_X) || defined (PNG_1_2_X) 790 png_ptr->pass = 0; 791 #else 792 // FIXME: This sets pass as desired, but also sets iwidth. Is that ok? 793 png_set_interlaced_pass(png_ptr, 0); 794 #endif 795 png_read_update_info(png_ptr, info_ptr); 796 797 int actualTop = rect.fTop; 798 799 if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config) 800 && 1 == sampleSize) { 801 // A8 is only allowed if the original was GRAY. 802 SkASSERT(config != SkBitmap::kA8_Config 803 || PNG_COLOR_TYPE_GRAY == colorType); 804 805 for (int i = 0; i < number_passes; i++) { 806 png_configure_decoder(png_ptr, &actualTop, i); 807 for (int j = 0; j < rect.fTop - actualTop; j++) { 808 uint8_t* bmRow = decodedBitmap.getAddr8(0, 0); 809 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 810 } 811 png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height(); 812 for (png_uint_32 y = 0; y < bitmapHeight; y++) { 813 uint8_t* bmRow = decodedBitmap.getAddr8(0, y); 814 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 815 } 816 } 817 } else { 818 SkScaledBitmapSampler::SrcConfig sc; 819 int srcBytesPerPixel = 4; 820 821 if (colorTable != NULL) { 822 sc = SkScaledBitmapSampler::kIndex; 823 srcBytesPerPixel = 1; 824 } else if (SkBitmap::kA8_Config == config) { 825 // A8 is only allowed if the original was GRAY. 826 SkASSERT(PNG_COLOR_TYPE_GRAY == colorType); 827 sc = SkScaledBitmapSampler::kGray; 828 srcBytesPerPixel = 1; 829 } else if (hasAlpha) { 830 sc = SkScaledBitmapSampler::kRGBA; 831 } else { 832 sc = SkScaledBitmapSampler::kRGBX; 833 } 834 835 /* We have to pass the colortable explicitly, since we may have one 836 even if our decodedBitmap doesn't, due to the request that we 837 upscale png's palette to a direct model 838 */ 839 SkAutoLockColors ctLock(colorTable); 840 if (!sampler.begin(&decodedBitmap, sc, *this, ctLock.colors())) { 841 return false; 842 } 843 const int height = decodedBitmap.height(); 844 845 if (number_passes > 1) { 846 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 847 uint8_t* base = (uint8_t*)storage.get(); 848 size_t rb = origWidth * srcBytesPerPixel; 849 850 for (int i = 0; i < number_passes; i++) { 851 png_configure_decoder(png_ptr, &actualTop, i); 852 for (int j = 0; j < rect.fTop - actualTop; j++) { 853 uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels(); 854 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 855 } 856 uint8_t* row = base; 857 for (int32_t y = 0; y < rect.height(); y++) { 858 uint8_t* bmRow = row; 859 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 860 row += rb; 861 } 862 } 863 // now sample it 864 base += sampler.srcY0() * rb; 865 for (int y = 0; y < height; y++) { 866 reallyHasAlpha |= sampler.next(base); 867 base += sampler.srcDY() * rb; 868 } 869 } else { 870 SkAutoMalloc storage(origWidth * srcBytesPerPixel); 871 uint8_t* srcRow = (uint8_t*)storage.get(); 872 873 png_configure_decoder(png_ptr, &actualTop, 0); 874 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 875 876 for (int i = 0; i < rect.fTop - actualTop; i++) { 877 uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels(); 878 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 879 } 880 for (int y = 0; y < height; y++) { 881 uint8_t* tmp = srcRow; 882 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 883 reallyHasAlpha |= sampler.next(srcRow); 884 if (y < height - 1) { 885 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 886 } 887 } 888 } 889 } 890 891 if (0 != theTranspColor) { 892 reallyHasAlpha |= substituteTranspColor(&decodedBitmap, theTranspColor); 893 } 894 if (SkBitmap::kA8_Config == decodedBitmap.config()) { 895 reallyHasAlpha = true; 896 } 897 decodedBitmap.setIsOpaque(!reallyHasAlpha); 898 899 if (swapOnly) { 900 bm->swap(decodedBitmap); 901 return true; 902 } 903 return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(), 904 region.width(), region.height(), 0, rect.y()); 905 } 906 #endif 907 908 /////////////////////////////////////////////////////////////////////////////// 909 910 #include "SkColorPriv.h" 911 #include "SkUnPreMultiply.h" 912 913 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 914 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); 915 if (!sk_stream->write(data, len)) { 916 png_error(png_ptr, "sk_write_fn Error!"); 917 } 918 } 919 920 static transform_scanline_proc choose_proc(SkBitmap::Config config, 921 bool hasAlpha) { 922 // we don't care about search on alpha if we're kIndex8, since only the 923 // colortable packing cares about that distinction, not the pixels 924 if (SkBitmap::kIndex8_Config == config) { 925 hasAlpha = false; // we store false in the table entries for kIndex8 926 } 927 928 static const struct { 929 SkBitmap::Config fConfig; 930 bool fHasAlpha; 931 transform_scanline_proc fProc; 932 } gMap[] = { 933 { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, 934 { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, 935 { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, 936 { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, 937 { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, 938 { SkBitmap::kIndex8_Config, false, transform_scanline_memcpy }, 939 }; 940 941 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { 942 if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { 943 return gMap[i].fProc; 944 } 945 } 946 sk_throw(); 947 return NULL; 948 } 949 950 // return the minimum legal bitdepth (by png standards) for this many colortable 951 // entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, 952 // we can use fewer bits per in png 953 static int computeBitDepth(int colorCount) { 954 #if 0 955 int bits = SkNextLog2(colorCount); 956 SkASSERT(bits >= 1 && bits <= 8); 957 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) 958 return SkNextPow2(bits); 959 #else 960 // for the moment, we don't know how to pack bitdepth < 8 961 return 8; 962 #endif 963 } 964 965 /* Pack palette[] with the corresponding colors, and if hasAlpha is true, also 966 pack trans[] and return the number of trans[] entries written. If hasAlpha 967 is false, the return value will always be 0. 968 969 Note: this routine takes care of unpremultiplying the RGB values when we 970 have alpha in the colortable, since png doesn't support premul colors 971 */ 972 static inline int pack_palette(SkColorTable* ctable, 973 png_color* SK_RESTRICT palette, 974 png_byte* SK_RESTRICT trans, bool hasAlpha) { 975 SkAutoLockColors alc(ctable); 976 const SkPMColor* SK_RESTRICT colors = alc.colors(); 977 const int ctCount = ctable->count(); 978 int i, num_trans = 0; 979 980 if (hasAlpha) { 981 /* first see if we have some number of fully opaque at the end of the 982 ctable. PNG allows num_trans < num_palette, but all of the trans 983 entries must come first in the palette. If I was smarter, I'd 984 reorder the indices and ctable so that all non-opaque colors came 985 first in the palette. But, since that would slow down the encode, 986 I'm leaving the indices and ctable order as is, and just looking 987 at the tail of the ctable for opaqueness. 988 */ 989 num_trans = ctCount; 990 for (i = ctCount - 1; i >= 0; --i) { 991 if (SkGetPackedA32(colors[i]) != 0xFF) { 992 break; 993 } 994 num_trans -= 1; 995 } 996 997 const SkUnPreMultiply::Scale* SK_RESTRICT table = 998 SkUnPreMultiply::GetScaleTable(); 999 1000 for (i = 0; i < num_trans; i++) { 1001 const SkPMColor c = *colors++; 1002 const unsigned a = SkGetPackedA32(c); 1003 const SkUnPreMultiply::Scale s = table[a]; 1004 trans[i] = a; 1005 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); 1006 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); 1007 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); 1008 } 1009 // now fall out of this if-block to use common code for the trailing 1010 // opaque entries 1011 } 1012 1013 // these (remaining) entries are opaque 1014 for (i = num_trans; i < ctCount; i++) { 1015 SkPMColor c = *colors++; 1016 palette[i].red = SkGetPackedR32(c); 1017 palette[i].green = SkGetPackedG32(c); 1018 palette[i].blue = SkGetPackedB32(c); 1019 } 1020 return num_trans; 1021 } 1022 1023 class SkPNGImageEncoder : public SkImageEncoder { 1024 protected: 1025 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE; 1026 private: 1027 bool doEncode(SkWStream* stream, const SkBitmap& bm, 1028 const bool& hasAlpha, int colorType, 1029 int bitDepth, SkBitmap::Config config, 1030 png_color_8& sig_bit); 1031 1032 typedef SkImageEncoder INHERITED; 1033 }; 1034 1035 bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 1036 int /*quality*/) { 1037 SkBitmap::Config config = bitmap.getConfig(); 1038 1039 const bool hasAlpha = !bitmap.isOpaque(); 1040 int colorType = PNG_COLOR_MASK_COLOR; 1041 int bitDepth = 8; // default for color 1042 png_color_8 sig_bit; 1043 1044 switch (config) { 1045 case SkBitmap::kIndex8_Config: 1046 colorType |= PNG_COLOR_MASK_PALETTE; 1047 // fall through to the ARGB_8888 case 1048 case SkBitmap::kARGB_8888_Config: 1049 sig_bit.red = 8; 1050 sig_bit.green = 8; 1051 sig_bit.blue = 8; 1052 sig_bit.alpha = 8; 1053 break; 1054 case SkBitmap::kARGB_4444_Config: 1055 sig_bit.red = 4; 1056 sig_bit.green = 4; 1057 sig_bit.blue = 4; 1058 sig_bit.alpha = 4; 1059 break; 1060 case SkBitmap::kRGB_565_Config: 1061 sig_bit.red = 5; 1062 sig_bit.green = 6; 1063 sig_bit.blue = 5; 1064 sig_bit.alpha = 0; 1065 break; 1066 default: 1067 return false; 1068 } 1069 1070 if (hasAlpha) { 1071 // don't specify alpha if we're a palette, even if our ctable has alpha 1072 if (!(colorType & PNG_COLOR_MASK_PALETTE)) { 1073 colorType |= PNG_COLOR_MASK_ALPHA; 1074 } 1075 } else { 1076 sig_bit.alpha = 0; 1077 } 1078 1079 SkAutoLockPixels alp(bitmap); 1080 // readyToDraw checks for pixels (and colortable if that is required) 1081 if (!bitmap.readyToDraw()) { 1082 return false; 1083 } 1084 1085 // we must do this after we have locked the pixels 1086 SkColorTable* ctable = bitmap.getColorTable(); 1087 if (NULL != ctable) { 1088 if (ctable->count() == 0) { 1089 return false; 1090 } 1091 // check if we can store in fewer than 8 bits 1092 bitDepth = computeBitDepth(ctable->count()); 1093 } 1094 1095 return doEncode(stream, bitmap, hasAlpha, colorType, 1096 bitDepth, config, sig_bit); 1097 } 1098 1099 bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, 1100 const bool& hasAlpha, int colorType, 1101 int bitDepth, SkBitmap::Config config, 1102 png_color_8& sig_bit) { 1103 1104 png_structp png_ptr; 1105 png_infop info_ptr; 1106 1107 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 1108 NULL); 1109 if (NULL == png_ptr) { 1110 return false; 1111 } 1112 1113 info_ptr = png_create_info_struct(png_ptr); 1114 if (NULL == info_ptr) { 1115 png_destroy_write_struct(&png_ptr, png_infopp_NULL); 1116 return false; 1117 } 1118 1119 /* Set error handling. REQUIRED if you aren't supplying your own 1120 * error handling functions in the png_create_write_struct() call. 1121 */ 1122 if (setjmp(png_jmpbuf(png_ptr))) { 1123 png_destroy_write_struct(&png_ptr, &info_ptr); 1124 return false; 1125 } 1126 1127 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); 1128 1129 /* Set the image information here. Width and height are up to 2^31, 1130 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 1131 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 1132 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 1133 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 1134 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 1135 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 1136 */ 1137 1138 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 1139 bitDepth, colorType, 1140 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 1141 PNG_FILTER_TYPE_BASE); 1142 1143 // set our colortable/trans arrays if needed 1144 png_color paletteColors[256]; 1145 png_byte trans[256]; 1146 if (SkBitmap::kIndex8_Config == config) { 1147 SkColorTable* ct = bitmap.getColorTable(); 1148 int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); 1149 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 1150 if (numTrans > 0) { 1151 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL); 1152 } 1153 } 1154 1155 png_set_sBIT(png_ptr, info_ptr, &sig_bit); 1156 png_write_info(png_ptr, info_ptr); 1157 1158 const char* srcImage = (const char*)bitmap.getPixels(); 1159 SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); 1160 char* storage = (char*)rowStorage.get(); 1161 transform_scanline_proc proc = choose_proc(config, hasAlpha); 1162 1163 for (int y = 0; y < bitmap.height(); y++) { 1164 png_bytep row_ptr = (png_bytep)storage; 1165 proc(srcImage, bitmap.width(), storage); 1166 png_write_rows(png_ptr, &row_ptr, 1); 1167 srcImage += bitmap.rowBytes(); 1168 } 1169 1170 png_write_end(png_ptr, info_ptr); 1171 1172 /* clean up after the write, and free any memory allocated */ 1173 png_destroy_write_struct(&png_ptr, &info_ptr); 1174 return true; 1175 } 1176 1177 /////////////////////////////////////////////////////////////////////////////// 1178 DEFINE_DECODER_CREATOR(PNGImageDecoder); 1179 DEFINE_ENCODER_CREATOR(PNGImageEncoder); 1180 /////////////////////////////////////////////////////////////////////////////// 1181 1182 #include "SkTRegistry.h" 1183 1184 static bool is_png(SkStream* stream) { 1185 char buf[PNG_BYTES_TO_CHECK]; 1186 if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && 1187 !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 1188 return true; 1189 } 1190 return false; 1191 } 1192 1193 SkImageDecoder* sk_libpng_dfactory(SkStream* stream) { 1194 if (is_png(stream)) { 1195 return SkNEW(SkPNGImageDecoder); 1196 } 1197 return NULL; 1198 } 1199 1200 static SkImageDecoder::Format get_format_png(SkStream* stream) { 1201 if (is_png(stream)) { 1202 return SkImageDecoder::kPNG_Format; 1203 } 1204 return SkImageDecoder::kUnknown_Format; 1205 } 1206 1207 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 1208 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 1209 } 1210 1211 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory); 1212 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png); 1213 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); 1214