📄 imgdcd_png_decode.c
字号:
/* * * * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */#include <string.h>#include <jar.h>#include <pcsl_memory.h>#include <midp_logging.h>#include "imgdcd_intern_image_decode.h"#define UNDF_CHUNK 0x00000000#define IHDR_CHUNK 0x49484452#define PLTE_CHUNK 0x504C5445#define IDAT_CHUNK 0x49444154#define IEND_CHUNK 0x49454E44#define tRNS_CHUNK 0x74524E53#define CT_PALETTE 0x01#define CT_COLOR 0x02#define CT_ALPHA 0x04#define freeBytes(p) pcsl_mem_free((p))typedef struct _pngData { signed int width; signed int height; /* current location, for writing pixels */ int y; unsigned int scanlength; unsigned short bytesPerPixel; /* palette in stream is RGB (3 bytes) but we store it as XRGB (int) */ long *palette; unsigned short paletteLength; unsigned char *trans; unsigned short transLength; unsigned char pass; /* pass #, for interlace loading */ unsigned char depth; /* bits per pixel: 1,2,4,8,16 */ unsigned char colorType; /* 1=palette 2=hasColor 4=hasAlpha */ unsigned char compress; /* compression type, must be zero */ unsigned char filter; /* filter type, must be zero */ unsigned char interlace; /* interlacing: 0 (none) or 1 (adam7) */ unsigned int lineBytes[7]; unsigned int passSize[7];} pngData;static unsigned long readHeader(imageSrcPtr, long, pngData *, unsigned long);static unsigned long readPalette(imageSrcPtr, long, pngData *, long *, unsigned long);static unsigned long readTransPal(imageSrcPtr, long, pngData *, unsigned char *, unsigned long);static bool handleImageData(unsigned char *, int, imageDstPtr, pngData *);static unsigned long getInt(imageSrcPtr);static unsigned long skip(imageSrcPtr, int, unsigned long);static bool getChunk(imageSrcPtr, unsigned long *, long *);static bool signatureOK(imageSrcPtr);static bool headerOK(pngData *);static unsigned long init_CRC(unsigned long);static bool check_CRC(imageSrcPtr, unsigned long);static unsigned long update_crc(unsigned long, unsigned char *, int);static int findPassWidth(int, pngData *);typedef struct _iid { imageSrcPtr src; long clen;} idatInflateData;static intPNGdecodeImage_getByte(void *p){ idatInflateData *d = (idatInflateData *)p; imageSrcPtr src = d->src; unsigned long chunkType = UNDF_CHUNK; unsigned int byte; /* while, because it's possible to have 0-length chunks! */ while (d->clen == 0) { /* unsigned long CRC = */ (void)getInt(src); getChunk(src, &chunkType, &(d->clen)); if (chunkType != IDAT_CHUNK) { return -1; } } --(d->clen); byte = src->getByte(src); return byte;}static longPNGdecodeImage_getBytes(void *p, unsigned char *buffer, long count){ idatInflateData *d = (idatInflateData *)p; imageSrcPtr src = d->src; unsigned long chunkType = UNDF_CHUNK; /* while, because it's possible to have 0-length chunks! */ while (d->clen == 0) { /* unsigned long CRC = */ (void)getInt(src); getChunk(src, &chunkType, &(d->clen)); if (chunkType != IDAT_CHUNK) { return 0; } } if (d->clen <= (int)count) { count = d->clen; } count = (long)(src->getBytes(src, buffer, (int)count)); d->clen -= (int)count; return count;}static long PNGdecodeImage_size(void* p) { /* This function is not used by inflateData. */ (void)p; return 0;}/* Emulates fseek. See fseek doc for offset and whence values. */static int PNGdecodeImage_seek(void* p, long offset, int whence) { /* This function is not used by inflateData */ (void)p; (void)offset; (void)whence; return -1;}/* returns a memory handle, call addrFromHandle to use */static void* allocFunction(void* state, int n) { (void)state; return pcsl_mem_malloc(n);}/* handle, is a memory handle */static void freeFunction(void* state, void* handle) { (void)state; pcsl_mem_free(handle);}/* This function is to support heaps that compact memory. */static void* addrFromHandleFunction(void* state, void* handle) { (void)state; return handle;}bool get_decoded_png_imagesize(imageSrcPtr src, int* width, int* height) { unsigned long chunkType = UNDF_CHUNK; long chunkLength; unsigned long CRC; pngData data; if (!signatureOK(src)) { /* not a PNG image */ return FALSE; } if (!getChunk(src, &chunkType, &chunkLength)) { return FALSE; } CRC = init_CRC(chunkType); if (chunkType != IHDR_CHUNK) { return FALSE; } if (chunkLength < 13) { return FALSE; } memset(&data, 0, sizeof(data)); CRC = readHeader(src, chunkLength, &data, CRC); if (!headerOK(&data)) { return FALSE; } *width = data.width; *height = data.height; return TRUE;}staticboolPNGdecodeImage_real(imageSrcPtr src, imageDstPtr dst, long *paletteData, unsigned char *transData) { bool OK = TRUE; bool saw_IDAT = FALSE, saw_PLTE = FALSE, saw_tRNS = FALSE; pngData data; unsigned long chunkType = UNDF_CHUNK; long chunkLength; unsigned long CRC; if (!signatureOK(src)) { goto formaterror; /* not a PNG image */ } memset(&data, 0, sizeof(data)); while (getChunk(src, &chunkType, &chunkLength)) { CRC = init_CRC(chunkType); if (chunkType == IHDR_CHUNK) { /* size of header is known. headerOK => IHDR_CHUNK already seen */ if ((chunkLength < 13) || headerOK(&data)) { goto formaterror; } CRC = readHeader(src, chunkLength, &data, CRC); if (!headerOK(&data)) { goto formaterror; } dst->setSize(dst, data.width, data.height); if ((data.colorType & CT_COLOR) == 0) { /* grayscale--set up a palette */ int n = 0; long _p[4]; switch (data.depth) { case 1: _p[0] = 0; _p[1] = 0xffffff; n = 2; dst->setColormap(dst, _p, n); break; case 2: _p[0] = 0; _p[1] = 0x555555; _p[2] = 0xaaaaaa; _p[3] = 0xffffff; n = 4; dst->setColormap(dst, _p, n); break; case 4: { long p[16]; for (n = 0; n < 16; ++n) { p[n] = n*0x111111; } dst->setColormap(dst, p, n); } break; default: { long p[256]; for (n = 0; n < 256; ++n) { p[n] = (n << 16) | (n << 8) | n; } dst->setColormap(dst, p, n); } break; } } } else if (chunkType == PLTE_CHUNK) { if ((chunkLength < 0) || (chunkLength > (256 * 3)) || ((chunkLength % 3) != 0)) { goto formaterror; } if ((data.paletteLength > 0) || saw_IDAT || saw_tRNS) { goto formaterror; } CRC = readPalette(src, chunkLength, &data, paletteData, CRC); if (data.palette == NULL) { goto formaterror; } if (data.colorType & CT_PALETTE) { dst->setColormap(dst, data.palette, data.paletteLength); } saw_PLTE = TRUE; } else if (chunkType == tRNS_CHUNK) { if (saw_IDAT || data.colorType == 4 || data.colorType == 6) { goto formaterror; } CRC = readTransPal(src, chunkLength, &data, transData, CRC); if (data.trans == NULL) { goto formaterror; } dst->setTransMap(dst, data.trans, data.transLength, saw_PLTE ? data.paletteLength : -1); saw_tRNS = TRUE; } else if (chunkType == IDAT_CHUNK) { idatInflateData _data; FileObj fileObj; HeapManObj heapManObj; int compLen = 0; int decompLen = data.scanlength * data.height; unsigned char *decompBuf; long startPos = 0, lastGoodPos = 0; saw_IDAT = TRUE; if (data.interlace) { int i; /* decompLen is harder to calculate--there are extra rows! */ decompLen = 0; for (i = 0; i < 7; ++i) { int off = 7 >> (i/2); /* 7 7 3 3 1 1 0 */ int shift = 3 - (((i - 1) / 2)); /* 3 3 3 2 2 1 1 */ int height = ((data.height + off) >> shift); int width = findPassWidth(i, &data); data.lineBytes[i] = width; data.passSize[i] = width * height; decompLen += data.passSize[i]; } } else { data.lineBytes[6] = data.scanlength; data.passSize[6] = decompLen; } if ((data.colorType & CT_PALETTE) && (data.palette == NULL)) { goto formaterror; } /* * we need to decompress all of the IDAT chunks en masse. * first step is to find out how much actual data there is. * While we're at it, we can look at the CRCs for all of * the blocks. */ _data.src = src; _data.clen = chunkLength; lastGoodPos = startPos = src->getpos(src); do { /* Make sure we only process IDAT chunks */ if (chunkType != IDAT_CHUNK) break; CRC = init_CRC(chunkType); compLen += chunkLength; CRC = skip(src, chunkLength, CRC); lastGoodPos = src->getpos(src); if (!check_CRC(src, CRC)) { goto formaterror; } } while (getChunk(src, &chunkType, &chunkLength)); /* * IMPORTANT: CRC now contains the correct value for * the last IDAT_CHUNK. This is checked at the bottom * of the loop so it must contain the right value. */ src->seek(src, startPos); /* reset to the first IDAT_CHUNK */ decompBuf = (unsigned char*)pcsl_mem_malloc(decompLen); if (decompBuf == NULL) { OK = FALSE; goto done; } /* * inflate ignores the method and flags */ compLen -= 2; PNGdecodeImage_getByte(&_data); PNGdecodeImage_getByte(&_data); fileObj.state = &_data; fileObj.size = PNGdecodeImage_size; fileObj.read = PNGdecodeImage_getBytes; fileObj.seek = PNGdecodeImage_seek; fileObj.readChar = PNGdecodeImage_getByte; heapManObj.state = NULL; heapManObj.alloc = allocFunction; heapManObj.free = freeFunction; heapManObj.addrFromHandle = addrFromHandleFunction; /* subtract 4 bytes from compLen -- it's the ZLIB trailer */ if (inflateData(&fileObj, &heapManObj, compLen - 4, decompBuf, decompLen, 0) != 0) { freeBytes(decompBuf); goto formaterror; } OK = handleImageData(decompBuf, decompLen, dst, &data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -