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