apng2gif-1.5.orig/0000755000000000000000000000000011727050103012505 5ustar rootrootapng2gif-1.5.orig/apng2gif.c0000644000000000000000000014442111717260120014355 0ustar rootroot/* apng2gif version 1.5 * * This program converts APNG animations into animated GIF format. * Wu64 quantizer is used for true-color files. * * http://apng2gif.sourceforge.net/ * * Copyright (c) 2010-2012 Max Stepin * maxst at users.sourceforge.net * * zlib license * ------------ * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * */ #include #include #include #include "zlib.h" #define PNG_DISPOSE_OP_NONE 0x00 #define PNG_DISPOSE_OP_BACKGROUND 0x01 #define PNG_DISPOSE_OP_PREVIOUS 0x02 #define PNG_BLEND_OP_SOURCE 0x00 #define PNG_BLEND_OP_OVER 0x01 #define notabc(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) #define ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ ((width) * (((unsigned int)(pixel_bits)) >> 3)) : \ (( ((width) * ((unsigned int)(pixel_bits))) + 7) >> 3) ) #define indx(r, g, b) ((r << 12) + (r << 7) + r + (g << 6) + g + b) #define RED 2 #define GREEN 1 #define BLUE 0 unsigned char png_sign[8] = {137, 80, 78, 71, 13, 10, 26, 10}; int mask4[2]={240,15}; int shift4[2]={4,0}; int mask2[4]={192,48,12,3}; int shift2[4]={6,4,2,0}; int mask1[8]={128,64,32,16,8,4,2,1}; int shift1[8]={7,6,5,4,3,2,1,0}; unsigned int keep_original = 1; unsigned char pal[256][3]; unsigned char trns[256]; unsigned int palsize, trnssize; unsigned short trns1, trns2, trns3; int trns_idx; unsigned int accum; unsigned char bits, codesize; unsigned char buf[288]; unsigned char bigcube[128][128][128]; int wt[65*65*65]; int mr[65*65*65]; int mg[65*65*65]; int mb[65*65*65]; double m2[65*65*65]; unsigned char tag[65*65*65]; typedef struct {int r0; int r1; int g0; int g1; int b0; int b1; int vol; } box; int tlevel, bcolor, back_r, back_g, back_b; int read32(unsigned int *val, FILE * f1) { unsigned char a, b, c, d; if (fread(&a, 1, 1, f1) == 1 && fread(&b, 1, 1, f1) == 1 && fread(&c, 1, 1, f1) == 1 && fread(&d, 1, 1, f1) == 1) { *val = ((unsigned int)a<<24)+((unsigned int)b<<16)+((unsigned int)c<<8)+(unsigned int)d; return 0; } return 1; } int read16(unsigned short *val, FILE * f1) { unsigned char a, b; if (fread(&a, 1, 1, f1) == 1 && fread(&b, 1, 1, f1) == 1) { *val = ((unsigned short)a<<8)+(unsigned short)b; return 0; } return 1; } unsigned short readshort(unsigned char * p) { return ((unsigned short)(*p)<<8)+(unsigned short)(*(p+1)); } void read_sub_row(unsigned char * row, unsigned int rowbytes, unsigned int bpp) { unsigned int i; for (i=bpp; i>1; for (i=bpp; i>1; } else { for (i=bpp; i>1; } } void read_paeth_row(unsigned char * row, unsigned char * prev_row, unsigned int rowbytes, unsigned int bpp) { unsigned int i; int a, b, c, pa, pb, pc, p; if (prev_row) { for (i=0; i>1] & mask4[i&1]) >> shift4[i&1]; a = 0xFF; if (trnssize && g==trns1) a = 0; *dp1++ = g*0x11; *dp2++ = (a<<24) + g*0x111111; } break; case 2: for (i=0; i>2] & mask2[i&3]) >> shift2[i&3]; a = 0xFF; if (trnssize && g==trns1) a = 0; *dp1++ = g*0x55; *dp2++ = (a<<24) + g*0x555555; } break; case 1: for (i=0; i>3] & mask1[i&7]) >> shift1[i&7]; a = 0xFF; if (trnssize && g==trns1) a = 0; *dp1++ = g*0xFF; *dp2++ = (a<<24) + g*0xFFFFFF; } break; } } else /* PNG_BLEND_OP_OVER */ { switch (depth) { case 16: for (i=0; i>1] & mask4[i&1]) >> shift4[i&1]; if (g != trns1) { *dp1 = g*0x11; *dp2 = 0xFF000000+g*0x111111; } } break; case 2: for (i=0; i>2] & mask2[i&3]) >> shift2[i&3]; if (g != trns1) { *dp1 = g*0x55; *dp2 = 0xFF000000+g*0x555555; } } break; case 1: for (i=0; i>3] & mask1[i&7]) >> shift1[i&7]; if (g != trns1) { *dp1 = g*0xFF; *dp2 = 0xFF000000+g*0xFFFFFF; } } break; } } src += srcbytes; dst1 += dstbytes1; dst2 += dstbytes2; } } void compose2(unsigned char * dst, unsigned int dstbytes, unsigned char * src, unsigned int srcbytes, unsigned int w, unsigned int h, unsigned int bop, unsigned char depth) { unsigned int i, j; unsigned int r, g, b, a; unsigned char * sp; unsigned int * dp; for (j=0; j>3] & mask1[i&7]) >> shift1[i&7]; break; case 2: col = (sp[i>>2] & mask2[i&3]) >> shift2[i&3]; break; case 4: col = (sp[i>>1] & mask4[i&1]) >> shift4[i&1]; break; default: col = sp[i]; } r = pal[col][0]; g = pal[col][1]; b = pal[col][2]; a = trns[col]; if (bop == PNG_BLEND_OP_SOURCE) { *dp1++ = col; *dp2++ = (a << 24) + (b << 16) + (g << 8) + r; } else /* PNG_BLEND_OP_OVER */ { if (a == 255) { *dp1++ = col; *dp2++ = (a << 24) + (b << 16) + (g << 8) + r; } else if (a != 0) { if ((a2 = (*dp2)>>24) != 0) { keep_original = 0; u = a*255; v = (255-a)*a2; al = 255*255-(255-a)*(255-a2); r2 = ((*dp2)&255); g2 = (((*dp2)>>8)&255); b2 = (((*dp2)>>16)&255); r = (r*u + r2*v)/al; g = (g*u + g2*v)/al; b = (b*u + b2*v)/al; a = al/255; } *dp1++ = col; *dp2++ = (a << 24) + (b << 16) + (g << 8) + r; } else { dp1++; dp2++; } } } src += srcbytes; dst1 += dstbytes1; dst2 += dstbytes2; } } void compose4(unsigned char * dst, unsigned int dstbytes, unsigned char * src, unsigned int srcbytes, unsigned int w, unsigned int h, unsigned int bop, unsigned char depth) { unsigned int i, j, step; unsigned int g, a, g2, a2; int u, v, al; unsigned char * sp; unsigned int * dp; step = (depth+7)/8; for (j=0; j>24) != 0) { u = a*255; v = (255-a)*a2; al = 255*255-(255-a)*(255-a2); g2 = ((*dp)&255); g = (g*u + g2*v)/al; a = al/255; } *dp++ = (a << 24) + (g << 16) + (g << 8) + g; } else dp++; } } src += srcbytes; dst += dstbytes; } } void compose6(unsigned char * dst, unsigned int dstbytes, unsigned char * src, unsigned int srcbytes, unsigned int w, unsigned int h, unsigned int bop, unsigned char depth) { unsigned int i, j, step; unsigned int r, g, b, a; unsigned int r2, g2, b2, a2; int u, v, al; unsigned char * sp; unsigned int * dp; step = (depth+7)/8; for (j=0; j>24) != 0) { u = a*255; v = (255-a)*a2; al = 255*255-(255-a)*(255-a2); r2 = ((*dp)&255); g2 = (((*dp)>>8)&255); b2 = (((*dp)>>16)&255); r = (r*u + r2*v)/al; g = (g*u + g2*v)/al; b = (b*u + b2*v)/al; a = al/255; } *dp++ = (a << 24) + (b << 16) + (g << 8) + r; } else dp++; } } src += srcbytes; dst += dstbytes; } } int LoadAPNG(char * szIn, int *pWidth, int *pHeight, int *pColType, int *pFrames, int *pLoops, unsigned char **ppOut1, unsigned char **ppOut2, unsigned short ** ppDelays) { unsigned char sig[8]; unsigned int i, j; unsigned int len, chunk, seq, crc; unsigned int w, h, w0, h0, x0, y0; unsigned char depth, coltype, compr, filter, interl; unsigned char pixeldepth, bpp; unsigned int rowbytes, frames, loops, fctl, frames_decoded; unsigned int outrow1, outrow2, outimg1, outimg2; unsigned short d1, d2; unsigned char c, dop, bop; int imagesize, zbuf_size, zsize; z_stream zstream; unsigned char * pOut1; unsigned char * pOut2; unsigned char * pTemp; unsigned char * pData; unsigned char * pImg1; unsigned char * pImg2; unsigned char * pDst1; unsigned char * pDst2; unsigned short * pDelays; FILE * f1; int res = 1; if ((f1 = fopen(szIn, "rb")) == 0) { printf("Error: can't open '%s'\n", szIn); return res; } printf("Reading '%s'...\n", szIn); frames = 1; loops = 0; fctl = 0; frames_decoded = 0; zsize = 0; x0 = 0; y0 = 0; bop = PNG_BLEND_OP_SOURCE; palsize = 0; trnssize = 0; trns_idx = -1; memset(trns, 255, 256); zstream.zalloc = Z_NULL; zstream.zfree = Z_NULL; zstream.opaque = Z_NULL; inflateInit(&zstream); do { if (fread(sig, 1, 8, f1) != 8) { printf("Error: can't read the sig\n"); break; } if (memcmp(sig, png_sign, 8) != 0) { printf("Error: wrong PNG sig\n"); break; } if (read32(&len, f1)) break; if (read32(&chunk, f1)) break; if (len != 13 || chunk != 0x49484452) /* IHDR */ { printf("Error: missing IHDR\n"); break; } if (read32(&w, f1)) break; if (read32(&h, f1)) break; w0 = w; h0 = h; if (fread(&depth, 1, 1, f1) != 1) break; if (fread(&coltype, 1, 1, f1) != 1) break; if (fread(&compr, 1, 1, f1) != 1) break; if (fread(&filter, 1, 1, f1) != 1) break; if (fread(&interl, 1, 1, f1) != 1) break; if (read32(&crc, f1)) break; pixeldepth = depth; if (coltype == 2) pixeldepth = depth*3; else if (coltype == 4) pixeldepth = depth*2; else if (coltype == 6) pixeldepth = depth*4; bpp = (pixeldepth + 7) >> 3; rowbytes = ROWBYTES(pixeldepth, w); imagesize = (rowbytes + 1) * h; zbuf_size = imagesize + ((imagesize + 7) >> 3) + ((imagesize + 63) >> 6) + 11; /* * We'll render into 2 output buffers, first in original coltype, * second in RGBA. * * It's better to try to keep the original coltype, but if dispose/blend * operations will make it impossible, then we'll use RGBA version instead. */ outrow1 = w; /* output coltype = input coltype */ outrow2 = w*4; /* output coltype = RGBA */ outimg1 = h*outrow1; outimg2 = h*outrow2; pOut1 = (unsigned char *)malloc((frames+1)*outimg1*4); pOut2 = (unsigned char *)malloc((frames+1)*outimg2); pDelays = (unsigned short *)malloc((frames+1)*2); pTemp = (unsigned char *)malloc(imagesize); pData = (unsigned char *)malloc(zbuf_size); if (!pOut1 || !pOut2 || !pDelays || !pTemp || !pData) { printf("Error: not enough memory\n"); break; } pImg1 = pOut1; pImg2 = pOut2; memset(pOut1, 0, outimg1); memset(pOut2, 0, outimg2); pDelays[0] = 10; while ( !feof(f1) ) { if (read32(&len, f1)) break; if (read32(&chunk, f1)) break; if (chunk == 0x504C5445) /* PLTE */ { unsigned int col; for (i=0; i 0) { if (dop == PNG_DISPOSE_OP_PREVIOUS) { if (coltype == 0 || coltype == 3) memcpy(pImg1 + outimg1, pImg1, outimg1); memcpy(pImg2 + outimg2, pImg2, outimg2); } pDst1 = pImg1 + y0*outrow1 + x0; pDst2 = pImg2 + y0*outrow2 + x0*4; unpack(zstream, pTemp, imagesize, pData, zsize, h0, rowbytes, bpp); switch (coltype) { case 0: compose0(pDst1, outrow1, pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 2: compose2( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 3: compose3(pDst1, outrow1, pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 4: compose4( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 6: compose6( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; } zsize = 0; if (dop != PNG_DISPOSE_OP_PREVIOUS) { if (coltype == 0 || coltype == 3) memcpy(pImg1 + outimg1, pImg1, outimg1); memcpy(pImg2 + outimg2, pImg2, outimg2); if (dop == PNG_DISPOSE_OP_BACKGROUND) { if (coltype == 0 || coltype == 3) { if (trns_idx >= 0) { pDst1 += outimg1; for (j=0; j 0) { pImg1 += outimg1; pImg2 += outimg2; frames_decoded++; } } if (read32(&seq, f1)) break; if (read32(&w0, f1)) break; if (read32(&h0, f1)) break; if (read32(&x0, f1)) break; if (read32(&y0, f1)) break; if (read16(&d1, f1)) break; if (read16(&d2, f1)) break; if (fread(&dop, 1, 1, f1) != 1) break; if (fread(&bop, 1, 1, f1) != 1) break; if (read32(&crc, f1)) break; if (d2==0 || d2==100) pDelays[fctl] = d1; else if (d2==10) pDelays[fctl] = d1*10; else if (d2==1000) pDelays[fctl] = d1/10; else pDelays[fctl] = d1*100/d2; if (fctl == 0) { bop = PNG_BLEND_OP_SOURCE; if (dop == PNG_DISPOSE_OP_PREVIOUS) dop = PNG_DISPOSE_OP_BACKGROUND; } if (coltype<=3 && trnssize==0) bop = PNG_BLEND_OP_SOURCE; rowbytes = ROWBYTES(pixeldepth, w0); fctl++; } else if (chunk == 0x49444154) /* IDAT */ { if (fread(pData + zsize, 1, len, f1) != len) break; zsize += len; if (read32(&crc, f1)) break; } else if (chunk == 0x66644154) /* fdAT */ { if (read32(&seq, f1)) break; len -= 4; if (fread(pData + zsize, 1, len, f1) != len) break; zsize += len; if (read32(&crc, f1)) break; } else if (chunk == 0x49454E44) /* IEND */ { pDst1 = pImg1 + y0*outrow1 + x0; pDst2 = pImg2 + y0*outrow2 + x0*4; unpack(zstream, pTemp, imagesize, pData, zsize, h0, rowbytes, bpp); switch (coltype) { case 0: compose0(pDst1, outrow1, pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 2: compose2( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 3: compose3(pDst1, outrow1, pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 4: compose4( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; case 6: compose6( pDst2, outrow2, pTemp, rowbytes+1, w0, h0, bop, depth); break; } frames_decoded++; if (frames_decoded == frames) res = 0; break; } else { c = (unsigned char)(chunk>>24); if (notabc(c)) break; c = (unsigned char)((chunk>>16) & 0xFF); if (notabc(c)) break; c = (unsigned char)((chunk>>8) & 0xFF); if (notabc(c)) break; c = (unsigned char)(chunk & 0xFF); if (notabc(c)) break; fseek(f1, len, SEEK_CUR); if (read32(&crc, f1)) break; } } *pWidth = w; *pHeight = h; *pColType = coltype; *pFrames = frames; *pLoops = loops; *ppOut1 = pOut1; *ppOut2 = pOut2; *ppDelays = pDelays; free(pData); free(pTemp); } while (0); inflateEnd(&zstream); fclose(f1); return res; } void WuHistogram(int size, unsigned char *pOut1, unsigned char *pOut2) { int i, j, r, g, b, inr, ing, inb; unsigned char * ps; unsigned int * pd; int table[256]; for (i=0; i<256; i++) table[i]=i*i; memset(wt, 0, 65*65*65*sizeof(int)); memset(mr, 0, 65*65*65*sizeof(int)); memset(mg, 0, 65*65*65*sizeof(int)); memset(mb, 0, 65*65*65*sizeof(int)); memset(m2, 0, 65*65*65*sizeof(double)); ps = pOut2; pd = (unsigned int *)pOut1; for (i=0; i= tlevel) { inr = (r>>2)+1; ing = (g>>2)+1; inb = (b>>2)+1; *pd++ = j = indx(inr, ing, inb); wt[j]++; mr[j] += r; mg[j] += g; mb[j] += b; m2[j] += (double)(table[r]+table[g]+table[b]); } else *pd++ = 0; } } void WuMoments() { unsigned int ind1, ind2; unsigned char i, r, g, b; int line, line_r, line_g, line_b; double line2; int area[65], area_r[65], area_g[65], area_b[65]; double area2[65]; for (r=1; r<=64; r++) { for (i=0; i<=64; i++) { area[i] = area_r[i] = area_g[i] = area_b[i] = 0; area2[i] = (double)0.0; } for (g=1; g<=64; g++) { line = line_r = line_g = line_b = 0; line2 = (double)0.0; for (b=1; b<=64; b++) { ind1 = indx(r, g, b); line += wt[ind1]; line_r += mr[ind1]; line_g += mg[ind1]; line_b += mb[ind1]; line2 += m2[ind1]; area[b] += line; area_r[b] += line_r; area_g[b] += line_g; area_b[b] += line_b; area2[b] += line2; ind2 = ind1 - 65*65; wt[ind1] = wt[ind2] + area[b]; mr[ind1] = mr[ind2] + area_r[b]; mg[ind1] = mg[ind2] + area_g[b]; mb[ind1] = mb[ind2] + area_b[b]; m2[ind1] = m2[ind2] + area2[b]; } } } } int WuCubeStat(box *cube, int *m) { return ( m[indx(cube->r1, cube->g1, cube->b1)] - m[indx(cube->r1, cube->g1, cube->b0)] - m[indx(cube->r1, cube->g0, cube->b1)] + m[indx(cube->r1, cube->g0, cube->b0)] - m[indx(cube->r0, cube->g1, cube->b1)] + m[indx(cube->r0, cube->g1, cube->b0)] + m[indx(cube->r0, cube->g0, cube->b1)] - m[indx(cube->r0, cube->g0, cube->b0)] ); } int WuBottomStat(box * cube, unsigned char dir, int *m) { switch(dir) { case RED: return ( -m[indx(cube->r0, cube->g1, cube->b1)] +m[indx(cube->r0, cube->g1, cube->b0)] +m[indx(cube->r0, cube->g0, cube->b1)] -m[indx(cube->r0, cube->g0, cube->b0)] ); break; case GREEN: return ( -m[indx(cube->r1, cube->g0, cube->b1)] +m[indx(cube->r1, cube->g0, cube->b0)] +m[indx(cube->r0, cube->g0, cube->b1)] -m[indx(cube->r0, cube->g0, cube->b0)] ); break; case BLUE: return ( -m[indx(cube->r1, cube->g1, cube->b0)] +m[indx(cube->r1, cube->g0, cube->b0)] +m[indx(cube->r0, cube->g1, cube->b0)] -m[indx(cube->r0, cube->g0, cube->b0)] ); break; } return 0; } int WuTopStat(box * cube, unsigned char dir, int pos, int *m) { switch(dir) { case RED: return ( m[indx(pos, cube->g1, cube->b1)] -m[indx(pos, cube->g1, cube->b0)] -m[indx(pos, cube->g0, cube->b1)] +m[indx(pos, cube->g0, cube->b0)] ); break; case GREEN: return ( m[indx(cube->r1, pos, cube->b1)] -m[indx(cube->r1, pos, cube->b0)] -m[indx(cube->r0, pos, cube->b1)] +m[indx(cube->r0, pos, cube->b0)] ); break; case BLUE: return ( m[indx(cube->r1, cube->g1, pos)] -m[indx(cube->r1, cube->g0, pos)] -m[indx(cube->r0, cube->g1, pos)] +m[indx(cube->r0, cube->g0, pos)] ); break; } return 0; } double WuVariance(box * cube) { double dr, dg, db, dt, xx; dr = (double)WuCubeStat(cube, mr); dg = (double)WuCubeStat(cube, mg); db = (double)WuCubeStat(cube, mb); dt = (double)WuCubeStat(cube, wt); xx = m2[indx(cube->r1, cube->g1, cube->b1)] -m2[indx(cube->r1, cube->g1, cube->b0)] -m2[indx(cube->r1, cube->g0, cube->b1)] +m2[indx(cube->r1, cube->g0, cube->b0)] -m2[indx(cube->r0, cube->g1, cube->b1)] +m2[indx(cube->r0, cube->g1, cube->b0)] +m2[indx(cube->r0, cube->g0, cube->b1)] -m2[indx(cube->r0, cube->g0, cube->b0)]; return( xx - (dr*dr+dg*dg+db*db)/dt ); } double WuMaximize(box * cube, unsigned char dir, int first, int last, int *cut, int whole_r, int whole_g, int whole_b, int whole_w) { int half_r, half_g, half_b, half_w; int base_r, base_g, base_b, base_w; int i; double temp, res; base_r = WuBottomStat(cube, dir, mr); base_g = WuBottomStat(cube, dir, mg); base_b = WuBottomStat(cube, dir, mb); base_w = WuBottomStat(cube, dir, wt); res = (double)0.0; *cut = -1; for (i=first; i res) { res = temp; *cut = i; } } return res; } int WuCut(box * set1, box * set2) { unsigned char dir; double maxr, maxg, maxb; int cutr, cutg, cutb; int whole_r, whole_g, whole_b, whole_w; whole_r = WuCubeStat(set1, mr); whole_g = WuCubeStat(set1, mg); whole_b = WuCubeStat(set1, mb); whole_w = WuCubeStat(set1, wt); maxr = WuMaximize(set1, RED, set1->r0+1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w); maxg = WuMaximize(set1, GREEN, set1->g0+1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w); maxb = WuMaximize(set1, BLUE, set1->b0+1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w); if (maxr >= maxg && maxr >= maxb) { dir = RED; if (cutr < 0) return 0; } else if (maxg >= maxr && maxg >= maxb) dir = GREEN; else dir = BLUE; set2->r1 = set1->r1; set2->g1 = set1->g1; set2->b1 = set1->b1; switch (dir) { case RED: set2->r0 = set1->r1 = cutr; set2->g0 = set1->g0; set2->b0 = set1->b0; break; case GREEN: set2->g0 = set1->g1 = cutg; set2->r0 = set1->r0; set2->b0 = set1->b0; break; case BLUE: set2->b0 = set1->b1 = cutb; set2->r0 = set1->r0; set2->g0 = set1->g0; break; } set1->vol = (set1->r1-set1->r0)*(set1->g1-set1->g0)*(set1->b1-set1->b0); set2->vol = (set2->r1-set2->r0)*(set2->g1-set2->g0)*(set2->b1-set2->b0); return 1; } void ConvertTo8bit(int coltype, int size, unsigned char *pOut1, unsigned char *pOut2) { int i, j, k, n, trans, colors8, colors7, weight; unsigned int c; unsigned char r, g, b, a; unsigned char * ps; unsigned char * pd; unsigned int * pt; unsigned int bit[256]; box cube[256]; double temp; double vv[256]; if (coltype == 2 || coltype == 4 || coltype == 6 || keep_original == 0) { memset(pal, 0, 256*3); for (i=0; i<256; i++) bit[i] = ((i>>7)&1) + ((i>>6)&1) + ((i>>5)&1) + ((i>>4)&1) + ((i>>3)&1) + ((i>>2)&1) + ((i>>1)&1) + (i&1); memset(bigcube, 0, 128*128*128); trans = 0; ps = pOut2; if (bcolor == -1) { for (i=0; i= tlevel) bigcube[r>>1][g>>1][b>>1] |= (1<<(((r&1)<<2) + ((g&1)<<1) + (b&1))); else trans = 1; } if (coltype == 2 && trnssize > 0) { pal[0][0] = (unsigned char)trns1; pal[0][1] = (unsigned char)trns2; pal[0][2] = (unsigned char)trns3; } } else { for (i=0; i 0) { if (a < 255) { ps[0] = r = (r*a + back_r*(255-a))/255; ps[1] = g = (g*a + back_g*(255-a))/255; ps[2] = b = (b*a + back_b*(255-a))/255; ps[3] = 255; } bigcube[r>>1][g>>1][b>>1] |= (1<<(((r&1)<<2) + ((g&1)<<1) + (b&1))); } else trans = 1; } pal[0][0] = back_r; pal[0][1] = back_g; pal[0][2] = back_b; } colors8 = colors7 = trans; for (i=0; i<128; i++) for (j=0; j<128; j++) for (k=0; k<128; k++) if ((a = bigcube[i][j][k]) != 0) { colors8 += bit[a]; colors7++; } printf("%d colors.\n", colors8); if (colors8<=256) { if (colors8<256) trans = 1; palsize = trans; trns_idx = -1; if (trans) trns_idx = 0; for (i=0; i<128; i++) for (j=0; j<128; j++) for (k=0; k<128; k++) if ((a = bigcube[i][j][k]) != 0) { for (n=0; n<8; n++, a>>=1) if (a&1) { pal[palsize][0] = (i<<1) + ((n>>2)&1); pal[palsize][1] = (j<<1) + ((n>>1)&1); pal[palsize][2] = (k<<1) + (n&1); palsize++; } } ps = pOut2; pd = pOut1; for (i=0; i= tlevel) { for (c=trans; c= tlevel) { r &= 0xFE; g &= 0xFE; b &= 0xFE; for (c=trans; c1) ? WuVariance(&cube[n]) : (double)0.0; vv[i] = (cube[i].vol>1) ? WuVariance(&cube[i]) : (double)0.0; } else { vv[n] = (double)0.0; i--; } palsize = i+1; n = 1; temp = vv[1]; for (k=2; k<=i; k++) if (vv[k] > temp) { temp = vv[k]; n = k; } if (temp <= 0.0) break; } memset(tag, 0, 65*65*65); for (c=1; c= 0) { ps = pOut1; for (i=0; i= 0) { if (bcolor != -1) { pal[0][0] = back_r; pal[0][1] = back_g; pal[0][2] = back_b; } else if (trnssize > 0) { pal[0][0] = (unsigned char)trns1; pal[0][1] = (unsigned char)trns1; pal[0][2] = (unsigned char)trns1; } palsize++; } for (i=0; i<256; i++) if (gray[i] != 0) { pal[palsize][0] = i; pal[palsize][1] = i; pal[palsize][2] = i; palsize++; } ps = pOut1; if (trns_idx == -1) { for (i=0; i= 8) { buf[++buf[0]] = accum & 255; accum >>= 8; bits -= 8; if (buf[0] == 255) { if (fwrite(buf, 1, 256, f1) != 256) return 1; buf[0] = 0; } } return 0; } int EncodeLZW(unsigned char * data, int datasize, FILE * f1, unsigned char mincodesize) { int hash[65536]; int dict[65536]; int i; int clearcode, nextcode, cw, addr, w; unsigned char c; if (mincodesize == 1) mincodesize++; if (fwrite(&mincodesize, 1, 1, f1) != 1) return 1; memset(&hash, 0, sizeof(hash)); clearcode = 1 << mincodesize; codesize = mincodesize + 1; nextcode = clearcode + 2; accum = 0; bits = 0; buf[0] = 0; if (outcode(clearcode, f1)) return 1; w = *data++; for (i=1; i>8)&0xFF, h&0xFF, (h>>8)&0xFF, 0, (trns_idx >= 0) ? trns_idx : 0, 0}; unsigned char netscape[19] = {0x21, 0xFF, 0x0B, 'N', 'E', 'T', 'S', 'C', 'A', 'P', 'E', '2', '.', '0', 3, 1, loops&0xFF, (loops>>8)&0xFF, 0}; unsigned char gce[8] = {0x21, 0xF9, 4, 4, 10, 0, (trns_idx >= 0) ? trns_idx : 0, 0}; unsigned char img_head[10] = {0x2C, 0, 0, 0, 0, w&0xFF, (w>>8)&0xFF, h&0xFF, (h>>8)&0xFF, 0}; unsigned char bits = 7; unsigned char end = 0x3B; unsigned char trns_bit = (trns_idx >= 0) ? 1 : 0; unsigned char *ptemp; unsigned char *pa; unsigned char *pb; unsigned char *pc; int i, j, n, disp0, x0, y0, w0, h0, x1, y1, w1, h1; int x_min, y_min, x_max, y_max; int imagesize = w * h; int res = 1; FILE * f1; if ((f1 = fopen(szOut, "wb")) == 0) { printf("Error: can't open '%s'\n", szOut); return res; } if ((ptemp = (unsigned char *)malloc(imagesize)) == 0) { printf("Error: not enough memory\n"); return res; } printf("Writing '%s'...\n", szOut); do { if (palsize <= 2) bits = 0; else if (palsize <= 4) bits = 1; else if (palsize <= 8) bits = 2; else if (palsize <= 16) bits = 3; else if (palsize <= 32) bits = 4; else if (palsize <= 64) bits = 5; else if (palsize <= 128) bits = 6; gif_head[10] = 0x80 + 0x11*bits; bits++; palsize = 1 << bits; if (fwrite(gif_head, 1, 13, f1) != 13) break; if (fwrite(pal, 3, palsize, f1) != palsize) break; if (fwrite(netscape, 1, 19, f1) != 19) break; x0 = x1 = 0; y0 = y1 = 0; w0 = w1 = w; h0 = h1 = h; for (n=0; n x_max) x_max = i; if (j < y_min) y_min = j; if (j > y_max) y_max = j; if (trns_idx >= 0) { if (*pb == trns_idx && *pa != trns_idx) { disp0 = 2; if (i < x0) { w0 += x0-i; x0 = i; }; if (i >= x0+w0) { w0 = i-x0+1; }; if (j < y0) { h0 += y0-j; y0 = j; }; if (j >= y0+h0) { h0 = j-y0+1; }; } } } pa++; pb++; } if (x_min <= x_max) { x1 = x_min; y1 = y_min; w1 = x_max-x_min+1; h1 = y_max-y_min+1; } else { x1 = y1 = 0; w1 = h1 = 1; } } pc = ptemp; pb = pimg + imagesize*n + y0*w + x0; if (trns_idx >= 0 && n > 0) { pa = pb - imagesize; for (j=0; j>8; img_head[1] = x0&0xFF; img_head[2] = (x0>>8)&0xFF; img_head[3] = y0&0xFF; img_head[4] = (y0>>8)&0xFF; img_head[5] = w0&0xFF; img_head[6] = (w0>>8)&0xFF; img_head[7] = h0&0xFF; img_head[8] = (h0>>8)&0xFF; if (fwrite(gce, 1, 8, f1) != 8) break; if (fwrite(img_head, 1, 10, f1) != 10) break; if (EncodeLZW(ptemp, w0*h0, f1, bits)) break; if (disp0 == 2) { pb = pimg + imagesize*n + y0*w + x0; for (j=0; j x_max) x_max = i; if (j < y_min) y_min = j; if (j > y_max) y_max = j; } } if (x_min <= x_max) { x1 = x_min; y1 = y_min; w1 = x_max-x_min+1; h1 = y_max-y_min+1; } else { x1 = y1 = 0; w1 = h1 = 1; } } x0 = x1; y0 = y1; w0 = w1; h0 = h1; } if (fwrite(&end, 1, 1, f1) != 1) break; res = 0; } while (0); free(ptemp); fclose(f1); return res; } int main(int argc, char** argv) { char * szIn; char szOut[256]; char * szOpt; char * szExt; unsigned char * pOut1 = NULL; unsigned char * pOut2 = NULL; unsigned short * pDelays = NULL; int i, w, h, coltype, frames, loops; printf("\napng2gif 1.5\n\n"); if (argc <= 1) { printf("Usage : apng2gif anim.png [anim.gif] [/t tlevel] [/b bcolor]\n\n" "tlevel: transparency threshold level (format: /t 128)\n" "bcolor: background blend color (format: /b #808080 or /b 128 128 128)\n" "When /b is used, /t is ignored. Default is /t 128, no bcolor.\n"); return 1; } szIn = argv[1]; szOut[0] = 0; tlevel = 128; bcolor = -1; back_r = back_g = back_b = 0; for (i=2; i 255) tlevel = 128; } } } else if (szOpt[1] == 'b' || szOpt[1] == 'B') { bcolor = 0x808080; back_r = back_g = back_b = 128; if (i>16)&0xFF; back_g = (bcolor>>8)&0xFF; back_b = (bcolor)&0xFF; } else if (i 255) back_r = 255; if (back_g < 0) back_g = 0; if (back_g > 255) back_g = 255; if (back_b < 0) back_b = 0; if (back_b > 255) back_b = 255; bcolor = (back_r<<16) + (back_g<<8) + back_b; } } } } else if (szOut[0] == 0) strcpy(szOut, szOpt); } if (bcolor != -1) tlevel = 1; if (szOut[0] == 0) { strcpy(szOut, szIn); if ((szExt = strrchr(szOut, '.')) != NULL) *szExt = 0; strcat(szOut, ".gif"); } if (LoadAPNG(szIn, &w, &h, &coltype, &frames, &loops, &pOut1, &pOut2, &pDelays) != 0) { printf("Error: can't load '%s'\n", szIn); return 1; } printf("%d frame%s.\n", frames, (frames==1) ? "" : "s"); ConvertTo8bit(coltype, w*h*frames, pOut1, pOut2); if (SaveAGIF(szOut, pOut1, pDelays, w, h, frames, loops) != 0) { printf("Error: can't save '%s'\n", szOut); return 1; } if (pOut1) free(pOut1); if (pOut2) free(pOut2); if (pDelays) free(pDelays); printf("all done\n"); return 0; } apng2gif-1.5.orig/readme.txt0000644000000000000000000000165411717260114014515 0ustar rootroot apng2gif version 1.5 This program converts APNG animations into animated GIF format. Wu quantizer is used for true-color files. http://apng2gif.sourceforge.net/ Copyright (c) 2010-2012 Max Stepin maxst@users.sourceforge.net License: zlib license -------------------------------- Changes in version 1.5: - fixed loading of 1,2,4-bit per pixel paletted APNGs. -------------------------------- Usage (for command-line version): apng2gif anim.png [anim.gif] [/t tlevel] [/b bcolor] Options: /t 128 will set the transparency threshold level as 128, so pixels with alpha level less than 128 will become fully transparent. /b #ff0000 /b 255 0 0 will set the background color as red, so partially transparent pixels will be composed over red. When /b is used, /t is ignored. When no options are specified, default threshold is 128, no background color. apng2gif-1.5.orig/Makefile0000644000000000000000000000005111717260114014145 0ustar rootrootall: gcc -O2 -o apng2gif apng2gif.c -lz