PNG格式解码,难!
本想直接调用libpng来解码PNG文件,无奈libpng的说明我看不太懂,不会用。于是,又想自己编码读取PNG文件。结果,深陷数据压缩算法中……感觉自己这方面的知识少得可怜,学习学习也好。继续努力中……下面这个地址是在网上找到的关于PNG文件格式的中文说明:
http://www.ismyway.com/png/index.htm
根据学到的一点知识,写了一个小小程序,没有什么作用,只当是学习记录吧
/******************************************************************************
* readpng.c
* allen
* [email protected]
* 2006/11/16
******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int png_header_print(char *filename);
int png_chunks_list(char *filename);
int png_chunk_read(FILE *fp);
/******************************************************************************
*
******************************************************************************/
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("usage: %s filename\n", argv[0]);
return 0;
}
printf("\n\tFile Name : [%s]\n\n", argv[1]);
png_header_print(argv[1]);
printf("\n");
png_chunks_list(argv[1]);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_header_print(char *filename)
{
int i, num;
FILE *fp;
char tmp[100];
unsigned char pngflag[8], pngIHDR[25];
fp = fopen(filename, "rb");
if (NULL == fp)
{
return 0;
}
fread(pngflag, sizeof(pngflag), 1, fp);
printf("\t------------ PNG signature ------------\n\t");
for(i=0; i<sizeof(pngflag); i++)
{
printf("[%02x]%c", pngflag[i], i == (sizeof(pngflag)-1) ? '\n' : ' ');
}
printf("\n");
fread(pngIHDR, sizeof(pngIHDR), 1, fp);
printf("\t---------- IHDR Image header ----------\n");
memcpy(&num, pngIHDR, 4);
printf("\tLENGTH : [%d]\n", htonl(num));
memset(tmp, 0x00, sizeof(tmp));
memcpy(tmp, pngIHDR+4, 4);
printf("\tCHUNK TYPE : [%s]\n", tmp);
printf("\tCHUNK DATA\n");
memcpy(&num, pngIHDR+8, 4);
printf("\t\tWidth (4 bytes): [%d]\n", htonl(num));
memcpy(&num, pngIHDR+12, 4);
printf("\t\tHeight (4 bytes): [%d]\n", htonl(num));
printf("\t\tBitdepth (1 bytes): [%d]\n", (int)pngIHDR[16]);
printf("\t\tColor Type (1 bytes): [%d]\n", (int)pngIHDR[17]);
printf("\t\tCompression method (1 bytes): [%d]\n", (int)pngIHDR[18]);
printf("\t\tFilter method (1 bytes): [%d]\n", (int)pngIHDR[19]);
printf("\t\tInterlace method (1 bytes): [%d]\n", (int)pngIHDR[20]);
printf("\tCRC : [%02x] [%02x] [%02x] [%02x]\n",
pngIHDR[21], pngIHDR[22], pngIHDR[23], pngIHDR[24]);
fclose(fp);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_chunks_list(char *filename)
{
FILE *fp;
int rc = 0;
unsigned char png_sign[8] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
unsigned char file_sign[8];
fp = fopen(filename, "rb");
if (NULL == fp)
{
return 0;
}
rc = fread(file_sign, sizeof(file_sign), 1, fp);
if ((rc != 1) ||
(memcmp(file_sign, png_sign, sizeof(png_sign)) != 0))
{
printf("Error : %s is not a png file!\n", filename);
printf("rc = [%d]\n", rc);
printf("[%02x] [%02x] [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]\n",
file_sign[0], file_sign[1], file_sign[2], file_sign[3],
file_sign[4], file_sign[5], file_sign[6], file_sign[7]);
return 0;
}
while(!feof(fp))
{
if (png_chunk_read(fp) <= 0)
break;
}
fclose(fp);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_chunk_read(FILE *fp)
{
int len = 0;
unsigned char name[5], data[65535], crc[4];
if (fread(&len, 4, 1, fp) != 1)
return 0;
len = htonl(len);
memset(name, 0x00, sizeof(name));
if (fread(name, 4, 1, fp) != 1)
return 0;
if (len > 0)
{
memset(data, 0x00, sizeof(data));
if (fread(data, len, 1, fp) != 1)
return 0;
}
memset(crc, 0x00, sizeof(crc));
if (fread(crc, 4, 1, fp) != 1)
return 0;
printf("LENGTH:[%8d] TYPE:[%s] DATA:[...] CRC:[%02x%02x%02x%02x]\n",
len, name, crc[0], crc[1], crc[2], crc[3]);
return 1;
}
取得一点点进步!通过对网上相关资料的查询,得到一个解压缩函数,运用到对PNG文件的IDAT数据块进行解压。经试验,目前这个函数对于不带透明效果的PNG文件可以解压IDAT数据块。下面的这个小程序演示了这一过程。测试用的PNG文件是使用PHOTOSHOP软件制作的10X10像素(不带透明效果)。通过这个程序,我观察到,对于这个10X10像素的PNG文件,不带透明效果,且是真彩色的,它的图象是由一行一行组成的,每行10像素,每个像素3个字节。这样一行就有30个字节了,另外,每一行数据前面还会添加一个字节。目前我还不知道是干什么用的。
/******************************************************************************
* readpng.c
* allen
* [email protected]
* 2006/11/16
******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include "zlib.h"
#define CHUNK 65536
unsigned char idat[CHUNK], img[CHUNK];
int idat_len = 0, img_len = 0;
int png_header_print(char *filename);
int png_chunks_list(char *filename);
int png_chunk_read(FILE *fp);
int inf(unsigned char *source, int src_len, unsigned char *dest);
int decode(unsigned char *dest, int *destLen, unsigned char *source, int sourceLen);
/******************************************************************************
*
******************************************************************************/
int main(int argc, char *argv[])
{
int i, j, rc;
if (argc != 2)
{
printf("usage: %s filename\n", argv[0]);
return 0;
}
printf("\n\tFile Name : [%s]\n\n", argv[1]);
/*
png_header_print(argv[1]);
printf("\n");
*/
png_chunks_list(argv[1]);
if (idat_len > 0)
{
/*
printf("*IDAT* Detail:\n");
for(i=0; i<idat_len; i++)
{
printf("[%02x]%c", idat[i], (i+1) % 8 ? ' ' : '\n');
}
*/
img_len = sizeof(img);
memset(img, 0x00, sizeof(img));
rc = decode(img, &img_len, idat, idat_len);
printf("decode return : [%d]\n", rc);
printf("idat_len : [%d] img_len : [%d]\n", idat_len, img_len);
for(i=0; i<img_len; i=i+31)
{
printf("Line[%02x]:\n", img[i]);
for (j=1; j<31; j++)
printf("[%02x]%c", img[i+j], j%10?' ':'\n');
printf("\n");
}
printf("\n");
}
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_header_print(char *filename)
{
int i, num;
FILE *fp;
char tmp[100];
unsigned char pngflag[8], pngIHDR[25];
fp = fopen(filename, "rb");
if (NULL == fp)
{
return 0;
}
fread(pngflag, sizeof(pngflag), 1, fp);
printf("\t------------ PNG signature ------------\n\t");
for(i=0; i<sizeof(pngflag); i++)
{
printf("[%02x]%c", pngflag[i], i == (sizeof(pngflag)-1) ? '\n' : ' ');
}
printf("\n");
fread(pngIHDR, sizeof(pngIHDR), 1, fp);
printf("\t---------- IHDR Image header ----------\n");
memcpy(&num, pngIHDR, 4);
printf("\tLENGTH : [%d]\n", htonl(num));
memset(tmp, 0x00, sizeof(tmp));
memcpy(tmp, pngIHDR+4, 4);
printf("\tCHUNK TYPE : [%s]\n", tmp);
printf("\tCHUNK DATA\n");
memcpy(&num, pngIHDR+8, 4);
printf("\t\tWidth (4 bytes): [%d]\n", htonl(num));
memcpy(&num, pngIHDR+12, 4);
printf("\t\tHeight (4 bytes): [%d]\n", htonl(num));
printf("\t\tBitdepth (1 bytes): [%d]\n", (int)pngIHDR[16]);
printf("\t\tColor Type (1 bytes): [%d]\n", (int)pngIHDR[17]);
printf("\t\tCompression method (1 bytes): [%d]\n", (int)pngIHDR[18]);
printf("\t\tFilter method (1 bytes): [%d]\n", (int)pngIHDR[19]);
printf("\t\tInterlace method (1 bytes): [%d]\n", (int)pngIHDR[20]);
printf("\tCRC : [%02x] [%02x] [%02x] [%02x]\n",
pngIHDR[21], pngIHDR[22], pngIHDR[23], pngIHDR[24]);
fclose(fp);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_chunks_list(char *filename)
{
FILE *fp;
int rc = 0;
unsigned char png_sign[8] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
unsigned char file_sign[8];
fp = fopen(filename, "rb");
if (NULL == fp)
{
return 0;
}
rc = fread(file_sign, sizeof(file_sign), 1, fp);
if ((rc != 1) ||
(memcmp(file_sign, png_sign, sizeof(png_sign)) != 0))
{
printf("Error : %s is not a png file!\n", filename);
printf("rc = [%d]\n", rc);
printf("[%02x] [%02x] [%02x] [%02x] [%02x] [%02x] [%02x] [%02x]\n",
file_sign[0], file_sign[1], file_sign[2], file_sign[3],
file_sign[4], file_sign[5], file_sign[6], file_sign[7]);
return 0;
}
while(!feof(fp))
{
if (png_chunk_read(fp) <= 0)
break;
}
fclose(fp);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_chunk_read(FILE *fp)
{
int len = 0;
unsigned char name[5], data[65535], crc[4];
if (fread(&len, 4, 1, fp) != 1)
return 0;
len = htonl(len);
memset(name, 0x00, sizeof(name));
if (fread(name, 4, 1, fp) != 1)
return 0;
if (len > 0)
{
memset(data, 0x00, sizeof(data));
if (fread(data, 1, len, fp) != len)
return 0;
}
memset(crc, 0x00, sizeof(crc));
if (fread(crc, 4, 1, fp) != 1)
return 0;
printf("LENGTH:[%8d] TYPE:[%s] DATA:[...] CRC:[%02x%02x%02x%02x]\n",
len, name, crc[0], crc[1], crc[2], crc[3]);
if ((memcmp(name, "IDAT", 4) == 0) && (len > 0))
{
/*
idat = (unsigned char *)malloc(len);
memset(idat, 0x00, len);
*/
memcpy(idat, data, len);
idat_len = len;
}
return 1;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
int inf(unsigned char *source, int src_len, unsigned char *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do
{
memcpy(in, source, src_len);
strm.avail_in = src_len;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
/*assert(ret != Z_STREAM_ERROR); state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
memcpy(dest, out, have);
img_len = have;
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
int decode(unsigned char *dest, int *destLen, unsigned char *source, int sourceLen)
{
z_stream stream;
int err;
stream.next_in = source;
stream.avail_in = sourceLen;
stream.next_out = dest;
stream.avail_out = *destLen;
/* if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; */
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
err = inflateInit(&stream);
if (err != Z_OK)
{
printf("inflateInit error!\n");
return err;
}
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
{
printf("inflate error! err=[%d]\n", err);
inflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream);
return err;
}
egui 里面有png的demo的例子,包括透明的例子.
看egui桌面图标. 我对PNG的分析过程中,遇到一个障碍,那就是“Filter type 3: Average”!PNG图像为了加大压缩率对像素阵列进行了重新筛选(Filter)。四种筛选方式中,唯独第3种让我摸不着头绪。PNG标准中描述的还原公式为:“Recon(x) = Filt(x) + floor((Recon(a) + Recon(b)) / 2)”。但是对于结果超出255却没有具体说明。
/******************************************************************************
* showpng.c - 对PNG文件进行简单地解码, 还原像素序列, 并在framebuffer中显示出来
* 目前它对PNG文件中含有Filter3的解码有问题, 且只能处理24位的图像.
*
* Author : allen
* Email: [email protected]
* Date : 2006/11/19
******************************************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <math.h>
#include "zlib.h"
#define CHUNK 65536
struct png_info
{
int width;
int height;
char bit_depth;
char colour_type;
char compression_method;
char filter_method;
char interlace_method;
int bpp;
unsigned char *idat;
long idat_len;
unsigned char *img;
long img_len;
};
int png_reader(struct png_info *pnginfo, char *filename);
int idat_read(struct png_info *pnginfo, FILE *fp);
int decompress(unsigned char *dest, long *destLen, unsigned char *source, long sourceLen);
int decode(struct png_info *pnginfo, unsigned char *src, long src_len);
unsigned char reconstruct(int f, unsigned char x, unsigned char a,
unsigned char b, unsigned char c);
unsigned char paeth(unsigned char a, unsigned char b, unsigned char c);
char *fbp = 0;
int xres = 0;
int yres = 0;
int bits_per_pixel = 0;
intshow_png(char *bmpfile);
/******************************************************************************
*
******************************************************************************/
int main( int argc, char *argv[] )
{
int fbfd = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
long int screensize = 0;
if (argc != 2)
{
printf("usage: %s filename\n", argv[0]);
return 0;
}
// Open the file for reading and writing
fbfd = open("/dev/fb0", O_RDWR);
if (!fbfd)
{
printf("Error: cannot open framebuffer device.\n");
exit(1);
}
// Get fixed screen information
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo))
{
printf("Error reading fixed information.\n");
exit(2);
}
// Get variable screen information
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo))
{
printf("Error reading variable information.\n");
exit(3);
}
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel );
xres = vinfo.xres;
yres = vinfo.yres;
bits_per_pixel = vinfo.bits_per_pixel;
// Figure out the size of the screen in bytes
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
// Map the device to memory
fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fbfd, 0);
if ((int)fbp == -1)
{
printf("Error: failed to map framebuffer device to memory.\n");
exit(4);
}
show_png(argv[1]);
munmap(fbp, screensize);
close(fbfd);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int show_png(char *bmpfile)
{
int rc;
int i, j, pos;
long tmp_len;
struct png_info pnginfo;
unsigned char tmp[CHUNK];
long int location = 0;
/*从PNG文件中读取需要的内容*/
png_reader(&pnginfo, bmpfile);
tmp_len = sizeof(tmp);
memset(tmp, 0x00, sizeof(tmp));
/*解压缩图像信息*/
rc = decompress(tmp, &tmp_len, pnginfo.idat, pnginfo.idat_len);
if (rc != 0)
{
printf("Decompress Error!\n");
free(pnginfo.idat);
free(pnginfo.img);
return 0;
}
/*解码图像信息*/
rc = decode(&pnginfo, tmp, tmp_len);
if (rc != 0)
{
printf("Decode Error!\n");
free(pnginfo.idat);
free(pnginfo.img);
return 0;
}
/*显示图像信息*/
for (i=0; i<pnginfo.height; i++)
{
for (j=0; j<pnginfo.width; j++)
{
location = i * xres * bits_per_pixel / 8 + j * bits_per_pixel / 8;
pos = i * (pnginfo.width * pnginfo.bpp) + (j * pnginfo.bpp);
*(fbp + location + 0) = *(pnginfo.img + pos + 2); /*Blue */
*(fbp + location + 1) = *(pnginfo.img + pos + 1); /*Green*/
*(fbp + location + 2) = *(pnginfo.img + pos + 0); /*Red*/
*(fbp + location + 3) = 0x00; /*Reserved*/
}
}
free(pnginfo.idat);
free(pnginfo.img);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int png_reader(struct png_info *pnginfo, char *filename)
{
int num;
FILE *fp;
unsigned char png_sign[8] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
unsigned char file_sign[8];
unsigned char pngIHDR[25];
fp = fopen(filename, "rb");
if (NULL == fp)
{
printf("Error : can not open [%s]!\n", filename);
return -1;
}
if (fread(file_sign, 1, sizeof(file_sign), fp) != sizeof(file_sign))
{
printf("Error : can not read [%s]!\n", filename);
fclose(fp);
return -2;
}
if (memcmp(file_sign, png_sign, sizeof(png_sign)) != 0)
{
printf("Error : [%s] is not a png file!\n", filename);
fclose(fp);
return -3;
}
if (fread(pngIHDR, 1, sizeof(pngIHDR), fp) != sizeof(pngIHDR))
{
printf("Error : can not read IHDR chunk!\n");
fclose(fp);
return -4;
}
memcpy(&num, pngIHDR, 4);
if ((htonl(num) != 13) || (memcmp("IHDR", pngIHDR+4, 4) != 0))
{
printf("Error : can not read IHDR chunk!\n");
fclose(fp);
return -5;
}
memcpy(&num, pngIHDR+8, 4);
pnginfo->width = htonl(num);
memcpy(&num, pngIHDR+12, 4);
pnginfo->height = htonl(num);
pnginfo->bit_depth = (int)pngIHDR[16];
pnginfo->colour_type = (int)pngIHDR[17];
pnginfo->compression_method = (int)pngIHDR[18];
pnginfo->filter_method = (int)pngIHDR[19];
pnginfo->interlace_method = (int)pngIHDR[20];
/*我现在测试用的PNG图片都是24位的, 所以BYTE PER PIXEL就是3*/
pnginfo->bpp = 3;
if (!idat_read(pnginfo, fp))
{
printf("Error : can not read IDAT chunk!\n");
fclose(fp);
return -6;
}
fclose(fp);
pnginfo->img_len = (pnginfo->width * 3) * pnginfo->height;
pnginfo->img = malloc(pnginfo->img_len);
memset(pnginfo->img, 0x00, pnginfo->img_len);
return 0;
}
/******************************************************************************
*
******************************************************************************/
int idat_read(struct png_info *pnginfo, FILE *fp)
{
int len = 0, find = 0;
unsigned char name[5], data[65535], crc[4];
while(!find)
{
if (fread(&len, 1, 4, fp) != 4)
break;
len = htonl(len);
memset(name, 0x00, sizeof(name));
if (fread(name, 1, 4, fp) != 4)
break;
if (len > 0)
{
memset(data, 0x00, sizeof(data));
if (fread(data, 1, len, fp) != len)
break;
}
memset(crc, 0x00, sizeof(crc));
if (fread(crc, 1, 4, fp) != 4)
break;
if ((memcmp(name, "IDAT", 4) == 0) && (len > 0))
{
find = 1;
break;
}
}
if (find)
{
pnginfo->idat = malloc(len);
memcpy(pnginfo->idat, data, len);
pnginfo->idat_len = len;
}
return find;
}
/******************************************************************************
*
******************************************************************************/
int decompress(unsigned char *dest, long *destLen,
unsigned char *source, long sourceLen)
{
z_stream stream;
int err;
stream.next_in = source;
stream.avail_in = sourceLen;
stream.next_out = dest;
stream.avail_out = *destLen;
/* if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; */
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
err = inflateInit(&stream);
if (err != Z_OK)
{
printf("inflateInit error!\n");
return err;
}
err = inflate(&stream, Z_FINISH);
if (err != Z_STREAM_END)
{
printf("inflate error! err=[%d]\n", err);
inflateEnd(&stream);
return err == Z_OK ? Z_BUF_ERROR : err;
}
*destLen = stream.total_out;
err = inflateEnd(&stream);
return err;
}
/******************************************************************************
*
******************************************************************************/
int decode(struct png_info *pnginfo, unsigned char *src, long src_len)
{
/*int pos;*/
int i, j, k, linebytes;
int f, width, height, bpp;
long tmp_size = 0;
unsigned char *tmp, x, a, b, c;
bpp = pnginfo->bpp;
linebytes = pnginfo->width * bpp;
width = pnginfo->width + 1;
height = pnginfo->height + 1;
tmp_size = height * width * bpp;
/*
printf("pnginfo->width:%d\n", pnginfo->width);
printf("pnginfo->height:%d\n", pnginfo->height);
printf("width:%d\n", width);
printf("height:%d\n", height);
printf("tmp_size:%ld\n", tmp_size);
*/
tmp = malloc(tmp_size);
memset(tmp, 0x00, tmp_size);
/*将解压缩过的数据拷贝到临时数据中*/
for (i=1; i<height; i++)
{
memcpy(tmp+width*bpp*i+bpp, src+(linebytes+1)*(i-1)+1, linebytes);
}
/*
for (i=0; i<height; i++)
{
for (j=0; j<width; j++)
{
pos = i * (width * 3) + (j * 3);
printf("[%02x][%02x][%02x] ", *(tmp+pos), *(tmp+pos+1), *(tmp+pos+2));
}
printf("\n");
}
printf("------------------------------------------------------------\n");
*/
/*对每一个像素进行解码*/
for (i=1; i<height; i++)
{
f = *(src + (linebytes + 1) * (i - 1));
for (j=1; j<width; j++)
{
for (k=0; k<3; k++)
{
x = *(tmp + (linebytes + bpp) * i + j * bpp + k);
a = *(tmp + (linebytes + bpp) * i + (j - 1) * bpp + k);
b = *(tmp + (linebytes + bpp) * (i - 1) + j * bpp + k);
c = *(tmp + (linebytes + bpp) * (i - 1) + (j - 1) * bpp + k);
*(tmp + (linebytes + bpp) * i + j * bpp + k) = reconstruct(f, x, a, b, c);
}
}
}
/*打印一下解码后的数据
for (i=0; i<height; i++)
{
for (j=0; j<width; j++)
{
pos = i * (width * 3) + (j * 3);
printf("[%02x][%02x][%02x] ", *(tmp+pos), *(tmp+pos+1), *(tmp+pos+2));
}
printf("\n");
}*/
/*拷贝解码后的数据到图像阵列中*/
for (i=1; i<height; i++)
{
memcpy(pnginfo->img+linebytes*(i-1), tmp+width*bpp*i+bpp, linebytes);
}
free(tmp);
return 0;
}
/******************************************************************************
*
******************************************************************************/
unsigned char reconstruct(int f, unsigned char x, unsigned char a,
unsigned char b, unsigned char c)
{
unsigned char ret = 0x00;
switch(f)
{
case 0:
ret = x;
break;
case 1:
ret = x + a;
break;
case 2:
ret = x + b;
break;
case 3:
ret = x + floor((a + b) / 2);
break;
case 4:
ret = x + paeth(a, b, c);
break;
}
return ret;
}
/******************************************************************************
*
******************************************************************************/
unsigned char paeth(unsigned char a, unsigned char b, unsigned char c)
{
unsigned char p, pa, pb, pc, pr;
p = a + b - c;
pa = abs(p - a);
pb = abs(p - b);
pc = abs(p - c);
if ((pa <= pb) && (pa <= pc))
pr = a;
else if (pb <= pc)
pr = b;
else
pr = c;
return pr;
}
页:
[1]