10910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* libs/graphics/images/SkImageDecoder_libpng.cpp 20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** 30910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Copyright 2006, The Android Open Source Project 40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** 50910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License"); 60910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** you may not use this file except in compliance with the License. 70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** You may obtain a copy of the License at 80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** 90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** http://www.apache.org/licenses/LICENSE-2.0 100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** 110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Unless required by applicable law or agreed to in writing, software 120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS, 130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** See the License for the specific language governing permissions and 150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** limitations under the License. 160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/ 170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageDecoder.h" 190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageEncoder.h" 200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColor.h" 210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h" 220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkDither.h" 230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkMath.h" 240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkScaledBitmapSampler.h" 250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStream.h" 260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTemplates.h" 270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUtils.h" 280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectextern "C" { 300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "png.h" 310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageDecoder : public SkImageDecoder { 340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic: 350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual Format getFormat() const { 360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return kPNG_Format; 370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 400a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); 410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifndef png_jmpbuf 440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PNG_BYTES_TO_CHECK 4 480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Automatically clean up after throwing an exception */ 500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstruct PNGAutoClean { 510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} 520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ~PNGAutoClean() { 530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); 540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate: 560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { 610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkStream* sk_stream = (SkStream*) png_ptr->io_ptr; 620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project size_t bytes = sk_stream->read(data, length); 630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bytes != length) { 640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "Read Error!"); 650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkImageDecoder::Peeker* peeker = 700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); 710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // peek() returning true means continue decoding 720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? 730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1 : -1; 740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("------ png error %s\n", msg); 790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project longjmp(png_jmpbuf(png_ptr), 1); 810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { 840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < count; i++) { 850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = storage; 860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool pos_le(int value, int max) { 910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return value > 0 && value <= max; 920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { 950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config); 960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = bm->height() - 1; y >= 0; --y) { 1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor* p = bm->getAddr32(0, y); 1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int x = bm->width() - 1; x >= 0; --x) { 1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (match == *p) { 1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *p = 0; 1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha = true; 1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project p += 1; 1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return reallyHasAlpha; 1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1120a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedstatic bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig, 113fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool srcHasAlpha) { 1140a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed switch (dstConfig) { 115fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_8888_Config: 116fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kARGB_4444_Config: 117fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return true; 118fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed case SkBitmap::kRGB_565_Config: 119fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed // only return true if the src is opaque (since 565 is opaque) 120fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return !srcHasAlpha; 121fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed default: 122fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 123fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 124fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed} 125fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 126fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed// call only if color_type is PALETTE. Returns true if the ctable has alpha 127fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reedstatic bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { 128fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_bytep trans; 129fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed int num_trans; 130fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed 131fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 132fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 133fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return num_trans > 0; 134fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed } 135fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed return false; 13618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed} 13718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, 1390a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed Mode mode) { 1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// SkAutoTrace apr("SkPNGImageDecoder::onDecode"); 1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Create and initialize the png_struct with the desired error handler 1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * functions. If you want to use the default stderr and longjump method, 1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * you can supply NULL for the last three parameters. We also supply the 1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the compiler header file version, so that we know if the application 1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * was compiled with a compatible version of the library. */ 1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL, sk_error_fn, NULL); 1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // png_voidp user_error_ptr, user_error_fn, user_warning_fn); 1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (png_ptr == NULL) { 1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Allocate/initialize the memory for image information. */ 1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr = png_create_info_struct(png_ptr); 1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (info_ptr == NULL) { 1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); 1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNGAutoClean autoClean(png_ptr, info_ptr); 1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling if you are using the setjmp/longjmp method (this is 1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the normal method of doing things with libpng). REQUIRED unless you 1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * set up your own error handlers in the png_create_read_struct() earlier. 1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If you are using replacement read functions, instead of calling 1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_init_io() here you would call: 1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); 1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* where user_io_ptr is a structure you want available to the callbacks */ 1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* If we have already read some of the signature */ 1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); 1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // hookup our peeker so we can see any user-chunks the caller may be interested in 1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (this->getPeeker()) { 1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); 1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* The call to png_read_info() gives us all of the information from the 1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG file before the first IDAT (image data chunk). */ 1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_info(png_ptr, info_ptr); 1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_uint_32 origWidth, origHeight; 1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bit_depth, color_type, interlace_type; 1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type, 1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project &interlace_type, int_p_NULL, int_p_NULL); 1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* tell libpng to strip 16 bit/color files down to 8 bits/color */ 1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth == 16) { 1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_strip_16(png_ptr); 1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single 1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * byte into separate bytes (useful for paletted and grayscale images). */ 1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (bit_depth < 8) { 2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_packing(png_ptr); 2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ 2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { 2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_1_2_4_to_8(png_ptr); 2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Make a grayscale image into RGB. */ 2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_GRAY || 2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { 2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_gray_to_rgb(png_ptr); 2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config; 2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha = false; 2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool doDither = this->getDitherImage(); 2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor theTranspColor = 0; // 0 tells us not to try to match 2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check for sBIT chunk data, in case we should disable dithering because 2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // our data is not truely 8bits per component 2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (doDither) { 2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red, 2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.green, info_ptr->sig_bit.blue, 2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr->sig_bit.alpha); 2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // 0 seems to indicate no information available 2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) && 2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.green, SK_G16_BITS) && 2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) { 2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project doDither = false; 2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 235fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); 2360a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha); 2370a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now see if we can upscale to their requested config 2380a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) { 2390a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed config = SkBitmap::kIndex8_Config; 240421adab1be5bb9c1cd419138ceda375aef649077Mike Reed } 2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_16p transpColor = NULL; 2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int numTransp = 0; 2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor); 2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); 2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid && numTransp == 1 && transpColor != NULL) { 2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Compute our transparent color, which we'll match against later. 2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project We don't really handle 16bit components properly here, since we 2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project do our compare *after* the values have been knocked down to 8bit 2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project which means we will find more matches than we should. The real 2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project fix seems to be to see the actual 16bit components, do the 2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project compare, and then knock it down to 8bits ourselves. 2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type & PNG_COLOR_MASK_COLOR) { 2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8, 2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green >> 8, transpColor->blue >> 8); 2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project theTranspColor = SkPackARGB32(0xFF, transpColor->red, 2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->green, transpColor->blue); 2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { // gray 2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (16 == bit_depth) { 2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8, 2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray >> 8, transpColor->gray >> 8); 2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project theTranspColor = SkPackARGB32(0xFF, transpColor->gray, 2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transpColor->gray, transpColor->gray); 2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (valid || 2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_RGB_ALPHA == color_type || 2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_COLOR_TYPE_GRAY_ALPHA == color_type) { 2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project hasAlpha = true; 2800a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } 2810a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha); 2820a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed // now match the request against our capabilities 2830a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed if (hasAlpha) { 2840a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed if (config != SkBitmap::kARGB_4444_Config) { 2850a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed config = SkBitmap::kARGB_8888_Config; 2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2870a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed } else { 2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (config != SkBitmap::kRGB_565_Config && 2890a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed config != SkBitmap::kARGB_4444_Config) { 2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project config = SkBitmap::kARGB_8888_Config; 2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 29418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 29518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // sanity check for size 29618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed { 29718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed Sk64 size; 29818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size.setMul(origWidth, origHeight); 29918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.isNeg() || !size.is32()) { 30018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 30118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 30218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now check that if we are 4-bytes per pixel, we also don't overflow 30318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (size.get32() > (0x7FFFFFFF >> 2)) { 30418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 30518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 30618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 30718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!this->chooseFromOneChoice(config, origWidth, origHeight)) { 3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int sampleSize = this->getSampleSize(); 3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); 3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setConfig(config, sampler.scaledWidth(), 3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sampler.scaledHeight(), 0); 3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkImageDecoder::kDecodeBounds_Mode == mode) { 3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // from here down we are concerned with colortables and pixels 3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype 3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // draw lots faster if we can flag the bitmap has being opaque 3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool reallyHasAlpha = false; 3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* colorTable = NULL; 3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_PALETTE) { 3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int num_palette; 3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_colorp palette; 3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_bytep trans; 3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int num_trans; 3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); 3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* BUGGY IMAGE WORKAROUND 3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count 3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project which is a problem since we use the byte as an index. To work around this we grow 3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project the colortable by 1 (if its < 256) and duplicate the last color into that slot. 3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int colorCount = num_palette + (num_palette < 256); 3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorTable = SkNEW_ARGS(SkColorTable, (colorCount)); 3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor* colorPtr = colorTable->lockColors(); 3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); 3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project hasAlpha = (num_trans > 0); 3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans = 0; 3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag); 3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check for bad images that might make us crash 3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (num_trans > num_palette) { 3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans = num_palette; 3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int index = 0; 3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int transLessThanFF = 0; 3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (; index < num_trans; index++) { 3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transLessThanFF |= (int)*trans - 0xFF; 3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); 3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette++; 3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= (transLessThanFF < 0); 3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (; index < num_palette; index++) { 3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); 3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette++; 3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // see BUGGY IMAGE WORKAROUND comment above 3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (num_palette < 256) { 3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *colorPtr = colorPtr[-1]; 3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorTable->unlockColors(true); 3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoUnref aur(colorTable); 3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 38418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (!this->allocPixelRef(decodedBitmap, 385421adab1be5bb9c1cd419138ceda375aef649077Mike Reed SkBitmap::kIndex8_Config == config ? 386421adab1be5bb9c1cd419138ceda375aef649077Mike Reed colorTable : NULL)) { 3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockPixels alp(*decodedBitmap); 3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ 3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) 3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// ; // png_set_swap_alpha(png_ptr); 3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* swap bytes of 16 bit files to least significant byte first */ 3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // png_set_swap(png_ptr); 3980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Add filler (or alpha) byte (before/after each RGB triplet) */ 4000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) { 4010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); 4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Turn on interlace handling. REQUIRED if you are not using 4050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * png_read_image(). To see how to handle interlacing passes, 4060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * see the png_read_row() method below: 4070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int number_passes = interlace_type != PNG_INTERLACE_NONE ? 4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_interlace_handling(png_ptr) : 1; 4100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Optional call to gamma correct and add the background to the palette 4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * and update info structure. REQUIRED if you are expecting libpng to 4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * update the palette for you (ie you selected such a transform above). 4140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 4150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_update_info(png_ptr, info_ptr); 4160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { 4180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < number_passes; i++) { 4190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (png_uint_32 y = 0; y < origHeight; y++) { 4200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* bmRow = decodedBitmap->getAddr8(0, y); 4210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 4220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 4250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkScaledBitmapSampler::SrcConfig sc; 4260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int srcBytesPerPixel = 4; 4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 42818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (colorTable != NULL) { 4290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kIndex; 4300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcBytesPerPixel = 1; 4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else if (hasAlpha) { 4320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBA; 4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sc = SkScaledBitmapSampler::kRGBX; 4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 43718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed /* We have to pass the colortable explicitly, since we may have one 43818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed even if our decodedBitmap doesn't, due to the request that we 43918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed upscale png's palette to a direct model 44018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed */ 44118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoLockColors ctLock(colorTable); 44218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) { 44318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed return false; 44418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int height = decodedBitmap->height(); 4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 44718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (number_passes > 1) { 44818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); 44918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* base = (uint8_t*)storage.get(); 45018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed size_t rb = origWidth * srcBytesPerPixel; 45118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 45218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int i = 0; i < number_passes; i++) { 45318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* row = base; 45418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (png_uint_32 y = 0; y < origHeight; y++) { 45518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed uint8_t* bmRow = row; 45618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); 45718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed row += rb; 45818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 4590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 46018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // now sample it 46118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcY0() * rb; 46218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed for (int y = 0; y < height; y++) { 46318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed reallyHasAlpha |= sampler.next(base); 46418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed base += sampler.srcDY() * rb; 46518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 46618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } else { 46718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkAutoMalloc storage(origWidth * srcBytesPerPixel); 4680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* srcRow = (uint8_t*)storage.get(); 4690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcY0()); 4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < height; y++) { 4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project uint8_t* tmp = srcRow; 4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); 4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= sampler.next(srcRow); 4750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (y < height - 1) { 4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); 4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 47918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed 4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // skip the rest of the rows (if any) 4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_uint_32 read = (height - 1) * sampler.srcDY() + 4820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sampler.srcY0() + 1; 4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(read <= origHeight); 4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project skip_src_rows(png_ptr, srcRow, origHeight - read); 4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_read_end(png_ptr, info_ptr); 4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != theTranspColor) { 4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project decodedBitmap->setIsOpaque(!reallyHasAlpha); 4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h" 5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUnPreMultiply.h" 5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr; 5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!sk_stream->write(data, len)) { 5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_error(png_ptr, "sk_write_fn Error!"); 5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projecttypedef void (*transform_scanline_proc)(const char* SK_RESTRICT src, 5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int width, char* SK_RESTRICT dst); 5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_565(const char* SK_RESTRICT src, int width, 5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src; 5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned c = *srcP++; 5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToR32(c); 5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToG32(c); 5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked16ToB32(c); 5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_888(const char* SK_RESTRICT src, int width, 5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *srcP++; 5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedR32(c); 5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedG32(c); 5310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkGetPackedB32(c); 5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_444(const char* SK_RESTRICT src, int width, 5360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor16 c = *srcP++; 5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToR32(c); 5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToG32(c); 5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = SkPacked4444ToB32(c); 5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_8888(const char* SK_RESTRICT src, int width, 5470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 5480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src; 5490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 5500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 5510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 5530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *srcP++; 5540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned a = SkGetPackedA32(c); 5550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned r = SkGetPackedR32(c); 5560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned g = SkGetPackedG32(c); 5570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned b = SkGetPackedB32(c); 5580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != a && 255 != a) { 5600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::Scale scale = table[a]; 5610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project r = SkUnPreMultiply::ApplyScale(scale, r); 5620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project g = SkUnPreMultiply::ApplyScale(scale, g); 5630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project b = SkUnPreMultiply::ApplyScale(scale, b); 5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = r; 5660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = g; 5670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = b; 5680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = a; 5690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_4444(const char* SK_RESTRICT src, int width, 5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 5740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src; 5750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 5760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 5770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = 0; i < width; i++) { 5790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor16 c = *srcP++; 5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned a = SkPacked4444ToA32(c); 5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned r = SkPacked4444ToR32(c); 5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned g = SkPacked4444ToG32(c); 5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project unsigned b = SkPacked4444ToB32(c); 5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (0 != a && 255 != a) { 5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::Scale scale = table[a]; 5870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project r = SkUnPreMultiply::ApplyScale(scale, r); 5880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project g = SkUnPreMultiply::ApplyScale(scale, g); 5890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project b = SkUnPreMultiply::ApplyScale(scale, b); 5900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = r; 5920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = g; 5930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = b; 5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project *dst++ = a; 5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_index8(const char* SK_RESTRICT src, int width, 5990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* SK_RESTRICT dst) { 6000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project memcpy(dst, src, width); 6010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 6020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic transform_scanline_proc choose_proc(SkBitmap::Config config, 6040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool hasAlpha) { 6050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we don't care about search on alpha if we're kIndex8, since only the 6060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // colortable packing cares about that distinction, not the pixels 6070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkBitmap::kIndex8_Config == config) { 6080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project hasAlpha = false; // we store false in the table entries for kIndex8 6090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project static const struct { 6120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config fConfig; 6130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bool fHasAlpha; 6140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc fProc; 6150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } gMap[] = { 6160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kRGB_565_Config, false, transform_scanline_565 }, 6170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 }, 6180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 }, 6190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 }, 6200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 }, 6210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project { SkBitmap::kIndex8_Config, false, transform_scanline_index8 }, 6220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project }; 6230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) { 6250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) { 6260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return gMap[i].fProc; 6270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sk_throw(); 6300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 6310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 6320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return the minimum legal bitdepth (by png standards) for this many colortable 6340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16, 6350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// we can use fewer bits per in png 6360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int computeBitDepth(int colorCount) { 6370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0 6380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bits = SkNextLog2(colorCount); 6390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkASSERT(bits >= 1 && bits <= 8); 6400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) 6410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNextPow2(bits); 6420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else 6430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // for the moment, we don't know how to pack bitdepth < 8 6440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return 8; 6450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif 6460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 6470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also 6490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project pack trans[] and return the number of trans[] entries written. If hasAlpha 6500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project is false, the return value will always be 0. 6510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project Note: this routine takes care of unpremultiplying the RGB values when we 6530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project have alpha in the colortable, since png doesn't support premul colors 6540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/ 6550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline int pack_palette(SkColorTable* ctable, 6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color* SK_RESTRICT palette, 6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_byte* SK_RESTRICT trans, bool hasAlpha) { 6580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockColors alc(ctable); 6590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor* SK_RESTRICT colors = alc.colors(); 6600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const int ctCount = ctable->count(); 6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int i, num_trans = 0; 6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* first see if we have some number of fully opaque at the end of the 6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project ctable. PNG allows num_trans < num_palette, but all of the trans 6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project entries must come first in the palette. If I was smarter, I'd 6670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project reorder the indices and ctable so that all non-opaque colors came 6680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project first in the palette. But, since that would slow down the encode, 6690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project I'm leaving the indices and ctable order as is, and just looking 6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project at the tail of the ctable for opaqueness. 6710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 6720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans = ctCount; 6730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = ctCount - 1; i >= 0; --i) { 6740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (SkGetPackedA32(colors[i]) != 0xFF) { 6750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 6760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project num_trans -= 1; 6780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale* SK_RESTRICT table = 6810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkUnPreMultiply::GetScaleTable(); 6820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = 0; i < num_trans; i++) { 6840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkPMColor c = *colors++; 6850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const unsigned a = SkGetPackedA32(c); 6860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const SkUnPreMultiply::Scale s = table[a]; 6870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project trans[i] = a; 6880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); 6890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); 6900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); 6910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // now fall out of this if-block to use common code for the trailing 6930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // opaque entries 6940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 6950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 6960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // these (remaining) entries are opaque 6970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (i = num_trans; i < ctCount; i++) { 6980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkPMColor c = *colors++; 6990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].red = SkGetPackedR32(c); 7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].green = SkGetPackedG32(c); 7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project palette[i].blue = SkGetPackedB32(c); 7020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return num_trans; 7040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 7050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageEncoder : public SkImageEncoder { 7070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected: 7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}; 7100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, 7120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int /*quality*/) { 7130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkBitmap::Config config = bitmap.getConfig(); 7140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const bool hasAlpha = !bitmap.isOpaque(); 7160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int colorType = PNG_COLOR_MASK_COLOR; 7170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project int bitDepth = 8; // default for color 7180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_color_8 sig_bit; 7190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project switch (config) { 7210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kIndex8_Config: 7220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_PALETTE; 7230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // fall through to the ARGB_8888 case 7240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_8888_Config: 7250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 8; 7260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 8; 7270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 8; 7280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 8; 7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 7300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kARGB_4444_Config: 7310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 4; 7320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 4; 7330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 4; 7340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 4; 7350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 7360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project case SkBitmap::kRGB_565_Config: 7370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.red = 5; 7380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.green = 6; 7390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.blue = 5; 7400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 7410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project break; 7420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project default: 7430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (hasAlpha) { 7470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // don't specify alpha if we're a palette, even if our ctable has alpha 7480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!(colorType & PNG_COLOR_MASK_PALETTE)) { 7490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project colorType |= PNG_COLOR_MASK_ALPHA; 7500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } else { 7520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project sig_bit.alpha = 0; 7530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoLockPixels alp(bitmap); 7560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // readyToDraw checks for pixels (and colortable if that is required) 7570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (!bitmap.readyToDraw()) { 7580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // we must do this after we have locked the pixels 7620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkColorTable* ctable = bitmap.getColorTable(); 7630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL != ctable) { 7640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (ctable->count() == 0) { 7650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project // check if we can store in fewer than 8 bits 7680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth = computeBitDepth(ctable->count()); 7690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_structp png_ptr; 7720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_infop info_ptr; 7730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn, 7750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project NULL); 7760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == png_ptr) { 7770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project info_ptr = png_create_info_struct(png_ptr); 7810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (NULL == info_ptr) { 7820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, png_infopp_NULL); 7830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set error handling. REQUIRED if you aren't supplying your own 7870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * error handling functions in the png_create_write_struct() call. 7880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 7890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (setjmp(png_jmpbuf(png_ptr))) { 7900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 7910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return false; 7920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 7930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL); 7950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 7960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* Set the image information here. Width and height are up to 2^31, 7970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on 7980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, 7990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, 8000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or 8010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST 8020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED 8030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project */ 8040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), 8060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project bitDepth, colorType, 8070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, 8080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project PNG_FILTER_TYPE_BASE); 8090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 81018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed // set our colortable/trans arrays if needed 81118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_color paletteColors[256]; 81218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_byte trans[256]; 81318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (SkBitmap::kIndex8_Config == config) { 81418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed SkColorTable* ct = bitmap.getColorTable(); 81518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha); 81618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); 81718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed if (numTrans > 0) { 81818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL); 81918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 82018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed } 8210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_set_sBIT(png_ptr, info_ptr, &sig_bit); 8230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_info(png_ptr, info_ptr); 8240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project const char* srcImage = (const char*)bitmap.getPixels(); 8260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2); 8270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char* storage = (char*)rowStorage.get(); 8280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project transform_scanline_proc proc = choose_proc(config, hasAlpha); 8290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project for (int y = 0; y < bitmap.height(); y++) { 8310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_bytep row_ptr = (png_bytep)storage; 8320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project proc(srcImage, bitmap.width(), storage); 8330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_rows(png_ptr, &row_ptr, 1); 8340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project srcImage += bitmap.rowBytes(); 8350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_write_end(png_ptr, info_ptr); 8380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project /* clean up after the write, and free any memory allocated */ 8400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project png_destroy_write_struct(&png_ptr, &info_ptr); 8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return true; 8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////// 8450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h" 8470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageDecoder* DFactory(SkStream* stream) { 8490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project char buf[PNG_BYTES_TO_CHECK]; 8500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && 8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { 8520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return SkNEW(SkPNGImageDecoder); 8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project } 8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return NULL; 8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageEncoder* EFactory(SkImageEncoder::Type t) { 8580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 8590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project} 8600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project 8610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory); 8620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory); 863