Compare commits

...

35 Commits

Author SHA1 Message Date
Glenn Randers-Pehrson
3091454eb4 [pngzop] Minor editing of the license information 2013-07-04 20:42:32 -05:00
Glenn Randers-Pehrson
71bd5668c4 [pngzop] Updated pngzop_references.html and removed some old results files. 2013-07-01 13:08:07 -05:00
Glenn Randers-Pehrson
6b1a1dc2eb [pngzop] Removed no-longer-used shell scripts 2013-07-01 13:02:44 -05:00
Glenn Randers-Pehrson
358d887036 [pngzop] Fix typo in usage ("-e png" should be "-e .png") 2013-07-01 13:00:42 -05:00
Glenn Randers-Pehrson
85f9eed197 [pngzop] Fix typo in README and pngzop usage comment ("-ext" should be "-e") 2013-07-01 12:55:02 -05:00
Glenn Randers-Pehrson
3da0defbb9 [pngzop] Updated pngzop_README.txt with license and disclaimer. 2013-07-01 12:14:58 -05:00
Glenn Randers-Pehrson
f1462e8653 [pngzop] Put working files in /tmp (or $TMPDIR if it exists) 2013-07-01 11:43:18 -05:00
Glenn Randers-Pehrson
c02d9e88fc [pngzop] Run a pre-pass with pngcrush to reduce and optionally blacken the input 2013-07-01 10:29:33 -05:00
Glenn Randers-Pehrson
aafceed9bf [pngzop] Removed "--brute" option and always do the "brute" method. 2013-07-01 08:34:43 -05:00
Glenn Randers-Pehrson
abc0f446e5 [pngzop] Added CMF optimization using "pngfix" from libpng-1.6.3beta10 2013-07-01 08:09:02 -05:00
Glenn Randers-Pehrson
11de8b90fd [pngzop] Added "pngzop" script that combines several of the *.sh scripts
and adds "-e extension" and "-d directory" options similar to those in
pngcrush.
2013-04-10 10:04:01 -05:00
Glenn Randers-Pehrson
53359724c0 [pngzop] Revised comments in pngzop_brute.sh and pngzop_pngcrush.sh 2013-04-08 09:04:25 -05:00
Glenn Randers-Pehrson
3bb43e3df4 [pngzop] Updated references to include a pointer to "zlib/examples/pipe.c" 2013-03-26 21:48:08 -05:00
Glenn Randers-Pehrson
1384c6cebe [pngzop] Added "pngzop_smallest.sh" script 2013-03-25 10:29:47 -05:00
Glenn Randers-Pehrson
e8be910287 [pngzop] Revised pngzop_brute_zopfli.sh; it was copying the filename
instead of the entire file into the output PNG.
2013-03-25 10:09:08 -05:00
Glenn Randers-Pehrson
79e24b63dc [pngzop] Added some test results 2013-03-22 23:27:17 -05:00
Glenn Randers-Pehrson
2e9519340e [pngzop] Renamed scripts to reflect what they do. 2013-03-22 10:28:37 -05:00
Glenn Randers-Pehrson
47b0c0d309 [pngzop] Renamed try-pngzop to pngzop-try, fixed pngzop 2013-03-11 22:19:45 -05:00
Glenn Randers-Pehrson
e892d57dfa [pngzop] Deleted picksmaller (no longer used); added try-pngzop script 2013-03-11 18:26:14 -05:00
Glenn Randers-Pehrson
999c3bc431 [pngzop] Added commentary and license info to the new pngzop script. 2013-03-11 18:01:18 -05:00
Glenn Randers-Pehrson
d2472fb14f [pngzop] Added pngzop script. 2013-03-11 17:56:48 -05:00
Glenn Randers-Pehrson
e14cbe60a6 [pngzop] Removed debug printout from pngidat and pngzdat 2013-03-11 17:55:41 -05:00
Glenn Randers-Pehrson
6b6d4b3a24 [pngzop] Fix usage comment in picksmaller. 2013-03-10 10:09:04 -05:00
Glenn Randers-Pehrson
bc8c917bf3 [pngzop] Use "ls -S" instead of editing output of "ls -L" to pick smallest file. 2013-03-10 10:04:10 -05:00
Glenn Randers-Pehrson
854e3237ab [pngzop] Added results.txt (preliminary test results) 2013-03-08 18:44:26 -06:00
Glenn Randers-Pehrson
f35bac9bdd [pngzop] Added pngihdr.c and pngiend.c 2013-03-06 19:35:11 -06:00
Glenn Randers-Pehrson
45bcb5ddd3 [pngzop] Added move_best script 2013-03-06 14:08:29 -06:00
Glenn Randers-Pehrson
56f554022e [pngzop] Added picksmaller script, added license info. 2013-03-06 12:39:12 -06:00
Glenn Randers-Pehrson
3aeca85c4c [pngzop] Added pngzdat tool to extract compressed IDAT data from a PNG. 2013-03-04 00:29:20 -06:00
Glenn Randers-Pehrson
8ce5e66c5c [pngzop] Added pngidat script and pngidat.c, and updated references to
include pigz
2013-03-02 20:39:03 -06:00
Glenn Randers-Pehrson
5b037b394c [pngzop] Reformatted pngzop-references.html as a "<ul>" 2013-03-02 11:14:04 -06:00
Glenn Randers-Pehrson
c73dbcd42c [pngzop] Removed whitespace from link in pngzip-references.html 2013-03-02 11:10:42 -06:00
Glenn Randers-Pehrson
a1369d4f5f [pngzop] Added reference to the zopfli PDF 2013-03-02 11:06:24 -06:00
Glenn Randers-Pehrson
da6b9d1cb9 [pngzop] swap master and pngzop README files. 2013-03-02 10:53:49 -06:00
Glenn Randers-Pehrson
2e848c92cc Mention pngmeta and pnguri branches. 2012-10-12 10:15:13 -05:00
8 changed files with 640 additions and 6 deletions

View File

@@ -1,6 +0,0 @@
/*
This is the master branch of the "pmt" tree.
Individual projects are in separate branches,
e.g. pngcrush is in the "pngcrush" branch.
*/

167
pngzop Executable file
View File

@@ -0,0 +1,167 @@
#!/bin/sh
# pngzop
# Copyright 2013 by Glenn Randers-Pehrson
# Released under the pngcrush license (which is equivalent to the zlib
# license plus UCITA disclaimers).
# Extracts the concatenated data from the IDAT chunks in a set of PNG files,
# recompresses them with zopfli, and embeds them in a new set of PNG files
# with suffix ".png" replaced (by default) with "_pngzop.png"
# Requires zopfli, pngcrush (version 1.7.65 or later), zpipe (from the
# zlib-1.2.7 or later distribution, in the "examples" directory), pngfix
# (from the libpng-1.6.3 or later distribution), and "mkdir -p",
# along with these programs that should have been installed along with
# this "pngzop" script:
#
# pngzop_get_ihdr.exe
# pngzop_get_idat.exe
# pngzop_get_iend.exe
# pngzop_zlib_to_idat.exe
# Usage:
# pngzop [-b|--blacken] [-d|--directory dir] [-e|--extension ext] *.png
# (to overwrite the input, use "-e .png")
# Input: *.png
# Output: *_pngzop.png
# Get temporary directory; use TMPDIR if defined, otherwise /tmp
case x${TMPDIR} in
x)
temp=/tmp/pngzop-$$
;;
*)
temp=$TMPDIR/pngzop-$$
;;
esac
mkdir -p $temp
blacken=
directory=.
extension=
for x in $*
do
case $1 in
-b|--blacken)
blacken="-blacken"
shift;;
-d|--directory)
shift
directory=$1
shift;;
-e|--extension)
shift
extension=$1
shift;;
*)
break;;
esac
done
# If a directory was defined, don't change filenames (extension == .png)
# unless an extension was also defined.
case x$directory in
x.)
;;
*)
case x$extension in
x)
extension=.png
;;
*)
;;
esac
mkdir -p $directory
;;
esac
case x$extension in
x)
extension=_pngzop.png
;;
*)
;;
esac
for x in $*
do
root=`echo $x | sed -e s/.png$//`
# prepass to reduce and possibly blacken
pngcrush -q -m 1 -force -reduce $blacken $x ${temp}/${root}_temp.png
pngzop_get_ihdr.exe < ${temp}/${root}_temp.png > ${temp}/${root}_pz.png
# Generate trial PNGs with filter none, 4 PNG filters, and adaptive
# filter
for f in 0 1 2 3 4 5
do
pngcrush -q -m 1 -f $f -force ${temp}/${root}_temp.png \
${temp}/${root}_f$f.png &
done
wait
# Extract and decompress the zlib datastream from the concatenated
# IDAT chunks.
for f in 0 1 2 3 4 5
do
pngzop_get_idat.exe < ${temp}/${root}_f$f.png | zpipe -d > \
${temp}/${root}_f$f.idat &
done
wait
rm -f ${temp}/${root}_f?.png
# Recompress the IDAT data using zopfli
for f in 0 1 2 3 4 5
do
zopfli --i25 --zlib ${temp}/${root}_f$f.idat &
done
wait
rm -f ${temp}/${root}_f?.idat
# Copy the smallest result to file.zlib
file=${temp}/${root}_f0.idat.zlib
smallest=$file
smallsize=`ls -l $file | sed -e "
s/[^ ]*[ ]*\
[^ ]*[ ]*\
[^ ]*[ ]*\
[^ ]*[ ]*\
//" -e "s/[ ].*//"`
for f in 1 2 3 4 5
do
file=${temp}/${root}_f$f.idat.zlib
size=`ls -l $file | sed -e "
s/[^ ]*[ ]*\
[^ ]*[ ]*\
[^ ]*[ ]*\
[^ ]*[ ]*\
//" -e "s/[ ].*//"`
if [ $smallsize -gt $size ] ; then
smallest=$file
smallsize=$size
fi
done
pngzop_zlib_to_idat.exe < $smallest >> ${temp}/${root}_pz.png
rm -f ${temp}/${root}_f?.idat.zlib
pngzop_get_iend.exe < ${temp}/${root}_temp.png >> ${temp}/${root}_pz.png
rm ${temp}/${root}_temp.png
# Optimize the CMF bytes and put the result in desired destination.
pngfix -o --quiet --out=${directory}/${root}${extension} \
${temp}/${root}_pz.png
rm ${temp}/${root}_pz.png
done
rm -rf $temp

77
pngzop-1.0.1-README.txt Normal file
View File

@@ -0,0 +1,77 @@
/*
This is the pngzop branch of the "pmt" tree.
Code for supporting the "zopfli" compression method
in PNG files will appear here.
Eventually this collection of scripts might be incorporated
into pngcrush.
Copyright 2013 by Glenn Randers-Pehrson
Released under the pngcrush license (which is equivalent to the zlib
license plus UCITA disclaimers). See DISCLAIMERS and LICENSE below.
Usage:
pngzop [-b|--blacken] [-d|--directory dir] [-e|--extension ext] *.png
Input: *.png
Output (default): *_pngzop.png (to overwrite the input, use "-e .png")
Pngzop does the following:
1. Preprocesses the input file(s) with pngcrush -reduce
(and optionally -blacken to clean up "dirty" transparent pixels)
2. Uses pngcrush to write 6 test files, with 5 PNG filters and adaptive
filtering.
3. Extracts the IDAT contents from each of the 6 files.
4. Recompresses the IDAT contents with zopfli (25 iterations).
5. Reassembles the PNG file using the smallest of the zopfli-compressed
results.
6. Postprocesses the PNG file with "pngfix" to optimize the windowBits
field, to minimize memory use during later decompression.
Pngzop requires zopfli, pngcrush (version 1.7.65 or later), zpipe (from
the "examples" directory of the zlib-1.2.7 or later distribution),
pngfix (from the libpng-1.6.3 or later distribution), and "mkdir -p",
along with these programs that should have been installed from their "C"
sources along with this "pngzop" script:
pngzop_get_ihdr.exe
pngzop_get_idat.exe
pngzop_get_iend.exe
pngzop_zlib_to_idat.exe
DISCLAIMERS:
The pngzop software is supplied "AS IS". The Author disclaims all
warranties, expressed or implied, including, without limitation, the
warranties of merchantability and of fitness for any purpose. The
Author assumes no liability for direct, indirect, incidental, special,
exemplary, or consequential damages, which may result from the use of
the pngzop software, even if advised of the possibility of such damage.
There is no warranty against interference with your enjoyment of the
computer software or against infringement. There is no warranty that
the Author's efforts or the computer software will fulfill any of your
particular purposes or needs. This computer software is provided with
all faults, and the entire risk of satisfactory quality, performance,
accuracy, and effort is with the user.
LICENSE:
Permission is hereby irrevocably granted to everyone to use, copy,
modify, and distribute this source code, or portions hereof, or
executable programs compiled from it, for any purpose, without payment
of any fee, subject to the following restrictions:
1. The origin of this source code must not be misrepresented.
2. Altered versions must be plainly marked as such and must not be
misrepresented as being the original source.
3. This Copyright notice, disclaimer, and license may not be removed
or altered from any source or altered source distribution.
*/

76
pngzop_get_idat.c Normal file
View File

@@ -0,0 +1,76 @@
#include <stdio.h>
/* Copyright 2013 Glenn Randers-Pehrson
* Released under the pngcrush license (equivalent to the libpng license)
*/
/* Usage:
* pngidat.exe < file.png > file.zdat
*
* file.idat is the zlib datastream from the PNG IDAT chunks.
*
*/
main()
{
unsigned int i;
unsigned int buf[5];
unsigned int c;
buf[4]='\0';
/* Skip 8-byte signature */
for (i=8; i; i--)
c=getchar();
for (;;)
{
/* read length */
unsigned int length;
buf[0]=getchar();
if (buf[0] == EOF)
break;
buf[1]=getchar();
buf[2]=getchar();
buf[3]=getchar();
length=buf[0]<<24 | buf[1]<<16 | buf[2] << 8 | buf[3];
/* read chunkname */
buf[0]=getchar();
buf[1]=getchar();
buf[2]=getchar();
buf[3]=getchar();
if (buf[0] == 'I' && buf[1] == 'D' && buf[2] == 'A' && buf[3] == 'T')
{
/* copy the data bytes */
for (i=length; i; i--)
{
c=getchar();
if (c == EOF)
break;
putchar(c);
}
if (c == EOF)
break;
/* skip crc bytes */
for (i=4; i; i--)
{
c=getchar();
}
}
else if (buf[0] == 'I' && buf[1] == 'E' && buf[2] == 'N' && buf[3] == 'D')
break;
else
{
for (i=length+4; i; i--)
{
c=getchar();
if (c == EOF)
break;
}
if (c == EOF)
break;
}
}
}

112
pngzop_get_iend.c Normal file
View File

@@ -0,0 +1,112 @@
#include <stdio.h>
/* Copyright 2013 Glenn Randers-Pehrson */
/* Usage:
* pngiend.exe < file.png > file.iend
*
* file.iend is the image datastream, minus everything through the
* last IDAT chunk.
*/
main()
{
unsigned int c;
unsigned int i;
unsigned int len[5];
unsigned int length;
unsigned int mode;
unsigned int name[5];
len[4]='\0';
name[4]='\0';
mode=0; /* Looking for IDAT */
/* Skip 8-byte signature */
for (i=8; i; i--)
{
c=getchar();
if (c == EOF)
break;
}
for (;;)
{
/* read length */
len[0]=getchar();
if (len[0] == EOF)
break;
len[1]=getchar();
len[2]=getchar();
len[3]=getchar();
if (len[3] == EOF)
break;
length=len[0]<<24 | len[1]<<16 | len[2]<< 8 | len[3];
/* read chunkname */
name[0]=getchar();
name[1]=getchar();
name[2]=getchar();
name[3]=getchar();
if (name[3] == EOF)
break;
if (name[0] == 'I' && name[1] == 'D' && name[2] == 'A' && \
name[3] == 'T')
{
if (mode == 0)
mode = 1; /* found IDAT */
}
else
{
if (mode == 1)
mode = 2; /* found chunk after IDAT */
}
if (mode == 2)
{
/* copy the length bytes */
putchar(len[0]);
putchar(len[1]);
putchar(len[2]);
putchar(len[3]);
/* copy the name bytes */
putchar(name[0]);
putchar(name[1]);
putchar(name[2]);
putchar(name[3]);
}
/* skip or copy the data bytes */
for (i=length; i; i--)
{
c=getchar();
if (c == EOF)
break;
if (mode == 2)
putchar(c);
}
if (c == EOF)
break;
/* skip or copy crc bytes */
for (i=4; i; i--)
{
c=getchar();
if (c == EOF)
break;
if (mode == 2)
putchar(c);
}
if (c == EOF)
break;
if (name[0] == 'I' && name[1] == 'E' && name[2] == 'N' && \
name[3] == 'D')
{
break;
}
}
}

98
pngzop_get_ihdr.c Normal file
View File

@@ -0,0 +1,98 @@
#include <stdio.h>
/* Copyright 2013 Glenn Randers-Pehrson */
/* Usage:
* pngidat.exe < file.png > file.ihdr
*
* file.ihdr is the image datastream, with the PNG signature bytes
* and all chunks up to the first IDAT.
*/
main()
{
unsigned int i;
unsigned int len[5];
unsigned int name[5];
unsigned int c;
len[4]='\0';
name[4]='\0';
/* Copy 8-byte signature */
for (i=8; i; i--)
{
c=getchar();
if (c == EOF)
break;
putchar(c);
}
for (;;)
{
/* read length */
unsigned int length;
len[0]=getchar();
if (len[0] == EOF)
break;
len[1]=getchar();
len[2]=getchar();
len[3]=getchar();
if (len[3] == EOF)
break;
length=len[0]<<24 | len[1]<<16 | len[2] << 8 | len[3];
/* read chunkname */
name[0]=getchar();
name[1]=getchar();
name[2]=getchar();
name[3]=getchar();
if (name[3] == EOF)
break;
if (name[0] == 'I' && name[1] == 'D' && name[2] == 'A' && name[3] == 'T')
break;
/* copy the length bytes */
putchar(len[0]);
putchar(len[1]);
putchar(len[2]);
putchar(len[3]);
/* copy the name bytes */
putchar(name[0]);
putchar(name[1]);
putchar(name[2]);
putchar(name[3]);
/* copy the data bytes */
for (i=length; i; i--)
{
c=getchar();
if (c == EOF)
break;
putchar(c);
}
if (c == EOF)
break;
/* copy crc bytes */
for (i=4; i; i--)
{
c=getchar();
if (c == EOF)
break;
putchar(c);
}
if (c == EOF)
break;
if (name[0] == 'I' && name[1] == 'E' && name[2] == 'N' && name[3] == 'D')
{
/* should not happen */
break;
}
}
}

15
pngzop_references.html Normal file
View File

@@ -0,0 +1,15 @@
<html><head><title>Zopli references</title></head>
<body>
<h2>Zopfli references</h2>
<ul>
<li>
<a href="https://code.google.com/p/zopfli/downloads/detail?name=Data_compression_using_Zopfli.pdf&can=2&q=">
Data_compression_using_Zopfli.pdf</a>
<li><a href="http://zlib.net/pigz/">zlib.net/pigz</a> (parallel gzip)
<li><a href="http://zlib.net/zlib/">zlib.net</a> (zlib/examples/zpipe.c)
<li><a href="http://pmt.sourceforge.net/pngcrush/">pngcrush</a>
<li><a href="http://libpng.sourceforge.net/>pngfix</a>
(in contrib/tools of libpng-1.6.3 or later)
</ul>
</body>
</html>

95
pngzop_zlib_to_idat.c Normal file
View File

@@ -0,0 +1,95 @@
/* pngzopz2i */
/* Copyright 2013 Glenn Randers-Pehrson
* Released under the pngcrush license (equivalent to the libpng license)
*/
/* Usage:
* pngzop_zlib_to_idat < file.zlib > file_out.idat
*
* file.zlib is the zlib datastream from zopli --zlib file_in.idat
* file_out.idat is the zlib datastream enclosed in PNG IDAT chunks.
* This is a single file that may contain multiple IDAT chunks.
*
* To do: make the maximum IDAT chunk data length an option (currently fixed
* at 250000 bytes).
*
*/
#include <stdio.h>
#include <zlib.h> /* for crc32 */
void
put_uLong(uLong val)
{
putchar(val >> 24);
putchar(val >> 16);
putchar(val >> 8);
putchar(val >> 0);
}
void
put_chunk(const unsigned char *chunk, uInt length)
{
uLong crc;
put_uLong(length-4); /* Exclude the tag */
fwrite(chunk, 1, length, stdout);
crc = crc32(0, Z_NULL, 0);
put_uLong(crc32(crc, chunk, length));
}
int
main()
{
unsigned char buf[250000];
int c;
const unsigned char idat[] = { 73, 68, 65, 84 /* "IDAT" */ };
int n=6;
/* IDAT */
buf[0]=idat[0];
buf[1]=idat[1];
buf[2]=idat[2];
buf[3]=idat[3];
/* CMF */
c=getchar();
if (c != EOF)
buf[4]=(unsigned char) c;
/* FLAGS */
if (c != EOF)
{
c=getchar();
if (c != EOF)
buf[5]=(unsigned char) c;
}
if (c != EOF)
for(;;)
{
/* read up to n=250000 bytes */
c=getchar();
if (c != EOF)
{
buf[n]=(unsigned char) c;
n++;
}
if (c != EOF && n < 250000)
continue;
put_chunk(buf, n);
if (c == EOF)
break;
n=4;
}
}