Imported Upstream version 0.72

This commit is contained in:
TANIGUCHI Takaki
2009-11-21 16:29:02 +09:00
commit a39ce4fddf
879 changed files with 252874 additions and 0 deletions

4
tools/Makefile Normal file
View File

@@ -0,0 +1,4 @@
all:
@echo
@echo "Please create a Makefile by entering \"./configure\" first"
@echo

106
tools/Makefile.template Normal file
View File

@@ -0,0 +1,106 @@
######################################################################
# Take over variables from configure
######################################################################
VERSION = $(CFG_VERSION)
SRCDIR = $(CFG_SRCDIR)
PREFIX = $(CFG_PREFIX)
BINDIR = $(CFG_BINDIR)
EFENCE_LFLAGS = $(CFG_EFENCE_LFLAGS)
EFENCE_LIBS = $(CFG_EFENCE_LIBS)
BZ2_INCL = $(CFG_BZ2_INCL)
BZ2_LFLAGS = $(CFG_BZ2_LFLAGS)
BZ2_LIBS = $(CFG_BZ2_LIBS)
PNG_INCL = $(CFG_PNG_INCL)
PNG_LFLAGS = $(CFG_PNG_LFLAGS)
PNG_LIBS = $(CFG_PNG_LIBS)
SYS_OPTIONS = $(CFG_SYS_OPTIONS)
HAVE_OPTIONS = $(CFG_HAVE_OPTIONS)
WITH_OPTIONS = $(CFG_WITH_OPTIONS)
EXE_SUFFIX = $(CFG_EXE_SUFFIX)
LOCATIONS = -DSRCDIR=\"$(SRCDIR)\" -DBINDIR=\"$(BINDIR)\" -DDOCDIR=\"$(DOCDIR)\" -DLOCALEDIR=\"$(LOCALEDIR)\"
COPTS = $(CFLAGS) $(LOCATIONS) $(SYS_OPTIONS) $(HAVE_OPTIONS) $(WITH_OPTIONS) $(BZ2_INCL) $(PNG_INCL)
LOPTS = $(LDFLAGS) $(BZ2_LFLAGS) $(PNG_LFLAGS)
LIBS = $(EFENCE_LIBS) $(BZ2_LIBS) $(PNG_LIBS) -lm
CFILES = $(CFG_CFILES)
OFILES = $(CFG_OFILES)
######################################################################
# Compilation related
######################################################################
.PHONY : show
.c.o:
@echo "Compiling:" $*.c
@$(CC) $(COPTS) -DPNGPACK -c $*.c
# Note that we build a self-contained (statically linked) pngpack.exe
# under Windows so that we do not have to ship the .dll files for
# bzip2, libpng, and zlib.
pngpack: $(OFILES)
@echo "Linking : pngpack";
@if test $(CFG_SYS_OPTIONS) == -DSYS_MINGW; \
then $(CC) $(LOPTS) $(OFILES) $(LIBS) -lz --static -o pngpack; \
else $(CC) $(LOPTS) $(OFILES) $(LIBS) -o pngpack; \
fi
show:
@echo -e "Current build configuration in ./Makefile:\n"
@echo "VERSION = " $(VERSION)
@echo "CC = " $(CC)
@echo "MAKE = " $(MAKE)
@echo "SHELL = " $(SHELL)
@echo "SRCDIR = " $(SRCDIR)
@echo "PREFIX = " $(PREFIX)
@echo "BINDIR = " $(BINDIR)
@echo
@echo "EFENCE_LFLAGS= " $(EFENCE_LFLAGS)
@echo "EFENCE_LIBS = " $(EFENCE_LIBS)
@echo
@echo "PNG_LFLAGS = " $(PNG_LFLAGS)
@echo "PNG_LIBS = " $(PNG_LIBS)
@echo
@echo "SYS_OPTIONS = " $(SYS_OPTIONS)
@echo "EXE_SUFFIX = " $(EXE_SUFFIX)
@echo "HAVE_OPTIONS = " $(HAVE_OPTIONS)
@echo "WITH_OPTIONS = " $(WITH_OPTIONS)
@echo
@echo "CFLAGS = " $(CFLAGS)
@echo "COPTS = " $(COPTS)
@echo "LDFLAGS = " $(LDFLAGS)
@echo "LOPTS = " $(LOPTS)
@echo "LIBS = " $(LIBS)
######################################################################
# Distribution management
######################################################################
.PHONY : clean distclean
distclean:
@echo "Removing local .png and .pngpack files in ./tools"
@rm -f *.png
@echo "Removing symbolic links in ./tools"
@rm -f md5.h md5.c
@echo "Removing configuration files in ./tools"
@rm -f configure.log Makefile.config Makefile
@echo "all:" >>Makefile
@echo -e "\t@echo" >>Makefile
@echo -e "\t@echo \"Please create a Makefile by entering \\\"./configure\\\" first\"" >>Makefile
@echo -e "\t@echo" >>Makefile
clean:
@echo "Removing rebuildable files in ./tools"
@rm -rf *.o pngpack *.exe *.dll *.dll.a core *.stackdump
@find . -name \*\~ -print | xargs rm -f;

31
tools/README Normal file
View File

@@ -0,0 +1,31 @@
pngpack: lossless image compression for a series of screen shots
Copyright (C) 2005-2009 Carsten Gnoerlich.
pngpack is a specialized archival format for distributing screen
shots (which are typically shipped with on-line documentation).
pngpack provides lossless compression which exploits redundancy
in a series of images. For example, if you have a collection of
screen shots which all contain a "Quit" button, the image of the
"Quit" button is stored once and will then be re-used in all other
images.
In a typical scenario, a single image compresses about
30-40% better than PNG, and a series of 10 similar images
can save upto 90% of the storage if PNG had been used.
However, no offense is intended against PNG - PNG is a great
general purpose format and it is actually used as input and
output format for pngpack.
In order to get the best compression out of pngpack,
use images with a regular structure and very few colors.
pngpack works best with screen shots of user interfaces
and simple computer generated charts and slides.
Avoid including color gradients, background patterns and
photorealistic backgrounds. For screen shots, do not use
theming and use a single color for your window and desktop
background.

701
tools/codec.c Normal file
View File

@@ -0,0 +1,701 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <bzlib.h>
#include "pngio.h"
#include "codec.h"
#include "md5.h"
#include "memory.h"
/***
*** Find most used color
***/
static void find_background(Image *pi)
{ unsigned int *pixel,*count,*color,size,t_used,t_max,i,max_color;
color = calloc(4, sizeof(unsigned int));
count = calloc(4, sizeof(unsigned int));
t_used = 1;
t_max = 4;
size = pi->width * pi->height;
pixel = pi->image;
color[0] = *pixel;
while(size--)
{ for(i=0; i<t_used; i++)
if(color[i] == *pixel)
{ count[i]++;
break;
}
if(i == t_used)
{ t_used++;
if(t_used == t_max)
{ t_max *= 2;
color = realloc(color, t_max * sizeof(unsigned int));
count = realloc(count, t_max * sizeof(unsigned int));
if(!color && !count) Stop("out of memory enlarging color table to %d", t_max);
}
color[t_used-1] = *pixel;
count[t_used-1] = 1;
}
pixel++;
}
max_color = 0;
for(i=0; i<t_used; i++)
if(count[i] > max_color)
{ max_color += count[i];
pi->tile_background = color[i];
}
fprintf(stdout, " %d colors, tile background is %x (%d pixels).\n", t_used,pi->tile_background,max_color);
free(color);
free(count);
}
/***
*** Maintain the tile database
***/
typedef struct
{ unsigned int image[MAX_TILE_SIZE][MAX_TILE_SIZE];
unsigned int width, height;
unsigned int background;
} tile;
typedef struct
{ unsigned int image[2*MAX_TILE_SIZE][MAX_TILE_SIZE];
unsigned int width, height;
unsigned int basey;
unsigned int basex,minx,maxx;
} work_tile;
typedef struct
{ int x,y; /* Position of tile */
unsigned int n; /* Index of tile */
} opcode;
Image **img_list;
unsigned int img_n,img_max;
tile **tile_db;
unsigned int db_n,db_max;
opcode *oc_list;
unsigned int oc_n,oc_max;
void InitTileDatabase()
{
img_max = db_max = oc_max = 4;
img_list = malloc(sizeof(Image*)*img_max);
tile_db = malloc(sizeof(tile*)*db_max);
oc_list = malloc(sizeof(opcode)*oc_max);
}
void FreeTileDatabase()
{ int i;
for(i=0; i<img_n; i++)
free(img_list[i]);
free(img_list);
for(i=0; i<db_n; i++)
free(tile_db[i]);
free(tile_db);
free(oc_list);
}
static void add_image(Image *pi)
{
if(++img_n >= img_max)
{ img_max *= 2;
img_list = realloc(img_list, sizeof(Image*)*img_max);
if(!img_list) Stop("out of memory expanding image list");
}
img_list[img_n-1] = pi;
}
static int tilecmp(tile *a, tile *b)
{ unsigned int i,j;
if(a->width != b->width || a->height != b->height) return 1;
for(j=0; j<a->height; j++)
for(i=0; i<a->width; i++)
if( a->image[i][j] != b->image[i][j]
&& (a->image[i][j] != a->background || b->image[i][j] != b->background)
)
return 1;
return 0;
}
static int add_tile(tile *new_tile, int x, int y)
{ unsigned int idx;
opcode *lidx;
int new_needed = 1;
for(idx = 0; idx < db_n; idx++)
if(!tilecmp(new_tile, tile_db[idx]))
{ new_needed = 0;
break;
}
if(new_needed)
{ idx = db_n;
if(++db_n >= db_max)
{ db_max *= 2;
tile_db = realloc(tile_db, sizeof(tile*)*db_max);
if(!tile_db) Stop("out of memory expanding tile data base");
}
tile_db[idx] = malloc(sizeof(tile));
if(!tile_db[idx]) Stop("out of memory adding tile to the data base");
memcpy(tile_db[idx], new_tile, sizeof(tile));
}
if(++oc_n >= oc_max)
{ oc_max *= 2;
oc_list = realloc(oc_list, sizeof(opcode)*oc_max);
if(!oc_list) Stop("out of memory expanding opcode table");
}
lidx = &oc_list[oc_n - 1];
lidx->x = x;
lidx->y = y;
lidx->n = idx;
return new_needed;
}
/***
*** Transform image into tiles
***/
unsigned int clr[] = { 0xff0000, 0x00ff00, 0xffff00, 0x00ffff, 0x0000ff };
#define PIXEL(pi,px,py) (pi->image[(px)+(py)*pi->width])
static void create_tile(Image *pi, work_tile *t, unsigned int x, unsigned int y)
{
/* Stop recursion if background or maximal tile size is reached */
if( (x < t->minx || x > t->maxx)
&& t->maxx-t->minx >= MAX_TILE_SIZE-1)
return;
if(y < t->basey) return;
if(y - t->basey >= MAX_TILE_SIZE) return;
if(PIXEL(pi,x,y) == pi->tile_background)
return;
/* Add current pixel to the tile */
t->image[(MAX_TILE_SIZE+x)-t->basex][y-t->basey] = PIXEL(pi,x,y);
if(x < t->minx) { t->minx=x; t->width = t->maxx - t->minx + 1; }
if(x > t->maxx) { t->maxx=x; t->width = t->maxx - t->minx + 1; }
if(y - t->basey + 1 > t->height) t->height = y - t->basey + 1;
PIXEL(pi,x,y) = pi->tile_background;
/* Recursively check the neighboring pixels */
if(x>0) create_tile(pi, t, x-1, y);
if(x<pi->width-1) create_tile(pi, t, x+1, y);
if(y>0) create_tile(pi, t, x, y-1);
if(y<pi->height-1) create_tile(pi, t, x, y+1);
}
static void create_tiles(Image *pi)
{ work_tile *wt = malloc(sizeof(work_tile));
tile *t = malloc(sizeof(tile));
unsigned int x,y;
// int cidx=0;
int n_tiles = 0;
int r_tiles = 0;
int deltax,deltay;
int lastx = 0, lasty = 0;
t->background = pi->tile_background;
for(y=0; y<pi->height; y++)
for(x=0; x<pi->width; x++)
{ int i,j,off;
if(PIXEL(pi,x,y) == pi->tile_background)
continue;
/* initialize the tile */
for(i=0; i<2*MAX_TILE_SIZE; i++)
for(j=0; j<MAX_TILE_SIZE; j++)
wt->image[i][j] = pi->tile_background;
wt->width = wt->height = 1;
wt->basey = y;
wt->basex = wt->minx = wt->maxx = x;
create_tile(pi, wt, x, y);
off = (MAX_TILE_SIZE + wt->minx) - wt->basex;
for(i=0; i<MAX_TILE_SIZE; i++)
for(j=0; j<MAX_TILE_SIZE; j++)
t->image[i][j] = wt->image[i+off][j];
t->width = wt->width;
t->height = wt->height;
deltax = x+wt->minx-wt->basex - lastx;
deltay = y - lasty;
if(add_tile(t, deltax, deltay)) n_tiles++;
else r_tiles++;
lastx += deltax;
lasty = y;
}
fprintf(stdout, " %d new tiles, %d reused tiles\n",n_tiles,r_tiles);
#if 0
lastx = lasty = 0;
for(x=0; x<oc_n; x++)
{ tile *t;
opcode *oc;
int i,j;
oc = &oc_list[x];
t = tile_db[oc->n];
lastx += oc->x;
lasty += oc->y;
for(i=0; i<t->width; i++)
for(j=0; j<t->height; j++)
if(t->image[i][j] != pi->tile_background)
#if 1
PIXEL(pi, i+lastx, j+lasty) = clr[cidx];
#else
PIXEL(pi, i+lastx, j+lasty) = t->image[i][j];
#endif
cidx = (cidx+1)%5;
}
#endif
free(wt);
free(t);
}
/***
*** .ppk format loading and saving
***/
static void bz_write(BZFILE *b, void *buf, int size)
{ int bzerror;
BZ2_bzWrite(&bzerror, b, buf, size);
if(bzerror != BZ_OK)
{ BZ2_bzWriteClose(&bzerror, b, 0, NULL, NULL);
Stop("Write error in bz2 library: %s\n",strerror(errno));
}
}
static void save_int(BZFILE *file, int value)
{ unsigned char buf[4];
int bzerror;
buf[0] = value>>24 & 0xff;
buf[1] = value>>16 & 0xff;
buf[2] = value>> 8 & 0xff;
buf[3] = value & 0xff;
BZ2_bzWrite(&bzerror, file, buf, 4);
if(bzerror != BZ_OK)
{ BZ2_bzWriteClose(&bzerror, file, 0, NULL, NULL);
Stop("Write error in bz2 library: %s\n",strerror(errno));
}
}
static void save_uint(BZFILE *file, unsigned int value)
{ unsigned char buf[4];
int bzerror;
buf[0] = value>>24 & 0xff;
buf[1] = value>>16 & 0xff;
buf[2] = value>> 8 & 0xff;
buf[3] = value & 0xff;
BZ2_bzWrite(&bzerror, file, buf, 4);
if(bzerror != BZ_OK)
{ BZ2_bzWriteClose(&bzerror, file, 0, NULL, NULL);
Stop("Write error in bz2 library: %s\n",strerror(errno));
}
}
void SavePPK(char *name)
{ FILE *file;
BZFILE *bzfile;
unsigned int i;
int bzerror;
fprintf(stdout, "Compressing pingpack archive...");
fflush(stdout);
file = fopen(name, "wb");
if(!file)
Stop("Could not open %s: %s\n",name,strerror(errno));
bzfile = BZ2_bzWriteOpen(&bzerror, file, 9, 0, 30);
if(bzerror != BZ_OK)
Stop("Could not open %s for bz2\n",name);
/* The header contains the string ".pngpack", four zeros and the FILEFORMAT as a 4 byte value. */
bz_write(bzfile, ".pngpack", 8);
save_int(bzfile, 0);
save_int(bzfile, FILEFORMAT);
/* The image section contains the string "Images\000\000",
the number of images as a 4 byte value,
and the image description itself.
The image name is preceeded by its length as a 4 byte value. */
bz_write(bzfile, "Images\000\000", 8);
save_int(bzfile, img_n);
for(i=0; i<img_n; i++)
{ Image *pi = img_list[i];
unsigned int len = strlen(pi->name);
save_uint(bzfile, pi->width);
save_uint(bzfile, pi->height);
bz_write(bzfile, pi->checksum, 16);
save_uint(bzfile, pi->tile_background);
save_uint(bzfile, pi->png_background);
save_uint(bzfile, pi->channels);
save_uint(bzfile, pi->first_opcode);
save_uint(bzfile, pi->last_opcode);
save_uint(bzfile, len);
bz_write(bzfile, pi->name, len);
}
/* The opcode section contains the string "Opcodes\000",
the number of opcodes as a 4 byte value,
and then the opcodes itself. */
bz_write(bzfile, "Opcodes\000", 8);
save_uint(bzfile, oc_n);
for(i=0; i<oc_n; i++)
{ opcode *oc = &oc_list[i];
save_int(bzfile, oc->x);
save_int(bzfile, oc->y);
save_uint(bzfile, oc->n);
}
/* The tile section contains the string "Tiles\000\000\000",
the number of tiles as a 4 byte value,
and then the tiles itself. */
bz_write(bzfile, "Tiles\000\000\000", 8);
save_uint(bzfile, db_n);
for(i=0; i<db_n; i++)
{ tile *t = tile_db[i];
unsigned int x,y;
save_uint(bzfile, t->width);
save_uint(bzfile, t->height);
for(y=0; y<t->height; y++)
for(x=0; x<t->width; x++)
save_uint(bzfile, t->image[x][y]);
}
BZ2_bzWriteClose(&bzerror, bzfile, 0, NULL, NULL);
if(bzerror != BZ_OK)
Stop("Failed to close bz2 file handle: %s\n",strerror(errno));
if(fclose(file))
Stop("Could not close %s: %s\n",name,strerror(errno));
fprintf(stdout, "DONE.\n");
}
static void bz_read(BZFILE *b, void *buf, int size)
{ int bzerror,ignore;
BZ2_bzRead(&bzerror, b, buf, size);
if(bzerror != BZ_OK && bzerror != BZ_STREAM_END)
{ BZ2_bzReadClose(&ignore, b);
Stop("Read error in bz2 library: %d,%s\n",bzerror,strerror(errno));
}
}
static int load_int(BZFILE *file)
{ unsigned char buf[4];
int bzerror, ignore;
BZ2_bzRead(&bzerror, file, buf, 4);
if(bzerror != BZ_OK && bzerror != BZ_STREAM_END)
{ BZ2_bzReadClose(&ignore, file);
Stop("Read error in bz2 library: %d,%s\n",bzerror,strerror(errno));
}
return buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
}
static unsigned int load_uint(BZFILE *file)
{ unsigned char buf[4];
int bzerror,ignore;
BZ2_bzRead(&bzerror, file, buf, 4);
if(bzerror != BZ_OK && bzerror != BZ_STREAM_END)
{ BZ2_bzReadClose(&ignore, file);
Stop("Read error in bz2 library: %d,%s\n",bzerror,strerror(errno));
}
return buf[0]<<24 | buf[1]<<16 | buf[2]<<8 | buf[3];
}
void LoadPPK(char *name, Image ***list_out, int *n_out)
{ FILE *file;
BZFILE *bzfile;
char header[9];
unsigned int i,file_format;
int bzerror;
int j;
file = fopen(name, "rb");
if(!file)
Stop("Could not open %s: %s\n",name,strerror(errno));
bzfile = BZ2_bzReadOpen(&bzerror, file, 0, 0, NULL, 0);
if(bzerror != BZ_OK)
Stop("Could not open %s for bz2\n",name);
/* evaluate the header */
bz_read(bzfile, header, 8);
if(strncmp(header, ".pngpack", 8))
Stop("%s is not a pngpack file",name);
file_format = load_int(bzfile); /* always zero */
file_format = load_int(bzfile);
/* read the image list */
bz_read(bzfile, header, 8);
if(strncmp(header, "Images\000\000", 8))
Stop("%s: missing images chunk",name);
img_n = load_uint(bzfile);
img_list = realloc(img_list, sizeof(Image*)*img_n);
if(!img_list) Stop("out of memory allocating the image table");
fprintf(stdout, "%s contains %d images:\n",name,img_n);
for(i=0; i<img_n; i++)
{ int len;
Image *pi;
pi = img_list[i] = malloc(sizeof(Image));
if(!pi) Stop("out of memory allocating image structure");
pi->width = load_uint(bzfile);
pi->height = load_uint(bzfile);
bz_read(bzfile, pi->checksum, 16);
pi->tile_background = load_uint(bzfile);
pi->png_background = load_uint(bzfile);
pi->channels = load_uint(bzfile);
pi->first_opcode = load_uint(bzfile);
pi->last_opcode = load_uint(bzfile);
len = load_uint(bzfile);
pi->name = malloc(len+1);
if(!pi->name) Stop("out of memory allocating image name");
bz_read(bzfile, pi->name, len);
pi->name[len] = 0;
fprintf(stdout, "%4d x %4d: %s\n",pi->width,pi->height,pi->name);
}
/* read the opcode list */
bz_read(bzfile, header, 8);
if(strncmp(header, "Opcodes\000", 8))
Stop("%s: missing opcodes chunk",name);
oc_n = load_uint(bzfile);
oc_list = realloc(oc_list,sizeof(opcode)*oc_n);
if(!oc_list) Stop("out of memory allocating the opcode table");
for(i=0; i<oc_n; i++)
{ opcode *oc = &oc_list[i];
oc->x = load_int(bzfile);
oc->y = load_int(bzfile);
oc->n = load_uint(bzfile);
}
/* read the tile list */
bz_read(bzfile, header, 8);
if(strncmp(header, "Tiles\000\000\000", 8))
Stop("%s: missing tiles chunk",name);
db_n = load_uint(bzfile);
tile_db = realloc(tile_db,sizeof(tile*)*db_n);
if(!tile_db) Stop("out of memory allocating the tile data base");
for(i=0; i<db_n; i++)
{ tile *t = malloc(sizeof(tile));
unsigned int x,y;
if(!t) Stop("out of memory allocating more tiles");
tile_db[i] = t;
t->width = load_uint(bzfile);
t->height = load_uint(bzfile);
for(y=0; y<t->height; y++)
for(x=0; x<t->width; x++)
t->image[x][y] = load_uint(bzfile);
}
fprintf(stdout, "%d tiles, %d opcodes\n\n", db_n, oc_n);
BZ2_bzReadClose(&bzerror, bzfile);
if(bzerror != BZ_OK)
Stop("Failed to close bz2 file handle: %s\n",strerror(errno));
fclose(file);
/* restore original background value of each tile */
for(j=img_n-1; j>=0; j--)
{ Image *pi = img_list[j];
for(i=pi->first_opcode; i<=pi->last_opcode; i++)
{ opcode *oc = &oc_list[i];
tile *t = tile_db[oc->n];
t->background = pi->tile_background;
}
}
*n_out = img_n;
*list_out = img_list;
}
/***
*** Encode image (add it to the tile data base)
***/
void EncodeImage(Image *pi)
{
pi->first_opcode = oc_n;
find_background(pi);
add_image(pi);
create_tiles(pi);
pi->last_opcode = oc_n-1;
}
/***
*** Render image from the ppk
***/
void RenderImage(Image *pi)
{ struct MD5Context md5ctxt;
unsigned char checksum[16];
unsigned int oidx,i,*p;
unsigned int background;
int x=0, y=0;
/* Clear the image */
i = pi->width * pi->height;
p = pi->image;
#ifdef HAVE_LITTLE_ENDIAN
background = pi->tile_background;
while(i--)
*p++ = background;
#else
background = SwapBytes32(pi->tile_background);
while(i--)
*p++ = background;
#endif
/* Render it */
for(oidx=pi->first_opcode; oidx<=pi->last_opcode; oidx++)
{ tile *t;
opcode *oc;
unsigned int i,j;
oc = &oc_list[oidx];
t = tile_db[oc->n];
x += oc->x;
y += oc->y;
for(i=0; i<t->width; i++)
for(j=0; j<t->height; j++)
if(t->image[i][j] != t->background)
#ifdef HAVE_LITTLE_ENDIAN
PIXEL(pi, i+x, j+y) = t->image[i][j];
#else
PIXEL(pi, i+x, j+y) = SwapBytes32(t->image[i][j]);
#endif
}
/* verify md5sum */
MD5Init(&md5ctxt);
MD5Update(&md5ctxt, (unsigned char*)pi->image, pi->bytesize);
MD5Final(checksum, &md5ctxt);
if(!memcmp(pi->checksum, checksum, 16))
fprintf(stdout, "\n");
else fprintf(stdout, " - DECODING FAILURE (checksum error).\n");
}

34
tools/codec.h Normal file
View File

@@ -0,0 +1,34 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#ifndef CODEC_H
#define CODEC_H
#define FILEFORMAT 1
#define MAX_TILE_SIZE 32
void InitTileDatabase();
void FreeTileDatabase();
void RenderImage(Image*);
void EncodeImage(Image*);
void LoadPPK(char*, Image***, int*);
void SavePPK(char*);
#endif /* CODEC_H */

105
tools/configure vendored Executable file
View File

@@ -0,0 +1,105 @@
#! /bin/bash
# Load the shell functions needed for the rest of this script.
BASH_BASED_CONFIGURE=../scripts/bash-based-configure
REQUIRED_CFLAGS="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE"
RECOMMENDED_CFLAGS="-O2 -Wall"
DEBUG_CFLAGS="-ggdb -Wall"
CFG_USE_CYGWIN="no" # do not change
if test -e $BASH_BASED_CONFIGURE; then
source $BASH_BASED_CONFIGURE
else
echo "Could not find $BASH_BASED_CONFIGURE"
echo "You're probably not in the right directory."
exit 1
fi
# Set the package name and version
PACKAGE pngpack 0.11
# Check for some essential tools.
REQUIRE_GMAKE
REQUIRE_GCC
# Find out and verify the basedir of the source installation,
# and where to install the binary.
GET_SRCDIR Makefile.template
GET_PREFIX /usr/local
GET_BINDIR
# Look for required libraries
PRINT_MESSAGE "\nLooking for includes and libraries:"
REQUIRE_INCLUDE bzlib.h bz2
REQUIRE_LIBRARY bz2 BZ2_bzReadOpen bz2
REQUIRE_INCLUDE png.h png
REQUIRE_LIBRARY png png_sig_cmp png
# Byte order
echo
CHECK_ENDIAN
WITH_OPTION memdebug no "[no | yes]"
# Do not proceed further if in --help mode
if test -n "$cfg_help_mode"; then
FINALIZE_HELP
exit 0
fi
# Fetch the source files and build the CFILES/OFILES list
PRINT_MESSAGE "\nCollecting source files:"
if ! test -e md5.h; then ln -s ../md5.h md5.h; fi
if ! test -e md5.c; then ln -s ../md5.c md5.c; fi
rm -f conftest.c
cfiles=
ofiles=
for cfile in *.c; do
cfile_prefix=`echo $cfile | sed -e 's/\.c//'`
cfiles="$cfiles $cfile"
ofiles="$ofiles $cfile_prefix.o"
echo -n " $cfile_prefix"
done
echo
echo -e "\nCFG_CFILES = $cfiles" >> Makefile.config
echo "CFG_OFILES = $ofiles" >> Makefile.config
# Okay, hopefully we've got everything together now.
CREATE_MAKEFILES Makefile
echo
echo "Configuration is complete."
echo "Type 'make show' to verify the settings,"
echo "or enter 'make' to start the build immediately."
echo
if test -n "$CFLAGS"; then
echo "* Note that your \$CFLAGS=$CFLAGS"
echo "* have been included into the configuration."
echo "* It is recommended not to specify additional \$CFLAGS,"
echo "* but feel free to continue at your own risk."
echo
fi
if test -n "$LDFLAGS"; then
echo "* Note that your \$LDFLAGS=$LDFLAGS"
echo "* have been included into the configuration."
echo "* It is recommended not to specify additional \$LDFLAGS,"
echo "* but feel free to continue at your own risk."
echo
fi

127
tools/decimate.c Normal file
View File

@@ -0,0 +1,127 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "pngio.h"
#include "memory.h"
/*
* Thumbnail generation
*/
void SaveThumbnail(Image *pi, char *name, int thumb_size, char *thumb_dir)
{ Image *thumb;
char tname[strlen(thumb_dir)+strlen(name)+2];
double ratio, inv_ratio;
unsigned int size, *pixel;
int i,j;
/* sanity check */
if(pi->width < thumb_size && pi->height < thumb_size)
{ fprintf(stdout, "... NOT creating thumbnail because of image size (%dx%d)\n",
pi->width, pi->height);
return;
}
/* Create thumbnail copy from image */
thumb=malloc(sizeof(Image));
memcpy(thumb, pi, sizeof(Image));
if(thumb->width > thumb->height)
inv_ratio = (double)thumb->width/(double)thumb_size;
else inv_ratio = (double)thumb->height/(double)thumb_size;
ratio = 1.0/inv_ratio;
thumb->width = (int)((double)thumb->width*ratio+0.5);
thumb->height = (int)((double)thumb->height*ratio+0.5);
sprintf(tname, "%s/%s", thumb_dir, name);
fprintf(stdout, "... and %dx%d thumbnail %s\n", thumb->width, thumb->height, tname);
size = thumb->width * thumb->height;
thumb->bytesize = sizeof(unsigned int) * size;
thumb->image = malloc(thumb->bytesize);
if(!thumb->image) Stop("out of memory for image");
/*
* Decimate the image
*/
pixel = thumb->image;
for(i=0; i<thumb->height; i++)
for(j=0; j<thumb->width; j++)
{ double first_x = j*inv_ratio;
double first_y = i*inv_ratio;
double last_x = (j+1)*inv_ratio;
double last_y = (i+1)*inv_ratio;
double area = 0.0;
int x0 = floor(first_x);
int x1 = ceil(last_x);
int y0 = floor(first_y);
int y1 = ceil(last_y);
int x,y;
double c1,c2,c3,c4;
unsigned int ci1,ci2,ci3,ci4;
#if 0
printf("%d %d -> (%d %d) - (%d %d)\n", j,i, x0,y0, x1, y1);
printf("%f %f %f %f\n", first_x, first_y, last_x, last_y);
printf("%f %f\n", ratio, inv_ratio);
#endif
if(x1>=pi->width) x1=pi->width-1;
if(y1>=pi->height) y1=pi->height-1;
c1 = c2 = c3 = c4 = 0.0;
for(y=y0; y<=y1; y++)
{ double ysize = 1.0;
double size;
if(y<y0) ysize = 1.0-(y0-y);
if(y>y1) ysize = 1.0-(y-y1);
for(x=x0; x<=x1; x++)
{ int idx = x+y*pi->width;
size = ysize;
if(x<x0) size *= (1.0-(x0-x));
if(x>x1) size *= (1-0-(x-x1));
c1 += size * ((pi->image[idx]>>24)&0xff);
c2 += size * ((pi->image[idx]>>16)&0xff);
c3 += size * ((pi->image[idx]>> 8)&0xff);
c4 += size * ((pi->image[idx] )&0xff);
area += size;
}
}
ci1 = c1/area; ci2 = c2/area; ci3 = c3/area; ci4 = c4/area;
*pixel++ = (ci1<<24) | (ci2<<16) | (ci3<<8) | ci4;
}
SavePNG(thumb, tname);
free(thumb->image);
free(thumb);
}

25
tools/decimate.h Normal file
View File

@@ -0,0 +1,25 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#ifndef DECIMATE_H
#define DECIMATE_H
void SaveThumbnail(Image*, char*, int, char*);
#endif /* DECIMATE_H */

293
tools/memory.c Normal file
View File

@@ -0,0 +1,293 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#if !defined(SYS_FREEBSD) && !defined(SYS_DARWIN) /* FreeBSD declares malloc() in stdlib.h */
#include <malloc.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Endian fiddling
*/
unsigned int SwapBytes32(unsigned int in)
{
return
((in & 0xff000000) >> 24)
| ((in & 0x00ff0000) >> 8)
| ((in & 0x0000ff00) << 8)
| ((in & 0x000000ff) << 24);
}
/*
* Tell user that current action was aborted due to a serious error.
*/
void Stop(char *format, ...)
{ va_list argp;
/*** Show message depending on commandline / GUI mode */
fprintf(stdout, "*\n* pngpack - can not continue:\n*\n");
va_start(argp, format);
vfprintf(stdout, format, argp);
va_end(argp);
fprintf(stdout, "\n\n");
fflush(stdout);
exit(EXIT_FAILURE);
}
/***
*** Keeping track of allocated pointers.
***/
/*
* A structure containing info about each pointer which was
* produced through our memory allocation routines.
*/
typedef struct _memchunk
{ void *ptr; /* allocated memory chunk */
int size; /* size of chunk */
char *file; /* source file this was allocated in */
int line; /* line number of source file */
} memchunk;
static struct _memchunk **ptrhash[64]; /* 64 buckets of memory chunks */
static int phCnt[64];
static int phMax[64];
static int currentAllocation; /* current memory allocation */
static int peakAllocation; /* maximum allocation */
/*
* Remember an allocated pointer.
*/
void remember(void *ptr, int size, char *file, int line)
{ memchunk *mc;
int hash_idx;
hash_idx = (((long)ptr)>>3)&63;
if(phCnt[hash_idx] >= phMax[hash_idx])
{ if(!phMax[hash_idx]) phMax[hash_idx] = 16;
else phMax[hash_idx] *= 2;
if(!(ptrhash[hash_idx] = realloc(ptrhash[hash_idx], sizeof(memchunk*)*phMax[hash_idx])))
Stop("can't realloc memchunk hashtable");
}
if(!(mc=malloc(sizeof(memchunk))))
Stop("can't alloc memchunk");
ptrhash[hash_idx][phCnt[hash_idx]++] = mc;
mc->ptr = ptr;
mc->size = size;
mc->file = file;
mc->line = line;
currentAllocation += size;
if(currentAllocation > peakAllocation)
peakAllocation = currentAllocation;
}
/*
* Remove a remembered pointer from the hash bucket.
*/
int forget(void *ptr)
{ memchunk **ptrlist;
int hash_idx;
int i;
hash_idx = (((long)ptr)>>3)&63;
ptrlist = ptrhash[hash_idx];
for(i=0; i<phCnt[hash_idx]; i++)
if(ptrlist[i]->ptr==ptr)
{ currentAllocation -= ptrlist[i]->size;
free(ptrlist[i]);
phCnt[hash_idx]--;
if(phCnt[hash_idx] > 0)
ptrlist[i] = ptrlist[phCnt[hash_idx]];
return 0;
}
return 1;
}
/*
* Print the contents of the ptrlist.
*/
static void print_ptr(memchunk *mc, int size)
{ char strbuf[16];
char *ptr = (char*)mc->ptr;
int j,maxlen;
if(mc->size < size) maxlen = mc->size; else maxlen = size;
for(j=0; j<15; j++)
{ if(ptr[j]<32) break;
strbuf[j] = ptr[j];
}
if(j)
{ strbuf[j]=0;
fprintf(stdout, "Address 0x%lx (\"%s\"), %d bytes, from %s, line %d\n",
(unsigned long)mc->ptr,strbuf,mc->size,mc->file,mc->line);
}
else
fprintf(stdout, "Address 0x%lx (binary data), %d bytes, from %s, line %d\n",
(unsigned long)mc->ptr,mc->size,mc->file,mc->line);
}
static void print_ptrs(char *msg)
{ int bucket,i,n=0;
fprintf(stdout, msg);
for(bucket=0; bucket<64; bucket++)
for(i=0; i<phCnt[bucket]; i++)
{
print_ptr(ptrhash[bucket][i], 15);
n++;
}
fprintf(stdout, "%d memory chunks total.\n",n);
}
/***
*** Replacements for the libc memory allocators.
***/
/*
* Protected malloc().
*/
void *malloc_ext(int size, char* file, int line)
{ void *ptr;
#if 0
printf("allocating %d bytes from file %s, line %d\n", size, file, line);
#endif
if(!(ptr = calloc(1,size)))
Stop("out of memory while allocating %d bytes",size);
remember(ptr,size,file,line);
return ptr;
}
/*
* Protected calloc().
*/
void *calloc_ext(int n, int size, char* file, int line)
{ void *ptr;
if(!(ptr = calloc(n,size)))
Stop("out of memory while allocating %d bytes",size);
remember(ptr,size,file,line);
return ptr;
}
/*
* Protected realloc().
*/
void *realloc_ext(void *ptr, int size, char *file, int line)
{ void *ret;
if(ptr && forget(ptr))
{ fprintf(stdout, "trying to realloc undefined pointer 0x%lx\n"
"file: %s, line: %d",(long)ptr,file,line);
exit(EXIT_FAILURE);
}
if(!(ret=realloc(ptr,size)))
{ fprintf(stdout, "out of memory for ptr 0x%lx, %d bytes\n",(long)ptr,size);
exit(EXIT_FAILURE);
}
remember(ret,size,file,line);
return ret;
}
/*
* String duplication.
*/
char *strdup_ext(const char *string, char *file, int line)
{ int length = strlen(string)+1;
char *copy;
if(!(copy = calloc(1,length)))
Stop("out of memory while allocating %d bytes",length);
strcpy(copy,string);
remember(copy,length,file,line);
return copy;
}
/*
* Free and forget a pointer
*/
void free_ext(void *ptr, char *file, int line)
{
if(forget(ptr))
{ fprintf(stdout, "trying to free undefined pointer 0x%lx\n"
"file: %s, line: %d",(long)ptr,file,line);
exit(EXIT_FAILURE);
}
free(ptr);
}
/***
*** Checking for memory leaks.
***/
void CheckMemleaks(void)
{ int i,memleak = 0;
/*** See if some memory chunks have been left over */
for(i=0; i<64; i++)
if(phCnt[i])
memleak = 1;
if(memleak)
{ char msg[80];
sprintf(msg,"\npngpack:\nMemory leak warning,"
" non-freed memory chunks detected.\n\n");
print_ptrs(msg);
}
else fprintf(stdout, "\npngpack: No memory leaks found.\n");
}

44
tools/memory.h Normal file
View File

@@ -0,0 +1,44 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#ifndef MEMORY_H
#define MEMORY_H
unsigned int SwapBytes32(unsigned int);
void Stop(char*, ...);
#ifdef WITH_MEMDEBUG_YES
#undef strdup
#define malloc(size) malloc_ext(size,__FILE__,__LINE__)
#define calloc(n,size) calloc_ext(n,size,__FILE__,__LINE__)
#define realloc(ptr,size) realloc_ext(ptr,size,__FILE__,__LINE__)
#define strdup(str) strdup_ext(str,__FILE__,__LINE__)
#define free(size) free_ext(size,__FILE__,__LINE__)
void* malloc_ext(int,char*,int);
void* calloc_ext(int,int,char*,int);
void* realloc_ext(void*, int, char*, int);
char* strdup_ext(const char*,char*,int);
void free_ext(void*,char*,int);
void CheckMemleaks(void);
#endif /* WITH_MEMDEBUG_YES */
#endif /* MEMORY_H */

244
tools/pngio.c Normal file
View File

@@ -0,0 +1,244 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "pngio.h"
#include "md5.h"
#include "memory.h"
/***
*** aux stuff
***/
void FreeImage(Image *i)
{
if(i->image) free(i->image);
if(i->file) fclose(i->file);
if(i->row_pointers) free(i->row_pointers);
if(i->png_read) png_destroy_read_struct(&i->png_read, &i->png_info, NULL);
if(i->png_write) png_destroy_write_struct(&i->png_write, &i->png_info);
free(i);
}
/***
*** PNG reading
***/
Image *LoadPNG(char *name)
{ struct MD5Context md5ctxt;
struct stat mystat;
Image *pi;
png_byte *pb;
unsigned char buf[256];
unsigned int depth,size,i;
png_color_16p background;
fprintf(stdout,"Loading %s ... ", name);
/* stat ppm file */
if(stat(name, &mystat) == -1)
{ fprintf(stdout, "COULD NOT STAT %s!\n", name);
fflush(stdout);
return NULL;
}
/* create image struct, really open */
pi = calloc(1,sizeof(Image));
if(!pi) Stop("out of memory for image");
pi->name = name;
pi->file = fopen(name, "rb");
if(!pi->file)
{ fprintf(stdout, "COULD NOT OPEN %s!\n", name);
fflush(stdout);
return NULL;
}
/* verify that we've got a png file */
fread(buf, 1, 8, pi->file);
if(png_sig_cmp(buf, 0, 8))
{ fclose(pi->file);
fprintf(stdout, "%s is not a .png file!\n", name);
fflush(stdout);
return NULL;
}
/* set up png data structs */
pi->png_read = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
pi->png_info = png_create_info_struct(pi->png_read);
if(!pi->png_read || !pi->png_info)
Stop("failed to initialize png structs");
if(setjmp(png_jmpbuf(pi->png_read)))
{ FreeImage(pi);
fprintf(stdout, "error decoding .png file!\n");
fflush(stdout);
return NULL;
}
png_init_io(pi->png_read, pi->file);
png_set_sig_bytes(pi->png_read, 8);
/* read and evaluate info portion */
png_read_info(pi->png_read, pi->png_info);
pi->width = png_get_image_width(pi->png_read, pi->png_info);
pi->height = png_get_image_height(pi->png_read, pi->png_info);
depth = png_get_bit_depth(pi->png_read, pi->png_info);
pi->channels = png_get_channels(pi->png_read, pi->png_info);
fprintf(stdout, "%dx%d %s image",pi->width,pi->height,pi->channels==3?"RBG":"RBGA");
if(depth != 8)
{ FreeImage(pi);
fprintf(stdout, ", ILLEGAL DEPTH: %d\n",depth);
fflush(stdout);
return NULL;
}
if(pi->channels == 3)
png_set_filler(pi->png_read, 0, PNG_FILLER_AFTER);
/* remember the png background color if there is one */
if(png_get_bKGD(pi->png_read, pi->png_info, &background))
pi->png_background = (background->red << 16) | (background->green << 8) | background->blue;
else pi->png_background = 0;
/* alloc memory for image */
size = pi->width * pi->height;
pi->bytesize = sizeof(unsigned int) * size;
pi->image = malloc(pi->bytesize);
if(!pi->image) Stop("out of memory for image");
pi->row_pointers = malloc(sizeof(png_byte*) * pi->height);
pb = (png_byte*)pi->image;
for(i=0; i<pi->height; i++)
{ pi->row_pointers[i] = pb;
pb += pi->width*sizeof(unsigned int);
}
png_read_image(pi->png_read, pi->row_pointers);
/* Clean up */
fprintf(stdout,".\n");
fflush(stdout);
fclose(pi->file);
png_destroy_read_struct(&pi->png_read, &pi->png_info, NULL);
free(pi->row_pointers);
/* calculate md5sum of image */
MD5Init(&md5ctxt);
MD5Update(&md5ctxt, (unsigned char*)pi->image, pi->bytesize);
MD5Final(pi->checksum, &md5ctxt);
return pi;
}
/***
*** PNG writing
***/
void SavePNG(Image *pi, char *name)
{ png_byte *pb;
unsigned int i;
png_color_16 background;
/* open file */
pi->file = fopen(name, "wb");
if(!pi->file)
Stop("Could not open %s: %s\n",name,strerror(errno));
/* set up png data structs */
pi->png_write = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
pi->png_info = png_create_info_struct(pi->png_write);
if(!pi->png_write || !pi->png_info)
Stop("failed to initialize png structs");
if(setjmp(png_jmpbuf(pi->png_write)))
{ png_destroy_write_struct(&pi->png_write, &pi->png_info);
fclose(pi->file);
fprintf(stdout, "error creating .png file!\n");
fflush(stdout);
return;
}
png_init_io(pi->png_write, pi->file);
/* supply image info to png library */
png_set_compression_level(pi->png_write, Z_BEST_COMPRESSION);
png_set_IHDR(pi->png_write, pi->png_info,
pi->width, pi->height, 8,
pi->channels == 4 ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
background.red = (pi->png_background >> 16) & 0xff;
background.green = (pi->png_background >> 8) & 0xff;
background.blue = pi->png_background & 0xff;
png_set_bKGD(pi->png_write, pi->png_info, &background);
pi->row_pointers = malloc(sizeof(png_byte*) * pi->height);
pb = (png_byte*)pi->image;
for(i=0; i<pi->height; i++)
{ pi->row_pointers[i] = pb;
pb += pi->width*sizeof(unsigned int);
}
/* and write it out */
png_write_info(pi->png_write, pi->png_info);
if(pi->channels == 3)
png_set_filler(pi->png_write, 0, PNG_FILLER_AFTER);
png_write_image(pi->png_write, pi->row_pointers);
png_write_end(pi->png_write, NULL);
/* clean up */
if(fclose(pi->file))
Stop("Could not close %s: %s\n",name,strerror(errno));
free(pi->row_pointers);
png_destroy_write_struct(&pi->png_write, &pi->png_info);
}

50
tools/pngio.h Normal file
View File

@@ -0,0 +1,50 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#ifndef PNGIO_H
#define PNGIO_H
#include <png.h>
typedef struct
{ char *name;
unsigned int width, height;
unsigned int *image;
unsigned int bytesize;
unsigned int tile_background;
unsigned int png_background;
unsigned int channels;
unsigned int first_opcode, last_opcode;
unsigned char checksum[16];
/* The rest is only used for png reading/writing */
FILE *file;
png_byte **row_pointers;
png_struct *png_read, *png_write;
png_info *png_info;
} Image;
Image *LoadPNG(char*);
void SavePNG(Image*, char*);
void FreeImage(Image*);
#endif /* PNGIO_H */

204
tools/pngpack.c Normal file
View File

@@ -0,0 +1,204 @@
/* pngpack: lossless image compression for a series of screen shots
* Copyright (C) 2005-2009 Carsten Gnoerlich.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#define VERSION "0.20"
#include <getopt.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "md5.h"
#include "pngio.h"
#include "codec.h"
#include "decimate.h"
#include "memory.h"
/***
*** main()
***/
typedef enum
{ MODE_NONE,
MODE_HELP,
MODE_PACK,
MODE_UNPACK,
MODIFIER_THUMBS
} run_mode;
int main(int argc, char *argv[])
{ int mode = MODE_NONE;
char *arch_file = NULL;
int thumbnails = 0;
int thumb_width = 160;
char *thumb_dir = strdup("../thumbnails");
/*** Parse the options */
for(;;)
{ int option_index,c;
static struct option long_options[] =
{ {"help", 0, 0, 'h'},
{"pack", 1, 0, 'p'},
{"unpack", 1, 0, 'u'},
{"thumbnails", 2, 0, 't'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"hp:u:t::",
long_options, &option_index);
if(c == -1) break;
switch(c)
{ case 'p': mode = MODE_PACK;
arch_file = strdup(optarg);
break;
case 'u': mode = MODE_UNPACK;
arch_file = strdup(optarg);
break;
case 't': thumbnails=1;
if(optarg)
{ char *copy=strdup(optarg);
char *comma=strchr(copy, ',');
if(comma)
{ *comma=0;
thumb_width=atoi(copy);
free(thumb_dir);
thumb_dir=strdup(comma+1);
free(copy);
}
else
{ int val = strtol(optarg, NULL, 0);
if(val > 0 ) thumb_width=val;
else thumb_dir=copy;
}
}
break;
case 'h':
case '?':
mode = MODE_HELP; break;
break;
default: fprintf(stdout, "?? illegal getopt return value %d\n",c); break;
}
}
/*** Perform the action */
if(mode != MODE_NONE && mode != MODE_HELP)
fprintf(stdout, "pngpack-0.20 *** Copyright 2005-2009 Carsten Gnoerlich.\n"
"This software comes with ABSOLUTELY NO WARRANTY. This\n"
"is free software and you are welcome to redistribute it\n"
"under the conditions of the GNU GENERAL PUBLIC LICENSE.\n"
"See the file \"COPYING\" for further information.\n\n");
switch(mode)
{ case MODE_PACK:
{ Image *pi;
int i;
InitTileDatabase();
for(i=optind; i<argc; i++)
{
pi = LoadPNG(argv[i]);
if(!pi) continue;
EncodeImage(pi);
free(pi->image);
}
SavePPK(arch_file);
FreeTileDatabase();
}
break;
case MODE_UNPACK:
{ Image **img_list;
int img_n;
unsigned int i;
InitTileDatabase();
LoadPPK(arch_file, &img_list, &img_n);
for(i=0; i<img_n; i++)
{ struct stat mystat;
Image *pi = img_list[i];
char *c;
/* Do not overwrite existing files */
if(stat(pi->name, &mystat) != -1)
{ c = strrchr(pi->name, '.');
if(c)
{ char *n = malloc(strlen(pi->name)+2);
*c = 0;
sprintf(n, "_%s.png", pi->name);
free(pi->name);
pi->name = n;
}
}
fprintf(stdout, "rendering %s (opcodes %d - %d)",pi->name,pi->first_opcode,pi->last_opcode);
pi->bytesize = sizeof(unsigned int) * pi->width*pi->height;
pi->image = malloc(pi->bytesize);
if(!pi->image) Stop("out of memory for image");
RenderImage(pi);
SavePNG(pi, pi->name);
if(thumbnails)
SaveThumbnail(pi, pi->name, thumb_width, thumb_dir);
free(pi->name);
free(pi->image);
}
FreeTileDatabase();
}
break;
case MODE_NONE:
case MODE_HELP:
fprintf(stdout, "Usage: pngpack [OPTION...] [FILE]...\n"
"pngpack maintains archives of PNG images. Depending on the similarity between\n"
"the images, very high compression ratios can be reached. It is especially\n"
"suitable for distribution of screen shots for online documentation.\n\n"
"Examples:\n"
" pngpack --pack arch.pngpack img1.png img2.png ... - create archive\n"
" pngpack --unpack arch.pngpack - unpack archive\n"
" pngpack --unpack arch.pngpack --thumbnails 160 ../thumbs\n"
" unpacks archive and creates thumbnails of width 160\n"
" in the directory ../thumbs\n\n"
"Main operation:\n"
"-p, --pack=ARCH - pack png images into archive\n"
"-u, --unpack=ARCH - unpack png images from archive\n\n"
"Modifiers:\n"
"-t, --thumbnails=WIDTH,DIR\n"
" Create thumbnails while unpacking.\n"
" Defaults are WIDTH=160 and DIR=../thumbnails\n");
exit(EXIT_FAILURE);
}
free(arch_file);
free(thumb_dir);
#ifdef WITH_MEMDEBUG_YES
CheckMemleaks();
#endif
return EXIT_SUCCESS;
}