11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/* 31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project 41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * 51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be 61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file. 71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */ 81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageDecoder.h" 110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageEncoder.h" 120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColor.h" 130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h" 140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkDither.h" 150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkMath.h" 160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkScaledBitmapSampler.h" 170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStream.h" 180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTemplates.h" 190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUtils.h" 20363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger#include "transform_scanline.h" 210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectextern "C" { 230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "png.h" 240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenclass SkPNGImageIndex { 2758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenpublic: 2858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageIndex() { 2958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen inputStream = NULL; 3058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_ptr = NULL; 3158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen virtual ~SkPNGImageIndex() { 3358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (png_ptr) { 3458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 3558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (inputStream) { 3758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen delete inputStream; 3858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 4058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 4158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 4258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkStream *inputStream; 4358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen}; 4458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageDecoder : public SkImageDecoder { 460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic: 4758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageDecoder() { 4858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen index = NULL; 4958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual Format getFormat() const { 510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return kPNG_Format; 520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen virtual ~SkPNGImageDecoder() { 5458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (index) { 5558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen delete index; 5658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 5758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 5858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 6014496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen virtual bool onBuildTileIndex(SkStream *stream, 6114496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen int *width, int *height); 62943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect region); 630a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 6458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenprivate: 6658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, 6758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop *info_ptrp); 6858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool decodePalette(png_structp png_ptr, png_infop info_ptr, 6958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep); 7058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 7158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config *config, bool *hasAlpha, bool *doDither, 7258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor *theTranspColor); 7358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageIndex *index; 740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifndef png_jmpbuf 770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PNG_BYTES_TO_CHECK 4 810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Automatically clean up after throwing an exception */ 830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstruct PNGAutoClean { 840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ~PNGAutoClean() { 860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate: 890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project size_t bytes = sk_stream->read(data, length); 960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bytes != length) { 970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "Read Error!"); 980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenstatic void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) { 10258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 10358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sk_stream->rewind(); 10458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen (void)sk_stream->skip(offset); 10558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 10658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkImageDecoder::Peeker* peeker = 1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // peek() returning true means continue decoding 1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1 : -1; 1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("------ png error %s\n", msg); 1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project longjmp(png_jmpbuf(png_ptr), 1); 1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < count; i++) { 1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = storage; 1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool pos_le(int value, int max) { 1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return value > 0 && value <= max; 1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = bm->height() - 1; y >= 0; --y) { 1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor* p = bm->getAddr32(0, y); 1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int x = bm->width() - 1; x >= 0; --x) { 1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (match == *p) { 1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *p = 0; 1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha = true; 1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project p += 1; 1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return reallyHasAlpha; 1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1510a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedstatic bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig, 152fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool srcHasAlpha) { 1530a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed switch (dstConfig) { 154fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_8888_Config: 155fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_4444_Config: 156fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return true; 157fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kRGB_565_Config: 158fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed // only return true if the src is opaque (since 565 is opaque) 159fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return !srcHasAlpha; 160fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed default: 161fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 162fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 163fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed} 164fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 165fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed// call only if color_type is PALETTE. Returns true if the ctable has alpha 166fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reedstatic bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { 167fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_bytep trans; 168fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed int num_trans; 169fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 170fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 171fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 172fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return num_trans > 0; 173fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 174fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 17518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed} 17618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 17758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, 17858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp *png_ptrp, png_infop *info_ptrp) 17958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen{ 1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Create and initialize the png_struct with the desired error handler 1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * functions. If you want to use the default stderr and longjump method, 1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * you can supply NULL for the last three parameters. We also supply the 1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the compiler header file version, so that we know if the application 1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * was compiled with a compatible version of the library. */ 1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL, sk_error_fn, NULL); 1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (png_ptr == NULL) { 1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 19158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *png_ptrp = png_ptr; 1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Allocate/initialize the memory for image information. */ 1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr = png_create_info_struct(png_ptr); 1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (info_ptr == NULL) { 1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); 1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 19958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *info_ptrp = info_ptr; 2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling if you are using the setjmp/longjmp method (this is 2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the normal method of doing things with libpng). REQUIRED unless you 2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * set up your own error handlers in the png_create_read_struct() earlier. 2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If you are using replacement read functions, instead of calling 2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_init_io() here you would call: 2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 21358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_seek_fn(png_ptr, sk_seek_fn); 2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* where user_io_ptr is a structure you want available to the callbacks */ 2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If we have already read some of the signature */ 21658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // hookup our peeker so we can see any user-chunks the caller may be interested in 2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (this->getPeeker()) { 2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); 2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* The call to png_read_info() gives us all of the information from the 2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG file before the first IDAT (image data chunk). */ 2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_info(png_ptr, info_ptr); 2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_uint_32 origWidth, origHeight; 2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bit_depth, color_type, interlace_type; 22958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 23058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth == 16) { 2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_strip_16(png_ptr); 2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * byte into separate bytes (useful for paletted and grayscale images). */ 2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth < 8) { 2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_packing(png_ptr); 2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_1_2_4_to_8(png_ptr); 2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 24558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Make a grayscale image into RGB. */ 2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY || 2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_to_rgb(png_ptr); 2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 25158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 25258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 25358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 25458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 25558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen Mode mode) { 25658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 25758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 25858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 25958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { 26058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 26158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 26258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (setjmp(png_jmpbuf(png_ptr))) { 26458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 26558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 26658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen PNGAutoClean autoClean(png_ptr, info_ptr); 26858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 27058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 27158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 27258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 27358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config; 2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha = false; 2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool doDither = this->getDitherImage(); 2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor theTranspColor = 0; // 0 tells us not to try to match 27858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 27958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, 28058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &doDither, &theTranspColor) == false) { 28158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 28258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 28358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 28458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int sampleSize = this->getSampleSize(); 28558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 28658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2879717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->lockPixels(); 2889717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase void* rowptr = (void*) decodedBitmap->getPixels(); 2899717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase bool reuseBitmap = (rowptr != NULL); 2909717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->unlockPixels(); 2919717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() || 2929717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase sampler.scaledHeight() != decodedBitmap->height())) { 2939717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase // Dimensions must match 2949717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase return false; 2959717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 2969717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase 2979717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!reuseBitmap) { 2989717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->setConfig(config, sampler.scaledWidth(), 2999717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase sampler.scaledHeight(), 0); 3009717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 30158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (SkImageDecoder::kDecodeBounds_Mode == mode) { 30258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 30358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 30458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 30558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // from here down we are concerned with colortables and pixels 30658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 30758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 30858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 30958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // draw lots faster if we can flag the bitmap has being opaque 31058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool reallyHasAlpha = false; 31158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkColorTable* colorTable = NULL; 31258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 31358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (color_type == PNG_COLOR_TYPE_PALETTE) { 31458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodePalette(png_ptr, info_ptr, &hasAlpha, 31558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &reallyHasAlpha, &colorTable); 31658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 31758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 31858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoUnref aur(colorTable); 31958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 3209717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!reuseBitmap) { 3219717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!this->allocPixelRef(decodedBitmap, 3229717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase SkBitmap::kIndex8_Config == config ? 3239717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase colorTable : NULL)) { 3249717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase return false; 3259717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 32658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 32758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 32858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockPixels alp(*decodedBitmap); 32958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 33058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Add filler (or alpha) byte (before/after each RGB triplet) */ 33158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 33258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 33358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 33458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 33558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Turn on interlace handling. REQUIRED if you are not using 33658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * png_read_image(). To see how to handle interlacing passes, 33758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * see the png_read_row() method below: 33858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 33958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 34058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_interlace_handling(png_ptr) : 1; 34158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 34258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Optional call to gamma correct and add the background to the palette 34358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * and update info structure. REQUIRED if you are expecting libpng to 34458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * update the palette for you (ie you selected such a transform above). 34558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 34658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_update_info(png_ptr, info_ptr); 34758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 34858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 34958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < number_passes; i++) { 35058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (png_uint_32 y = 0; y < origHeight; y++) { 35158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 35258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 35358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 35458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 35558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 35658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkScaledBitmapSampler::SrcConfig sc; 35758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int srcBytesPerPixel = 4; 35858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 35958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (colorTable != NULL) { 36058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kIndex; 36158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen srcBytesPerPixel = 1; 36258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else if (hasAlpha) { 36358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kRGBA; 36458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 36558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kRGBX; 36658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 36758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 36858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* We have to pass the colortable explicitly, since we may have one 36958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen even if our decodedBitmap doesn't, due to the request that we 37058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen upscale png's palette to a direct model 37158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 37258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockColors ctLock(colorTable); 37358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 37458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 37558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 37658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int height = decodedBitmap->height(); 37758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 37858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (number_passes > 1) { 37958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 38058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* base = (uint8_t*)storage.get(); 38158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen size_t rb = origWidth * srcBytesPerPixel; 38258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 38358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < number_passes; i++) { 38458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* row = base; 38558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (png_uint_32 y = 0; y < origHeight; y++) { 38658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = row; 38758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 38858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen row += rb; 38958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 39058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 39158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // now sample it 39258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen base += sampler.srcY0() * rb; 39358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int y = 0; y < height; y++) { 39458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= sampler.next(base); 39558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen base += sampler.srcDY() * rb; 39658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 39758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 39858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoMalloc storage(origWidth * srcBytesPerPixel); 39958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* srcRow = (uint8_t*)storage.get(); 40058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 40158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 40258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int y = 0; y < height; y++) { 40358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* tmp = srcRow; 40458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 40558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= sampler.next(srcRow); 40658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (y < height - 1) { 40758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 40858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 40958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 41058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 41158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // skip the rest of the rows (if any) 41258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 read = (height - 1) * sampler.srcDY() + 41358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sampler.srcY0() + 1; 41458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkASSERT(read <= origHeight); 41558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, origHeight - read); 41658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 41758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 41858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 41958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 42058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_end(png_ptr, info_ptr); 42158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 42258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (0 != theTranspColor) { 42358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 42458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 42558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodedBitmap->setIsOpaque(!reallyHasAlpha); 4269717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (reuseBitmap) { 4279717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->notifyPixelsChanged(); 4289717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 42958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 43058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 43158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43214496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chenbool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, 43314496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen int *height) { 43458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 43558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 43658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index = new SkPNGImageIndex(); 43858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { 44058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 44158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 44258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4432dad62296f6b4c462b329c48b3bcc31cfdc56accRuben Brunk if (setjmp(png_jmpbuf(png_ptr)) != 0) { 4442dad62296f6b4c462b329c48b3bcc31cfdc56accRuben Brunk png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 4452dad62296f6b4c462b329c48b3bcc31cfdc56accRuben Brunk return false; 4462dad62296f6b4c462b329c48b3bcc31cfdc56accRuben Brunk } 4472dad62296f6b4c462b329c48b3bcc31cfdc56accRuben Brunk 44858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 44958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 45058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 45158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 45258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 45358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *width = origWidth; 45458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *height = origHeight; 45558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 45658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_build_index(png_ptr); 45758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index->png_ptr = png_ptr; 45858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index->info_ptr = info_ptr; 45958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 46058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 46158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 46258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 46358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config *configp, bool *hasAlphap, bool *doDitherp, 46458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor *theTranspColorp) { 46558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 46658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 46758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 46858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 46958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check for sBIT chunk data, in case we should disable dithering because 4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // our data is not truely 8bits per component 47258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*doDitherp) { 4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, 4750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.green, info_ptr->sig_bit.blue, 4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.alpha); 4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // 0 seems to indicate no information available 4790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && 4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && 4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { 48258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *doDitherp = false; 4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 48558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 487fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 48858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 4890a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now see if we can upscale to their requested config 49058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) { 49158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kIndex8_Config; 492421adab1be5bb9c1cd419138ceda375aef649077Mike Reed } 4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_16p transpColor = NULL; 4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int numTransp = 0; 49658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 49858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 50058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid && numTransp == 1 && transpColor != NULL) { 5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Compute our transparent color, which we'll match against later. 5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project We don't really handle 16bit components properly here, since we 5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project do our compare *after* the values have been knocked down to 8bit 5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project which means we will find more matches than we should. The real 5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project fix seems to be to see the actual 16bit components, do the 5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project compare, and then knock it down to 8bits ourselves. 5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type & PNG_COLOR_MASK_COLOR) { 5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 51158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8, 5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green >> 8, transpColor->blue >> 8); 5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 51458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->red, 5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green, transpColor->blue); 5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { // gray 5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 51958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8, 5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray >> 8, transpColor->gray >> 8); 5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 52258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray, 5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray, transpColor->gray); 5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid || 5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_RGB_ALPHA == color_type || 5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { 53158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *hasAlphap = true; 5320a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } 53358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap); 5340a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now match the request against our capabilities 53558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*hasAlphap) { 53658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*configp != SkBitmap::kARGB_4444_Config) { 53758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kARGB_8888_Config; 5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5390a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } else { 54058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*configp != SkBitmap::kRGB_565_Config && 54158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp != SkBitmap::kARGB_4444_Config) { 54258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kARGB_8888_Config; 5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 54618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 54718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // sanity check for size 54818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed { 54918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed Sk64 size; 55018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size.setMul(origWidth, origHeight); 55118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.isNeg() || !size.is32()) { 55218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 55318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 55418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now check that if we are 4-bytes per pixel, we also don't overflow 55518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.get32() > (0x7FFFFFFF >> 2)) { 55618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 55718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 55818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 55918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 56058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) { 5610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 5620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 56358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 56458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 56558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 56658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, 56758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep) { 56858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int num_palette; 56958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_colorp palette; 57058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_bytep trans; 57158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int num_trans; 57258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool reallyHasAlpha = false; 57358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkColorTable* colorTable = NULL; 57458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); 57658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* BUGGY IMAGE WORKAROUND 57858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count 58058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen which is a problem since we use the byte as an index. To work around this we grow 58158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen the colortable by 1 (if its < 256) and duplicate the last color into that slot. 58258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 58358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int colorCount = num_palette + (num_palette < 256); 58458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 58558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); 58658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 58758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor* colorPtr = colorTable->lockColors(); 58858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 58958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 59058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *hasAlphap = (num_trans > 0); 59158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 59258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen num_trans = 0; 59358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); 59458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 59558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // check for bad images that might make us crash 59658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (num_trans > num_palette) { 59758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen num_trans = num_palette; 59858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 59958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 60058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int index = 0; 60158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int transLessThanFF = 0; 60258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 60358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (; index < num_trans; index++) { 60458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen transLessThanFF |= (int)*trans - 0xFF; 60558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); 60658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen palette++; 60758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 60858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= (transLessThanFF < 0); 60958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 61058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (; index < num_palette; index++) { 61158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); 61258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen palette++; 61358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 61458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 61558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // see BUGGY IMAGE WORKAROUND comment above 61658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (num_palette < 256) { 61758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr = colorPtr[-1]; 61858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 61958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable->unlockColors(true); 62058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorTablep = colorTable; 62158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *reallyHasAlphap = reallyHasAlpha; 62258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 62358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 62458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 625943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Linbool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) { 62658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int i; 62758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr = this->index->png_ptr; 62858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr = this->index->info_ptr; 62958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (setjmp(png_jmpbuf(png_ptr))) { 63058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 63158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 63258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 63358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 63458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 63558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 63658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 63758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 638943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin SkIRect rect = SkIRect::MakeWH(origWidth, origHeight); 639943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin 640943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (!rect.intersect(region)) { 641943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin // If the requested region is entirely outsides the image, just 642943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin // returns false 643943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin return false; 644943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } 645943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin 64658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config config; 64758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool hasAlpha = false; 64858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool doDither = this->getDitherImage(); 64958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor theTranspColor = 0; // 0 tells us not to try to match 65058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 65158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, 65258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &doDither, &theTranspColor) == false) { 65358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 65458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 65558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int sampleSize = this->getSampleSize(); 657943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); 65858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 65958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap *decodedBitmap = new SkBitmap; 66058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoTDelete<SkBitmap> adb(decodedBitmap); 6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setConfig(config, sampler.scaledWidth(), 6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sampler.scaledHeight(), 0); 66458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // from here down we are concerned with colortables and pixels 6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 6680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 6690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // draw lots faster if we can flag the bitmap has being opaque 6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 6710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* colorTable = NULL; 6720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 67458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodePalette(png_ptr, info_ptr, &hasAlpha, 67558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &reallyHasAlpha, &colorTable); 6760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 67758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoUnref aur(colorTable); 6790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 680c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // Check ahead of time if the swap(dest, src) is possible in crop or not. 681c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening. 682c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // If no, then we will use alloc to allocate pixels to prevent garbage collection. 683943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin int w = rect.width() / sampleSize; 684943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin int h = rect.height() / sampleSize; 685943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin bool swapOnly = (rect == region) && (w == decodedBitmap->width()) && 686943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin (h == decodedBitmap->height()) && 687943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin ((0 - rect.x()) / sampleSize == 0) && bm->isNull(); 688943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (swapOnly) { 689c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin if (!this->allocPixelRef(decodedBitmap, 690c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { 691c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin return false; 692c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin } 693943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } else { 694c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin if (!decodedBitmap->allocPixels( 695c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin NULL, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { 696c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin return false; 697c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin } 6980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 69958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockPixels alp(*decodedBitmap); 7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Add filler (or alpha) byte (before/after each RGB triplet) */ 7020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 7030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 7040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Turn on interlace handling. REQUIRED if you are not using 7070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_read_image(). To see how to handle interlacing passes, 7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * see the png_read_row() method below: 7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 71058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 7110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_interlace_handling(png_ptr) : 1; 7120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Optional call to gamma correct and add the background to the palette 7140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * and update info structure. REQUIRED if you are expecting libpng to 7150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * update the palette for you (ie you selected such a transform above). 7160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 71758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_ptr->pass = 0; 7180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_update_info(png_ptr, info_ptr); 7190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 72058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int actualTop = rect.fTop; 72158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 7220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 7230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < number_passes; i++) { 72458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, i); 72558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int j = 0; j < rect.fTop - actualTop; j++) { 72658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, 0); 72758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 72858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (png_uint_32 y = 0; y < origHeight; y++) { 7300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 7310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 7320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 7350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkScaledBitmapSampler::SrcConfig sc; 7360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int srcBytesPerPixel = 4; 73758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 73818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (colorTable != NULL) { 7390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kIndex; 7400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcBytesPerPixel = 1; 7410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else if (hasAlpha) { 7420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBA; 7430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 7440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBX; 7450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 74718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed /* We have to pass the colortable explicitly, since we may have one 74818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed even if our decodedBitmap doesn't, due to the request that we 74918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed upscale png's palette to a direct model 75018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed */ 75118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoLockColors ctLock(colorTable); 75218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 75318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 75418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 7550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int height = decodedBitmap->height(); 7560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 75718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (number_passes > 1) { 75818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 75918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* base = (uint8_t*)storage.get(); 76018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size_t rb = origWidth * srcBytesPerPixel; 76118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 76218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int i = 0; i < number_passes; i++) { 76358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, i); 76458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int j = 0; j < rect.fTop - actualTop; j++) { 7656699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru uint8_t* bmRow = (uint8_t*)decodedBitmap->getPixels(); 76658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 76758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 76818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* row = base; 769943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin for (png_uint_32 y = 0; y < rect.height(); y++) { 77018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* bmRow = row; 77118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 77218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed row += rb; 77318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 7740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 77518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now sample it 77618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcY0() * rb; 77718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int y = 0; y < height; y++) { 77818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed reallyHasAlpha |= sampler.next(base); 77918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcDY() * rb; 78018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 78118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } else { 78218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * srcBytesPerPixel); 7830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* srcRow = (uint8_t*)storage.get(); 78458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 78558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, 0); 7860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 7870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 78858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < rect.fTop - actualTop; i++) { 7896699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru uint8_t* bmRow = (uint8_t*)decodedBitmap->getPixels(); 79058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 79158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 7920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < height; y++) { 7930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = srcRow; 7940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 7950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= sampler.next(srcRow); 7960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (y < height - 1) { 7970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 7980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 802943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (swapOnly) { 803943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin bm->swap(*decodedBitmap); 804943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } else { 805943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin cropBitmap(bm, decodedBitmap, sampleSize, region.x(), region.y(), 806943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin region.width(), region.height(), 0, rect.y()); 807943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } 8080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != theTranspColor) { 8100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 8110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setIsOpaque(!reallyHasAlpha); 8130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 8140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 8170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h" 8190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUnPreMultiply.h" 8200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 8220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr; 8230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!sk_stream->write(data, len)) { 8240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "sk_write_fn Error!"); 8250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic transform_scanline_proc choose_proc(SkBitmap::Config config, 8290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha) { 8300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we don't care about search on alpha if we're kIndex8, since only the 8310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // colortable packing cares about that distinction, not the pixels 8320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config) { 8330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project hasAlpha = false; // we store false in the table entries for kIndex8 8340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project static const struct { 8370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config fConfig; 8380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool fHasAlpha; 8390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc fProc; 8400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } gMap[] = { 8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, 8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, 8430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, 8440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, 8450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, 846363e546ed626b6dbbc42f5db87b3594bc0b5944bDerek Sollenberger { SkBitmap::kIndex8_Config, false, transform_scanline_memcpy }, 8470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project }; 8480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { 8500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { 8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return gMap[i].fProc; 8520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sk_throw(); 8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 8560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return the minimum legal bitdepth (by png standards) for this many colortable 8590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, 8600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// we can use fewer bits per in png 8610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int computeBitDepth(int colorCount) { 8620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 8630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bits = SkNextLog2(colorCount); 8640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bits >= 1 && bits <= 8); 8650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) 8660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNextPow2(bits); 8670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else 8680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // for the moment, we don't know how to pack bitdepth < 8 8690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return 8; 8700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 8710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also 8740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pack trans[] and return the number of trans[] entries written. If hasAlpha 8750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project is false, the return value will always be 0. 8760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project Note: this routine takes care of unpremultiplying the RGB values when we 8780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project have alpha in the colortable, since png doesn't support premul colors 8790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/ 8800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline int pack_palette(SkColorTable* ctable, 8810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color* SK_RESTRICT palette, 8820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_byte* SK_RESTRICT trans, bool hasAlpha) { 8830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockColors alc(ctable); 8840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT colors = alc.colors(); 8850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int ctCount = ctable->count(); 8860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int i, num_trans = 0; 8870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 8890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* first see if we have some number of fully opaque at the end of the 8900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ctable. PNG allows num_trans < num_palette, but all of the trans 8910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project entries must come first in the palette. If I was smarter, I'd 8920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reorder the indices and ctable so that all non-opaque colors came 8930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project first in the palette. But, since that would slow down the encode, 8940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project I'm leaving the indices and ctable order as is, and just looking 8950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project at the tail of the ctable for opaqueness. 8960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 8970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans = ctCount; 8980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = ctCount - 1; i >= 0; --i) { 8990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkGetPackedA32(colors[i]) != 0xFF) { 9000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 9010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans -= 1; 9030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 9060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 9070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = 0; i < num_trans; i++) { 9090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor c = *colors++; 9100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const unsigned a = SkGetPackedA32(c); 9110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale s = table[a]; 9120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project trans[i] = a; 9130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); 9140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); 9150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); 9160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now fall out of this if-block to use common code for the trailing 9180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // opaque entries 9190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // these (remaining) entries are opaque 9220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = num_trans; i < ctCount; i++) { 9230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *colors++; 9240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkGetPackedR32(c); 9250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkGetPackedG32(c); 9260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkGetPackedB32(c); 9270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return num_trans; 9290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 9300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageEncoder : public SkImageEncoder { 9320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 9330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 9341cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerprivate: 9351cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger bool doEncode(SkWStream* stream, const SkBitmap& bm, 9361cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger const bool& hasAlpha, int colorType, 9371cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger int bitDepth, SkBitmap::Config config, 9381cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger png_color_8& sig_bit); 9390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 9400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 9420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int /*quality*/) { 9430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config = bitmap.getConfig(); 9440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const bool hasAlpha = !bitmap.isOpaque(); 9460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int colorType = PNG_COLOR_MASK_COLOR; 9470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bitDepth = 8; // default for color 9480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_8 sig_bit; 9490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project switch (config) { 9510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kIndex8_Config: 9520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_PALETTE; 9530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // fall through to the ARGB_8888 case 9540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_8888_Config: 9550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 8; 9560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 8; 9570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 8; 9580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 8; 9590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 9600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_4444_Config: 9610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 4; 9620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 4; 9630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 4; 9640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 4; 9650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 9660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kRGB_565_Config: 9670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 5; 9680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 6; 9690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 5; 9700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 9710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 9720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project default: 9730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 9740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 9770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // don't specify alpha if we're a palette, even if our ctable has alpha 9780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!(colorType & PNG_COLOR_MASK_PALETTE)) { 9790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_ALPHA; 9800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 9820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 9830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockPixels alp(bitmap); 9860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // readyToDraw checks for pixels (and colortable if that is required) 9870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!bitmap.readyToDraw()) { 9880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 9890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we must do this after we have locked the pixels 9920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* ctable = bitmap.getColorTable(); 9930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL != ctable) { 9940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (ctable->count() == 0) { 9950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 9960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check if we can store in fewer than 8 bits 9980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth = computeBitDepth(ctable->count()); 9990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10011cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger return doEncode(stream, bitmap, hasAlpha, colorType, 10021cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger bitDepth, config, sig_bit); 10031cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger} 10041cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 10051cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, 10061cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger const bool& hasAlpha, int colorType, 10071cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger int bitDepth, SkBitmap::Config config, 10081cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger png_color_8& sig_bit) { 10091cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 10100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 10110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 10120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 10140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL); 10150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == png_ptr) { 10160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr = png_create_info_struct(png_ptr); 10200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == info_ptr) { 10210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, png_infopp_NULL); 10220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling. REQUIRED if you aren't supplying your own 10260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * error handling functions in the png_create_write_struct() call. 10270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 10280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 10290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 10300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); 10340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set the image information here. Width and height are up to 2^31, 10360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 10370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 10380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 10390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 10400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 10410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 10420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 10430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 10450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth, colorType, 10460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 10470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_FILTER_TYPE_BASE); 10480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 104918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // set our colortable/trans arrays if needed 105018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_color paletteColors[256]; 105118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_byte trans[256]; 105218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (SkBitmap::kIndex8_Config == config) { 105318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkColorTable* ct = bitmap.getColorTable(); 105418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); 105518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 105618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (numTrans > 0) { 105718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL); 105818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 105918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 10600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_sBIT(png_ptr, info_ptr, &sig_bit); 10620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_info(png_ptr, info_ptr); 10630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const char* srcImage = (const char*)bitmap.getPixels(); 10650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); 10660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* storage = (char*)rowStorage.get(); 10670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc proc = choose_proc(config, hasAlpha); 10680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < bitmap.height(); y++) { 10700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_bytep row_ptr = (png_bytep)storage; 10710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project proc(srcImage, bitmap.width(), storage); 10720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_rows(png_ptr, &row_ptr, 1); 10730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcImage += bitmap.rowBytes(); 10740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_end(png_ptr, info_ptr); 10770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* clean up after the write, and free any memory allocated */ 10790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 10800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 10810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 10820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 108480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruDEFINE_DECODER_CREATOR(PNGImageDecoder); 108580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste QueruDEFINE_ENCODER_CREATOR(PNGImageEncoder); 108680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/////////////////////////////////////////////////////////////////////////////// 10870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h" 10890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1090579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed#ifdef SK_ENABLE_LIBPNG 1091579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed SkImageDecoder* sk_libpng_dfactory(SkStream*); 1092579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type); 1093579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed#endif 1094579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed 1095579d35c405d37b1f8c9afdefaa37e836fb6b956fMike ReedSkImageDecoder* sk_libpng_dfactory(SkStream* stream) { 10960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char buf[PNG_BYTES_TO_CHECK]; 10970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && 10980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 10990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNEW(SkPNGImageDecoder); 11000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 11020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 11030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1104579d35c405d37b1f8c9afdefaa37e836fb6b956fMike ReedSkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 11050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 11060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 11070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1108579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reedstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory); 1109579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reedstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); 1110