Imported Upstream version 0.72
This commit is contained in:
4
tools/Makefile
Normal file
4
tools/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
all:
|
||||
@echo
|
||||
@echo "Please create a Makefile by entering \"./configure\" first"
|
||||
@echo
|
||||
106
tools/Makefile.template
Normal file
106
tools/Makefile.template
Normal 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
31
tools/README
Normal 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
701
tools/codec.c
Normal 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
34
tools/codec.h
Normal 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
105
tools/configure
vendored
Executable 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
127
tools/decimate.c
Normal 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
25
tools/decimate.h
Normal 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
293
tools/memory.c
Normal 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
44
tools/memory.h
Normal 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
244
tools/pngio.c
Normal 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
50
tools/pngio.h
Normal 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
204
tools/pngpack.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user