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" 200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectextern "C" { 220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "png.h" 230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenclass SkPNGImageIndex { 2658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenpublic: 2758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageIndex() { 2858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen inputStream = NULL; 2958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_ptr = NULL; 3058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen virtual ~SkPNGImageIndex() { 3258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (png_ptr) { 3358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 3458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (inputStream) { 3658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen delete inputStream; 3758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 3958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 4058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 4158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkStream *inputStream; 4258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen}; 4358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageDecoder : public SkImageDecoder { 450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic: 4658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageDecoder() { 4758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen index = NULL; 4858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual Format getFormat() const { 500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return kPNG_Format; 510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen virtual ~SkPNGImageDecoder() { 5358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (index) { 5458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen delete index; 5558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 5658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 5758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 5914496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen virtual bool onBuildTileIndex(SkStream *stream, 6014496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen int *width, int *height); 61943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect region); 620a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 6358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenprivate: 6558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, 6658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop *info_ptrp); 6758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool decodePalette(png_structp png_ptr, png_infop info_ptr, 6858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep); 6958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 7058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config *config, bool *hasAlpha, bool *doDither, 7158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor *theTranspColor); 7258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPNGImageIndex *index; 730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifndef png_jmpbuf 760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PNG_BYTES_TO_CHECK 4 800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Automatically clean up after throwing an exception */ 820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstruct PNGAutoClean { 830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ~PNGAutoClean() { 850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate: 880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project size_t bytes = sk_stream->read(data, length); 950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bytes != length) { 960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "Read Error!"); 970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenstatic void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) { 10158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 10258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sk_stream->rewind(); 10358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen (void)sk_stream->skip(offset); 10458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 10558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkImageDecoder::Peeker* peeker = 1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // peek() returning true means continue decoding 1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1 : -1; 1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("------ png error %s\n", msg); 1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project longjmp(png_jmpbuf(png_ptr), 1); 1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < count; i++) { 1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = storage; 1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool pos_le(int value, int max) { 1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return value > 0 && value <= max; 1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = bm->height() - 1; y >= 0; --y) { 1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor* p = bm->getAddr32(0, y); 1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int x = bm->width() - 1; x >= 0; --x) { 1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (match == *p) { 1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *p = 0; 1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha = true; 1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project p += 1; 1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return reallyHasAlpha; 1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1500a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedstatic bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig, 151fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool srcHasAlpha) { 1520a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed switch (dstConfig) { 153fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_8888_Config: 154fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_4444_Config: 155fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return true; 156fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kRGB_565_Config: 157fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed // only return true if the src is opaque (since 565 is opaque) 158fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return !srcHasAlpha; 159fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed default: 160fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 161fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 162fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed} 163fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 164fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed// call only if color_type is PALETTE. Returns true if the ctable has alpha 165fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reedstatic bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { 166fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_bytep trans; 167fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed int num_trans; 168fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 169fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 170fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 171fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return num_trans > 0; 172fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 173fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 17418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed} 17518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 17658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, 17758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp *png_ptrp, png_infop *info_ptrp) 17858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen{ 1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Create and initialize the png_struct with the desired error handler 1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * functions. If you want to use the default stderr and longjump method, 1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * you can supply NULL for the last three parameters. We also supply the 1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the compiler header file version, so that we know if the application 1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * was compiled with a compatible version of the library. */ 1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL, sk_error_fn, NULL); 1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (png_ptr == NULL) { 1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 19058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *png_ptrp = png_ptr; 1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Allocate/initialize the memory for image information. */ 1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr = png_create_info_struct(png_ptr); 1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (info_ptr == NULL) { 1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); 1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 19858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *info_ptrp = info_ptr; 1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling if you are using the setjmp/longjmp method (this is 2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the normal method of doing things with libpng). REQUIRED unless you 2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * set up your own error handlers in the png_create_read_struct() earlier. 2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If you are using replacement read functions, instead of calling 2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_init_io() here you would call: 2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 21258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_seek_fn(png_ptr, sk_seek_fn); 2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* where user_io_ptr is a structure you want available to the callbacks */ 2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If we have already read some of the signature */ 21558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // hookup our peeker so we can see any user-chunks the caller may be interested in 2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (this->getPeeker()) { 2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); 2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* The call to png_read_info() gives us all of the information from the 2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG file before the first IDAT (image data chunk). */ 2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_info(png_ptr, info_ptr); 2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_uint_32 origWidth, origHeight; 2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bit_depth, color_type, interlace_type; 22858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 22958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth == 16) { 2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_strip_16(png_ptr); 2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * byte into separate bytes (useful for paletted and grayscale images). */ 2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth < 8) { 2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_packing(png_ptr); 2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_1_2_4_to_8(png_ptr); 2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 24458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Make a grayscale image into RGB. */ 2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY || 2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_to_rgb(png_ptr); 2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 25058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 25158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 25258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 25358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 25458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen Mode mode) { 25558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 25658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 25758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 25858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { 25958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 26058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 26158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (setjmp(png_jmpbuf(png_ptr))) { 26358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 26458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 26558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen PNGAutoClean autoClean(png_ptr, info_ptr); 26758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 26858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 26958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 27058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 27158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 27258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config; 2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha = false; 2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool doDither = this->getDitherImage(); 2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor theTranspColor = 0; // 0 tells us not to try to match 27758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 27858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, 27958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &doDither, &theTranspColor) == false) { 28058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 28158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 28258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 28358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int sampleSize = this->getSampleSize(); 28458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 28558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 2869717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->lockPixels(); 2879717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase void* rowptr = (void*) decodedBitmap->getPixels(); 2889717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase bool reuseBitmap = (rowptr != NULL); 2899717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->unlockPixels(); 2909717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() || 2919717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase sampler.scaledHeight() != decodedBitmap->height())) { 2929717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase // Dimensions must match 2939717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase return false; 2949717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 2959717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase 2969717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!reuseBitmap) { 2979717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->setConfig(config, sampler.scaledWidth(), 2989717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase sampler.scaledHeight(), 0); 2999717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 30058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (SkImageDecoder::kDecodeBounds_Mode == mode) { 30158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 30258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 30358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 30458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // from here down we are concerned with colortables and pixels 30558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 30658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 30758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 30858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // draw lots faster if we can flag the bitmap has being opaque 30958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool reallyHasAlpha = false; 31058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkColorTable* colorTable = NULL; 31158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 31258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (color_type == PNG_COLOR_TYPE_PALETTE) { 31358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodePalette(png_ptr, info_ptr, &hasAlpha, 31458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &reallyHasAlpha, &colorTable); 31558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 31658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 31758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoUnref aur(colorTable); 31858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 3199717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!reuseBitmap) { 3209717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (!this->allocPixelRef(decodedBitmap, 3219717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase SkBitmap::kIndex8_Config == config ? 3229717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase colorTable : NULL)) { 3239717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase return false; 3249717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 32558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 32658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 32758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockPixels alp(*decodedBitmap); 32858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 32958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Add filler (or alpha) byte (before/after each RGB triplet) */ 33058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 33158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 33258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 33358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 33458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Turn on interlace handling. REQUIRED if you are not using 33558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * png_read_image(). To see how to handle interlacing passes, 33658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * see the png_read_row() method below: 33758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 33858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 33958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_set_interlace_handling(png_ptr) : 1; 34058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 34158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* Optional call to gamma correct and add the background to the palette 34258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * and update info structure. REQUIRED if you are expecting libpng to 34358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen * update the palette for you (ie you selected such a transform above). 34458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 34558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_update_info(png_ptr, info_ptr); 34658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 34758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 34858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < number_passes; i++) { 34958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (png_uint_32 y = 0; y < origHeight; y++) { 35058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 35158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 35258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 35358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 35458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 35558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkScaledBitmapSampler::SrcConfig sc; 35658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int srcBytesPerPixel = 4; 35758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 35858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (colorTable != NULL) { 35958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kIndex; 36058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen srcBytesPerPixel = 1; 36158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else if (hasAlpha) { 36258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kRGBA; 36358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 36458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sc = SkScaledBitmapSampler::kRGBX; 36558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 36658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 36758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* We have to pass the colortable explicitly, since we may have one 36858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen even if our decodedBitmap doesn't, due to the request that we 36958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen upscale png's palette to a direct model 37058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 37158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockColors ctLock(colorTable); 37258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 37358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 37458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 37558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int height = decodedBitmap->height(); 37658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 37758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (number_passes > 1) { 37858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 37958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* base = (uint8_t*)storage.get(); 38058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen size_t rb = origWidth * srcBytesPerPixel; 38158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 38258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < number_passes; i++) { 38358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* row = base; 38458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (png_uint_32 y = 0; y < origHeight; y++) { 38558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = row; 38658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 38758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen row += rb; 38858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 38958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 39058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // now sample it 39158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen base += sampler.srcY0() * rb; 39258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int y = 0; y < height; y++) { 39358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= sampler.next(base); 39458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen base += sampler.srcDY() * rb; 39558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 39658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 39758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoMalloc storage(origWidth * srcBytesPerPixel); 39858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* srcRow = (uint8_t*)storage.get(); 39958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 40058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 40158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int y = 0; y < height; y++) { 40258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* tmp = srcRow; 40358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 40458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= sampler.next(srcRow); 40558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (y < height - 1) { 40658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 40758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 40858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 40958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 41058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // skip the rest of the rows (if any) 41158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 read = (height - 1) * sampler.srcDY() + 41258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen sampler.srcY0() + 1; 41358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkASSERT(read <= origHeight); 41458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen skip_src_rows(png_ptr, srcRow, origHeight - read); 41558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 41658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 41758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 41858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 41958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_end(png_ptr, info_ptr); 42058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 42158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (0 != theTranspColor) { 42258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 42358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 42458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodedBitmap->setIsOpaque(!reallyHasAlpha); 4259717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase if (reuseBitmap) { 4269717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase decodedBitmap->notifyPixelsChanged(); 4279717bd93d86e12d2b9a506179493dd50613e99b2Chet Haase } 42858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 42958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 43058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43114496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chenbool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, 43214496db08e9c54a5012933b8c25a58348627d646Wei-Ta Chen int *height) { 43358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr; 43458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr; 43558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index = new SkPNGImageIndex(); 43758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 43858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (onDecodeInit(sk_stream, &png_ptr, &info_ptr) == false) { 43958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 44058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 44158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 44258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 44358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 44458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 44558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 44658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 44758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *width = origWidth; 44858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *height = origHeight; 44958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 45058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_build_index(png_ptr); 45158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index->png_ptr = png_ptr; 45258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen this->index->info_ptr = info_ptr; 45358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 45458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 45558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 45658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 45758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config *configp, bool *hasAlphap, bool *doDitherp, 45858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor *theTranspColorp) { 45958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 46058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 46158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 46258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 46358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check for sBIT chunk data, in case we should disable dithering because 4650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // our data is not truely 8bits per component 46658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*doDitherp) { 4670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 4680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, 4690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.green, info_ptr->sig_bit.blue, 4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.alpha); 4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // 0 seems to indicate no information available 4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && 4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && 4750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { 47658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *doDitherp = false; 4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 47958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 481fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 48258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 4830a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now see if we can upscale to their requested config 48458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) { 48558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kIndex8_Config; 486421adab1be5bb9c1cd419138ceda375aef649077Mike Reed } 4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_16p transpColor = NULL; 4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int numTransp = 0; 49058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 49258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 49458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid && numTransp == 1 && transpColor != NULL) { 4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Compute our transparent color, which we'll match against later. 4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project We don't really handle 16bit components properly here, since we 4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project do our compare *after* the values have been knocked down to 8bit 4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project which means we will find more matches than we should. The real 5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project fix seems to be to see the actual 16bit components, do the 5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project compare, and then knock it down to 8bits ourselves. 5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type & PNG_COLOR_MASK_COLOR) { 5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 50558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8, 5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green >> 8, transpColor->blue >> 8); 5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 50858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->red, 5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green, transpColor->blue); 5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { // gray 5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 51358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8, 5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray >> 8, transpColor->gray >> 8); 5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 51658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray, 5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray, transpColor->gray); 5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid || 5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_RGB_ALPHA == color_type || 5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { 52558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *hasAlphap = true; 5260a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } 52758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap); 5280a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now match the request against our capabilities 52958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*hasAlphap) { 53058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*configp != SkBitmap::kARGB_4444_Config) { 53158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kARGB_8888_Config; 5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5330a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } else { 53458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (*configp != SkBitmap::kRGB_565_Config && 53558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp != SkBitmap::kARGB_4444_Config) { 53658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *configp = SkBitmap::kARGB_8888_Config; 5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 54018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 54118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // sanity check for size 54218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed { 54318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed Sk64 size; 54418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size.setMul(origWidth, origHeight); 54518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.isNeg() || !size.is32()) { 54618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 54718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 54818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now check that if we are 4-bytes per pixel, we also don't overflow 54918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.get32() > (0x7FFFFFFF >> 2)) { 55018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 55118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 55218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 55318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 55458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) { 5550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 5560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 55758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 55858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 55958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 56058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wenbool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, 56158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool *hasAlphap, bool *reallyHasAlphap, SkColorTable **colorTablep) { 56258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int num_palette; 56358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_colorp palette; 56458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_bytep trans; 56558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int num_trans; 56658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool reallyHasAlpha = false; 56758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkColorTable* colorTable = NULL; 56858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 56958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); 57058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen /* BUGGY IMAGE WORKAROUND 57258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count 57458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen which is a problem since we use the byte as an index. To work around this we grow 57558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen the colortable by 1 (if its < 256) and duplicate the last color into that slot. 57658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen */ 57758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int colorCount = num_palette + (num_palette < 256); 57858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 57958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); 58058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 58158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor* colorPtr = colorTable->lockColors(); 58258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 58358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 58458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *hasAlphap = (num_trans > 0); 58558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } else { 58658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen num_trans = 0; 58758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); 58858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 58958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // check for bad images that might make us crash 59058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (num_trans > num_palette) { 59158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen num_trans = num_palette; 59258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 59358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 59458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int index = 0; 59558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int transLessThanFF = 0; 59658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 59758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (; index < num_trans; index++) { 59858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen transLessThanFF |= (int)*trans - 0xFF; 59958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); 60058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen palette++; 60158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 60258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen reallyHasAlpha |= (transLessThanFF < 0); 60358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 60458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (; index < num_palette; index++) { 60558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); 60658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen palette++; 60758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 60858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 60958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen // see BUGGY IMAGE WORKAROUND comment above 61058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (num_palette < 256) { 61158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorPtr = colorPtr[-1]; 61258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 61358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen colorTable->unlockColors(true); 61458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *colorTablep = colorTable; 61558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen *reallyHasAlphap = reallyHasAlpha; 61658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return true; 61758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen} 61858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 619943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Linbool SkPNGImageDecoder::onDecodeRegion(SkBitmap* bm, SkIRect region) { 62058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int i; 62158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_structp png_ptr = this->index->png_ptr; 62258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_infop info_ptr = this->index->info_ptr; 62358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (setjmp(png_jmpbuf(png_ptr))) { 62458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 62558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 62658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 62758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_uint_32 origWidth, origHeight; 62858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int bit_depth, color_type, interlace_type; 62958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, 63058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &color_type, &interlace_type, int_p_NULL, int_p_NULL); 63158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 632943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin SkIRect rect = SkIRect::MakeWH(origWidth, origHeight); 633943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin 634943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (!rect.intersect(region)) { 635943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin // If the requested region is entirely outsides the image, just 636943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin // returns false 637943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin return false; 638943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } 639943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin 64058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap::Config config; 64158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool hasAlpha = false; 64258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen bool doDither = this->getDitherImage(); 64358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkPMColor theTranspColor = 0; // 0 tells us not to try to match 64458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 64558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen if (getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, 64658971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &doDither, &theTranspColor) == false) { 64758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen return false; 64858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 64958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int sampleSize = this->getSampleSize(); 651943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); 65258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 65358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkBitmap *decodedBitmap = new SkBitmap; 65458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoTDelete<SkBitmap> adb(decodedBitmap); 6550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setConfig(config, sampler.scaledWidth(), 6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sampler.scaledHeight(), 0); 65858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // from here down we are concerned with colortables and pixels 6600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // draw lots faster if we can flag the bitmap has being opaque 6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* colorTable = NULL; 6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 66858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen decodePalette(png_ptr, info_ptr, &hasAlpha, 66958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen &reallyHasAlpha, &colorTable); 6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 67158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 6720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoUnref aur(colorTable); 6730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 674c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // Check ahead of time if the swap(dest, src) is possible in crop or not. 675c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening. 676c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin // If no, then we will use alloc to allocate pixels to prevent garbage collection. 677943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin int w = rect.width() / sampleSize; 678943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin int h = rect.height() / sampleSize; 679943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin bool swapOnly = (rect == region) && (w == decodedBitmap->width()) && 680943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin (h == decodedBitmap->height()) && 681943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin ((0 - rect.x()) / sampleSize == 0) && bm->isNull(); 682943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (swapOnly) { 683c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin if (!this->allocPixelRef(decodedBitmap, 684c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { 685c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin return false; 686c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin } 687943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } else { 688c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin if (!decodedBitmap->allocPixels( 689c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin NULL, SkBitmap::kIndex8_Config == config ? colorTable : NULL)) { 690c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin return false; 691c85ca84d9f8bd5fe91b4315481858d01757ee500Owen Lin } 6920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 69358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen SkAutoLockPixels alp(*decodedBitmap); 6940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Add filler (or alpha) byte (before/after each RGB triplet) */ 6960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 6970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 6980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Turn on interlace handling. REQUIRED if you are not using 7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_read_image(). To see how to handle interlacing passes, 7020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * see the png_read_row() method below: 7030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 70458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 7050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_interlace_handling(png_ptr) : 1; 7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Optional call to gamma correct and add the background to the palette 7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * and update info structure. REQUIRED if you are expecting libpng to 7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * update the palette for you (ie you selected such a transform above). 7100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 71158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_ptr->pass = 0; 7120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_update_info(png_ptr, info_ptr); 7130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 71458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen int actualTop = rect.fTop; 71558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 7160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 7170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < number_passes; i++) { 71858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, i); 71958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int j = 0; j < rect.fTop - actualTop; j++) { 72058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, 0); 72158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 72258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 7230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (png_uint_32 y = 0; y < origHeight; y++) { 7240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 7250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 7260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkScaledBitmapSampler::SrcConfig sc; 7300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int srcBytesPerPixel = 4; 73158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 73218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (colorTable != NULL) { 7330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kIndex; 7340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcBytesPerPixel = 1; 7350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else if (hasAlpha) { 7360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBA; 7370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 7380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBX; 7390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 74118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed /* We have to pass the colortable explicitly, since we may have one 74218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed even if our decodedBitmap doesn't, due to the request that we 74318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed upscale png's palette to a direct model 74418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed */ 74518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoLockColors ctLock(colorTable); 74618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 74718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 74818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 7490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int height = decodedBitmap->height(); 7500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 75118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (number_passes > 1) { 75218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 75318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* base = (uint8_t*)storage.get(); 75418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size_t rb = origWidth * srcBytesPerPixel; 75518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 75618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int i = 0; i < number_passes; i++) { 75758971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, i); 75858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int j = 0; j < rect.fTop - actualTop; j++) { 75958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, 0); 76058971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 76158971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 76218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* row = base; 763943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin for (png_uint_32 y = 0; y < rect.height(); y++) { 76418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* bmRow = row; 76518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 76618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed row += rb; 76718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 7680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 76918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now sample it 77018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcY0() * rb; 77118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int y = 0; y < height; y++) { 77218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed reallyHasAlpha |= sampler.next(base); 77318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcDY() * rb; 77418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 77518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } else { 77618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * srcBytesPerPixel); 7770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* srcRow = (uint8_t*)storage.get(); 77858971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen 77958971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_configure_decoder(png_ptr, &actualTop, 0); 7800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 7810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 78258971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen for (int i = 0; i < rect.fTop - actualTop; i++) { 78358971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen uint8_t* bmRow = decodedBitmap->getAddr8(0, 0); 78458971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 78558971879258a502a7568fbad0e6852e78c3eca3cJoseph Wen } 7860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < height; y++) { 7870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = srcRow; 7880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 7890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= sampler.next(srcRow); 7900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (y < height - 1) { 7910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 7920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 796943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin if (swapOnly) { 797943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin bm->swap(*decodedBitmap); 798943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } else { 799943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin cropBitmap(bm, decodedBitmap, sampleSize, region.x(), region.y(), 800943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin region.width(), region.height(), 0, rect.y()); 801943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin } 8020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != theTranspColor) { 8040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 8050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setIsOpaque(!reallyHasAlpha); 8070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 8080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 8110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h" 8130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUnPreMultiply.h" 8140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 8160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr; 8170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!sk_stream->write(data, len)) { 8180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "sk_write_fn Error!"); 8190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projecttypedef void (*transform_scanline_proc)(const char* SK_RESTRICT src, 8230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int width, char* SK_RESTRICT dst); 8240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_565(const char* SK_RESTRICT src, int width, 8260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 8270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src; 8280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 8290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned c = *srcP++; 8300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToR32(c); 8310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToG32(c); 8320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToB32(c); 8330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_888(const char* SK_RESTRICT src, int width, 8370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 8380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 8390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 8400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *srcP++; 8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedR32(c); 8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedG32(c); 8430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedB32(c); 8440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_444(const char* SK_RESTRICT src, int width, 8480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 8490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 8500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor16 c = *srcP++; 8520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToR32(c); 8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToG32(c); 8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToB32(c); 8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_8888(const char* SK_RESTRICT src, int width, 8590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 8600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 8610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 8620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 8630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 8650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *srcP++; 8660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned a = SkGetPackedA32(c); 8670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned r = SkGetPackedR32(c); 8680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned g = SkGetPackedG32(c); 8690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned b = SkGetPackedB32(c); 8700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != a && 255 != a) { 8720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::Scale scale = table[a]; 8730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project r = SkUnPreMultiply::ApplyScale(scale, r); 8740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project g = SkUnPreMultiply::ApplyScale(scale, g); 8750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project b = SkUnPreMultiply::ApplyScale(scale, b); 8760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = r; 8780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = g; 8790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = b; 8800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = a; 8810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_4444(const char* SK_RESTRICT src, int width, 8850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 8860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 8870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 8880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 8890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 8910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor16 c = *srcP++; 8920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned a = SkPacked4444ToA32(c); 8930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned r = SkPacked4444ToR32(c); 8940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned g = SkPacked4444ToG32(c); 8950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned b = SkPacked4444ToB32(c); 8960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != a && 255 != a) { 8980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::Scale scale = table[a]; 8990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project r = SkUnPreMultiply::ApplyScale(scale, r); 9000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project g = SkUnPreMultiply::ApplyScale(scale, g); 9010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project b = SkUnPreMultiply::ApplyScale(scale, b); 9020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = r; 9040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = g; 9050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = b; 9060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = a; 9070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 9090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_index8(const char* SK_RESTRICT src, int width, 9110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 9120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project memcpy(dst, src, width); 9130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 9140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic transform_scanline_proc choose_proc(SkBitmap::Config config, 9160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha) { 9170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we don't care about search on alpha if we're kIndex8, since only the 9180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // colortable packing cares about that distinction, not the pixels 9190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config) { 9200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project hasAlpha = false; // we store false in the table entries for kIndex8 9210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project static const struct { 9240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config fConfig; 9250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool fHasAlpha; 9260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc fProc; 9270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } gMap[] = { 9280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, 9290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, 9300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, 9310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, 9320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, 9330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kIndex8_Config, false, transform_scanline_index8 }, 9340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project }; 9350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { 9370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { 9380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return gMap[i].fProc; 9390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sk_throw(); 9420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 9430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 9440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return the minimum legal bitdepth (by png standards) for this many colortable 9460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, 9470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// we can use fewer bits per in png 9480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int computeBitDepth(int colorCount) { 9490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 9500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bits = SkNextLog2(colorCount); 9510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bits >= 1 && bits <= 8); 9520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) 9530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNextPow2(bits); 9540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else 9550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // for the moment, we don't know how to pack bitdepth < 8 9560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return 8; 9570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 9580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 9590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also 9610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pack trans[] and return the number of trans[] entries written. If hasAlpha 9620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project is false, the return value will always be 0. 9630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project Note: this routine takes care of unpremultiplying the RGB values when we 9650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project have alpha in the colortable, since png doesn't support premul colors 9660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/ 9670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline int pack_palette(SkColorTable* ctable, 9680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color* SK_RESTRICT palette, 9690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_byte* SK_RESTRICT trans, bool hasAlpha) { 9700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockColors alc(ctable); 9710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT colors = alc.colors(); 9720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int ctCount = ctable->count(); 9730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int i, num_trans = 0; 9740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 9760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* first see if we have some number of fully opaque at the end of the 9770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ctable. PNG allows num_trans < num_palette, but all of the trans 9780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project entries must come first in the palette. If I was smarter, I'd 9790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reorder the indices and ctable so that all non-opaque colors came 9800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project first in the palette. But, since that would slow down the encode, 9810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project I'm leaving the indices and ctable order as is, and just looking 9820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project at the tail of the ctable for opaqueness. 9830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 9840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans = ctCount; 9850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = ctCount - 1; i >= 0; --i) { 9860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkGetPackedA32(colors[i]) != 0xFF) { 9870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 9880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans -= 1; 9900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 9910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 9930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 9940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 9950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = 0; i < num_trans; i++) { 9960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor c = *colors++; 9970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const unsigned a = SkGetPackedA32(c); 9980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale s = table[a]; 9990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project trans[i] = a; 10000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); 10010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); 10020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); 10030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now fall out of this if-block to use common code for the trailing 10050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // opaque entries 10060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // these (remaining) entries are opaque 10090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = num_trans; i < ctCount; i++) { 10100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *colors++; 10110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkGetPackedR32(c); 10120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkGetPackedG32(c); 10130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkGetPackedB32(c); 10140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return num_trans; 10160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 10170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageEncoder : public SkImageEncoder { 10190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 10200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 10211cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerprivate: 10221cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger bool doEncode(SkWStream* stream, const SkBitmap& bm, 10231cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger const bool& hasAlpha, int colorType, 10241cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger int bitDepth, SkBitmap::Config config, 10251cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger png_color_8& sig_bit); 10260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 10270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 10290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int /*quality*/) { 10300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config = bitmap.getConfig(); 10310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const bool hasAlpha = !bitmap.isOpaque(); 10330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int colorType = PNG_COLOR_MASK_COLOR; 10340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bitDepth = 8; // default for color 10350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_8 sig_bit; 10360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project switch (config) { 10380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kIndex8_Config: 10390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_PALETTE; 10400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // fall through to the ARGB_8888 case 10410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_8888_Config: 10420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 8; 10430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 8; 10440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 8; 10450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 8; 10460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 10470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_4444_Config: 10480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 4; 10490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 4; 10500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 4; 10510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 4; 10520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 10530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kRGB_565_Config: 10540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 5; 10550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 6; 10560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 5; 10570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 10580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 10590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project default: 10600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 10640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // don't specify alpha if we're a palette, even if our ctable has alpha 10650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!(colorType & PNG_COLOR_MASK_PALETTE)) { 10660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_ALPHA; 10670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 10690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 10700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockPixels alp(bitmap); 10730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // readyToDraw checks for pixels (and colortable if that is required) 10740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!bitmap.readyToDraw()) { 10750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we must do this after we have locked the pixels 10790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* ctable = bitmap.getColorTable(); 10800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL != ctable) { 10810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (ctable->count() == 0) { 10820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 10830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check if we can store in fewer than 8 bits 10850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth = computeBitDepth(ctable->count()); 10860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 10870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 10881cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger return doEncode(stream, bitmap, hasAlpha, colorType, 10891cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger bitDepth, config, sig_bit); 10901cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger} 10911cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 10921cab2921ab279367f8206cdadc9259d12e603548Derek Sollenbergerbool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, 10931cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger const bool& hasAlpha, int colorType, 10941cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger int bitDepth, SkBitmap::Config config, 10951cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger png_color_8& sig_bit) { 10961cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger 10970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 10980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 10990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 11010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL); 11020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == png_ptr) { 11030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 11040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr = png_create_info_struct(png_ptr); 11070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == info_ptr) { 11080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, png_infopp_NULL); 11090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 11100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling. REQUIRED if you aren't supplying your own 11130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * error handling functions in the png_create_write_struct() call. 11140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 11150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 11160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 11170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 11180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); 11210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set the image information here. Width and height are up to 2^31, 11230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 11240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 11250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 11260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 11270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 11280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 11290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 11300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 11320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth, colorType, 11330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 11340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_FILTER_TYPE_BASE); 11350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 113618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // set our colortable/trans arrays if needed 113718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_color paletteColors[256]; 113818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_byte trans[256]; 113918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (SkBitmap::kIndex8_Config == config) { 114018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkColorTable* ct = bitmap.getColorTable(); 114118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); 114218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 114318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (numTrans > 0) { 114418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL); 114518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 114618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 11470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_sBIT(png_ptr, info_ptr, &sig_bit); 11490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_info(png_ptr, info_ptr); 11500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const char* srcImage = (const char*)bitmap.getPixels(); 11520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); 11530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* storage = (char*)rowStorage.get(); 11540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc proc = choose_proc(config, hasAlpha); 11550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < bitmap.height(); y++) { 11570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_bytep row_ptr = (png_bytep)storage; 11580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project proc(srcImage, bitmap.width(), storage); 11590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_rows(png_ptr, &row_ptr, 1); 11600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcImage += bitmap.rowBytes(); 11610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_end(png_ptr, info_ptr); 11640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* clean up after the write, and free any memory allocated */ 11660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 11670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 11680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 11690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 11710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 11720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h" 11730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1174579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed#ifdef SK_ENABLE_LIBPNG 1175579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed SkImageDecoder* sk_libpng_dfactory(SkStream*); 1176579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type); 1177579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed#endif 1178579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reed 1179579d35c405d37b1f8c9afdefaa37e836fb6b956fMike ReedSkImageDecoder* sk_libpng_dfactory(SkStream* stream) { 11800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char buf[PNG_BYTES_TO_CHECK]; 11810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && 11820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 11830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNEW(SkPNGImageDecoder); 11840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 11850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 11860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 11870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1188579d35c405d37b1f8c9afdefaa37e836fb6b956fMike ReedSkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 11890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 11900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 11910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1192579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reedstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory); 1193579d35c405d37b1f8c9afdefaa37e836fb6b956fMike Reedstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); 1194