SkImageDecoder_libpng.cpp revision 3f1f06a26bdb2022a5c72f93ae623a57b6659464
1/* libs/graphics/images/SkImageDecoder_libpng.cpp 2** 3** Copyright 2006, The Android Open Source Project 4** 5** Licensed under the Apache License, Version 2.0 (the "License"); 6** you may not use this file except in compliance with the License. 7** You may obtain a copy of the License at 8** 9** http://www.apache.org/licenses/LICENSE-2.0 10** 11** Unless required by applicable law or agreed to in writing, software 12** distributed under the License is distributed on an "AS IS" BASIS, 13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14** See the License for the specific language governing permissions and 15** limitations under the License. 16*/ 17 18#include "SkImageDecoder.h" 19#include "SkImageEncoder.h" 20#include "SkColor.h" 21#include "SkColorPriv.h" 22#include "SkDither.h" 23#include "SkMath.h" 24#include "SkScaledBitmapSampler.h" 25#include "SkStream.h" 26#include "SkTemplates.h" 27#include "SkUtils.h" 28 29extern "C" { 30#include "png.h" 31} 32 33class SkPNGImageDecoder : public SkImageDecoder { 34public: 35 virtual Format getFormat() const { 36 return kPNG_Format; 37 } 38 39protected: 40 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 41}; 42 43#ifndef png_jmpbuf 44# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 45#endif 46 47#define PNG_BYTES_TO_CHECK 4 48 49/* Automatically clean up after throwing an exception */ 50struct PNGAutoClean { 51 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 52 ~PNGAutoClean() { 53 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 54 } 55private: 56 png_structp png_ptr; 57 png_infop info_ptr; 58}; 59 60static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 61 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 62 size_t bytes = sk_stream->read(data, length); 63 if (bytes != length) { 64 png_error(png_ptr, "Read Error!"); 65 } 66} 67 68static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 69 SkImageDecoder::Peeker* peeker = 70 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 71 // peek() returning true means continue decoding 72 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 73 1 : -1; 74} 75 76static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 77#if 0 78 SkDebugf("------ png error %s\n", msg); 79#endif 80 longjmp(png_jmpbuf(png_ptr), 1); 81} 82 83static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 84 for (int i = 0; i < count; i++) { 85 uint8_t* tmp = storage; 86 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 87 } 88} 89 90static bool pos_le(int value, int max) { 91 return value > 0 && value <= max; 92} 93 94static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 95 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 96 97 bool reallyHasAlpha = false; 98 99 for (int y = bm->height() - 1; y >= 0; --y) { 100 SkPMColor* p = bm->getAddr32(0, y); 101 for (int x = bm->width() - 1; x >= 0; --x) { 102 if (match == *p) { 103 *p = 0; 104 reallyHasAlpha = true; 105 } 106 p += 1; 107 } 108 } 109 return reallyHasAlpha; 110} 111 112static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig, 113 bool srcHasAlpha) { 114 switch (dstConfig) { 115 case SkBitmap::kARGB_8888_Config: 116 case SkBitmap::kARGB_4444_Config: 117 return true; 118 case SkBitmap::kRGB_565_Config: 119 // only return true if the src is opaque (since 565 is opaque) 120 return !srcHasAlpha; 121 default: 122 return false; 123 } 124} 125 126// call only if color_type is PALETTE. Returns true if the ctable has alpha 127static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { 128 png_bytep trans; 129 int num_trans; 130 131 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 132 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 133 return num_trans > 0; 134 } 135 return false; 136} 137 138bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 139 Mode mode) { 140// SkAutoTrace apr("SkPNGImageDecoder::onDecode"); 141 142 /* Create and initialize the png_struct with the desired error handler 143 * functions. If you want to use the default stderr and longjump method, 144 * you can supply NULL for the last three parameters. We also supply the 145 * the compiler header file version, so that we know if the application 146 * was compiled with a compatible version of the library. */ 147 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 148 NULL, sk_error_fn, NULL); 149 // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 150 if (png_ptr == NULL) { 151 return false; 152 } 153 154 /* Allocate/initialize the memory for image information. */ 155 png_infop info_ptr = png_create_info_struct(png_ptr); 156 if (info_ptr == NULL) { 157 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); 158 return false; 159 } 160 161 PNGAutoClean autoClean(png_ptr, info_ptr); 162 163 /* Set error handling if you are using the setjmp/longjmp method (this is 164 * the normal method of doing things with libpng). REQUIRED unless you 165 * set up your own error handlers in the png_create_read_struct() earlier. 166 */ 167 if (setjmp(png_jmpbuf(png_ptr))) { 168 return false; 169 } 170 171 /* If you are using replacement read functions, instead of calling 172 * png_init_io() here you would call: 173 */ 174 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 175 /* where user_io_ptr is a structure you want available to the callbacks */ 176 /* If we have already read some of the signature */ 177// png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 178 179 // hookup our peeker so we can see any user-chunks the caller may be interested in 180 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 181 if (this->getPeeker()) { 182 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); 183 } 184 185 /* The call to png_read_info() gives us all of the information from the 186 * PNG file before the first IDAT (image data chunk). */ 187 png_read_info(png_ptr, info_ptr); 188 png_uint_32 origWidth, origHeight; 189 int bit_depth, color_type, interlace_type; 190 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, 191 &interlace_type, int_p_NULL, int_p_NULL); 192 193 /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 194 if (bit_depth == 16) { 195 png_set_strip_16(png_ptr); 196 } 197 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 198 * byte into separate bytes (useful for paletted and grayscale images). */ 199 if (bit_depth < 8) { 200 png_set_packing(png_ptr); 201 } 202 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 203 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 204 png_set_gray_1_2_4_to_8(png_ptr); 205 } 206 207 /* Make a grayscale image into RGB. */ 208 if (color_type == PNG_COLOR_TYPE_GRAY || 209 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 210 png_set_gray_to_rgb(png_ptr); 211 } 212 213 SkBitmap::Config config; 214 bool hasAlpha = false; 215 bool doDither = this->getDitherImage(); 216 SkPMColor theTranspColor = 0; // 0 tells us not to try to match 217 218 // check for sBIT chunk data, in case we should disable dithering because 219 // our data is not truely 8bits per component 220 if (doDither) { 221#if 0 222 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, 223 info_ptr->sig_bit.green, info_ptr->sig_bit.blue, 224 info_ptr->sig_bit.alpha); 225#endif 226 // 0 seems to indicate no information available 227 if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && 228 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && 229 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { 230 doDither = false; 231 } 232 } 233 234 if (color_type == PNG_COLOR_TYPE_PALETTE) { 235 bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 236 config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 237 // now see if we can upscale to their requested config 238 if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) { 239 config = SkBitmap::kIndex8_Config; 240 } 241 } else { 242 png_color_16p transpColor = NULL; 243 int numTransp = 0; 244 245 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 246 247 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 248 249 if (valid && numTransp == 1 && transpColor != NULL) { 250 /* Compute our transparent color, which we'll match against later. 251 We don't really handle 16bit components properly here, since we 252 do our compare *after* the values have been knocked down to 8bit 253 which means we will find more matches than we should. The real 254 fix seems to be to see the actual 16bit components, do the 255 compare, and then knock it down to 8bits ourselves. 256 */ 257 if (color_type & PNG_COLOR_MASK_COLOR) { 258 if (16 == bit_depth) { 259 theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8, 260 transpColor->green >> 8, transpColor->blue >> 8); 261 } else { 262 theTranspColor = SkPackARGB32(0xFF, transpColor->red, 263 transpColor->green, transpColor->blue); 264 } 265 } else { // gray 266 if (16 == bit_depth) { 267 theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8, 268 transpColor->gray >> 8, transpColor->gray >> 8); 269 } else { 270 theTranspColor = SkPackARGB32(0xFF, transpColor->gray, 271 transpColor->gray, transpColor->gray); 272 } 273 } 274 } 275 276 if (valid || 277 PNG_COLOR_TYPE_RGB_ALPHA == color_type || 278 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { 279 hasAlpha = true; 280 } 281 config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha); 282 // now match the request against our capabilities 283 if (hasAlpha) { 284 if (config != SkBitmap::kARGB_4444_Config) { 285 config = SkBitmap::kARGB_8888_Config; 286 } 287 } else { 288 if (config != SkBitmap::kRGB_565_Config && 289 config != SkBitmap::kARGB_4444_Config) { 290 config = SkBitmap::kARGB_8888_Config; 291 } 292 } 293 } 294 295 // sanity check for size 296 { 297 Sk64 size; 298 size.setMul(origWidth, origHeight); 299 if (size.isNeg() || !size.is32()) { 300 return false; 301 } 302 // now check that if we are 4-bytes per pixel, we also don't overflow 303 if (size.get32() > (0x7FFFFFFF >> 2)) { 304 return false; 305 } 306 } 307 308 if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { 309 return false; 310 } 311 312 const int sampleSize = this->getSampleSize(); 313 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 314 315 decodedBitmap->setConfig(config, sampler.scaledWidth(), 316 sampler.scaledHeight(), 0); 317 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 318 return true; 319 } 320 321 // from here down we are concerned with colortables and pixels 322 323 // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 324 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 325 // draw lots faster if we can flag the bitmap has being opaque 326 bool reallyHasAlpha = false; 327 SkColorTable* colorTable = NULL; 328 329 if (color_type == PNG_COLOR_TYPE_PALETTE) { 330 int num_palette; 331 png_colorp palette; 332 png_bytep trans; 333 int num_trans; 334 335 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); 336 337 /* BUGGY IMAGE WORKAROUND 338 339 We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count 340 which is a problem since we use the byte as an index. To work around this we grow 341 the colortable by 1 (if its < 256) and duplicate the last color into that slot. 342 */ 343 int colorCount = num_palette + (num_palette < 256); 344 345 colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); 346 347 SkPMColor* colorPtr = colorTable->lockColors(); 348 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 349 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 350 hasAlpha = (num_trans > 0); 351 } else { 352 num_trans = 0; 353 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); 354 } 355 // check for bad images that might make us crash 356 if (num_trans > num_palette) { 357 num_trans = num_palette; 358 } 359 360 int index = 0; 361 int transLessThanFF = 0; 362 363 for (; index < num_trans; index++) { 364 transLessThanFF |= (int)*trans - 0xFF; 365 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); 366 palette++; 367 } 368 reallyHasAlpha |= (transLessThanFF < 0); 369 370 for (; index < num_palette; index++) { 371 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); 372 palette++; 373 } 374 375 // see BUGGY IMAGE WORKAROUND comment above 376 if (num_palette < 256) { 377 *colorPtr = colorPtr[-1]; 378 } 379 colorTable->unlockColors(true); 380 } 381 382 SkAutoUnref aur(colorTable); 383 384 if (!this->allocPixelRef(decodedBitmap, 385 SkBitmap::kIndex8_Config == config ? 386 colorTable : NULL)) { 387 return false; 388 } 389 390 SkAutoLockPixels alp(*decodedBitmap); 391 392 /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ 393// if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) 394// ; // png_set_swap_alpha(png_ptr); 395 396 /* swap bytes of 16 bit files to least significant byte first */ 397 // png_set_swap(png_ptr); 398 399 /* Add filler (or alpha) byte (before/after each RGB triplet) */ 400 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 401 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 402 } 403 404 /* Turn on interlace handling. REQUIRED if you are not using 405 * png_read_image(). To see how to handle interlacing passes, 406 * see the png_read_row() method below: 407 */ 408 const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 409 png_set_interlace_handling(png_ptr) : 1; 410 411 /* Optional call to gamma correct and add the background to the palette 412 * and update info structure. REQUIRED if you are expecting libpng to 413 * update the palette for you (ie you selected such a transform above). 414 */ 415 png_read_update_info(png_ptr, info_ptr); 416 417 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 418 for (int i = 0; i < number_passes; i++) { 419 for (png_uint_32 y = 0; y < origHeight; y++) { 420 uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 421 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 422 } 423 } 424 } else { 425 SkScaledBitmapSampler::SrcConfig sc; 426 int srcBytesPerPixel = 4; 427 428 if (colorTable != NULL) { 429 sc = SkScaledBitmapSampler::kIndex; 430 srcBytesPerPixel = 1; 431 } else if (hasAlpha) { 432 sc = SkScaledBitmapSampler::kRGBA; 433 } else { 434 sc = SkScaledBitmapSampler::kRGBX; 435 } 436 437 /* We have to pass the colortable explicitly, since we may have one 438 even if our decodedBitmap doesn't, due to the request that we 439 upscale png's palette to a direct model 440 */ 441 SkAutoLockColors ctLock(colorTable); 442 if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 443 return false; 444 } 445 const int height = decodedBitmap->height(); 446 447 if (number_passes > 1) { 448 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 449 uint8_t* base = (uint8_t*)storage.get(); 450 size_t rb = origWidth * srcBytesPerPixel; 451 452 for (int i = 0; i < number_passes; i++) { 453 uint8_t* row = base; 454 for (png_uint_32 y = 0; y < origHeight; y++) { 455 uint8_t* bmRow = row; 456 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 457 row += rb; 458 } 459 } 460 // now sample it 461 base += sampler.srcY0() * rb; 462 for (int y = 0; y < height; y++) { 463 reallyHasAlpha |= sampler.next(base); 464 base += sampler.srcDY() * rb; 465 } 466 } else { 467 SkAutoMalloc storage(origWidth * srcBytesPerPixel); 468 uint8_t* srcRow = (uint8_t*)storage.get(); 469 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 470 471 for (int y = 0; y < height; y++) { 472 uint8_t* tmp = srcRow; 473 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 474 reallyHasAlpha |= sampler.next(srcRow); 475 if (y < height - 1) { 476 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 477 } 478 } 479 480 // skip the rest of the rows (if any) 481 png_uint_32 read = (height - 1) * sampler.srcDY() + 482 sampler.srcY0() + 1; 483 SkASSERT(read <= origHeight); 484 skip_src_rows(png_ptr, srcRow, origHeight - read); 485 } 486 } 487 488 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 489 png_read_end(png_ptr, info_ptr); 490 491 if (0 != theTranspColor) { 492 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 493 } 494 decodedBitmap->setIsOpaque(!reallyHasAlpha); 495 return true; 496} 497 498/////////////////////////////////////////////////////////////////////////////// 499 500#include "SkColorPriv.h" 501#include "SkUnPreMultiply.h" 502 503static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 504 SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr; 505 if (!sk_stream->write(data, len)) { 506 png_error(png_ptr, "sk_write_fn Error!"); 507 } 508} 509 510typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src, 511 int width, char* SK_RESTRICT dst); 512 513static void transform_scanline_565(const char* SK_RESTRICT src, int width, 514 char* SK_RESTRICT dst) { 515 const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src; 516 for (int i = 0; i < width; i++) { 517 unsigned c = *srcP++; 518 *dst++ = SkPacked16ToR32(c); 519 *dst++ = SkPacked16ToG32(c); 520 *dst++ = SkPacked16ToB32(c); 521 } 522} 523 524static void transform_scanline_888(const char* SK_RESTRICT src, int width, 525 char* SK_RESTRICT dst) { 526 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 527 for (int i = 0; i < width; i++) { 528 SkPMColor c = *srcP++; 529 *dst++ = SkGetPackedR32(c); 530 *dst++ = SkGetPackedG32(c); 531 *dst++ = SkGetPackedB32(c); 532 } 533} 534 535static void transform_scanline_444(const char* SK_RESTRICT src, int width, 536 char* SK_RESTRICT dst) { 537 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 538 for (int i = 0; i < width; i++) { 539 SkPMColor16 c = *srcP++; 540 *dst++ = SkPacked4444ToR32(c); 541 *dst++ = SkPacked4444ToG32(c); 542 *dst++ = SkPacked4444ToB32(c); 543 } 544} 545 546static void transform_scanline_8888(const char* SK_RESTRICT src, int width, 547 char* SK_RESTRICT dst) { 548 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 549 const SkUnPreMultiply::Scale* SK_RESTRICT table = 550 SkUnPreMultiply::GetScaleTable(); 551 552 for (int i = 0; i < width; i++) { 553 SkPMColor c = *srcP++; 554 unsigned a = SkGetPackedA32(c); 555 unsigned r = SkGetPackedR32(c); 556 unsigned g = SkGetPackedG32(c); 557 unsigned b = SkGetPackedB32(c); 558 559 if (0 != a && 255 != a) { 560 SkUnPreMultiply::Scale scale = table[a]; 561 r = SkUnPreMultiply::ApplyScale(scale, r); 562 g = SkUnPreMultiply::ApplyScale(scale, g); 563 b = SkUnPreMultiply::ApplyScale(scale, b); 564 } 565 *dst++ = r; 566 *dst++ = g; 567 *dst++ = b; 568 *dst++ = a; 569 } 570} 571 572static void transform_scanline_4444(const char* SK_RESTRICT src, int width, 573 char* SK_RESTRICT dst) { 574 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 575 const SkUnPreMultiply::Scale* SK_RESTRICT table = 576 SkUnPreMultiply::GetScaleTable(); 577 578 for (int i = 0; i < width; i++) { 579 SkPMColor16 c = *srcP++; 580 unsigned a = SkPacked4444ToA32(c); 581 unsigned r = SkPacked4444ToR32(c); 582 unsigned g = SkPacked4444ToG32(c); 583 unsigned b = SkPacked4444ToB32(c); 584 585 if (0 != a && 255 != a) { 586 SkUnPreMultiply::Scale scale = table[a]; 587 r = SkUnPreMultiply::ApplyScale(scale, r); 588 g = SkUnPreMultiply::ApplyScale(scale, g); 589 b = SkUnPreMultiply::ApplyScale(scale, b); 590 } 591 *dst++ = r; 592 *dst++ = g; 593 *dst++ = b; 594 *dst++ = a; 595 } 596} 597 598static void transform_scanline_index8(const char* SK_RESTRICT src, int width, 599 char* SK_RESTRICT dst) { 600 memcpy(dst, src, width); 601} 602 603static transform_scanline_proc choose_proc(SkBitmap::Config config, 604 bool hasAlpha) { 605 // we don't care about search on alpha if we're kIndex8, since only the 606 // colortable packing cares about that distinction, not the pixels 607 if (SkBitmap::kIndex8_Config == config) { 608 hasAlpha = false; // we store false in the table entries for kIndex8 609 } 610 611 static const struct { 612 SkBitmap::Config fConfig; 613 bool fHasAlpha; 614 transform_scanline_proc fProc; 615 } gMap[] = { 616 { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, 617 { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, 618 { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, 619 { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, 620 { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, 621 { SkBitmap::kIndex8_Config, false, transform_scanline_index8 }, 622 }; 623 624 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { 625 if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { 626 return gMap[i].fProc; 627 } 628 } 629 sk_throw(); 630 return NULL; 631} 632 633// return the minimum legal bitdepth (by png standards) for this many colortable 634// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, 635// we can use fewer bits per in png 636static int computeBitDepth(int colorCount) { 637#if 0 638 int bits = SkNextLog2(colorCount); 639 SkASSERT(bits >= 1 && bits <= 8); 640 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) 641 return SkNextPow2(bits); 642#else 643 // for the moment, we don't know how to pack bitdepth < 8 644 return 8; 645#endif 646} 647 648/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also 649 pack trans[] and return the number of trans[] entries written. If hasAlpha 650 is false, the return value will always be 0. 651 652 Note: this routine takes care of unpremultiplying the RGB values when we 653 have alpha in the colortable, since png doesn't support premul colors 654*/ 655static inline int pack_palette(SkColorTable* ctable, 656 png_color* SK_RESTRICT palette, 657 png_byte* SK_RESTRICT trans, bool hasAlpha) { 658 SkAutoLockColors alc(ctable); 659 const SkPMColor* SK_RESTRICT colors = alc.colors(); 660 const int ctCount = ctable->count(); 661 int i, num_trans = 0; 662 663 if (hasAlpha) { 664 /* first see if we have some number of fully opaque at the end of the 665 ctable. PNG allows num_trans < num_palette, but all of the trans 666 entries must come first in the palette. If I was smarter, I'd 667 reorder the indices and ctable so that all non-opaque colors came 668 first in the palette. But, since that would slow down the encode, 669 I'm leaving the indices and ctable order as is, and just looking 670 at the tail of the ctable for opaqueness. 671 */ 672 num_trans = ctCount; 673 for (i = ctCount - 1; i >= 0; --i) { 674 if (SkGetPackedA32(colors[i]) != 0xFF) { 675 break; 676 } 677 num_trans -= 1; 678 } 679 680 const SkUnPreMultiply::Scale* SK_RESTRICT table = 681 SkUnPreMultiply::GetScaleTable(); 682 683 for (i = 0; i < num_trans; i++) { 684 const SkPMColor c = *colors++; 685 const unsigned a = SkGetPackedA32(c); 686 const SkUnPreMultiply::Scale s = table[a]; 687 trans[i] = a; 688 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); 689 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); 690 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); 691 } 692 // now fall out of this if-block to use common code for the trailing 693 // opaque entries 694 } 695 696 // these (remaining) entries are opaque 697 for (i = num_trans; i < ctCount; i++) { 698 SkPMColor c = *colors++; 699 palette[i].red = SkGetPackedR32(c); 700 palette[i].green = SkGetPackedG32(c); 701 palette[i].blue = SkGetPackedB32(c); 702 } 703 return num_trans; 704} 705 706class SkPNGImageEncoder : public SkImageEncoder { 707protected: 708 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 709}; 710 711bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 712 int /*quality*/) { 713 SkBitmap::Config config = bitmap.getConfig(); 714 715 const bool hasAlpha = !bitmap.isOpaque(); 716 int colorType = PNG_COLOR_MASK_COLOR; 717 int bitDepth = 8; // default for color 718 png_color_8 sig_bit; 719 720 switch (config) { 721 case SkBitmap::kIndex8_Config: 722 colorType |= PNG_COLOR_MASK_PALETTE; 723 // fall through to the ARGB_8888 case 724 case SkBitmap::kARGB_8888_Config: 725 sig_bit.red = 8; 726 sig_bit.green = 8; 727 sig_bit.blue = 8; 728 sig_bit.alpha = 8; 729 break; 730 case SkBitmap::kARGB_4444_Config: 731 sig_bit.red = 4; 732 sig_bit.green = 4; 733 sig_bit.blue = 4; 734 sig_bit.alpha = 4; 735 break; 736 case SkBitmap::kRGB_565_Config: 737 sig_bit.red = 5; 738 sig_bit.green = 6; 739 sig_bit.blue = 5; 740 sig_bit.alpha = 0; 741 break; 742 default: 743 return false; 744 } 745 746 if (hasAlpha) { 747 // don't specify alpha if we're a palette, even if our ctable has alpha 748 if (!(colorType & PNG_COLOR_MASK_PALETTE)) { 749 colorType |= PNG_COLOR_MASK_ALPHA; 750 } 751 } else { 752 sig_bit.alpha = 0; 753 } 754 755 SkAutoLockPixels alp(bitmap); 756 // readyToDraw checks for pixels (and colortable if that is required) 757 if (!bitmap.readyToDraw()) { 758 return false; 759 } 760 761 // we must do this after we have locked the pixels 762 SkColorTable* ctable = bitmap.getColorTable(); 763 if (NULL != ctable) { 764 if (ctable->count() == 0) { 765 return false; 766 } 767 // check if we can store in fewer than 8 bits 768 bitDepth = computeBitDepth(ctable->count()); 769 } 770 771 png_structp png_ptr; 772 png_infop info_ptr; 773 774 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 775 NULL); 776 if (NULL == png_ptr) { 777 return false; 778 } 779 780 info_ptr = png_create_info_struct(png_ptr); 781 if (NULL == info_ptr) { 782 png_destroy_write_struct(&png_ptr, png_infopp_NULL); 783 return false; 784 } 785 786 /* Set error handling. REQUIRED if you aren't supplying your own 787 * error handling functions in the png_create_write_struct() call. 788 */ 789 if (setjmp(png_jmpbuf(png_ptr))) { 790 png_destroy_write_struct(&png_ptr, &info_ptr); 791 return false; 792 } 793 794 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); 795 796 /* Set the image information here. Width and height are up to 2^31, 797 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 798 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 799 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 800 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 801 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 802 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 803 */ 804 805 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 806 bitDepth, colorType, 807 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 808 PNG_FILTER_TYPE_BASE); 809 810 // set our colortable/trans arrays if needed 811 png_color paletteColors[256]; 812 png_byte trans[256]; 813 if (SkBitmap::kIndex8_Config == config) { 814 SkColorTable* ct = bitmap.getColorTable(); 815 int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); 816 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 817 if (numTrans > 0) { 818 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL); 819 } 820 } 821 822 png_set_sBIT(png_ptr, info_ptr, &sig_bit); 823 png_write_info(png_ptr, info_ptr); 824 825 const char* srcImage = (const char*)bitmap.getPixels(); 826 SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); 827 char* storage = (char*)rowStorage.get(); 828 transform_scanline_proc proc = choose_proc(config, hasAlpha); 829 830 for (int y = 0; y < bitmap.height(); y++) { 831 png_bytep row_ptr = (png_bytep)storage; 832 proc(srcImage, bitmap.width(), storage); 833 png_write_rows(png_ptr, &row_ptr, 1); 834 srcImage += bitmap.rowBytes(); 835 } 836 837 png_write_end(png_ptr, info_ptr); 838 839 /* clean up after the write, and free any memory allocated */ 840 png_destroy_write_struct(&png_ptr, &info_ptr); 841 return true; 842} 843 844/////////////////////////////////////////////////////////////////////////////// 845 846#include "SkTRegistry.h" 847 848static SkImageDecoder* DFactory(SkStream* stream) { 849 char buf[PNG_BYTES_TO_CHECK]; 850 if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && 851 !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 852 return SkNEW(SkPNGImageDecoder); 853 } 854 return NULL; 855} 856 857static SkImageEncoder* EFactory(SkImageEncoder::Type t) { 858 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 859} 860 861static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory); 862static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory); 863