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