diff options
author | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 1999-12-21 11:25:28 -0600 |
---|---|---|
committer | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 2009-04-16 10:46:37 -0500 |
commit | 7a16d67a4b39201c5ad78cf8b789039e2c8deed9 (patch) | |
tree | 264b2b10d681508d619cb0b833fbe9a6ccd87076 | |
parent | ce85ad6640b8718fd05f58a47c1f83d9e98aad94 (diff) | |
download | libpng-1.3.0.tar.gz |
Imported from pngcrush-1.3.0.tarv1.3.0
-rw-r--r-- | INSTALL | 14 | ||||
-rw-r--r-- | README.txt | 30 | ||||
-rw-r--r-- | deflate.c | 17 | ||||
-rw-r--r-- | makefile.gcc | 55 | ||||
-rw-r--r-- | png.c | 146 | ||||
-rw-r--r-- | png.h | 294 | ||||
-rw-r--r-- | pngconf.h | 284 | ||||
-rw-r--r-- | pngcrush.c | 486 | ||||
-rw-r--r-- | pngcrush.h | 30 | ||||
-rw-r--r-- | pngerror.c | 2 | ||||
-rw-r--r-- | pnggccrd.c | 4633 | ||||
-rw-r--r-- | pngget.c | 93 | ||||
-rw-r--r-- | pngmem.c | 2 | ||||
-rw-r--r-- | pngpread.c | 125 | ||||
-rw-r--r-- | pngread.c | 10 | ||||
-rw-r--r-- | pngrio.c | 2 | ||||
-rw-r--r-- | pngrtran.c | 45 | ||||
-rw-r--r-- | pngrutil.c | 313 | ||||
-rw-r--r-- | pngset.c | 308 | ||||
-rw-r--r-- | pngtrans.c | 2 | ||||
-rw-r--r-- | pngvcrd.c | 4 | ||||
-rw-r--r-- | pngwio.c | 2 | ||||
-rw-r--r-- | pngwrite.c | 204 | ||||
-rw-r--r-- | pngwtran.c | 2 | ||||
-rw-r--r-- | pngwutil.c | 232 | ||||
-rw-r--r-- | uncompr.c | 58 |
26 files changed, 6719 insertions, 674 deletions
@@ -1,17 +1,20 @@ -There's no makefile or "configure" for pngcrush. +There's a sample makefile.gcc for pngcrush, which you can use +by typing -All you should need to do is enter the pngcrush-1.2.l + make -f makefile.gcc + +However, all you should need to do is enter the pngcrush-1.3.0 directory and type cc -O -o pngcrush *.c -lm cp pngcrush /usr/local/bin # or wherever you want You might want to create a makefile if you are planning to do -something more complicated, like loading with your own shared +something more complicated, like loading with your system's shared libraries for libpng and zlib. -Here's the command for compiling on SGI IRIX: +Here's a command for compiling on SGI IRIX: cc -n32 -fullwarn -O2 -IPA:plimit=256 -OPT:Olimit=0 -o pngcrush *.c -lm cp pngcrush /usr/local/bin @@ -20,4 +23,5 @@ On a PC with DJGCC, you can type gcc -O3 -Wall -funroll-loops -o pngcrush *.c copy /B pmodstub.exe + pngcrush pngcrush.exe - then put pngcrush.exe wherever you want. + +then put pngcrush.exe wherever you want. diff --git a/README.txt b/README.txt index 534ade417..94dcdf250 100644 --- a/README.txt +++ b/README.txt @@ -1,8 +1,8 @@ - | pngcrush 1.2.1, Copyright (C) 1998, 1999, Glenn Randers-Pehrson + | pngcrush 1.3.0, Copyright (C) 1998, 1999, Glenn Randers-Pehrson | This is a free, open-source program. Permission is | granted to everyone to use pngcrush without fee. - | This program was built with libpng version 1.0.5f, + | This program was built with libpng version 1.0.5j, | Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc., | Copyright (C) 1996, 1997 Andreas Dilger, | Copyright (C) 1998, 1999, Glenn Randers-Pehrson, @@ -35,10 +35,25 @@ options: -text b[efore_IDAT]|a[fter_IDAT] "keyword" "text" -trns index red green blue gray -verbose (write more detailed information) - -w compression_window_size [32, 16, 8, 4, 2, 1, 512, 256] + -w compression_window_size [32, 16, 8, 4, 2, 1, 512] -h (help) -p (pause) + | pngcrush 1.3.0, Copyright (C) 1998, 1999, Glenn Randers-Pehrson + | This is a free, open-source program. Permission is + | granted to everyone to use pngcrush without fee. + | This program was built with libpng version 1.0.5j, + | Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc., + | Copyright (C) 1996, 1997 Andreas Dilger, + | Copyright (C) 1998, 1999, Glenn Randers-Pehrson, + | and zlib version 1.1.3, Copyright (c) 1998, + | Jean-loup Gailly and Mark Adler. + + +usage: pngcrush [options] infile.png outfile.png + pngcrush -e ext [other options] files.png ... + pngcrush -d dir [other options] files.png ... + options: -brute (Use brute-force, try 114 different methods) @@ -78,7 +93,7 @@ options: -f user_filter [0-5] filter to use with the method specified in the - preceding '-m method' argument. + preceding '-m method' or '-brute_force' argument. 0: none; 1-4: use specified filter; 5: adaptive. -force (Write a new output file even if larger than input) @@ -96,7 +111,8 @@ options: -l zlib_compression_level [0-9] zlib compression level to use with method specified - with the preceding '-m method' argument. + with the preceding '-m method' or '-brute_force' + argument. -m method [0 through 200] @@ -165,10 +181,10 @@ options: Repeat the option (use "-v -v") for even more. - -w compression_window_size [32, 16, 8, 4, 2, 1, 512, 256] + -w compression_window_size [32, 16, 8, 4, 2, 1, 512] Size of the sliding compression window, in kbytes - (or bytes, in case of 512 or 256). It's best to + (or bytes, in case of 512). It's best to use the default (32) unless you run out of memory. The program will use a smaller window anyway when the uncompressed file is smaller than 16k. @@ -101,7 +101,7 @@ local void check_match OF((deflate_state *s, IPos start, IPos match, /* Tail of hash chains */ #ifndef TOO_FAR -# define TOO_FAR 32767 /* changed from 4096 for pngcrush */ +# define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ @@ -261,8 +261,10 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->window = (Bytef *) ZALLOC(strm, (windowBits == 8 ? 264 : s->w_size), + 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, (windowBits == 8 ? 264 : s->w_size), + sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ @@ -1277,12 +1279,9 @@ local block_state deflate_slow(s, flush) } /* longest_match() sets match_start */ - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if (TOO_FAR <= 32767) - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. diff --git a/makefile.gcc b/makefile.gcc new file mode 100644 index 000000000..095868ba8 --- /dev/null +++ b/makefile.gcc @@ -0,0 +1,55 @@ +# Sample makefile for pngcrush using gcc and make. +# Glenn Randers-Pehrson +# Last modified: 7 December 1999 +# +# Invoke this makefile from a shell prompt in the usual way; for example: +# +# make -f makefile.unx +# +# This makefile builds a statically linked executable. + +# macros -------------------------------------------------------------------- + +CC = gcc +LD = gcc +RM = rm -f +CFLAGS = -O -Wall +# [note that -Wall is a gcc-specific compilation flag ("all warnings on")] +LDFLAGS = +O = .o +E = + +PNGCRUSH = pngcrush + +LIBS = -lm + +OBJS = $(PNGCRUSH)$(O) adler32$(O) crc32$(O) deflate$(O) gzio$(O) \ + infblock$(O) infcodes$(O) inffast$(O) inflate$(O) inftrees$(O) \ + infutil$(O) png$(O) pngerror$(O) pngget$(O) pngmem$(O) \ + pngpread$(O) pngread$(O) pngrio$(O) pngrtran$(O) pngrutil$(O) \ + pngset$(O) pngtrans$(O) pngvcrd$(O) pngwio$(O) pngwrite$(O) \ + pngwtran$(O) pngwutil$(O) trees$(O) zutil$(O) + +EXES = $(PNGCRUSH)$(E) + + +# implicit make rules ------------------------------------------------------- + +.c$(O): png.h pngconf.h zlib.h pngcrush.h + $(CC) -c $(CFLAGS) $< + + +# dependencies -------------------------------------------------------------- + +all: $(EXES) + + +$(PNGCRUSH)$(E): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(PNGCRUSH)$(O): $(PNGCRUSH).c png.h pngconf.h zlib.h pngcrush.h + +# maintenance --------------------------------------------------------------- + +clean: + $(RM) $(EXES) $(OBJS) @@ -1,15 +1,16 @@ /* png.c - location for general purpose libpng functions * - * libpng version 1.0.5f - December 6, 1999 + * libpng version 1.0.5j - December 21, 1999 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger * Copyright (c) 1998, 1999 Glenn Randers-Pehrson - * + * */ #define PNG_INTERNAL #define PNG_NO_EXTERN +#include <assert.h> #include "png.h" /* Version information for C files. This had better match the version @@ -18,12 +19,12 @@ #ifdef PNG_USE_GLOBAL_ARRAYS /* png_libpng_ver was changed to a function in version 1.0.5c */ -char png_libpng_ver[12] = "1.0.5f"; +char png_libpng_ver[12] = "1.0.5j"; /* png_sig was changed to a function in version 1.0.5c */ /* Place to hold the signature string for a PNG file. */ png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; - + /* Invoke global declarations for constant strings for known chunk types */ PNG_IHDR; PNG_IDAT; @@ -263,27 +264,28 @@ png_info_init(png_infop info_ptr) void png_free_text(png_structp png_ptr, png_infop info_ptr, int num) { - if (num != -1) - { - if (info_ptr->text[num].key) - { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; - } - if (info_ptr->text[num].lang) - { - png_free(png_ptr, info_ptr->text[num].lang); - info_ptr->text[num].lang = NULL; - } - } - else if (info_ptr->text != NULL) - { - int i; - for (i = 0; i < info_ptr->num_text; i++) - png_free_text(png_ptr, info_ptr, i); - png_free(png_ptr, info_ptr->text); - info_ptr->text = NULL; - } + if (png_ptr == NULL || info_ptr == NULL) + return; + if (num != -1) + { + if (info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } + } + else if (info_ptr->text != NULL) + { + int i; + if(info_ptr->text != NULL) + { + for (i = 0; i < info_ptr->num_text; i++) + png_free_text(png_ptr, info_ptr, i); + png_free(png_ptr, info_ptr->text); + info_ptr->text = NULL; + } + info_ptr->num_text=0; + } } #endif @@ -292,10 +294,18 @@ png_free_text(png_structp png_ptr, png_infop info_ptr, int num) void png_free_sCAL(png_structp png_ptr, png_infop info_ptr) { + if (png_ptr == NULL || info_ptr == NULL) + return; if (info_ptr->valid & PNG_INFO_sCAL) { - png_free(png_ptr, info_ptr->scal_unit); - info_ptr->valid &= ~PNG_INFO_sCAL; +#if defined(PNG_FIXED_POINT_SUPPORTED)&& !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, info_ptr->scal_s_width); + png_free(png_ptr, info_ptr->scal_s_height); +#else + if(png_ptr != NULL) + /* silence a compiler warning */ ; +#endif + info_ptr->valid &= ~PNG_INFO_sCAL; } } #endif @@ -305,6 +315,8 @@ png_free_sCAL(png_structp png_ptr, png_infop info_ptr) void png_free_pCAL(png_structp png_ptr, png_infop info_ptr) { + if (png_ptr == NULL || info_ptr == NULL) + return; if (info_ptr->valid & PNG_INFO_pCAL) { png_free(png_ptr, info_ptr->pcal_purpose); @@ -313,9 +325,9 @@ png_free_pCAL(png_structp png_ptr, png_infop info_ptr) { int i; for (i = 0; i < (int)info_ptr->pcal_nparams; i++) - { - png_free(png_ptr, info_ptr->pcal_params[i]); - } + { + png_free(png_ptr, info_ptr->pcal_params[i]); + } png_free(png_ptr, info_ptr->pcal_params); } info_ptr->valid &= ~PNG_INFO_pCAL; @@ -324,10 +336,12 @@ png_free_pCAL(png_structp png_ptr, png_infop info_ptr) #endif #if defined(PNG_iCCP_SUPPORTED) -/* free any pCAL entry */ +/* free any iCCP entry */ void png_free_iCCP(png_structp png_ptr, png_infop info_ptr) { + if (png_ptr == NULL || info_ptr == NULL) + return; if (info_ptr->valid & PNG_INFO_iCCP) { png_free(png_ptr, info_ptr->iccp_name); @@ -342,17 +356,23 @@ png_free_iCCP(png_structp png_ptr, png_infop info_ptr) void png_free_spalettes(png_structp png_ptr, png_infop info_ptr, int num) { + if (png_ptr == NULL || info_ptr == NULL) + return; if (num != -1) { png_free(png_ptr, info_ptr->splt_palettes[num].name); png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->valid &=~ PNG_INFO_sPLT; } else { - png_uint_32 i; + int i; + + if(info_ptr->splt_palettes_num == 0) + return; - for (i = 0; i < info_ptr->splt_palettes_num; i++) - png_free_spalettes(png_ptr, info_ptr, num); + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_free_spalettes(png_ptr, info_ptr, i); png_free(png_ptr, info_ptr->splt_palettes); info_ptr->splt_palettes_num = 0; @@ -360,6 +380,48 @@ png_free_spalettes(png_structp png_ptr, png_infop info_ptr, int num) } #endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void +png_free_unknown_chunks(png_structp png_ptr, png_infop info_ptr, int num) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + if (num != -1) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } + else + { + int i; + + if(info_ptr->unknown_chunks_num == 0) + return; + + for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++) + png_free_unknown_chunks(png_ptr, info_ptr, i); + + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks_num = 0; + } +} +#endif + +#if defined(PNG_hIST_SUPPORTED) +/* free any hIST entry */ +void +png_free_hIST(png_structp png_ptr, png_infop info_ptr) +{ + if (png_ptr == NULL || info_ptr == NULL) + return; + if (info_ptr->valid & PNG_INFO_hIST) + { + png_free(png_ptr, info_ptr->hist); + info_ptr->valid &= ~PNG_INFO_hIST; + } +} +#endif + /* This is an internal routine to free any memory that the info struct is * pointing to before re-using it or freeing the struct itself. Recall * that png_free() checks for NULL pointers for us. @@ -383,6 +445,12 @@ png_info_destroy(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_sPLT_SUPPORTED) png_free_spalettes(png_ptr, info_ptr, -1); #endif +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_unknown_chunks(png_ptr, info_ptr, -1); +#endif +#if defined(PNG_hIST_SUPPORTED) + png_free_hIST(png_ptr, info_ptr); +#endif png_info_init(info_ptr); } @@ -460,7 +528,7 @@ png_charp png_get_copyright(png_structp png_ptr) { if (png_ptr != NULL || png_ptr == NULL) /* silence compiler warning */ - return ("\n libpng version 1.0.5f - December 6, 1999\n\ + return ("\n libpng version 1.0.5j - December 21, 1999\n\ Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.\n\ Copyright (c) 1996, 1997 Andreas Dilger\n\ Copyright (c) 1998, 1999 Glenn Randers-Pehrson\n"); @@ -478,8 +546,8 @@ png_get_libpng_ver(png_structp png_ptr) { /* Version of *.c files used when building libpng */ if(png_ptr != NULL) /* silence compiler warning about unused png_ptr */ - return("1.0.5f"); - return("1.0.5f"); + return("1.0.5j"); + return("1.0.5j"); } png_charp @@ -503,8 +571,8 @@ png_get_header_version(png_structp png_ptr) /* Generate a compiler error if there is an old png.h in the search path. */ void png_check_version - (version_1_0_5f png_h_is_not_version_1_0_5f) + (version_1_0_5j png_h_is_not_version_1_0_5j) { - if(png_h_is_not_version_1_0_5f == NULL) + if(png_h_is_not_version_1_0_5j == NULL) return; } @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.0.5f - December 6, 1999 + * libpng version 1.0.5j - December 21, 1999 * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger * Copyright (c) 1998, 1999 Glenn Randers-Pehrson @@ -9,34 +9,34 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.89c, May 1996: Guy Schalnat * libpng versions 0.90, December 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.0.5f - December 6, 1999: Glenn + * libpng versions 0.97, January 1998, through 1.0.5j - December 21, 1999: Glenn * See also "Contributing Authors", below. * * Y2K compliance in libpng: * ========================= - * - * December 6, 1999 - * + * + * December 21, 1999 + * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. - * + * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.0.5f are Y2K compliant. It is my belief that earlier + * upward through 1.0.5j are Y2K compliant. It is my belief that earlier * versions were also Y2K compliant. - * + * * Libpng only has three year fields. One is a 2-byte unsigned integer * that will hold years up to 65535. The other two hold the date in text * format, and will hold years up to 9999. - * + * * The integer is * "png_uint_16 year" in png_time_struct. - * + * * The strings are * "png_charp time_buffer" in png_struct and * "near_time_buffer", which is a local character string in png.c. - * + * * There are seven time-related functions: - * png.c: png_convert_to_rfc_1123() in png.c + * png.c: png_convert_to_rfc_1123() in png.c * (formerly png_convert_to_rfc_1152() in error) * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c * png_convert_from_time_t() in pngwrite.c @@ -44,8 +44,8 @@ * png_handle_tIME() in pngrutil.c, called in pngread.c * png_set_tIME() in pngset.c * png_write_tIME() in pngwutil.c, called in pngwrite.c - * - * All handle dates properly in a Y2K environment. The + * + * All handle dates properly in a Y2K environment. The * png_convert_from_time_t() function calls gmtime() to convert from system * clock time, which returns (year - 1900), which we properly convert to * the full 4-digit year. There is a possibility that applications using @@ -55,19 +55,19 @@ * but this is not under our control. The libpng documentation has always * stated that it works with 4-digit years, and the APIs have been * documented as such. - * + * * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned * integer to hold the year, and can hold years as large as 65535. - * + * * zlib, upon which libpng depends, is also Y2K compliant. It contains * no date-related code. - * + * * Glenn Randers-Pehrson * libpng maintainer * PNG Development Group - * + * * Note about libpng version numbers: - * + * * Due to various miscommunications, unforeseen code incompatibilities * and occasional factors outside the authors' control, version numbering * on the library has not always been consistent and straightforward. @@ -98,7 +98,7 @@ * 1.0.4a-f 1.0.4a-f 10005 2.1.0.4a-f * 1.0.5 1.0.5 10005 2.1.0.5 * 1.0.5a-d 1.0.5a-d 10006 2.1.0.5a-d - * 1.0.5e-f 1.0.5e-f 10100 2.1.0.5e-f + * 1.0.5e-j 1.0.5e-j 10100 2.1.0.5e-j * 1.1.0 1.1.0 10100 3.1.0.0 * * Henceforth the source version will match the shared-library minor @@ -123,7 +123,7 @@ * Copyright (c) 1996, 1997 Andreas Dilger * (libpng versions 0.90, December 1996, through 0.96, May 1997) * Copyright (c) 1998, 1999 Glenn Randers-Pehrson - * (libpng versions 0.97, January 1998, through 1.0.5f, December 6, 1999) + * (libpng versions 0.97, January 1998, through 1.0.5j, December 21, 1999) * * For the purposes of this copyright and license, "Contributing Authors" * is defined as the following set of individuals: @@ -177,9 +177,9 @@ /* * A "png_get_copyright" function is available, for convenient use in "about" * boxes and the like: - * + * * printf("%s",png_get_copyright(NULL)); - * + * * Also, the PNG logo (in PNG format, of course) is supplied in the * file "pngnow.png". */ @@ -224,7 +224,7 @@ extern "C" { */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.0.5f" +#define PNG_LIBPNG_VER_STRING "1.0.5j" /* Careful here. At one time, Guy wanted to use 082, but that would be octal. * We must not include leading zeros. @@ -324,17 +324,23 @@ typedef png_spalette FAR * png_spalette_p; typedef png_spalette FAR * FAR * png_spalette_pp; #ifdef PNG_TEXT_SUPPORTED -/* png_text holds the contents of a text chunk in a PNG file, and whether - * that contents is compressed or not. The "keyword" field points to a - * regular C string. */ +/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, + * and whether that contents is compressed or not. The "key" field + * points to a regular C string. */ typedef struct png_text_struct { - int compression; /* compression value, see PNG_TEXT_COMPRESSION_ */ + int compression; /* compression value: + -1: tEXt, none + 0: zTXt, deflate + 1: iTXt, none + 2: iTXt, deflate */ png_charp key; /* keyword, 1-79 character description of "text" */ - png_charp lang; /* language code, 1-79 characters */ png_charp text; /* comment, may be an empty string (ie "") */ - /* text_length is no longer used, and now present for compatibility only */ - png_size_t text_length; /* length of "text" field (not used any more) */ + png_size_t text_length; /* length of the text string */ + png_size_t itxt_length; /* length of the itxt string */ + png_charp lang; /* language code, 1-79 characters */ + png_charp lang_key; /* keyword translated UTF-8 string, 0 or more + chars */ } png_text; typedef png_text FAR * png_textp; typedef png_text FAR * FAR * png_textpp; @@ -346,7 +352,9 @@ typedef png_text FAR * FAR * png_textpp; #define PNG_TEXT_COMPRESSION_zTXt_WR -2 #define PNG_TEXT_COMPRESSION_NONE -1 #define PNG_TEXT_COMPRESSION_zTXt 0 -#define PNG_TEXT_COMPRESSION_LAST 1 /* Not a valid value */ +#define PNG_ITXT_COMPRESSION_NONE 1 +#define PNG_ITXT_COMPRESSION_zTXt 2 +#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ /* png_time is a way to hold the time in an machine independent way. * Two conversions are provided, both from time_t and struct tm. There @@ -366,6 +374,26 @@ typedef struct png_time_struct typedef png_time FAR * png_timep; typedef png_time FAR * FAR * png_timepp; +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +/* png_unknown_chunk is a structure to hold queued chunks for which there is + * no specific support. The idea is that we can use this to queue + * up private chunks for output even though the library doesn't actually + * know about their semantics. + */ +typedef struct png_unknown_chunk_t +{ + png_byte name[5]; + png_byte *data; + png_size_t size; + + /* libpng-using applications should NOT directly modify this byte. */ + png_byte location; /* mode of operation at read time */ +} +png_unknown_chunk; +typedef png_unknown_chunk FAR * png_unknown_chunkp; +typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; +#endif + /* png_info is a structure that holds the information in a PNG file so * that the application can find out the characteristics of the image. * If you are reading the file, this structure will tell you what is @@ -389,16 +417,16 @@ typedef png_time FAR * FAR * png_timepp; * * The following members may have allocated storage attached that should be * cleaned up before the structure is discarded: palette, text, pcal_purpose, - * pcal_units, pcal_params, iccp_name, iccp_profile, splt_palettes, and - * scal_unit. Of these, the text, pcal_*, iccp_*, splt_*, and scal_unit - * members are automatically freed when the info structure is deallocated. + * pcal_units, pcal_params, hist, iccp_name, iccp_profile, splt_palettes, and + * scal_unit. Of these, the text, pcal_*, hist, iccp_*, splt_*, and scal_unit + * members are automatically freed when the info structure is deallocated. * The palette member is not. * * More allocation details: all the chunk-reading functions that change these * members go through the corresponding png_set_* functions. Functions to * clear these members are available: see png_free_*. The png_set_* functions - * do not depend on being able to point info structure members to any of the - * storage they are passed (they make their own copies), EXCEPT that the + * do not depend on being able to point info structure members to any of the + * storage they are passed (they make their own copies), EXCEPT that the * png_set_text function uses the same storage passed to them * in the text_ptr or itxt_ptr structure argument. */ @@ -435,8 +463,13 @@ typedef struct png_info_struct * on which the image was created, normally in the range [1.0, 2.5]. * Data is valid if (valid & PNG_INFO_gAMA) is non-zero. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */ +#endif +#endif #if defined(PNG_sRGB_SUPPORTED) /* GR-P, 0.96a */ @@ -447,7 +480,7 @@ typedef struct png_info_struct #if defined(PNG_TEXT_SUPPORTED) /* The tEXt, and zTXt chunks contain human-readable textual data in * uncompressed, compressed, and optionally compressed forms, respectively. - * The data in "text" is an array of pointers to uncompressed, + * The data in "text" is an array of pointers to uncompressed, * null-terminated C strings. Each chunk has a keyword that describes the * textual data contained in that chunk. Keywords are not required to be * unique, and the text string may be empty. Any number of text chunks may @@ -456,6 +489,9 @@ typedef struct png_info_struct int num_text; /* number of comments read/to write */ int max_text; /* current size of text array */ png_textp text; /* array of comments read/to write */ + int num_text_old; /* number of comments read/to write */ + png_textp text_old; /* array of comments read/to write, backward + compatible with libpng-1.0.5 and earlier */ #endif /* PNG_TEXT_SUPPORTED */ #if defined(PNG_tIME_SUPPORTED) @@ -538,6 +574,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * colors in the image as the creator. Values are in the range * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED float x_white; float y_white; float x_red; @@ -547,6 +584,17 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) float x_blue; float y_blue; #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_x_white; + png_fixed_point int_y_white; + png_fixed_point int_x_red; + png_fixed_point int_y_red; + png_fixed_point int_x_green; + png_fixed_point int_y_green; + png_fixed_point int_x_blue; + png_fixed_point int_y_blue; +#endif +#endif #if defined(PNG_pCAL_SUPPORTED) /* The pCAL chunk describes a transformation between the stored pixel @@ -585,18 +633,30 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) #endif #if defined(PNG_sCAL_SUPPORTED) - /* The sCAL chunk describes the actual physical dimensions of the + /* The sCAL chunk describes the actual physical dimensions of the * subject matter of the graphic. The chunk contains a unit specification - * (an ASCII string), and two ASCII strings representing floating-point + * a byte value, and two ASCII strings representing floating-point * values. The values are width and height corresponsing to one pixel * in the image. This external representation is converted to double * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero. */ - png_charp scal_unit; /* unit of physical scale */ + png_byte scal_unit; /* unit of physical scale */ +#ifdef PNG_FLOATING_POINT_SUPPORTED double scal_pixel_width; /* width of one pixel */ double scal_pixel_height; /* height of one pixel */ +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp scal_s_width; /* string containing height */ + png_charp scal_s_height; /* string containing width */ +#endif +#endif #endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) + /* storage for unknown chunks that the library doesn't recognize. */ + png_unknown_chunkp unknown_chunks; + png_size_t unknown_chunks_num; +#endif } png_info; typedef png_info FAR * png_infop; @@ -643,6 +703,12 @@ typedef png_info FAR * FAR * png_infopp; #define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ #define PNG_EQUATION_LAST 4 /* Not a valid value */ +/* These are for the sCAL chunk. These values should NOT be changed. */ +#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ +#define PNG_SCALE_METER 1 /* meters per pixel */ +#define PNG_SCALE_RADIAN 2 /* radians per pixel */ +#define PNG_SCALE_LAST 3 /* Not a valid value */ + /* These are for the pHYs chunk. These values should NOT be changed. */ #define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ #define PNG_RESOLUTION_METER 1 /* pixels/meter */ @@ -815,7 +881,9 @@ struct png_struct_def #if defined(PNG_READ_bKGD_SUPPORTED) png_byte background_gamma_type; +#ifdef PNG_FLOATING_POINT_SUPPORTED float background_gamma; +#endif png_color_16 background; /* background color in screen gamma space */ # if defined(PNG_READ_GAMMA_SUPPORTED) png_color_16 background_1; /* background normalized to gamma 1.0 */ @@ -830,9 +898,14 @@ struct png_struct_def #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) int gamma_shift; /* number of "insignificant" bits 16-bit gamma */ +#ifdef PNG_FLOATING_POINT_SUPPORTED float gamma; /* file gamma value */ float screen_gamma; /* screen gamma value (display_exponent) */ #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_gamma; +#endif +#endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) png_bytep gamma_table; /* gamma table for 8-bit depth files */ @@ -937,9 +1010,9 @@ struct png_struct_def }; /* This prevents a compiler error in png_get_copyright() in png.c if png.c -and png.h are both at * version 1.0.5f +and png.h are both at * version 1.0.5j */ -typedef png_structp version_1_0_5f; +typedef png_structp version_1_0_5j; typedef png_struct FAR * FAR * png_structpp; @@ -1056,8 +1129,10 @@ extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr)); #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) /* Reduce RGB to grayscale. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr, int error_action, double red, double green )); +#endif extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp png_ptr)); #endif @@ -1122,9 +1197,11 @@ extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr)); #if defined(PNG_READ_BACKGROUND_SUPPORTED) /* Handle alpha and tRNS by replacing with a background color. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr, png_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)); +#endif #define PNG_BACKGROUND_GAMMA_UNKNOWN 0 #define PNG_BACKGROUND_GAMMA_SCREEN 1 #define PNG_BACKGROUND_GAMMA_FILE 2 @@ -1145,9 +1222,11 @@ extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr, #if defined(PNG_READ_GAMMA_SUPPORTED) /* Handle gamma correction. Screen_gamma=(display_exponent) */ +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr, double screen_gamma, double default_file_gamma)); #endif +#endif #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) @@ -1312,9 +1391,11 @@ extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method, * the weights and costs are set to 1.0, this degenerates the WEIGHTED method * to the UNWEIGHTED method, but with added encoding time/computation. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr, int heuristic_method, int num_weights, png_doublep filter_weights, png_doublep filter_costs)); +#endif #endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ /* Heuristic used for row filter selection. These defines should NOT be @@ -1550,8 +1631,10 @@ extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp png_ptr, png_infop info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp png_ptr, png_infop info_ptr)); +#endif /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ extern PNG_EXPORT(png_uint_32, png_get_x_offset_pixels) PNGARG((png_structp @@ -1580,27 +1663,57 @@ extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr, #endif #if defined(PNG_READ_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr, png_infop info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, double *blue_y)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point + *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, + png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point + *int_blue_x, png_fixed_point *int_blue_y)); +#endif +#endif #if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr, png_infop info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif #if defined(PNG_READ_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr, png_infop info_ptr, double *file_gamma)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point *int_file_gamma)); +#endif +#endif #if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr, png_infop info_ptr, double file_gamma)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_fixed_point int_file_gamma)); +#endif +#endif #if defined(PNG_READ_hIST_SUPPORTED) extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr, @@ -1698,6 +1811,8 @@ extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr, extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr, png_infop info_ptr, png_charp name, int compression_type, png_charp profile, int proflen)); +extern PNG_EXPORT(void,png_free_iCCP) PNGARG((png_structp png_ptr, + png_infop info_ptr)); #endif #if defined(PNG_READ_sPLT_SUPPORTED) @@ -1708,14 +1823,23 @@ extern PNG_EXPORT(png_uint_32,png_get_spalettes) PNGARG((png_structp png_ptr, #if defined(PNG_sPLT_SUPPORTED) extern PNG_EXPORT(void,png_set_spalettes) PNGARG((png_structp png_ptr, png_infop info_ptr, png_spalette_p entries, int nentries)); +extern PNG_EXPORT(void,png_free_spalettes) PNGARG((png_structp png_ptr, + png_infop info_ptr, int num)); #endif -#if defined(PNG_sPLT_SUPPORTED) -extern PNG_EXPORT(void,png_free_spallettes) PNGARG((png_structp png_ptr, - png_infop info_ptr, int num)); +#if defined(PNG_READ_iTXt_SUPPORTED) +/* png_get_itxt also returns the number of text chunks in *num_text */ +extern PNG_EXPORT(png_uint_32,png_get_itxt) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp *text_ptr, int *num_text)); +#endif + +#if defined(PNG_TEXT_SUPPORTED) +extern PNG_EXPORT(void,png_set_itxt) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_textp text_ptr, int num_text)); #endif #if defined(PNG_READ_TEXT_SUPPORTED) +/* Old interface; apps should use png_get_itxt instead */ /* png_get_text also returns the number of text chunks in *num_text */ extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr, int *num_text)); @@ -1725,7 +1849,7 @@ extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr, extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, int num_text)); extern PNG_EXPORT(void,png_free_text) PNGARG((png_structp png_ptr, - png_infop info_ptr, int num_text)); + png_infop info_ptr, int num_text_old)); #endif #if defined(PNG_READ_tIME_SUPPORTED) @@ -1751,13 +1875,26 @@ extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr, #endif #if defined(PNG_READ_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charpp unit, double *width, double *height)); + png_infop info_ptr, int *unit, double *width, double *height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); +#endif +#endif #endif /* PNG_READ_sCAL_SUPPORTED */ -#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#if defined(PNG_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr, - png_infop info_ptr, png_charp unit, double width, double height)); + png_infop info_ptr, int unit, double width, double height)); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr, + png_infop info_ptr, int unit, png_charp swidth, png_charp sheight)); +#endif #endif /* PNG_READ_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ #if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) @@ -1765,6 +1902,17 @@ extern PNG_EXPORT(void,png_free_sCAL) PNGARG((png_structp png_ptr, png_infop info_ptr)); #endif /* PNG_READ_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */ +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp + png_ptr, int keep, png_bytep chunk_list, int num_chunks)); +extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)); +extern PNG_EXPORT(void,png_free_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, int num)); +extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkpp entries)); +#endif + /* Define PNG_DEBUG at compile time for debugging information. Higher * numbers for PNG_DEBUG mean more debugging information. This has * only been added since version 0.95 so it is not implemented throughout @@ -1804,7 +1952,7 @@ extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr)); extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr)); extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); -#define PNG_HEADER_VERSION_STRING " libpng version 1.0.5f - December 6, 1999 (header)\n" +#define PNG_HEADER_VERSION_STRING " libpng version 1.0.5j - December 21, 1999 (header)\n" #ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED /* With these routines we avoid an integer divide, which will be slower on @@ -1888,7 +2036,7 @@ extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); #define PNG_EXPAND 0x1000 #define PNG_GAMMA 0x2000 #define PNG_GRAY_TO_RGB 0x4000 -#define PNG_FILLER 0x8000 +#define PNG_FILLER 0x8000L #define PNG_PACKSWAP 0x10000L #define PNG_SWAP_ALPHA 0x20000L #define PNG_STRIP_ALPHA 0x40000L @@ -1924,6 +2072,8 @@ extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); #define PNG_FLAG_FREE_PALETTE 0x1000 #define PNG_FLAG_FREE_TRANS 0x2000 #define PNG_FLAG_FREE_HIST 0x4000 +#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L +#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ @@ -1948,6 +2098,7 @@ extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr)); #else #define png_sig png_sig_bytes(NULL) #endif +#endif /* PNG_NO_EXTERN */ /* Constant strings for known chunk types. If you need to add a chunk, * define the name here, and add an invocation of the macro in png.c and @@ -1999,7 +2150,6 @@ PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; #endif /* PNG_USE_GLOBAL_ARRAYS */ -#endif /* PNG_NO_EXTERN */ /* Inline macros to do direct reads of bytes from the input buffer. These * require that you are using an architecture that uses PNG byte ordering @@ -2132,8 +2282,14 @@ PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); #if defined(PNG_WRITE_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point + file_gamma)); +#endif +#endif #if defined(PNG_WRITE_sBIT_SUPPORTED) PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, @@ -2141,11 +2297,20 @@ PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, #endif #if defined(PNG_WRITE_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y)); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, + png_fixed_point int_white_x, png_fixed_point int_white_y, + png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point + int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)); +#endif +#endif #if defined(PNG_WRITE_sRGB_SUPPORTED) PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, @@ -2159,8 +2324,8 @@ PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, #endif #if defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_spalette_p palette)); +PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, + png_spalette_p palette)); #endif #if defined(PNG_WRITE_tRNS_SUPPORTED) @@ -2178,6 +2343,11 @@ PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, int num_hist)); #endif +#if defined(PNG_hIST_SUPPORTED) +extern PNG_EXPORT(void,png_free_hIST) PNGARG((png_structp png_ptr, + png_infop info_ptr)); +#endif + #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, @@ -2195,8 +2365,9 @@ PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, #endif #if defined(PNG_WRITE_iTXt_SUPPORTED) -PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, - int compression, png_charp key, png_charp lang, png_charp text)); +PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, + int compression, png_charp key, png_charp lang, png_charp lang_key, + png_charp text)); #endif #if defined(PNG_WRITE_oFFs_SUPPORTED) @@ -2222,8 +2393,15 @@ PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, #endif #if defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, - png_charp unit, double width, double height)); + int unit, double width, double height)); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, + int unit, png_charp width, png_charp height)); +#endif +#endif #endif /* Called when finished processing a row of data */ @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -17,21 +17,7 @@ #ifndef PNGCONF_H #define PNGCONF_H -#define PNG_NO_EASY_ACCESS -#define PNG_NO_READ_EMPTY_PLTE -#define PNG_NO_WRITE_TRANSFORMS -#define PNG_READ_USER_TRANSFORM_SUPPORTED -#define PNG_READ_STRIP_ALPHA_SUPPORTED -#define PNG_READ_EXPAND_SUPPORTED -#define PNG_READ_FILLER_SUPPORTED -#define PNG_READ_GRAY_TO_RGB_SUPPORTED -#define PNG_READ_RGB_TO_GRAY_SUPPORTED -#define PNG_READ_BACKGROUND_SUPPORTED -#define PNG_READ_GAMMA_SUPPORTED -#define PNG_ZBUF_SIZE 524288 -/* -#define PNG_NO_GLOBAL_ARRAYS -*/ +#include "pngcrush.h" /* except for this line, this is libpng's pngconf.h */ /* This is the size of the compression buffer, and thus the size of * an IDAT chunk. Make this whatever size you feel is best for your @@ -174,6 +160,7 @@ __dont__ include it again * them inside an appropriate ifdef/endif pair for portability. */ +#if !defined(PNG_NO_FLOATING_POINT_SUPPORTED) #if defined(MACOS) /* We need to check that <math.h> hasn't already been included earlier * as it seems it doesn't agree with <fp.h>, yet we should really use @@ -185,6 +172,7 @@ __dont__ include it again #else #include <math.h> #endif +#endif /* Codewarrior on NT has linking problems without this. */ #if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) @@ -276,6 +264,7 @@ __dont__ include it again */ + #if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \ !defined(PNG_NO_READ_TRANSFORMS) #define PNG_READ_TRANSFORMS_SUPPORTED @@ -434,6 +423,14 @@ __dont__ include it again #define PNG_ASSEMBLER_CODE_SUPPORTED #endif +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +#define PNG_FLOATING_POINT_SUPPORTED +#endif + +#ifndef PNG_NO_FIXED_POINT_SUPPORTED +#define PNG_FIXED_POINT_SUPPORTED +#endif + /* Do not use global arrays (helps with building DLL's) * They are no longer used in libpng itself, since version 1.0.5c, * but might be required for some pre-1.0.5c applications. @@ -480,199 +477,220 @@ __dont__ include it again #endif #ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED + +#ifdef PNG_NO_READ_TEXT +# define PNG_NO_READ_iTXt +# define PNG_NO_READ_tEXt +# define PNG_NO_READ_zTXt +#endif #ifndef PNG_NO_READ_bKGD -#define PNG_READ_bKGD_SUPPORTED -#define PNG_bKGD_SUPPORTED +# define PNG_READ_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED #endif #ifndef PNG_NO_READ_cHRM -#define PNG_READ_cHRM_SUPPORTED -#define PNG_cHRM_SUPPORTED +# define PNG_READ_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED #endif #ifndef PNG_NO_READ_gAMA -#define PNG_READ_gAMA_SUPPORTED -#define PNG_gAMA_SUPPORTED +# define PNG_READ_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED #endif #ifndef PNG_NO_READ_hIST -#define PNG_READ_hIST_SUPPORTED -#define PNG_hIST_SUPPORTED +# define PNG_READ_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED #endif #ifndef PNG_NO_READ_iCCP -#define PNG_READ_iCCP_SUPPORTED -#define PNG_iCCP_SUPPORTED +# define PNG_READ_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED #endif #ifndef PNG_NO_READ_iTXt -#define PNG_READ_iTXt_SUPPORTED -#define PNG_iTXt_SUPPORTED +# define PNG_READ_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED #endif #ifndef PNG_NO_READ_oFFs -#define PNG_READ_oFFs_SUPPORTED -#define PNG_oFFs_SUPPORTED +# define PNG_READ_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED #endif #ifndef PNG_NO_READ_pCAL -#define PNG_READ_pCAL_SUPPORTED -#define PNG_pCAL_SUPPORTED +# define PNG_READ_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED #endif #ifndef PNG_NO_READ_sCAL -#define PNG_READ_sCAL_SUPPORTED -#define PNG_sCAL_SUPPORTED +# define PNG_READ_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED #endif #ifndef PNG_NO_READ_pHYs -#define PNG_READ_pHYs_SUPPORTED -#define PNG_pHYs_SUPPORTED +# define PNG_READ_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED #endif #ifndef PNG_NO_READ_sBIT -#define PNG_READ_sBIT_SUPPORTED -#define PNG_sBIT_SUPPORTED +# define PNG_READ_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED #endif #ifndef PNG_NO_READ_sPLT -#define PNG_READ_sPLT_SUPPORTED -#define PNG_sPLT_SUPPORTED +# define PNG_READ_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED #endif #ifndef PNG_NO_READ_sRGB -#define PNG_READ_sRGB_SUPPORTED -#define PNG_sRGB_SUPPORTED +# define PNG_READ_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED #endif #ifndef PNG_NO_READ_tEXt -#define PNG_READ_tEXt_SUPPORTED -#define PNG_tEXt_SUPPORTED +# define PNG_READ_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED #endif #ifndef PNG_NO_READ_tIME -#define PNG_READ_tIME_SUPPORTED -#define PNG_tIME_SUPPORTED +# define PNG_READ_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED #endif #ifndef PNG_NO_READ_tRNS -#define PNG_READ_tRNS_SUPPORTED -#define PNG_tRNS_SUPPORTED +# define PNG_READ_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED #endif #ifndef PNG_NO_READ_zTXt -#define PNG_READ_zTXt_SUPPORTED -#define PNG_zTXt_SUPPORTED +# define PNG_READ_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +#endif +#ifndef PNG_NO_READ_UNKNOWN_CHUNKS +# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED #endif #ifndef PNG_NO_READ_OPT_PLTE -#define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the optional */ -#endif /* PLTE chunk in RGB and RGBA images */ +# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */ +#endif /* optional PLTE chunk in RGB and RGBA images */ #if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \ defined(PNG_READ_zTXt_SUPPORTED) -#define PNG_READ_TEXT_SUPPORTED -#define PNG_TEXT_SUPPORTED +# define PNG_READ_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED #endif #endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */ #ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED -#ifndef PNG_NO_WRITE_bKGD -#define PNG_WRITE_bKGD_SUPPORTED -#ifndef PNG_bKGD_SUPPORTED -# define PNG_bKGD_SUPPORTED +#ifdef PNG_NO_WRITE_TEXT +# define PNG_NO_WRITE_iTXt +# define PNG_NO_WRITE_tEXt +# define PNG_NO_WRITE_zTXt #endif +#ifndef PNG_NO_WRITE_bKGD +# define PNG_WRITE_bKGD_SUPPORTED +# ifndef PNG_bKGD_SUPPORTED +# define PNG_bKGD_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_cHRM -#define PNG_WRITE_cHRM_SUPPORTED -#ifndef PNG_cHRM_SUPPORTED -# define PNG_cHRM_SUPPORTED -#endif +# define PNG_WRITE_cHRM_SUPPORTED +# ifndef PNG_cHRM_SUPPORTED +# define PNG_cHRM_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_gAMA -#define PNG_WRITE_gAMA_SUPPORTED -#ifndef PNG_gAMA_SUPPORTED -# define PNG_gAMA_SUPPORTED -#endif +# define PNG_WRITE_gAMA_SUPPORTED +# ifndef PNG_gAMA_SUPPORTED +# define PNG_gAMA_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_hIST -#define PNG_WRITE_hIST_SUPPORTED -#ifndef PNG_hIST_SUPPORTED -# define PNG_hIST_SUPPORTED -#endif +# define PNG_WRITE_hIST_SUPPORTED +# ifndef PNG_hIST_SUPPORTED +# define PNG_hIST_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_iCCP -#define PNG_WRITE_iCCP_SUPPORTED -#ifndef PNG_iCCP_SUPPORTED -# define PNG_iCCP_SUPPORTED -#endif +# define PNG_WRITE_iCCP_SUPPORTED +# ifndef PNG_iCCP_SUPPORTED +# define PNG_iCCP_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_iTXt -#define PNG_WRITE_iTXt_SUPPORTED -#ifndef PNG_iTXt_SUPPORTED -# define PNG_iTXt_SUPPORTED -#endif +# define PNG_WRITE_iTXt_SUPPORTED +# ifndef PNG_iTXt_SUPPORTED +# define PNG_iTXt_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_oFFs -#define PNG_WRITE_oFFs_SUPPORTED -#ifndef PNG_oFFs_SUPPORTED -# define PNG_oFFs_SUPPORTED -#endif +# define PNG_WRITE_oFFs_SUPPORTED +# ifndef PNG_oFFs_SUPPORTED +# define PNG_oFFs_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_pCAL -#define PNG_WRITE_pCAL_SUPPORTED -#ifndef PNG_pCAL_SUPPORTED -# define PNG_pCAL_SUPPORTED -#endif +# define PNG_WRITE_pCAL_SUPPORTED +# ifndef PNG_pCAL_SUPPORTED +# define PNG_pCAL_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_sCAL -#define PNG_WRITE_sCAL_SUPPORTED -#ifndef PNG_sCAL_SUPPORTED -# define PNG_sCAL_SUPPORTED -#endif +# define PNG_WRITE_sCAL_SUPPORTED +# ifndef PNG_sCAL_SUPPORTED +# define PNG_sCAL_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_pHYs -#define PNG_WRITE_pHYs_SUPPORTED -#ifndef PNG_pHYs_SUPPORTED -# define PNG_pHYs_SUPPORTED -#endif +# define PNG_WRITE_pHYs_SUPPORTED +# ifndef PNG_pHYs_SUPPORTED +# define PNG_pHYs_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_sBIT -#define PNG_WRITE_sBIT_SUPPORTED -#ifndef PNG_sBIT_SUPPORTED -# define PNG_sBIT_SUPPORTED -#endif +# define PNG_WRITE_sBIT_SUPPORTED +# ifndef PNG_sBIT_SUPPORTED +# define PNG_sBIT_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_sPLT -#define PNG_WRITE_sPLT_SUPPORTED -#ifndef PNG_sPLT_SUPPORTED -# define PNG_sPLT_SUPPORTED -#endif +# define PNG_WRITE_sPLT_SUPPORTED +# ifndef PNG_sPLT_SUPPORTED +# define PNG_sPLT_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_sRGB -#define PNG_WRITE_sRGB_SUPPORTED -#ifndef PNG_sRGB_SUPPORTED -# define PNG_sRGB_SUPPORTED -#endif +# define PNG_WRITE_sRGB_SUPPORTED +# ifndef PNG_sRGB_SUPPORTED +# define PNG_sRGB_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_tEXt -#define PNG_WRITE_tEXt_SUPPORTED -#ifndef PNG_tEXt_SUPPORTED -# define PNG_tEXt_SUPPORTED -#endif +# define PNG_WRITE_tEXt_SUPPORTED +# ifndef PNG_tEXt_SUPPORTED +# define PNG_tEXt_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_tIME -#define PNG_WRITE_tIME_SUPPORTED -#ifndef PNG_tIME_SUPPORTED -# define PNG_tIME_SUPPORTED -#endif +# define PNG_WRITE_tIME_SUPPORTED +# ifndef PNG_tIME_SUPPORTED +# define PNG_tIME_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_tRNS -#define PNG_WRITE_tRNS_SUPPORTED -#ifndef PNG_tRNS_SUPPORTED -# define PNG_tRNS_SUPPORTED -#endif +# define PNG_WRITE_tRNS_SUPPORTED +# ifndef PNG_tRNS_SUPPORTED +# define PNG_tRNS_SUPPORTED +# endif #endif #ifndef PNG_NO_WRITE_zTXt -#define PNG_WRITE_zTXt_SUPPORTED -#ifndef PNG_zTXt_SUPPORTED -# define PNG_zTXt_SUPPORTED +# define PNG_WRITE_zTXt_SUPPORTED +# ifndef PNG_zTXt_SUPPORTED +# define PNG_zTXt_SUPPORTED +# endif #endif +#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS +# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED +# define PNG_UNKNOWN_CHUNKS_SUPPORTED +# endif #endif #if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \ defined(PNG_WRITE_zTXt_SUPPORTED) -#define PNG_WRITE_TEXT_SUPPORTED -#ifndef PNG_TEXT_SUPPORTED -# define PNG_TEXT_SUPPORTED -#endif +# define PNG_WRITE_TEXT_SUPPORTED +# ifndef PNG_TEXT_SUPPORTED +# define PNG_TEXT_SUPPORTED +# endif #endif #endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */ /* need the time information for reading tIME chunks */ #if defined(PNG_READ_tIME_SUPPORTED) || defined(PNG_WRITE_tIME_SUPPORTED) -#include <time.h> +# include <time.h> #endif /* Some typedefs to get us started. These should be safe on most of the @@ -755,6 +773,10 @@ typedef size_t png_size_t; #define FARDATA #endif +/* Typedef for floating-point numbers that are converted + to fixed-point with a multiple of 100,000, e.g., int_gamma */ +typedef png_int_32 png_fixed_point; + /* Add typedefs for pointers */ typedef void FAR * png_voidp; typedef png_byte FAR * png_bytep; @@ -764,7 +786,10 @@ typedef png_uint_16 FAR * png_uint_16p; typedef png_int_16 FAR * png_int_16p; typedef PNG_CONST char FAR * png_const_charp; typedef char FAR * png_charp; +typedef png_fixed_point FAR * png_fixed_point_p; +#ifdef PNG_FLOATING_POINT_SUPPORTED typedef double FAR * png_doublep; +#endif /* Pointers to pointers; i.e. arrays */ typedef png_byte FAR * FAR * png_bytepp; @@ -774,7 +799,10 @@ typedef png_uint_16 FAR * FAR * png_uint_16pp; typedef png_int_16 FAR * FAR * png_int_16pp; typedef PNG_CONST char FAR * FAR * png_const_charpp; typedef char FAR * FAR * png_charpp; +typedef png_fixed_point FAR * FAR * png_fixed_point_pp; +#ifdef PNG_FLOATING_POINT_SUPPORTED typedef double FAR * FAR * png_doublepp; +#endif /* Pointers to pointers to pointers; i.e. pointer to array */ typedef char FAR * FAR * FAR * png_charppp; @@ -823,7 +851,7 @@ typedef z_stream FAR * png_zstreamp; # define PNG_EXPORT_VAR(type) extern __declspec(dllexport) type # endif # ifdef PNG_ATTR_DLLEXP -# define PNG_EXPORT_VAR(type) extern type __attribute__((dllexport)) +# define PNG_EXPORT_VAR(type) extern type __attribute__((dllexport)) # endif # ifdef PNG_DECL_DLLIMP # define PNG_EXPORT_VAR(type) extern __declspec(dllimport) type @@ -863,7 +891,7 @@ typedef z_stream FAR * png_zstreamp; #endif /* End of memory model independent support */ -/* Just a double check that someone hasn't tried to define something +/* Just a little check that someone hasn't tried to define something * contradictory. */ #if (PNG_ZBUF_SIZE > 65536) && defined(PNG_MAX_MALLOC_64K) diff --git a/pngcrush.c b/pngcrush.c index 2a5f11039..19a14cb28 100644 --- a/pngcrush.c +++ b/pngcrush.c @@ -1,4 +1,4 @@ -/* crushpng.c - a simple program to recompress png files +/* pngcrush.c - a simple program to recompress png files * * This program reads in a PNG image, and writes it out again, with the * optimum filter_type and zlib_level. It uses brute force (trying @@ -6,20 +6,21 @@ * levels 3 and 9). It does the most time-consuming method last in case * it turns out to be the best. * - * Optionally, it can remove unwanted chunks or add gAMA and sRGB chunks. + * Optionally, it can remove unwanted chunks or add gAMA, sRGB, bKGD, + * tEXt/zTXt, and tRNS chunks. * - * Uses libpng-1.0.5a. This program was based upon libpng's pngtest.c. + * Uses libpng-1.0.5i. This program was based upon libpng's pngtest.c. * * Thanks to Greg Roelofs for various bug fixes, suggestions, and * occasionally creating Linux executables. */ -#define PNGCRUSH_VERSION "1.2.1" +#define PNGCRUSH_VERSION "1.2.2" /* * COPYRIGHT NOTICE, DISCLAIMER, AND LICENSE: * - * Copyright (c) 1998, 1999, Glenn Randers-Pehrson + * Copyright (c) 1998, 1999, Glenn Randers-Pehrson (randeg@alum.rpi.edu) * * The pngcrush program is supplied "AS IS". The Author disclaims all * warranties, expressed or implied, including, without limitation, the @@ -45,17 +46,47 @@ * * Version 1.2.*: check for unused alpha channel and ok-to-reduce-depth. * Rearrange palette to put most-used color first and - * transparent color second. + * transparent color second. Finish pplt (partial palette) feature. * - * Version 1.2.2: Add iCCP, iTXt, sCAL, and sPLT support, which are - * now supported by libpng. + * Version 1.2.*: Use an alternate write function for the trial passes, that + * simply counts bytes rather than actually writing to a file, to save wear + * and tear on disk drives. + * + * Version 1.2.*: Drop explicit support for pCAL, hIST, sCAL, sPLT, iCCP, + * tIME, and cHRM chunks and handle them as unknown but safe-to-copy, once + * libpng is able to override the unsafe-to-copy status of unknown chunks. * * Change log: * + * Version 1.2.2: Added support for handling unknown chunks. + * + * pngcrush is now fixed-point only, unless PNG_NO_FLOATING_POINT_SUPPORTED + * is undefined in pngcrush.h. + * + * Added support for the iCCP, iTXt, sCAL, and sPLT chunks, which + * are now supported by libpng (since libpng-1.0.5j). None of these have + * been adequately tested. + * + * #ifdef'ed out more unused code (weighted filters and progressive read; + * this saves about 15k in the size of the executable). + * + * Moved the special definitions from pngconf.h into a new pngcrush.h + * + * Disallow 256-byte compression window size when writing, to work around + * an apparent zlib bug. Either deflate was producing incorrect results in a + * 21x21 4-bit image or inflate was decoding it incorrectly; the uncompressed + * stream is 252 bytes, which is uncomfortably close to the resulting + * 256-byte compression window. This workaround can be removed when zlib + * is fixed. + * + * The "-m method" can be used any of the 124 methods, without having to + * specify the filter, level, and strategy, instead of just the first 10. + * * Version 1.2.1: Fixed -srgb parameter so it really does take an argument, * and so it continues to use "0" if an integer does not follow the -srgb. * Added "-plte_len n" argument for truncating the PLTE. Be sure not to * truncate it to less than the greatest index actually appearing in IDAT. + * Built with libpng-1.0.5f. * * Version 1.2.0: Removed registration requirement. Added open source * license. Redefined TOO_FAR=32k in deflate.c. @@ -128,17 +159,24 @@ static PNG_CONST char *dirname = "pngcrush.bak"; static PNG_CONST char *extension = "_C.png"; static int number_of_open_files; +static int do_pplt = 0; +char pplt_string[1024]; char *ip, *op, *dot; char in_string[256]; char prog_string[256]; char out_string[256]; char in_extension[256]; -int text_inputs=0; +static int text_inputs=0; int text_where[10]; /* 0: no text; 1: before PLTE; 2: after PLTE */ -int text_compression[10]; /* 0: tEXt; 1: zTXt */ +int text_compression[10]; /* -1: uncompressed tEXt; 0: compressed zTXt + 1: uncompressed iTXt; 2: compressed iTXt */ char text_text[20480]; /* It would be nice to png_malloc this, but we don't * have a png_ptr yet when we need it. */ char text_keyword[800]; +#ifdef PNG_iTXt_SUPPORTED +char text_lang[800]; +char text_lang_key[800]; +#endif int best; char buffer[256]; @@ -180,9 +218,11 @@ static int best_of_three; static int methods_specified=0; static int intent=-1; static int plte_len=-1; -static double specified_gamma=0.; -static double force_specified_gamma=0.; +#ifdef PNG_gAMA_SUPPORTED +static int specified_gamma=0; +static int force_specified_gamma=0; static int double_gamma=0; +#endif static int names; static int have_trns=0; static png_uint_16 trns_index=0; @@ -329,6 +369,8 @@ void png_crush_pause(void) char keystroke; fprintf(STDERR, "Press [ENTER] key to continue.\n"); keystroke=(char)getc(stdin); + if (keystroke) + /* stifle compiler warning */ ; } } #define PNG_CRUSH_CLEANUP \ @@ -376,16 +418,20 @@ int keep_chunk(png_const_charp name, char *argv[]) (!strncmp(name,"gIFx",4) && (!strncmp(argv[i],"gifx",4) || allb)) || (!strncmp(name,"hIST",4) && (!strncmp(argv[i],"hist",4) || allb)) || (!strncmp(name,"iCCP",4) && (!strncmp(argv[i],"iccp",4) || allb)) || + (!strncmp(name,"iTXt",4) && (!strncmp(argv[i],"itxt",4) || allb)) || + (!strncmp(name,"iTXt",4) && (!strncmp(argv[i],"text",4) )) || (!strncmp(name,"oFFs",4) && (!strncmp(argv[i],"offs",4) || allb)) || (!strncmp(name,"pHYs",4) && (!strncmp(argv[i],"phys",4) || allb)) || (!strncmp(name,"pCAL",4) && (!strncmp(argv[i],"pcal",4) || allb)) || (!strncmp(name,"sBIT",4) && (!strncmp(argv[i],"sbit",4) || allb)) || + (!strncmp(name,"sCAL",4) && (!strncmp(argv[i],"scal",4) || allb)) || (!strncmp(name,"sRGB",4) && (!strncmp(argv[i],"srgb",4) || allb)) || + (!strncmp(name,"sPLT",4) && (!strncmp(argv[i],"splt",4) || allb)) || (!strncmp(name,"tEXt",4) && (!strncmp(argv[i],"text",4) || allb)) || (!strncmp(name,"tIME",4) && (!strncmp(argv[i],"time",4) || allb)) || - (!strncmp(name,"tRNS",4) && (!strncmp(argv[i],"trns",4))) || - (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"text",4) || allb)) || - (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"ztxt",4)))) + (!strncmp(name,"tRNS",4) && (!strncmp(argv[i],"trns",4) )) || + (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"ztxt",4) || allb)) || + (!strncmp(name,"zTXt",4) && (!strncmp(argv[i],"text",4) ))) { things_have_changed=1; if(verbose > 0 && trial == 1) @@ -455,7 +501,10 @@ main(int argc, char *argv[]) int lv[MAX_METHODSP1]; int zs[MAX_METHODSP1]; int ntrial; - double file_gamma=0.; + int lev, strat, filt; +#ifdef PNG_gAMA_SUPPORTED + png_fixed_point file_gamma=0; +#endif char *cp; int i; @@ -492,7 +541,27 @@ main(int argc, char *argv[]) fm[1]=0; fm[2]=1; fm[4]=0; fm[5]=1; fm[7]=0; fm[8]=1; lv[1]=4; lv[2]=4; lv[3]=4; lv[9]=2; zs[1]=0; zs[2]=0; zs[5]= 0; zs[6]=0; zs[7]=0; zs[9]=2; - + method=11; + for(filt=0; filt<6; filt++) + { + zs[method]=2; + lv[method]=2; + fm[method]=filt; + method++; + } + for(lev=1; lev<10; lev++) + { + for(strat=0; strat<2; strat++) + { + for(filt=0; filt<6; filt++) + { + zs[method]=strat; + lv[method]=lev; + fm[method]=filt; + method++; + } + } + } names=1; for (i=1; i<argc; i++) @@ -503,28 +572,16 @@ main(int argc, char *argv[]) /* try two fast filters */ { methods_specified=1; - zs[11]=0; - lv[11]=4; - fm[11]=0; - try_method[11]=0; - zs[12]=2; - lv[12]=1; - fm[12]=5; - try_method[12]=0; + try_method[16]=0; + try_method[53]=0; } else if(!strncmp(argv[i],"-huffman",8)) /* try all filters with huffman */ { - int filt; methods_specified=1; - method=11; - for(filt=0; filt<6; filt++) + for(method=11; method<16; method++) { - zs[method]=2; - lv[method]=2; - fm[method]=filt; try_method[method]=0; - method++; } } @@ -543,37 +600,18 @@ main(int argc, char *argv[]) { int lev, strat, filt; methods_specified=1; - method=11; brute_force++; - brute_force_strategy=0; - for (strat=0; strat<3; strat++) - brute_force_strategies[strat]=0; - brute_force_level=0; - brute_force_filter=0; - for(filt=0; filt<6; filt++) - { - zs[method]=2; - lv[method]=2; - fm[method]=filt; - try_method[method]=0; - brute_force_filters[filt]=0; - method++; - } - for(lev=1; lev<10; lev++) - { - brute_force_levels[lev]=0; - for(strat=0; strat<2; strat++) - { - for(filt=0; filt<6; filt++) - { - zs[method]=strat; - lv[method]=lev; - fm[method]=filt; - try_method[method]=0; - method++; - } - } - } + for(method=11; method < 125; method++) + try_method[method]=0; + if(brute_force_filter==0) + for (filt=0; filt<6; filt++) + brute_force_filters[filt]=0; + if(brute_force_level==0) + for (lev=0; lev<10; lev++) + brute_force_levels[lev]=0; + if(brute_force_strategy == 0) + for (strat=0; strat<3; strat++) + brute_force_strategies[strat]=0; } else if(!strncmp(argv[i],"-bit_depth",10)) { @@ -585,11 +623,13 @@ main(int argc, char *argv[]) names++; force_output_color_type=atoi(argv[++i]); } +#ifdef PNG_gAMA_SUPPORTED else if(!strncmp(argv[i],"-dou",4)) { double_gamma++; things_have_changed=1; } +#endif else if(!strncmp(argv[i],"-d",2)) { i++; @@ -617,15 +657,14 @@ main(int argc, char *argv[]) fm[method]=specified_filter; else { - if(brute_force_filter == 0) - for (filt=0; filt<6; filt++) - brute_force_filters[filt]=1; + for (filt=0; filt<6; filt++) + brute_force_filters[filt]=1; brute_force_filters[specified_filter]=0; method=11; for(filt=0; filt<6; filt++) { try_method[method]= brute_force_filters[filt] | - brute_force_strategies[2]; + brute_force_strategies[2]; method++; } for(lev=1; lev<10; lev++) @@ -681,12 +720,14 @@ main(int argc, char *argv[]) brute_force_level++; } } +#ifdef PNG_gAMA_SUPPORTED else if(!strncmp(argv[i],"-g",2)) { names++; i++; - if (intent < 0) specified_gamma=atof(argv[i]); + if (intent < 0) specified_gamma=atoi(argv[i]); } +#endif else if(!strncmp(argv[i],"-h",2)) { help++; @@ -717,16 +758,25 @@ main(int argc, char *argv[]) names++; plte_len=atoi(argv[++i]); } + else if(!strncmp(argv[i],"-pplt",9)) + { + names++; + do_pplt++; + strcpy(pplt_string,argv[++i]); + things_have_changed=1; + } else if(!strncmp(argv[i],"-p",2)) { pauses++; } +#ifdef PNG_gAMA_SUPPORTED else if(!strncmp(argv[i],"-rep",4)) { names++; - force_specified_gamma=atof(argv[++i]); + force_specified_gamma=atoi(argv[++i]); things_have_changed=1; } +#endif else if(!strncmp(argv[i],"-res",4)) { names++; @@ -741,7 +791,9 @@ main(int argc, char *argv[]) else if( !strncmp(argv[i],"-srgb",5) || !strncmp(argv[i],"-sRGB",5)) { - specified_gamma=.45455; +#ifdef PNG_gAMA_SUPPORTED + specified_gamma=45455L; +#endif intent=0; i++; if(!strncmp(argv[i],"0",1) || @@ -760,21 +812,47 @@ main(int argc, char *argv[]) verbose=0; } else if( !strncmp(argv[i],"-text",5) || !strncmp(argv[i],"-tEXt",5) || - !strncmp(argv[i],"-ztxt",5) || !strncmp(argv[i],"-zTXt",5)) + !strncmp(argv[i],"-ztxt",5) || !strncmp(argv[i],"-zTXt",5) || + !strncmp(argv[i],"-zitxt",6) || !strncmp(argv[i],"-ziTXt",6) || + !strncmp(argv[i],"-itxt",5) || !strncmp(argv[i],"-iTXt",5)) { if(strlen(argv[i+2]) < 80 && strlen(argv[i+3]) < 2048 && text_inputs < 10) { - if( !strncmp(argv[i],"-z",2)) + if( !strncmp(argv[i],"-zi",3)) + { + text_compression[text_inputs] = PNG_ITXT_COMPRESSION_zTXt; + names+=2; + } + else if( !strncmp(argv[i],"-z",2)) text_compression[text_inputs] = PNG_TEXT_COMPRESSION_zTXt; - else + else if( !strncmp(argv[i],"-t",2)) text_compression[text_inputs] = PNG_TEXT_COMPRESSION_NONE; + else + { + text_compression[text_inputs] = PNG_ITXT_COMPRESSION_NONE; + names+=2; + printf("Adding an iTXt chunk.\n"); + } names+=3; if( !strncmp(argv[++i],"b",1)) text_where[text_inputs]=1; if( !strncmp(argv[i],"a",1)) text_where[text_inputs]=2; strcpy(&text_keyword[text_inputs*80],argv[++i]); +#ifdef PNG_iTXt_SUPPORTED + if(text_compression[text_inputs] <= 0) + { + text_lang[text_inputs*80] = '\0'; + text_lang_key[text_inputs*80] = '\0'; + } + else + { + strcpy(&text_lang[text_inputs*80],argv[++i]); + /* libpng-1.0.5j and later */ + strcpy(&text_lang_key[text_inputs*80],argv[++i]); + } +#endif strcpy(&text_text[text_inputs*2048],argv[++i]); text_inputs++; } @@ -788,6 +866,11 @@ main(int argc, char *argv[]) "keyword exceeds 79 characters or text exceeds 2047 characters\n"); i+=3; names+=3; + if( !strncmp(argv[i],"-i",2) || !strncmp(argv[i],"-zi",3)) + { + i+=2; + names+=2; + } } } else if( !strncmp(argv[i],"-trns",5) || @@ -1013,7 +1096,7 @@ main(int argc, char *argv[]) fprintf(STDERR, "\n filter to use with the method specified in the\n"); fprintf(STDERR, - " preceding '-m method' argument.\n"); + " preceding '-m method' or '-brute_force' argument.\n"); fprintf(STDERR, " 0: none; 1-4: use specified filter; 5: adaptive.\n\n"); } @@ -1047,10 +1130,12 @@ main(int argc, char *argv[]) fprintf(STDERR, "\n zlib compression level to use with method specified\n"); fprintf(STDERR, - " with the preceding '-m method' argument.\n\n"); + " with the preceding '-m method' or '-brute_force'\n"); + fprintf(STDERR, + " argument.\n\n"); } fprintf(STDERR, - " -m method [0 through 200]\n"); + " -m method [0 through %d]\n",MAX_METHODS); if(verbose > 1) { fprintf(STDERR, @@ -1192,13 +1277,13 @@ main(int argc, char *argv[]) fprintf(STDERR, "\n Repeat the option (use \"-v -v\") for even more.\n\n"); fprintf(STDERR, - " -w compression_window_size [32, 16, 8, 4, 2, 1, 512, 256]\n"); + " -w compression_window_size [32, 16, 8, 4, 2, 1, 512]\n"); if(verbose > 1) { fprintf(STDERR, "\n Size of the sliding compression window, in kbytes\n"); fprintf(STDERR, - " (or bytes, in case of 512 or 256). It's best to\n"); + " (or bytes, in case of 512). It's best to\n"); fprintf(STDERR, " use the default (32) unless you run out of memory.\n"); fprintf(STDERR, @@ -1562,15 +1647,15 @@ main(int argc, char *argv[]) #if !defined(PNG_NO_STDIO) png_init_io(read_ptr, fpin); if(nosave == 0) - png_init_io(write_ptr, fpout); + png_init_io(write_ptr, fpout); #else png_set_read_fn(read_ptr, (png_voidp)fpin, png_default_read_data); if(nosave == 0) - png_set_write_fn(write_ptr, (png_voidp)fpout, png_default_write_data, + png_set_write_fn(write_ptr, (png_voidp)fpout, png_default_write_data, #if defined(PNG_WRITE_FLUSH_SUPPORTED) - png_default_flush); + png_default_flush); #else - NULL); + NULL); #endif #endif @@ -1597,15 +1682,24 @@ main(int argc, char *argv[]) (png_bytep)png_malloc(read_ptr, (png_uint_32)read_ptr->zbuf_size); } if(nosave == 0) - if(write_ptr->zbuf_size > (png_size_t)max_idat_size) - { - if(verbose > 2) - printf("reinitializing write zbuf.\n"); - png_free(write_ptr, write_ptr->zbuf); - write_ptr->zbuf_size = (png_size_t)max_idat_size; - write_ptr->zbuf = - (png_bytep)png_malloc(write_ptr, (png_uint_32)write_ptr->zbuf_size); - } + if(write_ptr->zbuf_size > (png_size_t)max_idat_size) + { + if (verbose > 2) + printf("reinitializing write zbuf.\n"); + png_free(write_ptr, write_ptr->zbuf); + write_ptr->zbuf_size = (png_size_t)max_idat_size; + write_ptr->zbuf = + (png_bytep)png_malloc(write_ptr, + (png_uint_32)write_ptr->zbuf_size); + } + +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_set_keep_unknown_chunks(read_ptr, 2, (png_bytep)NULL, 0); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if(nosave == 0) + png_set_keep_unknown_chunks(write_ptr, 1, (png_bytep)NULL, 0); +#endif png_debug(0, "Reading info struct\n"); png_read_info(read_ptr, read_info_ptr); @@ -1647,9 +1741,15 @@ main(int argc, char *argv[]) if((color_type == 2 || color_type == 6 || color_type == 3) && (output_color_type == 0 || output_color_type == 4)) { +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) png_set_rgb_to_gray(read_ptr, 1, 54./255., 183./255.); if(output_bit_depth < 8)output_bit_depth=8; if(color_type == 3) need_expand = 1; +#else + printf(" Cannot reduce color image to grayscale unless\n"); + printf(" pngcrush is rebuilt with floating point support \n"); + output_color_type=input_color_type; +#endif } if(color_type != 3 && output_color_type == 3) @@ -1717,8 +1817,12 @@ main(int argc, char *argv[]) required_window=(int)(height*((width*channels*bit_depth+15)>>3)); +#ifdef WBITS_8_OK if (required_window <= 256)compression_window = 8; else if(required_window <= 512)compression_window = 9; +#else + if (required_window <= 512)compression_window = 9; +#endif else if(required_window <= 1024)compression_window = 10; else if(required_window <= 2048)compression_window = 11; else if(required_window <= 4096)compression_window = 12; @@ -1776,52 +1880,57 @@ main(int argc, char *argv[]) #endif #if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED) { - double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; + png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, + blue_x, blue_y; - if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y)) + if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { if(keep_chunk("cHRM",argv)) - png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); + png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, + red_x, red_y, green_x, green_y, blue_x, blue_y); } } #endif #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED) { - if(force_specified_gamma > 0.) + if(force_specified_gamma > 0) { if(trial == 1) { things_have_changed=1; if(verbose > 0) - fprintf(STDERR, " Inserting gAMA chunk with gamma=%f\n", + fprintf(STDERR, + " Inserting gAMA chunk with gamma=(%d/100000)\n", force_specified_gamma); } - png_set_gAMA(write_ptr, write_info_ptr, force_specified_gamma); - file_gamma=force_specified_gamma; + png_set_gAMA_fixed(write_ptr, write_info_ptr, + (png_fixed_point)force_specified_gamma); + file_gamma=(png_fixed_point)force_specified_gamma; } - else if (png_get_gAMA(read_ptr, read_info_ptr, &file_gamma)) + else if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &file_gamma)) { if(keep_chunk("gAMA",argv)) { if(verbose > 1 && trial == 1) - fprintf(STDERR, " gamma=%f\n", file_gamma); + fprintf(STDERR, " gamma=(%lu/100000)\n", file_gamma); if(double_gamma)file_gamma+=file_gamma; - png_set_gAMA(write_ptr, write_info_ptr, file_gamma); + png_set_gAMA_fixed(write_ptr, write_info_ptr, file_gamma); } } - else if(specified_gamma > 0.) + else if(specified_gamma > 0) { if(trial == 1) { things_have_changed=1; if(verbose > 0) - fprintf(STDERR, " Inserting gAMA chunk with gamma=%f\n", + fprintf(STDERR, + " Inserting gAMA chunk with gamma=(%d/100000)\n", specified_gamma); } - png_set_gAMA(write_ptr, write_info_ptr, specified_gamma); - file_gamma=specified_gamma; + png_set_gAMA_fixed(write_ptr, write_info_ptr, + (png_fixed_point)specified_gamma); + file_gamma=(png_fixed_point)specified_gamma; } } #endif @@ -1836,14 +1945,15 @@ main(int argc, char *argv[]) } else if(intent >= 0) { - if((int)(file_gamma*100 + .1) == 45) +#ifdef PNG_gAMA_SUPPORTED + if(file_gamma > 45000L && file_gamma < 46000L) { things_have_changed=1; if(trial == 1) fprintf(STDERR, " Inserting sRGB chunk with intent=%d\n",intent); png_set_sRGB(write_ptr, write_info_ptr, intent); } - else if((int)(file_gamma*100) == 0) + else if(file_gamma == 0) { things_have_changed=1; png_set_sRGB_gAMA_and_cHRM(write_ptr, write_info_ptr, intent); @@ -1853,10 +1963,11 @@ main(int argc, char *argv[]) if(trial == 1) { fprintf(STDERR, - " Ignoring sRGB request because gamma=%f is not approx. 0.45\n", + " Ignoring sRGB request; gamma=(%lu/100000) is not approx. 0.455\n", file_gamma); } } +#endif } } #endif @@ -1871,6 +1982,22 @@ main(int argc, char *argv[]) } } #endif +#if defined(PNG_iCCP_SUPPORTED) + { + png_charp name; + png_charp profile; + png_int_32 proflen; + int compression_type; + + if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, + &profile, &proflen)) + { + if(keep_chunk("iCCP",argv)) + png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, + profile, proflen); + } + } +#endif #if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED) { png_int_32 offset_x, offset_y; @@ -2035,6 +2162,10 @@ main(int argc, char *argv[]) { if (plte_len > 0) num_palette=plte_len; + if (do_pplt != 0) + { + printf("PPLT: %s\n",pplt_string); + } if(output_color_type == 3) png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); else if(keep_chunk("PLTE",argv)) @@ -2079,8 +2210,34 @@ main(int argc, char *argv[]) } } #endif -#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) || \ - (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED)) +#if defined(PNG_sCAL_SUPPORTED) + { + int unit; + png_charp width, height; + + if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &width, &height)) + { + if(keep_chunk("sCAL",argv)) + png_set_sCAL_s(write_ptr, write_info_ptr, unit, width, height); + } + } +#endif +#if defined(PNG_sPLT_SUPPORTED) + { + png_spalette_p entries; + int num_entries; + + num_entries = (int)png_get_spalettes(read_ptr, read_info_ptr, &entries); + if (num_entries) + { + if(keep_chunk("sPLT",argv)) + png_set_spalettes(write_ptr, write_info_ptr, entries, num_entries); + png_free_spalettes(read_ptr, read_info_ptr, num_entries); + } + } +#endif + +#if defined(PNG_TEXT_SUPPORTED) { png_textp text_ptr; int num_text=0; @@ -2093,17 +2250,26 @@ main(int argc, char *argv[]) if (verbose > 1 && trial == 1 && num_text > 0) { - fprintf(STDERR,"before IDAT, num_text= %d",num_text); for (ntext = 0; ntext < num_text; ntext++) { - fprintf(STDERR,"%d %s: ",ntext,text_ptr[ntext].key); - fprintf(STDERR,"%s\n",text_ptr[ntext].text); + fprintf(STDERR,"%d %s",ntext,text_ptr[ntext].key); + if(text_ptr[ntext].text_length != 0) + fprintf(STDERR,": %s\n",text_ptr[ntext].text); + else if (text_ptr[ntext].itxt_length != 0) + { + fprintf(STDERR," (%s: %s): \n", + text_ptr[ntext].lang, + text_ptr[ntext].lang_key); + fprintf(STDERR,"%s\n",text_ptr[ntext].text); + } + else + fprintf(STDERR,"\n"); } } if(num_text > 0) { - if(keep_chunk("tEXt/zTXt",argv)) + if(keep_chunk("text",argv)) png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); } for (ntext=0; ntext<text_inputs; ntext++) @@ -2114,12 +2280,20 @@ main(int argc, char *argv[]) added_text = (png_textp) png_malloc(write_ptr, (png_uint_32)sizeof(png_text)); added_text[0].key = &text_keyword[ntext*80]; + added_text[0].lang = &text_lang[ntext*80]; + added_text[0].lang_key = &text_lang_key[ntext*80]; added_text[0].text = &text_text[ntext*2048]; added_text[0].compression = text_compression[ntext]; - added_text[0].text_length = (png_size_t)strlen - (&text_text[ntext*2048]); png_set_text(write_ptr, write_info_ptr, added_text, 1); png_free(write_ptr,added_text); + if(added_text[0].compression < 0) + printf("Added a tEXt chunk.\n"); + else if(added_text[0].compression == 0) + printf("Added a zTXt chunk.\n"); + else if(added_text[0].compression == 1) + printf("Added an uncompressed iTXt chunk.\n"); + else + printf("Added a compressed iTXt chunk.\n"); } } } @@ -2152,6 +2326,23 @@ main(int argc, char *argv[]) else png_set_filter(write_ptr,0,PNG_FILTER_NONE); +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, + num_unknowns); + for (i = 0; i < read_info_ptr->unknown_chunks_num; i++) + write_info_ptr->unknown_chunks[i].location = + unknowns[i].location; + } + } +#endif + if(verbose > 2) printf("writing info structure.\n"); png_crush_pause(); @@ -2277,6 +2468,13 @@ main(int argc, char *argv[]) } #endif +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_unknown_chunks(read_ptr, read_info_ptr, -1); +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + png_free_unknown_chunks(write_ptr, write_info_ptr, -1); +#endif + png_debug(0, "Reading and writing end_info data\n"); png_read_end(read_ptr, end_info_ptr); @@ -2296,15 +2494,26 @@ main(int argc, char *argv[]) { for (ntext = 0; ntext < num_text; ntext++) { - fprintf(STDERR,"%d %s: ",ntext,text_ptr[ntext].key); - fprintf(STDERR,"%s\n",text_ptr[ntext].text); + fprintf(STDERR,"%d %s",ntext,text_ptr[ntext].key); + if(text_ptr[ntext].text_length != 0) + fprintf(STDERR,": %s\n",text_ptr[ntext].text); + else if (text_ptr[ntext].itxt_length != 0) + { + fprintf(STDERR," (%s: %s): \n", + text_ptr[ntext].lang, + text_ptr[ntext].lang_key); + fprintf(STDERR,"%s\n",text_ptr[ntext].text); + } + else + fprintf(STDERR,"\n"); } } if(num_text > 0) { - if(keep_chunk("tEXt/zTXt",argv)) - png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); + if(keep_chunk("text",argv)) + png_set_text(write_ptr, write_end_info_ptr, text_ptr, + num_text); } for (ntext=0; ntext<text_inputs; ntext++) { @@ -2314,12 +2523,20 @@ main(int argc, char *argv[]) added_text = (png_textp) png_malloc(write_ptr, (png_uint_32)sizeof(png_text)); added_text[0].key = &text_keyword[ntext*80]; + added_text[0].lang = &text_lang[ntext*80]; + added_text[0].lang_key = &text_lang_key[ntext*80]; added_text[0].text = &text_text[ntext*2048]; added_text[0].compression = text_compression[ntext]; - added_text[0].text_length = (png_size_t)strlen - (&text_text[ntext*2048]); png_set_text(write_ptr, write_end_info_ptr, added_text, 1); png_free(write_ptr,added_text); + if(added_text[0].compression < 0) + printf("Added a tEXt chunk after IDAT.\n"); + else if(added_text[0].compression == 0) + printf("Added a zTXt chunk after IDAT.\n"); + else if(added_text[0].compression == 1) + printf("Added an uncompressed iTXt chunk after IDAT.\n"); + else + printf("Added a compressed iTXt chunk after IDAT.\n"); } } } @@ -2337,6 +2554,23 @@ main(int argc, char *argv[]) } #endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + { + png_unknown_chunkp unknowns; + int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, + &unknowns); + if (num_unknowns && nosave == 0) + { + png_size_t i; + png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, + num_unknowns); + for (i = 0; i < read_info_ptr->unknown_chunks_num; i++) + write_end_info_ptr->unknown_chunks[i].location = + unknowns[i].location; + } + } +#endif + if(nosave == 0) png_write_end(write_ptr, write_end_info_ptr); @@ -2347,11 +2581,7 @@ main(int argc, char *argv[]) png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); if(nosave == 0) { - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - } - - if(nosave == 0) - { + png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); } read_ptr=NULL; diff --git a/pngcrush.h b/pngcrush.h new file mode 100644 index 000000000..5e48ecfbe --- /dev/null +++ b/pngcrush.h @@ -0,0 +1,30 @@ +/* pngcrush.h */ + +/* Special defines for pngcrush, mostly just to reduce the size of the + static executable. */ + +#define PNG_NO_FLOATING_POINT_SUPPORTED /* undef this if you want to be able + to reduce color to gray */ +#define PNG_NO_EASY_ACCESS +#define PNG_NO_READ_EMPTY_PLTE +#define PNG_NO_WRITE_TRANSFORMS +#define PNG_NO_PROGRESSIVE_READ +#define PNG_NO_WRITE_WEIGHTED_FILTER +#define PNG_READ_USER_TRANSFORM_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED +#define PNG_READ_EXPAND_SUPPORTED +#define PNG_READ_FILLER_SUPPORTED +#ifndef PNG_NO_FLOATING_POINT_SUPPORTED +# define PNG_READ_GRAY_TO_RGB_SUPPORTED +# define PNG_READ_RGB_TO_GRAY_SUPPORTED +# define PNG_READ_BACKGROUND_SUPPORTED +# define PNG_READ_GAMMA_SUPPORTED +#else +# define PNG_NO_READ_RGB_TO_GRAY +#endif +#define PNG_ZBUF_SIZE 524288 /* increases the IDAT size */ +/* +#define PNG_NO_GLOBAL_ARRAYS +*/ +#define TOO_FAR 32767 /* Improves zlib/deflate compression */ + diff --git a/pngerror.c b/pngerror.c index b1674eb18..6ebc5aa72 100644 --- a/pngerror.c +++ b/pngerror.c @@ -1,7 +1,7 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger diff --git a/pnggccrd.c b/pnggccrd.c new file mode 100644 index 000000000..6e9db58d1 --- /dev/null +++ b/pnggccrd.c @@ -0,0 +1,4633 @@ +/* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file + * + * For Intel x86 CPU (Pentium-MMX or later) and GNU C compiler. + * + * See http://www.intel.com/drg/pentiumII/appnotes/916/916.htm + * and http://www.intel.com/drg/pentiumII/appnotes/923/923.htm + * for Intel's performance analysis of the MMX vs. non-MMX code. + * + * libpng 1.0.5 - October 15, 1999 + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998, Intel Corporation + * Copyright (c) 1998, 1999 Glenn Randers-Pehrson + * + * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998. + * Interface to libpng contributed by Gilles Vollant, 1999. + * GNU C port by Greg Roelofs, 1999. + * + * Lines 2350-4300 converted in place with intel2gas 1.3.1: + * + * intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c + * + * and then cleaned up by hand. See http://hermes.terminal.at/intel2gas/ . + * + * NOTE: A sufficiently recent version of GNU as (or as.exe under DOS/Windows) + * is required to assemble the newer MMX instructions such as movq. + * For djgpp, see + * + * ftp://ftp.cdrom.com/pub/simtelnet/gnu/djgpp/v2gnu/bnu281b.zip + * + * (or a later version in the same directory). For Linux, check your + * distribution's web site(s) or try these links: + * + * http://rufus.w3.org/linux/RPM/binutils.html + * http://www.debian.org/Packages/stable/devel/binutils.html + * ftp://ftp.cdrom.com/pub/linux/slackware/slakware/d1/binutils.tgz + * + * For other platforms, see the main GNU site: + * + * ftp://ftp.gnu.org/pub/gnu/binutils/ + * + * Version 2.5.2l.15 is definitely too old... + */ +#if 0 +// GRR NOTES +// +// 19991006: +// - fixed sign error in post-MMX cleanup code (16- & 32-bit cases) +// +// 19991007: +// - additional optimizations (possible or definite): +// x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested] +// - write MMX code for 48-bit case (pixel_bytes == 6) +// - figure out what's up with 24-bit case (pixel_bytes == 3): +// why subtract 8 from width_mmx in the pass 4/5 case? +// (only width_mmx case) +// x [DONE] replace pixel_bytes within each block with the true +// constant value (or are compilers smart enough to do that?) +// - rewrite all MMX interlacing code so it's aligned with +// the *beginning* of the row buffer, not the end. This +// would not only allow one to eliminate half of the memory +// writes for odd passes (i.e., pass == odd), it may also +// eliminate some unaligned-data-access exceptions (assuming +// there's a penalty for not aligning 64-bit accesses on +// 64-bit boundaries). The only catch is that the "leftover" +// pixel(s) at the end of the row would have to be saved, +// but there are enough unused MMX registers in every case, +// so this is not a problem. A further benefit is that the +// post-MMX cleanup code (C code) in at least some of the +// cases could be done within the assembler block. +// x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing, +// inconsistent, and don't match the MMX Programmer's Reference +// Manual conventions anyway. They should be changed to +// "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that +// was lowest in memory (e.g., corresponding to a left pixel) +// and b7 is the byte that was highest (e.g., a right pixel). +// +// 19991016: +// - Brennan's Guide notwithstanding, gcc under Linux does *not* +// want globals prefixed by underscores when referencing them-- +// i.e., if the variable is const4, then refer to it as const4, +// not _const4. This seems to be a djgpp-specific requirement. +// Also, such variables apparently *must* be declared outside +// of functions; neither static nor automatic variables work if +// defined within the scope of a single function, but both +// static and truly global (multi-module) variables work fine. +// +// 19991023: +// - fixed png_combine_row() non-MMX replication bug (odd passes only?) +// - switched from string-concatenation-with-macros to cleaner method of +// renaming global variables for djgpp--i.e., always use prefixes in +// inlined assembler code (== strings) and conditionally rename the +// variables, not the other way around. Hence _const4, _mask8_0, etc. +// +// 19991024: +// - fixed mmxsupport()/png_do_interlace() first-row bug +// This one was severely weird: even though mmxsupport() doesn't touch +// ebx (where "row" pointer was stored), it nevertheless managed to zero +// the register (even in static/non-fPIC code--see below), which in turn +// caused png_do_interlace() to return prematurely on the first row of +// interlaced images (i.e., without expanding the interlaced pixels). +// Inspection of the generated assembly code didn't turn up any clues, +// although it did point at a minor optimization (i.e., get rid of +// mmx_supported_local variable and just use eax). Possibly the CPUID +// instruction is more destructive than it looks? (Not yet checked.) +// - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly +// listings... Apparently register spillage has to do with ebx, since +// it's used to index the global offset table. Commenting it out of the +// input-reg lists in png_combine_row() eliminated compiler barfage, so +// ifdef'd with __PIC__ macro: if defined, use a global for unmask +// +// 19991107: +// - verified CPUID clobberage: 12-char string constant ("GenuineIntel", +// "AuthenticAMD", etc.) placed in EBX:ECX:EDX. Still need to polish. +// +// 19991120: +// - made "diff" variable (now "_dif") global to simplify conversion of +// filtering routines (running out of regs, sigh). "diff" is still used +// in interlacing routines, however. +// - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX +// macro determines which is used); original not yet tested. +#endif + +#define PNG_INTERNAL +#include "png.h" + +#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGGCCRD) + +int mmxsupport(void); + +static int mmx_supported = 2; + +// djgpp adds its own underscores to global variables, so define them without: +#ifdef __DJGPP__ +# define _unmask unmask +# define _const4 const4 +# define _const6 const6 +# define _mask8_0 mask8_0 +# define _mask16_1 mask16_1 +# define _mask16_0 mask16_0 +# define _mask24_2 mask24_2 +# define _mask24_1 mask24_1 +# define _mask24_0 mask24_0 +# define _mask32_3 mask32_3 +# define _mask32_2 mask32_2 +# define _mask32_1 mask32_1 +# define _mask32_0 mask32_0 +# define _mask48_5 mask48_5 +# define _mask48_4 mask48_4 +# define _mask48_3 mask48_3 +# define _mask48_2 mask48_2 +# define _mask48_1 mask48_1 +# define _mask48_0 mask48_0 +# define _FullLength FullLength +# define _MMXLength MMXLength +# define _dif dif +#endif + +/* These constants are used in the inlined MMX assembly code. + Ignore gcc's "At top level: defined but not used" warnings. */ + +#ifdef __PIC__ +static int _unmask; // not enough regs when compiling with -fPIC, so... +#endif + +static unsigned long long _mask8_0 = 0x0102040810204080LL; + +static unsigned long long _mask16_1 = 0x0101020204040808LL; +static unsigned long long _mask16_0 = 0x1010202040408080LL; + +static unsigned long long _mask24_2 = 0x0101010202020404LL; +static unsigned long long _mask24_1 = 0x0408080810101020LL; +static unsigned long long _mask24_0 = 0x2020404040808080LL; + +static unsigned long long _mask32_3 = 0x0101010102020202LL; +static unsigned long long _mask32_2 = 0x0404040408080808LL; +static unsigned long long _mask32_1 = 0x1010101020202020LL; +static unsigned long long _mask32_0 = 0x4040404080808080LL; + +static unsigned long long _mask48_5 = 0x0101010101010202LL; +static unsigned long long _mask48_4 = 0x0202020204040404LL; +static unsigned long long _mask48_3 = 0x0404080808080808LL; +static unsigned long long _mask48_2 = 0x1010101010102020LL; +static unsigned long long _mask48_1 = 0x2020202040404040LL; +static unsigned long long _mask48_0 = 0x4040808080808080LL; + +static unsigned long long _const4 = 0x0000000000FFFFFFLL; +//static unsigned long long _const5 = 0x000000FFFFFF0000LL; // NOT USED +static unsigned long long _const6 = 0x00000000000000FFLL; + +// These are used in the row-filter routines and should/would be local +// variables if not for gcc addressing limitations. + +static png_uint_32 _FullLength; +static png_uint_32 _MMXLength; +static int _dif; + + +void +png_read_filter_row_c(png_structp png_ptr, png_row_infop row_info, + png_bytep row, png_bytep prev_row, int filter); + + +#if defined(PNG_HAVE_ASSEMBLER_COMBINE_ROW) + +/* Combines the row recently read in with the previous row. + This routine takes care of alpha and transparency if requested. + This routine also handles the two methods of progressive display + of interlaced images, depending on the mask value. + The mask value describes which pixels are to be combined with + the row. The pattern always repeats every 8 pixels, so just 8 + bits are needed. A one indicates the pixel is to be combined; a + zero indicates the pixel is to be skipped. This is in addition + to any alpha or transparency value associated with the pixel. + If you want all pixels to be combined, pass 0xff (255) in mask. */ + +/* Use this routine for the x86 platform - it uses a faster MMX routine + if the machine supports MMX. */ + +void +png_combine_row(png_structp png_ptr, png_bytep row, int mask) +{ + png_debug(1,"in png_combine_row_asm\n"); + + if (mmx_supported == 2) + mmx_supported = mmxsupport(); + +/* +fprintf(stderr, "GRR DEBUG: png_combine_row() pixel_depth = %d, mask = 0x%02x, unmask = 0x%02x\n", png_ptr->row_info.pixel_depth, mask, ~mask); +fflush(stderr); + */ + if (mask == 0xff) + { + png_memcpy(row, png_ptr->row_buf + 1, + (png_size_t)((png_ptr->width * png_ptr->row_info.pixel_depth + 7) >> 3)); + } + /* GRR: add "else if (mask == 0)" case? + * or does png_combine_row() not even get called in that case? */ + else + { + switch (png_ptr->row_info.pixel_depth) + { + case 1: // png_ptr->row_info.pixel_depth + { + png_bytep sp; + png_bytep dp; + int s_inc, s_start, s_end; + int m; + int shift; + png_uint_32 i; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 7; + s_inc = 1; + } + else +#endif + { + s_start = 7; + s_end = 0; + s_inc = -1; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + int value; + + value = (*sp >> shift) & 0x1; + *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 2: // png_ptr->row_info.pixel_depth + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 6; + s_inc = 2; + } + else +#endif + { + s_start = 6; + s_end = 0; + s_inc = -2; + } + + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0x3; + *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 4: // png_ptr->row_info.pixel_depth + { + png_bytep sp; + png_bytep dp; + int s_start, s_end, s_inc; + int m; + int shift; + png_uint_32 i; + int value; + + sp = png_ptr->row_buf + 1; + dp = row; + m = 0x80; +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (png_ptr->transformations & PNG_PACKSWAP) + { + s_start = 0; + s_end = 4; + s_inc = 4; + } + else +#endif + { + s_start = 4; + s_end = 0; + s_inc = -4; + } + shift = s_start; + + for (i = 0; i < png_ptr->width; i++) + { + if (m & mask) + { + value = (*sp >> shift) & 0xf; + *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); + *dp |= (png_byte)(value << shift); + } + + if (shift == s_end) + { + shift = s_start; + sp++; + dp++; + } + else + shift += s_inc; + if (m == 1) + m = 0x80; + else + m >>= 1; + } + break; + } + + case 8: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + + if (mmx_supported) + { + png_uint_32 len; + int diff; +#ifndef __PIC__ + int unmask = ~mask; +#else + _unmask = ~mask; // global variable for -fPIC version +#endif + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = png_ptr->width & 7; // amount lost + + __asm__ ( +#ifdef __PIC__ + "movd _unmask, %%mm7 \n\t" // load bit pattern +#else +// preload "movd unmask, %%mm7 \n\t" // (unmask is in ebx) + "movd %%ebx, %%mm7 \n\t" // load bit pattern (unmask) +#endif + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask8_0, %%mm0 \n\t" + "pand %%mm7, %%mm0 \n\t" // nonzero if keep byte + "pcmpeqb %%mm6, %%mm0 \n\t" // zeros->1s, v versa + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // len == 0 ? + "je mainloop8end \n\t" + + "mainloop8: \n\t" + "movq (%%esi), %%mm4 \n\t" // *srcptr + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" // *dstptr + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + "addl $8, %%esi \n\t" // inc by 8 bytes processed + "addl $8, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop8 \n\t" + + "mainloop8end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end8 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop8: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip8 \n\t" // if CF = 0 + "movb (%%esi), %%al \n\t" + "movb %%al, (%%edi) \n\t" + + "skip8: \n\t" + "incl %%esi \n\t" + "incl %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop8 \n\t" + + "end8: \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (srcptr), // esi // input regs + "D" (dstptr), // edi + "a" (diff), // eax +#ifndef __PIC__ + "b" (unmask), // ebx // Global Offset Table idx +#endif + "c" (len), // ecx + "d" (mask) // edx + + : "%esi", "%edi", "%eax", // clobber list + "%ecx", "%edx" +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm4", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ + { + register png_uint_32 i; + png_uint_32 initial_val = png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } /* end of else */ + + break; + } // end 8 bpp + + case 16: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + + if (mmx_supported) + { + png_uint_32 len; + int diff; +#ifndef __PIC__ + int unmask = ~mask; +#else + _unmask = ~mask; // global variable for -fPIC version +#endif + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = png_ptr->width & 7; // amount lost + + __asm__ ( +#ifdef __PIC__ + "movd _unmask, %%mm7 \n\t" // load bit pattern +#else +// preload "movd unmask, %%mm7 \n\t" // (unmask is in ebx) + "movd %%ebx, %%mm7 \n\t" // load bit pattern (unmask) +#endif + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask16_0, %%mm0 \n\t" + "movq _mask16_1, %%mm1 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop16end \n\t" + + "mainloop16: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "addl $16, %%esi \n\t" // inc by 16 bytes processed + "addl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop16 \n\t" + + "mainloop16end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end16 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop16: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip16 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + + "skip16: \n\t" + "addl $2, %%esi \n\t" + "addl $2, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop16 \n\t" + + "end16: \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (srcptr), // esi // input regs + "D" (dstptr), // edi + "a" (diff), // eax +#ifndef __PIC__ + "b" (unmask), // ebx // Global Offset Table idx +#endif + "c" (len), // ecx + "d" (mask) // edx + + : "%esi", "%edi", "%eax", // clobber list + "%ecx", "%edx" +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", + "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ + { + register png_uint_32 i; + png_uint_32 initial_val = 2 * png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = 2 * png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = 2 * png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = 2 * png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } /* end of else */ + + break; + } // end 16 bpp + + case 24: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + + if (mmx_supported) + { + png_uint_32 len; + int diff; +#ifndef __PIC__ + int unmask = ~mask; +#else + _unmask = ~mask; // global variable for -fPIC version +#endif + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = png_ptr->width & 7; // amount lost + + __asm__ ( +#ifdef __PIC__ + "movd _unmask, %%mm7 \n\t" // load bit pattern +#else +// preload "movd unmask, %%mm7 \n\t" // (unmask is in ebx) + "movd %%ebx, %%mm7 \n\t" // load bit pattern (unmask) +#endif + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask24_0, %%mm0 \n\t" + "movq _mask24_1, %%mm1 \n\t" + "movq _mask24_2, %%mm2 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop24end \n\t" + + "mainloop24: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "addl $24, %%esi \n\t" // inc by 24 bytes processed + "addl $24, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop24 \n\t" + + "mainloop24end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end24 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop24: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip24 \n\t" // if CF = 0 + "movw (%%esi), %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + "xorl %%eax, %%eax \n\t" + "movb 2(%%esi), %%al \n\t" + "movb %%al, 2(%%edi) \n\t" + + "skip24: \n\t" + "addl $3, %%esi \n\t" + "addl $3, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop24 \n\t" + + "end24: \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (srcptr), // esi // input regs + "D" (dstptr), // edi + "a" (diff), // eax +#ifndef __PIC__ + "b" (unmask), // ebx // Global Offset Table idx +#endif + "c" (len), // ecx + "d" (mask) // edx + + : "%esi", "%edi", "%eax", // clobber list + "%ecx", "%edx" +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", + "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ + { + register png_uint_32 i; + png_uint_32 initial_val = 3 * png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = 3 * png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = 3 * png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = 3 * png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } /* end of else */ + + break; + } // end 24 bpp + + case 32: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + + if (mmx_supported) + { + png_uint_32 len; + int diff; +#ifndef __PIC__ + int unmask = ~mask; +#else + _unmask = ~mask; // global variable for -fPIC version +#endif + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = png_ptr->width & 7; // amount lost + + __asm__ ( +#ifdef __PIC__ + "movd _unmask, %%mm7 \n\t" // load bit pattern +#else +// preload "movd unmask, %%mm7 \n\t" // (unmask is in ebx) + "movd %%ebx, %%mm7 \n\t" // load bit pattern (unmask) +#endif + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask32_0, %%mm0 \n\t" + "movq _mask32_1, %%mm1 \n\t" + "movq _mask32_2, %%mm2 \n\t" + "movq _mask32_3, %%mm3 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" // lcr + "jz mainloop32end \n\t" + + "mainloop32: \n\t" + "movq (%%esi), %%mm4 \n\t" + "pand %%mm0, %%mm4 \n\t" + "movq %%mm0, %%mm6 \n\t" + "movq (%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm6 \n\t" + "por %%mm6, %%mm4 \n\t" + "movq %%mm4, (%%edi) \n\t" + + "movq 8(%%esi), %%mm5 \n\t" + "pand %%mm1, %%mm5 \n\t" + "movq %%mm1, %%mm7 \n\t" + "movq 8(%%edi), %%mm6 \n\t" + "pandn %%mm6, %%mm7 \n\t" + "por %%mm7, %%mm5 \n\t" + "movq %%mm5, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm4 \n\t" + "movq 16(%%edi), %%mm7 \n\t" + "pandn %%mm7, %%mm4 \n\t" + "por %%mm4, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm5 \n\t" + "movq 24(%%edi), %%mm4 \n\t" + "pandn %%mm4, %%mm5 \n\t" + "por %%mm5, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "addl $32, %%esi \n\t" // inc by 32 bytes processed + "addl $32, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + "ja mainloop32 \n\t" + + "mainloop32end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end32 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // low byte => high byte + + "secondloop32: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip32 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip32: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop32 \n\t" + + "end32: \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (srcptr), // esi // input regs + "D" (dstptr), // edi + "a" (diff), // eax +#ifndef __PIC__ + "b" (unmask), // ebx // Global Offset Table idx +#endif + "c" (len), // ecx + "d" (mask) // edx + + : "%esi", "%edi", "%eax", // clobber list + "%ecx", "%edx" +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", + "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ + { + register png_uint_32 i; + png_uint_32 initial_val = 4 * png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = 4 * png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = 4 * png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = 4 * png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } /* end of else */ + + break; + } // end 32 bpp + + case 48: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + + if (mmx_supported) + { + png_uint_32 len; + int diff; +#ifndef __PIC__ + int unmask = ~mask; +#else + _unmask = ~mask; // global variable for -fPIC version +#endif + srcptr = png_ptr->row_buf + 1; + dstptr = row; + len = png_ptr->width &~7; // reduce to multiple of 8 + diff = png_ptr->width & 7; // amount lost + + __asm__ ( +#ifdef __PIC__ + "movd _unmask, %%mm7 \n\t" // load bit pattern +#else +// preload "movd unmask, %%mm7 \n\t" // (unmask is in ebx) + "movd %%ebx, %%mm7 \n\t" // load bit pattern (unmask) +#endif + "psubb %%mm6, %%mm6 \n\t" // zero mm6 + "punpcklbw %%mm7, %%mm7 \n\t" + "punpcklwd %%mm7, %%mm7 \n\t" + "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks + + "movq _mask48_0, %%mm0 \n\t" + "movq _mask48_1, %%mm1 \n\t" + "movq _mask48_2, %%mm2 \n\t" + "movq _mask48_3, %%mm3 \n\t" + "movq _mask48_4, %%mm4 \n\t" + "movq _mask48_5, %%mm5 \n\t" + + "pand %%mm7, %%mm0 \n\t" + "pand %%mm7, %%mm1 \n\t" + "pand %%mm7, %%mm2 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pand %%mm7, %%mm4 \n\t" + "pand %%mm7, %%mm5 \n\t" + + "pcmpeqb %%mm6, %%mm0 \n\t" + "pcmpeqb %%mm6, %%mm1 \n\t" + "pcmpeqb %%mm6, %%mm2 \n\t" + "pcmpeqb %%mm6, %%mm3 \n\t" + "pcmpeqb %%mm6, %%mm4 \n\t" + "pcmpeqb %%mm6, %%mm5 \n\t" + +// preload "movl len, %%ecx \n\t" // load length of line +// preload "movl srcptr, %%esi \n\t" // load source +// preload "movl dstptr, %%edi \n\t" // load dest + + "cmpl $0, %%ecx \n\t" + "jz mainloop48end \n\t" + + "mainloop48: \n\t" + "movq (%%esi), %%mm7 \n\t" + "pand %%mm0, %%mm7 \n\t" + "movq %%mm0, %%mm6 \n\t" + "pandn (%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, (%%edi) \n\t" + + "movq 8(%%esi), %%mm6 \n\t" + "pand %%mm1, %%mm6 \n\t" + "movq %%mm1, %%mm7 \n\t" + "pandn 8(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 8(%%edi) \n\t" + + "movq 16(%%esi), %%mm6 \n\t" + "pand %%mm2, %%mm6 \n\t" + "movq %%mm2, %%mm7 \n\t" + "pandn 16(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 16(%%edi) \n\t" + + "movq 24(%%esi), %%mm7 \n\t" + "pand %%mm3, %%mm7 \n\t" + "movq %%mm3, %%mm6 \n\t" + "pandn 24(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 24(%%edi) \n\t" + + "movq 32(%%esi), %%mm6 \n\t" + "pand %%mm4, %%mm6 \n\t" + "movq %%mm4, %%mm7 \n\t" + "pandn 32(%%edi), %%mm7 \n\t" + "por %%mm7, %%mm6 \n\t" + "movq %%mm6, 32(%%edi) \n\t" + + "movq 40(%%esi), %%mm7 \n\t" + "pand %%mm5, %%mm7 \n\t" + "movq %%mm5, %%mm6 \n\t" + "pandn 40(%%edi), %%mm6 \n\t" + "por %%mm6, %%mm7 \n\t" + "movq %%mm7, 40(%%edi) \n\t" + + "addl $48, %%esi \n\t" // inc by 48 bytes processed + "addl $48, %%edi \n\t" + "subl $8, %%ecx \n\t" // dec by 8 pixels processed + + "ja mainloop48 \n\t" + + "mainloop48end: \n\t" +// preload "movl diff, %%ecx \n\t" // (diff is in eax) + "movl %%eax, %%ecx \n\t" + "cmpl $0, %%ecx \n\t" + "jz end48 \n\t" +// preload "movl mask, %%edx \n\t" + "sall $24, %%edx \n\t" // make low byte, high byte + + "secondloop48: \n\t" + "sall %%edx \n\t" // move high bit to CF + "jnc skip48 \n\t" // if CF = 0 + "movl (%%esi), %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + + "skip48: \n\t" + "addl $4, %%esi \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz secondloop48 \n\t" + + "end48: \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (srcptr), // esi // input regs + "D" (dstptr), // edi + "a" (diff), // eax +#ifndef __PIC__ + "b" (unmask), // ebx // Global Offset Table idx +#endif + "c" (len), // ecx + "d" (mask) // edx + + : "%esi", "%edi", "%eax", // clobber list + "%ecx", "%edx" +#if 0 /* MMX regs (%mm0, etc.) not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", + "%mm4", "%mm5", "%mm6", "%mm7" +#endif + ); + } + else /* mmx _not supported - Use modified C routine */ + { + register png_uint_32 i; + png_uint_32 initial_val = 6 * png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = 6 * png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = 6 * png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = 6 * png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + } /* end of else */ + + break; + } // end 48 bpp + + case 64: // png_ptr->row_info.pixel_depth + { + png_bytep srcptr; + png_bytep dstptr; + register png_uint_32 i; + png_uint_32 initial_val = 8 * png_pass_start[png_ptr->pass]; + // png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + register int stride = 8 * png_pass_inc[png_ptr->pass]; + // png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + register int rep_bytes = 8 * png_pass_width[png_ptr->pass]; + // png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; + register png_uint_32 final_val = 8 * png_ptr->width; + + srcptr = png_ptr->row_buf + 1 + initial_val; + dstptr = row + initial_val; + + for (i = initial_val; i < final_val; i += stride) + { + png_memcpy(dstptr, srcptr, rep_bytes); + srcptr += stride; + dstptr += stride; + } + break; + } // end 64 bpp + + default: // png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 + { + // this should never happen + fprintf(stderr, + "libpng internal error: png_ptr->row_info.pixel_depth = %d\n", + png_ptr->row_info.pixel_depth); + fflush(stderr); + break; + } + } /* end switch (png_ptr->row_info.pixel_depth) */ + + } /* end if (non-trivial mask) */ + +} /* end png_combine_row() */ + +#endif /* PNG_HAVE_ASSEMBLER_COMBINE_ROW */ + + + +#if defined(PNG_READ_INTERLACING_SUPPORTED) +#if defined(PNG_HAVE_ASSEMBLER_READ_INTERLACE) + +/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion + * has taken place. [GRR: what other steps come before and/or after?] + */ + +void +png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations) +{ +/* +fprintf(stderr, "GRR DEBUG: entering png_do_read_interlace()\n"); +if (row == NULL) fprintf(stderr, "GRR DEBUG: row == NULL\n"); +if (row_info == NULL) fprintf(stderr, "GRR DEBUG: row_info == NULL\n"); +fflush(stderr); + */ + png_debug(1,"in png_do_read_interlace\n"); + + if (mmx_supported == 2) + mmx_supported = mmxsupport(); +/* +{ +fprintf(stderr, "GRR DEBUG: calling mmxsupport()\n"); +fprintf(stderr, "GRR DEBUG: done with mmxsupport() (mmx_supported = %d)\n", mmx_supported); +} + */ + +/* +this one happened on first row due to weirdness with mmxsupport(): +if (row == NULL) fprintf(stderr, "GRR DEBUG: now row == NULL!!!\n"); + row was in ebx, and even though nothing touched ebx, it still got wiped... + [weird side effect of CPUID instruction?] +if (row_info == NULL) fprintf(stderr, "GRR DEBUG: now row_info == NULL!!!\n"); + */ + if (row != NULL && row_info != NULL) + { + png_uint_32 final_width; + + final_width = row_info->width * png_pass_inc[pass]; + +/* +fprintf(stderr, "GRR DEBUG: png_do_read_interlace() row_info->width = %d, final_width = %d\n", row_info->width, final_width); +fprintf(stderr, "GRR DEBUG: png_do_read_interlace() pixel_depth = %d\n", row_info->pixel_depth); +fflush(stderr); + */ + switch (row_info->pixel_depth) + { + case 1: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_byte v; + png_uint_32 i; + int j; + + sp = row + (png_size_t)((row_info->width - 1) >> 3); + dp = row + (png_size_t)((final_width - 1) >> 3); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (int)((row_info->width + 7) & 7); + dshift = (int)((final_width + 7) & 7); + s_start = 7; + s_end = 0; + s_inc = -1; + } + else +#endif + { + sshift = 7 - (int)((row_info->width + 7) & 7); + dshift = 7 - (int)((final_width + 7) & 7); + s_start = 0; + s_end = 7; + s_inc = 1; + } + + for (i = row_info->width; i; i--) + { + v = (png_byte)((*sp >> sshift) & 0x1); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 2: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 2); + dp = row + (png_size_t)((final_width - 1) >> 2); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 3) & 3) << 1); + dshift = (png_size_t)(((final_width + 3) & 3) << 1); + s_start = 6; + s_end = 0; + s_inc = -2; + } + else +#endif + { + sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1); + dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1); + s_start = 0; + s_end = 6; + s_inc = 2; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0x3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + case 4: + { + png_bytep sp, dp; + int sshift, dshift; + int s_start, s_end, s_inc; + png_uint_32 i; + + sp = row + (png_size_t)((row_info->width - 1) >> 1); + dp = row + (png_size_t)((final_width - 1) >> 1); +#if defined(PNG_READ_PACKSWAP_SUPPORTED) + if (transformations & PNG_PACKSWAP) + { + sshift = (png_size_t)(((row_info->width + 1) & 1) << 2); + dshift = (png_size_t)(((final_width + 1) & 1) << 2); + s_start = 4; + s_end = 0; + s_inc = -4; + } + else +#endif + { + sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2); + dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2); + s_start = 0; + s_end = 4; + s_inc = 4; + } + + for (i = row_info->width; i; i--) + { + png_byte v; + int j; + + v = (png_byte)((*sp >> sshift) & 0xf); + for (j = 0; j < png_pass_inc[pass]; j++) + { + *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); + *dp |= (png_byte)(v << dshift); + if (dshift == s_end) + { + dshift = s_start; + dp--; + } + else + dshift += s_inc; + } + if (sshift == s_end) + { + sshift = s_start; + sp--; + } + else + sshift += s_inc; + } + break; + } + + //==================================================================== + + default: // 8-bit or larger (this is where the routine is modified) + { +// static unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// static unsigned long long const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long _const4 = 0x0000000000FFFFFFLL; no good +// unsigned long long const4 = 0x0000000000FFFFFFLL; no good + png_bytep sptr, dp; + png_uint_32 i; + png_size_t pixel_bytes; + int width = row_info->width; + + pixel_bytes = (row_info->pixel_depth >> 3); + + // point sptr at the last pixel in the pre-expanded row: + sptr = row + (width - 1) * pixel_bytes; + + // point dp at the last pixel position in the expanded row: + dp = row + (final_width - 1) * pixel_bytes; + + // New code by Nirav Chhatrapati - Intel Corporation + + if (mmx_supported) // use MMX code if machine supports it + { + //-------------------------------------------------------------- + if (pixel_bytes == 3) + { + if (((pass == 0) || (pass == 1)) && width) + { + __asm__ ( + "subl $21, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, %%mm3 \n\t" // 2 1 0 2 1 0 2 1 + "psllq $16, %%mm0 \n\t" // 0 2 1 0 2 1 z z + "movq %%mm3, %%mm4 \n\t" // 2 1 0 2 1 0 2 1 + "punpckhdq %%mm0, %%mm3 \n\t" // 0 2 1 0 2 1 0 2 + "movq %%mm4, 16(%%edi) \n\t" + "psrlq $32, %%mm0 \n\t" // z z z z 0 2 1 0 + "movq %%mm3, 8(%%edi) \n\t" + "punpckldq %%mm4, %%mm0 \n\t" // 1 0 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $24, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass0 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width) // ecx +// doesn't work "i" (0x0000000000FFFFFFLL) // %1 (a.k.a. _const4) + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4" +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + __asm__ ( + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x x 2 1 0 + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0 + "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z + "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z + "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z + "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1 + "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z + "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1 + "movq %%mm0, 4(%%edi) \n\t" + "psrlq $16, %%mm0 \n\t" // z z 2 1 0 2 1 0 + "subl $3, %%esi \n\t" + "movd %%mm0, (%%edi) \n\t" + "subl $12, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop3_pass2 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm2 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2" +#endif + ); + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 1) << 1) - 8; // GRR: huh? + if (width_mmx < 0) + width_mmx = 0; + width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes + if (width_mmx) + { + __asm__ ( + "subl $3, %%esi \n\t" + "subl $9, %%edi \n\t" + // (png_pass_inc[pass] - 1)*pixel_bytes + + ".loop3_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x 5 4 3 2 1 0 + "movq %%mm0, %%mm2 \n\t" // x x 5 4 3 2 1 0 + "psllq $24, %%mm0 \n\t" // 4 3 2 1 0 z z z + "pand _const4, %%mm0 \n\t" // z z z z z 2 1 0 + "psrlq $24, %%mm2 \n\t" // z z z x x 5 4 3 + "por %%mm1, %%mm0 \n\t" // 4 3 2 1 0 2 1 0 + "movq %%mm2, %%mm3 \n\t" // z z z x x 5 4 3 + "psllq $8, %%mm2 \n\t" // z z x x 5 4 3 z + "movq %%mm0, (%%edi) \n\t" + "psrlq $16, %%mm3 \n\t" // z z z z z x x 5 + "pand _const6, %%mm3 \n\t" // z z z z z z z 5 + "por %%mm3, %%mm2 \n\t" // z z x x 5 4 3 5 + "subl $6, %%esi \n\t" + "movd %%mm2, 8(%%edi) \n\t" + "subl $12, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop3_pass4 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm3 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3" +#endif + ); + } + + sptr -= width_mmx*3; + dp -= width_mmx*6; + for (i = width; i; i--) + { + png_byte v[8]; + int j; + + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + } /* end of pixel_bytes == 3 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 1) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + __asm__ ( + "subl $3, %%esi \n\t" + "subl $31, %%edi \n\t" + + ".loop1_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm2 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "movq %%mm0, %%mm3 \n\t" // 1 1 1 1 0 0 0 0 + "punpckldq %%mm0, %%mm0 \n\t" // 0 0 0 0 0 0 0 0 + "punpckhdq %%mm3, %%mm3 \n\t" // 1 1 1 1 1 1 1 1 + "movq %%mm0, (%%edi) \n\t" + "punpckhwd %%mm2, %%mm2 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm3, 8(%%edi) \n\t" + "movq %%mm2, %%mm4 \n\t" // 3 3 3 3 2 2 2 2 + "punpckldq %%mm2, %%mm2 \n\t" // 2 2 2 2 2 2 2 2 + "punpckhdq %%mm4, %%mm4 \n\t" // 3 3 3 3 3 3 3 3 + "movq %%mm2, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm4, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass0 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, ..., %mm4 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1", "%mm2", "%mm3", "%mm4" +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*8; + for (i = width; i; i--) + { + int j; + + /* I simplified this part in version 1.0.4e + * here and in several other instances where + * pixel_bytes == 1 -- GR-P + * + * Original code: + * + * png_byte v[8]; + * png_memcpy(v, sptr, pixel_bytes); + * for (j = 0; j < png_pass_inc[pass]; j++) + * { + * png_memcpy(dp, v, pixel_bytes); + * dp -= pixel_bytes; + * } + * sptr -= pixel_bytes; + * + * Replacement code is in the next three lines: + */ + + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + --sptr; + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 2) << 2); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + __asm__ ( + "subl $3, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "movq %%mm0, %%mm1 \n\t" // 3 3 2 2 1 1 0 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0 + "punpckhwd %%mm1, %%mm1 \n\t" // 3 3 3 3 2 2 2 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $4, %%ecx \n\t" + "jnz .loop1_pass2 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*4; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + --sptr; + } + } + else if (width) /* && ((pass == 4) || (pass == 5)) */ + { + int width_mmx = ((width >> 3) << 3); + width -= width_mmx; // 0-3 pixels => 0-3 bytes + if (width_mmx) + { + __asm__ ( + "subl $7, %%esi \n\t" + "subl $15, %%edi \n\t" + + ".loop1_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0 + "punpckhbw %%mm1, %%mm1 \n\t" // 7 7 6 6 5 5 4 4 + "movq %%mm1, 8(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $8, %%ecx \n\t" + "jnz .loop1_pass4 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= width_mmx; + dp -= width_mmx*2; + for (i = width; i; i--) + { + int j; + + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + --sptr; + } + } + } /* end of pixel_bytes == 1 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 2) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + __asm__ ( + "subl $2, %%esi \n\t" + "subl $30, %%edi \n\t" + + ".loop2_pass0: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass0 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*16 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + __asm__ ( + "subl $2, %%esi \n\t" + "subl $14, %%edi \n\t" + + ".loop2_pass2: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2 + "movq %%mm0, (%%edi) \n\t" + "subl $4, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass2 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*8 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,2 bytes + if (width_mmx) + { + __asm__ ( + "subl $2, %%esi \n\t" + "subl $6, %%edi \n\t" + + ".loop2_pass4: \n\t" + "movd (%%esi), %%mm0 \n\t" // x x x x 3 2 1 0 + "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0 + "subl $4, %%esi \n\t" + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop2_pass4 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0" +#endif + ); + } + + sptr -= (width_mmx*2 - 2); // sign fixed + dp -= (width_mmx*4 - 2); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 2; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 2; + png_memcpy(dp, v, 2); + } + } + } + } /* end of pixel_bytes == 2 */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 4) + { + if (((pass == 0) || (pass == 1)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes +/* +fprintf(stderr, "GRR DEBUG: png_do_read_interlace() pass = %d, width_mmx = %d, width = %d\n", pass, width_mmx, width); +fprintf(stderr, " sptr = 0x%08lx, dp = 0x%08lx\n", (unsigned long)sptr, (unsigned long)dp); +fflush(stderr); + */ + if (width_mmx) + { +#ifdef GRR_DEBUG + FILE *junk = fopen("junk.4bytes", "wb"); + if (junk) + fclose(junk); +#endif /* GRR_DEBUG */ + __asm__ ( + "subl $4, %%esi \n\t" + "subl $60, %%edi \n\t" + + ".loop4_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm1, 32(%%edi) \n\t" + "movq %%mm1, 40(%%edi) \n\t" + "movq %%mm1, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass0 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*32 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (((pass == 2) || (pass == 3)) && width) + { + int width_mmx = ((width >> 1) << 1); + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + __asm__ ( + "subl $4, %%esi \n\t" + "subl $28, %%edi \n\t" + + ".loop4_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm1, 16(%%edi) \n\t" + "movq %%mm1, 24(%%edi) \n\t" + "subl $8, %%esi \n\t" + "subl $32, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass2 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*16 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + else if (width) // pass == 4 or 5 + { + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; // 0,1 pixels => 0,4 bytes + if (width_mmx) + { + __asm__ ( + "subl $4, %%esi \n\t" + "subl $12, %%edi \n\t" + + ".loop4_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0 + "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0 + "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm1, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "subl $2, %%ecx \n\t" + "jnz .loop4_pass4 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width_mmx) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0, %mm1 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0", "%mm1" +#endif + ); + } + + sptr -= (width_mmx*4 - 4); // sign fixed + dp -= (width_mmx*8 - 4); // sign fixed + for (i = width; i; i--) + { + png_byte v[8]; + int j; + sptr -= 4; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + dp -= 4; + png_memcpy(dp, v, 4); + } + } + } + } /* end of pixel_bytes == 4 */ + +#define STILL_WORKING_ON_THIS +#ifdef STILL_WORKING_ON_THIS // GRR: should work, but needs testing + // (special 64-bit version of rpng2) + + //-------------------------------------------------------------- + else if (pixel_bytes == 8) + { + // GRR NOTE: no need to combine passes here! + if (((pass == 0) || (pass == 1)) && width) + { + // source is 8-byte RRGGBBAA + // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ... +#ifdef GRR_DEBUG + FILE *junk = fopen("junk.8bytes", "wb"); + if (junk) + fclose(junk); +#endif /* GRR_DEBUG */ + __asm__ ( + "subl $56, %%edi \n\t" // start of last block + + ".loop8_pass0: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "movq %%mm0, 32(%%edi) \n\t" + "movq %%mm0, 40(%%edi) \n\t" + "movq %%mm0, 48(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 56(%%edi) \n\t" + "subl $64, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass0 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0" +#endif + ); + } + else if (((pass == 2) || (pass == 3)) && width) + { + // source is 8-byte RRGGBBAA + // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + __asm__ ( + "subl $24, %%edi \n\t" // start of last block + + ".loop8_pass2: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "movq %%mm0, 16(%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 24(%%edi) \n\t" + "subl $32, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass2 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0" +#endif + ); + } + } + else if (width) // pass == 4 or 5 + { + // source is 8-byte RRGGBBAA + // dest is 16-byte RRGGBBAA RRGGBBAA + int width_mmx = ((width >> 1) << 1) ; + width -= width_mmx; + if (width_mmx) + { + __asm__ ( + "subl $8, %%edi \n\t" // start of last block + + ".loop8_pass4: \n\t" + "movq (%%esi), %%mm0 \n\t" // 7 6 5 4 3 2 1 0 + "movq %%mm0, (%%edi) \n\t" + "subl $8, %%esi \n\t" + "movq %%mm0, 8(%%edi) \n\t" + "subl $16, %%edi \n\t" + "decl %%ecx \n\t" + "jnz .loop8_pass4 \n\t" + "EMMS \n\t" // DONE + + : // output regs (none) + + : "S" (sptr), // esi // input regs + "D" (dp), // edi + "c" (width) // ecx + + : "%esi", "%edi", "%ecx" // clobber list +#if 0 /* %mm0 not supported by gcc 2.7.2.3 or egcs 1.1 */ + , "%mm0" +#endif + ); + } + } + + } /* end of pixel_bytes == 8 */ + +#endif /* STILL_WORKING_ON_THIS */ + + //-------------------------------------------------------------- + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } /* end of pixel_bytes == 6 */ + + //-------------------------------------------------------------- + else + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr-= pixel_bytes; + } + } + } // end of mmx_supported ========================================= + + else /* MMX not supported: use modified C code - takes advantage + * of inlining of memcpy for a constant */ + /* GRR 19991007: does it? or should pixel_bytes in each + * block be replaced with immediate value (e.g., 1)? */ + /* GRR 19991017: replaced with constants in each case */ + { + if (pixel_bytes == 1) + { + for (i = width; i; i--) + { + int j; + for (j = 0; j < png_pass_inc[pass]; j++) + *dp-- = *sptr; + --sptr; + } + } + else if (pixel_bytes == 3) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 3); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 3); + dp -= 3; + } + sptr -= 3; + } + } + else if (pixel_bytes == 2) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 2); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 2); + dp -= 2; + } + sptr -= 2; + } + } + else if (pixel_bytes == 4) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 4); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 4); + dp -= 4; + } + sptr -= 4; + } + } + else if (pixel_bytes == 6) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 6); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 6); + dp -= 6; + } + sptr -= 6; + } + } + else if (pixel_bytes == 8) + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, 8); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, 8); + dp -= 8; + } + sptr -= 8; + } + } + else // GRR: should never be reached + { + for (i = width; i; i--) + { + png_byte v[8]; + int j; + png_memcpy(v, sptr, pixel_bytes); + for (j = 0; j < png_pass_inc[pass]; j++) + { + png_memcpy(dp, v, pixel_bytes); + dp -= pixel_bytes; + } + sptr -= pixel_bytes; + } + } + + } /* end if (MMX not supported) */ + break; + } + } /* end switch (row_info->pixel_depth) */ + + row_info->width = final_width; + row_info->rowbytes = ((final_width * + (png_uint_32)row_info->pixel_depth + 7) >> 3); + } + +} /* end png_do_read_interlace() */ + +#endif /* PNG_HAVE_ASSEMBLER_READ_INTERLACE */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + + +// These variables are utilized in the functions below. They are declared +// globally here to ensure alignment on 8-byte boundaries. + +union uAll { + long long use; + double align; +} LBCarryMask = {0x0101010101010101LL}, + HBClearMask = {0x7f7f7f7f7f7f7f7fLL}, + ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem; + + +// Optimized code for PNG Average filter decoder +void +png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ + int bpp; +// int diff; GRR: global now (shortened to dif/_dif) + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + __asm__ ( + // Init address pointers and offset +//GRR "movl row, %%edi \n\t" // edi ==> Avg(x) + "xorl %%ebx, %%ebx \n\t" // ebx ==> x + "movl %%edi, %%edx \n\t" +//GRR "movl prev_row, %%esi \n\t" // esi ==> Prior(x) +//GRR "subl bpp, %%edx \n\t" // (bpp is preloaded into ecx) + "subl %%ecx, %%edx \n\t" // edx ==> Raw(x-bpp) + + "xorl %%eax,%%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Raw(x) = Avg(x) + (Prior(x)/2) + "avg_rlp: \n\t" + "movb (%%esi,%%ebx,),%%al \n\t" // Load al with Prior(x) + "incl %%ebx \n\t" + "shrb %%al \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,),%%al \n\t" // add Avg(x); -1 to offset inc ebx +//GRR "cmpl bpp, %%ebx \n\t" // (bpp is preloaded into ecx) + "cmpl %%ecx, %%ebx \n\t" + "movb %%al,-1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_rlp \n\t" // mov does not affect flags + + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "addl $0xf, _dif \n\t" // add 7+8 to incr past alignment bdry + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start => value ebx at alignment + "jz avg_go \n\t" + + // fix alignment + // Compute the Raw value for the bytes up to the alignment boundary + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%ecx, %%ecx \n\t" + "avg_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // add Avg(x); -1 to offset inc ebx + "cmpl _dif, %%ebx \n\t" // check if at alignment boundary + "movb %%al, -1(%%edi,%%ebx,) \n\t" // write Raw(x); -1 to offset inc ebx + "jb avg_lp1 \n\t" // repeat until at alignment boundary + + "avg_go: \n\t" + "movl _FullLength, %%eax \n\t" + "movl %%eax, %%ecx \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" + + : // output regs/vars here, e.g., "=m" (_MMXLength) instead of final instr + + : "S" (prev_row), // esi // input regs + "D" (row), // edi + "c" (bpp) // ecx + + : "%eax", "%ebx", "%ecx", // clobber list + "%edx", "%edi", "%esi" +// GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength) PROBABLY + ); + +#ifdef GRR_GCC_MMX_CONVERTED + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + __asm__ ( + // Re-init address pointers and offset + "movq $ActiveMask, %%mm7 \n\t" + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + "movq $LBCarryMask, %%mm5 \n\t" + "movl row, %%edi \n\t" // edi ==> Avg(x) + "movq $HBClearMask, %%mm4 \n\t" + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set) + "movq -8(%%edi,%%ebx,), %%mm2 \n\t" // Load previous aligned 8 bytes + // (we correct position in loop below) + "avg_3lp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" // Load mm0 with Avg(x) + // Add (Prev_row/2) to Average + "movq %%mm5, %%mm3 \n\t" + "psrlq $ShiftRem, %%mm2 \n\t" // Correct position Raw(x-bpp) data + "movq (%%esi,%%ebx,), %%mm1 \n\t" // Load mm1 with Prior(x) + "movq %%mm7, %%mm6 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + "psllq $ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 3-5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + + // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry + "psllq $ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover the last two + // bytes + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "addl $8, %%ebx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + // Move updated Raw(x) to use as Raw(x-bpp) for next loop + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, %%mm2 \n\t" // mov updated Raw(x) to mm2 + "jb avg_3lp \n\t" + + : // output regs/vars go here, e.g.: "=m" (memory_var) + + : "S" (prev_row), // esi // input regs + "D" (row) // edi + + : "%ebx", "%edi", "%esi" // clobber list +// GRR: INCLUDE "memory" as clobbered? (_dif, _MMXLength) PROBABLY +// , "%mm0", "%mm1", "%mm2", "%mm3", +// "%mm4", "%mm5", "%mm6", "%mm7" + ); + } + break; // end 3 bpp + + case 6: + case 4: + //case 7: // who wrote this? PNG doesn't support 5 or 7 bytes/pixel + //case 5: + { + ActiveMask.use = 0xffffffffffffffff; // use shift below to clear + // appropriate inactive bytes + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + __asm__ ( + "movq $HBClearMask, %%mm4 \n\t" + + // Re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + + // Load ActiveMask and clear all bytes except for 1st active group + "movq $ActiveMask, %%mm7 \n\t" + "movl row, %%edi \n\t" // edi ==> Avg(x) + "psrlq $ShiftRem, %%mm7 \n\t" + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + "movq %%mm7, %%mm6 \n\t" + "movq $LBCarryMask, %%mm5 \n\t" + "psllq $ShiftBpp, %%mm6 \n\t" // Create mask for 2nd active group + + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm2 \n\t" // Load previous aligned 8 bytes + // (we correct position in loop below) + "avg_4lp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "psrlq $ShiftRem, %%mm2 \n\t" // shift data to position correctly + "movq (%%esi,%%ebx,), %%mm1 \n\t" + // Add (Prev_row/2) to Average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm7, %%mm2 \n\t" // Leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + "addl $8, %%ebx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active + // byte + "cmpl _MMXLength, %%ebx \n\t" + // Now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + // Prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_4lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; // end 4,6 bpp + + case 2: + { + ActiveMask.use = 0x000000000000ffff; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + __asm__ ( + // Load ActiveMask + "movq $ActiveMask, %%mm7 \n\t" + // Re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + "movq $LBCarryMask, %%mm5 \n\t" + "movl row, %%edi \n\t" // edi ==> Avg(x) + "movq $HBClearMask, %%mm4 \n\t" + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm2 \n\t" // Load previous aligned 8 bytes + // (we correct position in loop below) + "avg_2lp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "psllq $ShiftRem, %%mm2 \n\t" // shift data to position correctly + "movq (%%esi,%%ebx,), %%mm1 \n\t" + // Add (Prev_row/2) to Average + "movq %%mm5, %%mm3 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "movq %%mm7, %%mm6 \n\t" + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 1 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry + "psllq $ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 2 & 3 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry + "psllq $ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 4 & 5 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry + "psllq $ShiftBpp, %%mm6 \n\t" // shift the mm6 mask to cover bytes 6 & 7 + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "psllq $ShiftBpp, %%mm2 \n\t" // shift data to position correctly + // Data only needs to be shifted once here to + // get the correct x-bpp offset. + "addl $8, %%ebx \n\t" + "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting LBCarrys + "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 (Only valid for active group) + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2) for each byte + "pand %%mm6, %%mm2 \n\t" // Leave only Active Group 2 bytes to add to Avg + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg for each Active byte + + "cmpl _MMXLength, %%ebx \n\t" + // Now ready to write back to memory + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + // Prep Raw(x-bpp) for next loop + "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2 + "jb avg_2lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; // end 2 bpp + + case 1: + { + __asm__ ( + // Re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + "movl row, %%edi \n\t" // edi ==> Avg(x) + "cmpl _FullLength, %%ebx \n\t" // Test if offset at end of array + "jnb avg_1end \n\t" + // Do Paeth decode for remaining bytes + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + "movl %%edi, %%edx \n\t" + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx in loop below + "subl bpp, %%edx \n\t" // edx ==> Raw(x-bpp) + "avg_1lp: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // Add Avg(x); -1 to offset inc ebx + "cmpl _FullLength, %%ebx \n\t" // Check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + "jb avg_1lp \n\t" + "avg_1end: \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); + } + return; // end 1 bpp + + case 8: + { + __asm__ ( + // Re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + "movq $LBCarryMask, %%mm5 \n\t" + "movl row, %%edi \n\t" // edi ==> Avg(x) + "movq $HBClearMask, %%mm4 \n\t" + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm2 \n\t" // Load previous aligned 8 bytes + // (NO NEED to correct position in loop below) + "avg_8lp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "addl $8, %%ebx \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg for each byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each byte + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + "movq %%mm0, %%mm2 \n\t" // reuse as Raw(x-bpp) + "jb avg_8lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" // CHECKASM: clobber list + ); + } + break; // end 8 bpp + + default: // bpp greater than 8 (!= 1,2,3,4,6,8) + { + + GRR: PRINT ERROR HERE: SHOULD NEVER BE REACHED (unless smaller than 1?) + + __asm__ ( + "movq $LBCarryMask, %%mm5 \n\t" + // Re-init address pointers and offset + "movl _dif, %%ebx \n\t" // ebx ==> x = offset to alignment boundary + "movl row, %%edi \n\t" // edi ==> Avg(x) + "movq $HBClearMask, %%mm4 \n\t" + "movl %%edi, %%edx \n\t" + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + "subl bpp, %%edx \n\t" // edx ==> Raw(x-bpp) + "avg_Alp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq %%mm5, %%mm3 \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte + "movq (%%edx,%%ebx,), %%mm2 \n\t" + "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2 + "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte where both + // lsb's were == 1 + "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2 + "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg for each byte + "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each byte + "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for each byte + "addl $8, %%ebx \n\t" + "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each byte + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + "jb avg_Alp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5" // CHECKASM: clobber list + ); + } + break; + } // end switch ( bpp ) + + __asm__ ( + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + "movl _MMXLength, %%ebx \n\t" // ebx ==> x = offset bytes remaining after MMX + "movl row, %%edi \n\t" // edi ==> Avg(x) + "cmpl _FullLength, %%ebx \n\t" // Test if offset at end of array + "jnb avg_end \n\t" + // Do Paeth decode for remaining bytes + "movl prev_row, %%esi \n\t" // esi ==> Prior(x) + "movl %%edi, %%edx \n\t" + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx in loop below + "subl bpp, %%edx \n\t" // edx ==> Raw(x-bpp) + "avg_lp2: \n\t" + // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2) + "xorl %%eax, %%eax \n\t" + "movb (%%esi,%%ebx,), %%cl \n\t" // load cl with Prior(x) + "movb (%%edx,%%ebx,), %%al \n\t" // load al with Raw(x-bpp) + "addw %%cx, %%ax \n\t" + "incl %%ebx \n\t" + "shrw %%ax \n\t" // divide by 2 + "addb -1(%%edi,%%ebx,), %%al \n\t" // Add Avg(x); -1 to offset inc ebx + "cmpl _FullLength, %%ebx \n\t" // Check if at end of array + "movb %%al, -1(%%edi,%%ebx,) \n\t" // Write back Raw(x); + // mov does not affect flags; -1 to offset inc ebx + "jb avg_lp2 \n\t" + "avg_end: \n\t" + "emms \n\t" // End MMX instructions; prep for possible FP instrs. + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); +#endif /* GRR_GCC_MMX_CONVERTED */ +} + +// Optimized code for PNG Paeth filter decoder +void +png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ +#ifdef GRR_GCC_MMX_CONVERTED + int bpp; + int patemp, pbtemp, pctemp; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + _FullLength = row_info->rowbytes; // # of bytes to filter + __asm__ ( + "xorl %%ebx, %%ebx \n\t" // ebx ==> x offset + "movl row, %%edi \n\t" + "xorl %%edx, %%edx \n\t" // edx ==> x-bpp offset + "movl prev_row, %%esi \n\t" + "xorl %%eax, %%eax \n\t" + + // Compute the Raw value for the first bpp bytes + // Note: the formula works out to be always + // Paeth(x) = Raw(x) + Prior(x) where x < bpp + "paeth_rlp: \n\t" + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl bpp, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" + "jb paeth_rlp \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl %%ebx, _dif \n\t" // add bpp + "xorl %%ecx, %%ecx \n\t" + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past alignment boundary + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value ebx at alignment + "jz paeth_go \n\t" + // fix alignment + "paeth_lp1: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_pca: \n\t" + "movl %%eax, pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + "paeth_pba: \n\t" + "movl %%ecx, pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_paa: \n\t" + "movl %%eax, patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb \n\t" + // pa > pb; now test if pb <= pc + "cmpl pctemp, %%ecx \n\t" + "jna paeth_bbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + "paeth_bbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth \n\t" + "paeth_abb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl pctemp, %%eax \n\t" + "jna paeth_abc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth \n\t" + "paeth_abc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + "paeth_paeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _dif, %%ebx \n\t" + "jb paeth_lp1 \n\t" + "paeth_go: \n\t" + "movl _FullLength, %%ecx \n\t" + "movl %%ecx, %%eax \n\t" + "subl %%ebx, %%eax \n\t" // subtract alignment fix + "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8 + "subl %%eax, %%ecx \n\t" // drop over bytes from original length + "movl %%ecx, _MMXLength \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); + + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000000000ffffff; + ActiveMaskEnd.use = 0xffff000000000000; + ShiftBpp.use = 24; // == bpp(3) * 8 + ShiftRem.use = 40; // == 64 - 24 + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "paeth_3lp: \n\t" + "psrlq $ShiftRem, %%mm1 \n\t" // shift last 3 bytes to 1st 3 bytes + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm1 \n\t" // Unpack High bytes of a + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // Prep c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + "psrlq $ShiftRem, %%mm3 \n\t" // shift last 3 bytes to 1st 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ebx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand $ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ebx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + "movq %%mm7, (%%edi,%%ebx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 2nd set of bytes (3-5) + "psrlq $ShiftBpp, %%mm2 \n\t" // load b=Prior(x) step 2 + "punpcklbw %%mm0, %%mm1 \n\t" // Unpack High bytes of a + "pxor %%mm7, %%mm7 \n\t" + "punpcklbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = + // pav + pbv = pbv + pav + "movq %%mm5, %%mm6 \n\t" + "paddw %%mm4, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm5, %%mm0 \n\t" // Create mask pbv bytes < 0 + "pcmpgtw %%mm4, %%mm7 \n\t" // Create mask pav bytes < 0 + "pand %%mm5, %%mm0 \n\t" // Only pbv bytes < 0 in mm0 + "pand %%mm4, %%mm7 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "psubw %%mm0, %%mm5 \n\t" + "psubw %%mm7, %%mm4 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq %%mm2, %%mm3 \n\t" // load c=Prior(x-bpp) step 1 + "pand $ActiveMask, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + "psllq $ShiftBpp, %%mm7 \n\t" // Shift bytes to 2nd group of 3 bytes + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "paddb (%%edi,%%ebx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "psllq $ShiftBpp, %%mm3 \n\t" // load c=Prior(x-bpp) step 2 + "movq %%mm7, (%%edi,%%ebx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + "psllq $ShiftBpp, %%mm1 \n\t" // Shift bytes + // Now mm1 will be used as Raw(x-bpp) + // Now do Paeth for 3rd, and final, set of bytes (6-7) + "pxor %%mm7, %%mm7 \n\t" + "punpckhbw %%mm0, %%mm1 \n\t" // Unpack High bytes of a + "psubw %%mm3, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "paddw %%mm5, %%mm6 \n\t" + + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "packuswb %%mm7, %%mm1 \n\t" + // Step ebx to next set of 8 bytes and repeat loop til done + "addl $8, %%ebx \n\t" + "pand $ActiveMaskEnd, %%mm1 \n\t" + "paddb -8(%%edi,%%ebx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + + "cmpl _MMXLength, %%ebx \n\t" + "pxor %%mm0, %%mm0 \n\t" // pxor does not affect flags + "movq %%mm1, -8(%%edi,%%ebx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + // mm3 ready to be used as Prior(x-bpp) next loop + "jb paeth_3lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + + case 6: + //case 7: // GRR BOGUS + //case 5: // GRR BOGUS + { + ActiveMask.use = 0x00000000ffffffff; + ActiveMask2.use = 0xffffffff00000000; + ShiftBpp.use = bpp << 3; // == bpp * 8 + ShiftRem.use = 64 - ShiftBpp.use; + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "paeth_6lp: \n\t" + // Must shift to position Raw(x-bpp) data + "psrlq $ShiftRem, %%mm1 \n\t" + // Do first set of 4 bytes + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // Unpack Low bytes of a + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // Unpack Low bytes of b + // Must shift to position Prior(x-bpp) data + "psrlq $ShiftRem, %%mm3 \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand $ActiveMask, %%mm7 \n\t" + "psrlq $ShiftRem, %%mm3 \n\t" + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ebx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "movq %%mm2, %%mm6 \n\t" + "movq %%mm7, (%%edi,%%ebx,) \n\t" // write back updated value + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "psllq $ShiftBpp, %%mm6 \n\t" + "movq %%mm7, %%mm5 \n\t" + "psrlq $ShiftRem, %%mm1 \n\t" + "por %%mm6, %%mm3 \n\t" + "psllq $ShiftBpp, %%mm5 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + "por %%mm5, %%mm1 \n\t" + // Do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // Step ex to next set of 8 bytes and repeat loop til done + "addl $8, %%ebx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ebx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm1, -8(%%edi,%%ebx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_6lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + + case 4: + { + ActiveMask.use = 0x00000000ffffffff; + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" // Only time should need to read + // a=Raw(x-bpp) bytes + "paeth_4lp: \n\t" + // Do first set of 4 bytes + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpckhbw %%mm0, %%mm1 \n\t" // Unpack Low bytes of a + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpckhbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq (%%esi,%%ebx,), %%mm3 \n\t" // load c=Prior(x-bpp) + "pand $ActiveMask, %%mm7 \n\t" + "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1 + "paddb (%%edi,%%ebx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpcklbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + "movq %%mm7, (%%edi,%%ebx,) \n\t" // write back updated value + "movq %%mm7, %%mm1 \n\t" // Now mm1 will be used as Raw(x-bpp) + // Do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // Unpack Low bytes of b + "punpcklbw %%mm0, %%mm1 \n\t" // Unpack Low bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // Step ex to next set of 8 bytes and repeat loop til done + "addl $8, %%ebx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ebx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm1, -8(%%edi,%%ebx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_4lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + case 8: // bpp == 8 + { + ActiveMask.use = 0x00000000ffffffff; + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + "pxor %%mm0, %%mm0 \n\t" + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" // Only time should need to read + // a=Raw(x-bpp) bytes + "paeth_8lp: \n\t" + // Do first set of 4 bytes + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "punpcklbw %%mm0, %%mm1 \n\t" // Unpack Low bytes of a + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "punpcklbw %%mm0, %%mm2 \n\t" // Unpack Low bytes of b + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + "punpcklbw %%mm0, %%mm3 \n\t" // Unpack Low bytes of c + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "packuswb %%mm1, %%mm7 \n\t" + "movq -8(%%esi,%%ebx,), %%mm3 \n\t" // read c=Prior(x-bpp) bytes + "pand $ActiveMask, %%mm7 \n\t" + "movq (%%esi,%%ebx,), %%mm2 \n\t" // load b=Prior(x) + "paddb (%%edi,%%ebx,), %%mm7 \n\t" // add Paeth predictor with Raw(x) + "punpckhbw %%mm0, %%mm3 \n\t" // Unpack High bytes of c + "movq %%mm7, (%%edi,%%ebx,) \n\t" // write back updated value + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" // read a=Raw(x-bpp) bytes + + // Do second set of 4 bytes + "punpckhbw %%mm0, %%mm2 \n\t" // Unpack High bytes of b + "punpckhbw %%mm0, %%mm1 \n\t" // Unpack High bytes of a + // pav = p - a = (a + b - c) - a = b - c + "movq %%mm2, %%mm4 \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movq %%mm1, %%mm5 \n\t" + "psubw %%mm3, %%mm4 \n\t" + "pxor %%mm7, %%mm7 \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "movq %%mm4, %%mm6 \n\t" + "psubw %%mm3, %%mm5 \n\t" + // pa = abs(p-a) = abs(pav) + // pb = abs(p-b) = abs(pbv) + // pc = abs(p-c) = abs(pcv) + "pcmpgtw %%mm4, %%mm0 \n\t" // Create mask pav bytes < 0 + "paddw %%mm5, %%mm6 \n\t" + "pand %%mm4, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "pcmpgtw %%mm5, %%mm7 \n\t" // Create mask pbv bytes < 0 + "psubw %%mm0, %%mm4 \n\t" + "pand %%mm5, %%mm7 \n\t" // Only pbv bytes < 0 in mm0 + "psubw %%mm0, %%mm4 \n\t" + "psubw %%mm7, %%mm5 \n\t" + "pxor %%mm0, %%mm0 \n\t" + "pcmpgtw %%mm6, %%mm0 \n\t" // Create mask pcv bytes < 0 + "pand %%mm6, %%mm0 \n\t" // Only pav bytes < 0 in mm7 + "psubw %%mm7, %%mm5 \n\t" + "psubw %%mm0, %%mm6 \n\t" + // test pa <= pb + "movq %%mm4, %%mm7 \n\t" + "psubw %%mm0, %%mm6 \n\t" + "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb? + "movq %%mm7, %%mm0 \n\t" + // use mm7 mask to merge pa & pb + "pand %%mm7, %%mm5 \n\t" + // use mm0 mask copy to merge a & b + "pand %%mm0, %%mm2 \n\t" + "pandn %%mm4, %%mm7 \n\t" + "pandn %%mm1, %%mm0 \n\t" + "paddw %%mm5, %%mm7 \n\t" + "paddw %%mm2, %%mm0 \n\t" + // test ((pa <= pb)? pa:pb) <= pc + "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc? + "pxor %%mm1, %%mm1 \n\t" + "pand %%mm7, %%mm3 \n\t" + "pandn %%mm0, %%mm7 \n\t" + "pxor %%mm1, %%mm1 \n\t" + "paddw %%mm3, %%mm7 \n\t" + "pxor %%mm0, %%mm0 \n\t" + // Step ex to next set of 8 bytes and repeat loop til done + "addl $8, %%ebx \n\t" + "packuswb %%mm7, %%mm1 \n\t" + "paddb -8(%%edi,%%ebx,), %%mm1 \n\t" // add Paeth predictor with Raw(x) + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm1, -8(%%edi,%%ebx,) \n\t" // write back updated value + // mm1 will be used as Raw(x-bpp) next loop + "jb paeth_8lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + + case 1: // bpp = 1 + case 2: // bpp = 2 + default: // bpp > 8 + { + __asm__ ( + "movl _dif, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_dend \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + // Do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx in loop below + "subl bpp, %%edx \n\t" // Set edx = ebx - bpp + "paeth_dlp: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpca \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_dpca: \n\t" + "movl %%eax, pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_dpba \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + "paeth_dpba: \n\t" + "movl %%ecx, pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_dpaa \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_dpaa: \n\t" + "movl %%eax, patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_dabb \n\t" + // pa > pb; now test if pb <= pc + "cmpl pctemp, %%ecx \n\t" + "jna paeth_dbbc \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + "paeth_dbbc: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_dpaeth \n\t" + "paeth_dabb: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl pctemp, %%eax \n\t" + "jna paeth_dabc \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_dpaeth \n\t" + "paeth_dabc: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + "paeth_dpaeth: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_dlp \n\t" + "paeth_dend: \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); + } + return; // No need to go further with this one + } // end switch ( bpp ) + __asm__ ( + // MMX acceleration complete now do clean-up + // Check if any remaining bytes left to decode + "movl _MMXLength, %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb paeth_end \n\t" + "movl row, %%edi \n\t" + "movl prev_row, %%esi \n\t" + // Do Paeth decode for remaining bytes + "movl %%ebx, %%edx \n\t" + "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx in loop below + "subl bpp, %%edx \n\t" // Set edx = ebx - bpp + "paeth_lp2: \n\t" + "xorl %%eax, %%eax \n\t" + // pav = p - a = (a + b - c) - a = b - c + "movb (%%esi,%%ebx,), %%al \n\t" // load Prior(x) into al + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, patemp \n\t" // Save pav for later use + "xorl %%eax, %%eax \n\t" + // pbv = p - b = (a + b - c) - b = a - c + "movb (%%edi,%%edx,), %%al \n\t" // load Raw(x-bpp) into al + "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp) + "movl %%eax, %%ecx \n\t" + // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv + "addl patemp, %%eax \n\t" // pcv = pav + pbv + // pc = abs(pcv) + "testl $0x80000000, %%eax \n\t" + "jz paeth_pca2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_pca2: \n\t" + "movl %%eax, pctemp \n\t" // save pc for later use + // pb = abs(pbv) + "testl $0x80000000, %%ecx \n\t" + "jz paeth_pba2 \n\t" + "negl %%ecx \n\t" // reverse sign of neg values + "paeth_pba2: \n\t" + "movl %%ecx, pbtemp \n\t" // save pb for later use + // pa = abs(pav) + "movl patemp, %%eax \n\t" + "testl $0x80000000, %%eax \n\t" + "jz paeth_paa2 \n\t" + "negl %%eax \n\t" // reverse sign of neg values + "paeth_paa2: \n\t" + "movl %%eax, patemp \n\t" // save pa for later use + // test if pa <= pb + "cmpl %%ecx, %%eax \n\t" + "jna paeth_abb2 \n\t" + // pa > pb; now test if pb <= pc + "cmpl pctemp, %%ecx \n\t" + "jna paeth_bbc2 \n\t" + // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + "paeth_bbc2: \n\t" + // pb <= pc; Raw(x) = Paeth(x) + Prior(x) + "movb (%%esi,%%ebx,), %%cl \n\t" // load Prior(x) into cl + "jmp paeth_paeth2 \n\t" + "paeth_abb2: \n\t" + // pa <= pb; now test if pa <= pc + "cmpl pctemp, %%eax \n\t" + "jna paeth_abc2 \n\t" + // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp) + "movb (%%esi,%%edx,), %%cl \n\t" // load Prior(x-bpp) into cl + "jmp paeth_paeth2 \n\t" + "paeth_abc2: \n\t" + // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp) + "movb (%%edi,%%edx,), %%cl \n\t" // load Raw(x-bpp) into cl + "paeth_paeth2: \n\t" + "incl %%ebx \n\t" + "incl %%edx \n\t" + // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256 + "addb %%cl, -1(%%edi,%%ebx,) \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb paeth_lp2 \n\t" + "paeth_end: \n\t" + "emms \n\t" // End MMX instructions; prep for possible FP instrs. + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); +#endif /* GRR_GCC_MMX_CONVERTED */ +} + +// Optimized code for PNG Sub filter decoder +void +png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row) +{ +#ifdef GRR_GCC_MMX_CONVERTED + int bpp; + + bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel + _FullLength = row_info->rowbytes - bpp; // # of bytes to filter + __asm__ ( + "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "addl bpp, %%edi \n\t" // rp = row + bpp + "xorl %%eax, %%eax \n\t" + // get # of bytes to alignment + "movl %%edi, _dif \n\t" // take start of row + "addl $0xf, _dif \n\t" // add 7 + 8 to incr past + // alignment boundary + "xorl %%ebx, %%ebx \n\t" + "andl $0xfffffff8, _dif \n\t" // mask to alignment boundary + "subl %%edi, _dif \n\t" // subtract from start ==> value + // ebx at alignment + "jz sub_go \n\t" + // fix alignment + "sub_lp1: \n\t" + "movb (%%esi,%%ebx,), %%al \n\t" + "addb %%al, (%%edi,%%ebx,) \n\t" + "incl %%ebx \n\t" + "cmpl _dif, %%ebx \n\t" + "jb sub_lp1 \n\t" + "sub_go: \n\t" + "movl _FullLength, %%ecx \n\t" + "movl %%ecx, %%edx \n\t" + "subl %%ebx, %%edx \n\t" // subtract alignment fix + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + "movl %%ecx, _MMXLength \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" // CHECKASM: clobber list + ); + + // Now do the math for the rest of the row + switch ( bpp ) + { + case 3: + { + ActiveMask.use = 0x0000ffffff000000; + ShiftBpp.use = 24; // == 3 * 8 + ShiftRem.use = 40; // == 64 - 24 + __asm__ ( + "movl row, %%edi \n\t" + "movq $ActiveMask, %%mm7 \n\t" // Load ActiveMask for 2nd active byte group + "movl %%edi, %%esi \n\t" // lp = row + "addl bpp, %%edi \n\t" // rp = row + bpp + "movq %%mm7, %%mm6 \n\t" + "movl _dif, %%ebx \n\t" + "psllq $ShiftBpp, %%mm6 \n\t" // Move mask in mm6 to cover 3rd active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "sub_3lp: \n\t" + "psrlq $ShiftRem, %%mm1 \n\t" // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + // Add 1st active group + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + // Add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + "pand %%mm7, %%mm1 \n\t" // mask to use only 2nd active group + "paddb %%mm1, %%mm0 \n\t" + // Add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + "pand %%mm6, %%mm1 \n\t" // mask to use only 3rd active group + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // Write updated Raws back to array + // Prep for doing 1st add at top of loop + "movq %%mm0, %%mm1 \n\t" + "jb sub_3lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + + case 1: + { + // Placed here just in case this is a duplicate of the + // non-MMX code for the SUB filter in png_read_filter_row above + // + // png_bytep rp; + // png_bytep lp; + // png_uint_32 i; + // bpp = (row_info->pixel_depth + 7) >> 3; + // for (i = (png_uint_32)bpp, rp = row + bpp, lp = row; + // i < row_info->rowbytes; i++, rp++, lp++) + // { + // *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff); + // } + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb sub_1end \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "xorl %%eax, %%eax \n\t" + "addl bpp, %%edi \n\t" // rp = row + bpp + "sub_1lp: \n\t" + "movb (%%esi,%%ebx,), %%al \n\t" + "addb %%al, (%%edi,%%ebx,) \n\t" + "incl %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb sub_1lp \n\t" + "sub_1end: \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%edi", "%esi" // CHECKASM: clobber list + ); + } + return; + + case 6: + case 7: + case 4: + case 5: + { + ShiftBpp.use = bpp << 3; + ShiftRem.use = 64 - ShiftBpp.use; + __asm__ ( + "movl row, %%edi \n\t" + "movl _dif, %%ebx \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "addl bpp, %%edi \n\t" // rp = row + bpp + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "sub_4lp: \n\t" + "psrlq $ShiftRem, %%mm1 \n\t" // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive bytes + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + // Add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + // there is no need for any mask + // since shift clears inactive bits/bytes + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" + "movq %%mm0, %%mm1 \n\t" // Prep for doing 1st add at top of loop + "jb sub_4lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1" // CHECKASM: clobber list + ); + } + break; + + case 2: + { + ActiveMask.use = 0x00000000ffff0000; + ShiftBpp.use = 16; // == 2 * 8 + ShiftRem.use = 48; // == 64 - 16 + __asm__ ( + "movq $ActiveMask, %%mm7 \n\t" // Load ActiveMask for 2nd active byte group + "movl _dif, %%ebx \n\t" + "movq %%mm7, %%mm6 \n\t" + "movl row, %%edi \n\t" + "psllq $ShiftBpp, %%mm6 \n\t" // Move mask in mm6 to cover 3rd active + // byte group + "movl %%edi, %%esi \n\t" // lp = row + "movq %%mm6, %%mm5 \n\t" + "addl bpp, %%edi \n\t" // rp = row + bpp + "psllq $ShiftBpp, %%mm5 \n\t" // Move mask in mm5 to cover 4th active + // byte group + // PRIME the pump (load the first Raw(x-bpp) data set + "movq -8(%%edi,%%ebx,), %%mm1 \n\t" + "sub_2lp: \n\t" + // Add 1st active group + "psrlq $ShiftRem, %%mm1 \n\t" // Shift data for adding 1st bpp bytes + // no need for mask; shift clears inactive + // bytes + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "paddb %%mm1, %%mm0 \n\t" + // Add 2nd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + "pand %%mm7, %%mm1 \n\t" // mask to use only 2nd active group + "paddb %%mm1, %%mm0 \n\t" + // Add 3rd active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + "pand %%mm6, %%mm1 \n\t" // mask to use only 3rd active group + "paddb %%mm1, %%mm0 \n\t" + // Add 4th active group + "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1 + "psllq $ShiftBpp, %%mm1 \n\t" // shift data to position correctly + "pand %%mm5, %%mm1 \n\t" // mask to use only 4th active group + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // Write updated Raws back to array + "movq %%mm0, %%mm1 \n\t" // Prep for doing 1st add at top of loop + "jb sub_2lp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + case 8: + { + __asm__ ( + "movl row, %%edi \n\t" + "movl _dif, %%ebx \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "addl bpp, %%edi \n\t" // rp = row + bpp + "movl _MMXLength, %%ecx \n\t" + "movq -8(%%edi,%%ebx,), %%mm7 \n\t" // PRIME the pump (load the first + // Raw(x-bpp) data set + "andl $0x0000003f, %%ecx \n\t" // calc bytes over mult of 64 + "sub_8lp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" // Load Sub(x) for 1st 8 bytes + "paddb %%mm7, %%mm0 \n\t" + "movq 8(%%edi,%%ebx,), %%mm1 \n\t" // Load Sub(x) for 2nd 8 bytes + "movq %%mm0, (%%edi,%%ebx,) \n\t" // Write Raw(x) for 1st 8 bytes + // Now mm0 will be used as Raw(x-bpp) for + // the 2nd group of 8 bytes. This will be + // repeated for each group of 8 bytes with + // the 8th group being used as the Raw(x-bpp) + // for the 1st group of the next loop. + "paddb %%mm0, %%mm1 \n\t" + "movq 16(%%edi,%%ebx,), %%mm2 \n\t" // Load Sub(x) for 3rd 8 bytes + "movq %%mm1, 8(%%edi,%%ebx,) \n\t" // Write Raw(x) for 2nd 8 bytes + "paddb %%mm1, %%mm2 \n\t" + "movq 24(%%edi,%%ebx,), %%mm3 \n\t" // Load Sub(x) for 4th 8 bytes + "movq %%mm2, 16(%%edi,%%ebx,) \n\t" // Write Raw(x) for 3rd 8 bytes + "paddb %%mm2, %%mm3 \n\t" + "movq 32(%%edi,%%ebx,), %%mm4 \n\t" // Load Sub(x) for 5th 8 bytes + "movq %%mm3, 24(%%edi,%%ebx,) \n\t" // Write Raw(x) for 4th 8 bytes + "paddb %%mm3, %%mm4 \n\t" + "movq 40(%%edi,%%ebx,), %%mm5 \n\t" // Load Sub(x) for 6th 8 bytes + "movq %%mm4, 32(%%edi,%%ebx,) \n\t" // Write Raw(x) for 5th 8 bytes + "paddb %%mm4, %%mm5 \n\t" + "movq 48(%%edi,%%ebx,), %%mm6 \n\t" // Load Sub(x) for 7th 8 bytes + "movq %%mm5, 40(%%edi,%%ebx,) \n\t" // Write Raw(x) for 6th 8 bytes + "paddb %%mm5, %%mm6 \n\t" + "movq 56(%%edi,%%ebx,), %%mm7 \n\t" // Load Sub(x) for 8th 8 bytes + "movq %%mm6, 48(%%edi,%%ebx,) \n\t" // Write Raw(x) for 7th 8 bytes + "addl $64, %%ebx \n\t" + "paddb %%mm6, %%mm7 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm7, -8(%%edi,%%ebx,) \n\t" // Write Raw(x) for 8th 8 bytes + "jb sub_8lp \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "jnb sub_8lt8 \n\t" + "sub_8lpA: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "addl $8, %%ebx \n\t" + "paddb %%mm7, %%mm0 \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // use -8 to offset early add to ebx + "movq %%mm0, %%mm7 \n\t" // Move calculated Raw(x) data to mm1 to + // be the new Raw(x-bpp) for the next loop + "jb sub_8lpA \n\t" + "sub_8lt8: \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%ecx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); + } + break; + + default: // bpp greater than 8 bytes + { + __asm__ ( + "movl _dif, %%ebx \n\t" + "movl row, %%edi \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "addl bpp, %%edi \n\t" // rp = row + bpp + "sub_Alp: \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl _MMXLength, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // mov does not affect flags; -8 to offset + // add ebx + "jb sub_Alp \n\t" + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%ebx", "%edi", "%esi", "%mm0", "%mm1" // CHECKASM: clobber list + ); + } + break; + + } // end switch ( bpp ) + + __asm__ ( + "movl _MMXLength, %%ebx \n\t" + "movl row, %%edi \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jnb sub_end \n\t" + "movl %%edi, %%esi \n\t" // lp = row + "xorl %%eax, %%eax \n\t" + "addl bpp, %%edi \n\t" // rp = row + bpp + "sub_lp2: \n\t" + "movb (%%esi,%%ebx,), %%al \n\t" + "addb %%al, (%%edi,%%ebx,) \n\t" + "incl %%ebx \n\t" + "cmpl _FullLength, %%ebx \n\t" + "jb sub_lp2 \n\t" + "sub_end: \n\t" + "emms \n\t" // end MMX instructions + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%edi", "%esi" // CHECKASM: clobber list + ); +#endif /* GRR_GCC_MMX_CONVERTED */ +} + +// Optimized code for PNG Up filter decoder +void +png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row, + png_bytep prev_row) +{ +#ifdef GRR_GCC_MMX_CONVERTED + png_uint_32 len; + + len = row_info->rowbytes; // # of bytes to filter + __asm__ ( + "movl row, %%edi \n\t" + // get # of bytes to alignment + "movl %%edi, %%ecx \n\t" + "xorl %%ebx, %%ebx \n\t" + "addl $0x7, %%ecx \n\t" + "xorl %%eax, %%eax \n\t" + "andl $0xfffffff8, %%ecx \n\t" + "movl prev_row, %%esi \n\t" + "subl %%edi, %%ecx \n\t" + "jz up_go \n\t" + // fix alignment + "up_lp1: \n\t" + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to offset inc ebx + "jb up_lp1 \n\t" + "up_go: \n\t" + "movl len, %%ecx \n\t" + "movl %%ecx, %%edx \n\t" + "subl %%ebx, %%edx \n\t" // subtract alignment fix + "andl $0x0000003f, %%edx \n\t" // calc bytes over mult of 64 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + // Unrolled loop - use all MMX registers and interleave to reduce + // number of branch instructions (loops) and reduce partial stalls + "up_loop: \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "movq 8(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 8(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, (%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 16(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 8(%%edi,%%ebx,) \n\t" + "movq 16(%%edi,%%ebx,), %%mm4 \n\t" + "movq 24(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 24(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 16(%%edi,%%ebx,) \n\t" + "paddb %%mm7, %%mm6 \n\t" + "movq 32(%%esi,%%ebx,), %%mm1 \n\t" + "movq %%mm6, 24(%%edi,%%ebx,) \n\t" + "movq 32(%%edi,%%ebx,), %%mm0 \n\t" + "movq 40(%%esi,%%ebx,), %%mm3 \n\t" + "paddb %%mm1, %%mm0 \n\t" + "movq 40(%%edi,%%ebx,), %%mm2 \n\t" + "movq %%mm0, 32(%%edi,%%ebx,) \n\t" + "paddb %%mm3, %%mm2 \n\t" + "movq 48(%%esi,%%ebx,), %%mm5 \n\t" + "movq %%mm2, 40(%%edi,%%ebx,) \n\t" + "movq 48(%%edi,%%ebx,), %%mm4 \n\t" + "movq 56(%%esi,%%ebx,), %%mm7 \n\t" + "paddb %%mm5, %%mm4 \n\t" + "movq 56(%%edi,%%ebx,), %%mm6 \n\t" + "movq %%mm4, 48(%%edi,%%ebx,) \n\t" + "addl $64, %%ebx \n\t" + "paddb %%mm7, %%mm6 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm6, -8(%%edi,%%ebx,) \n\t" // (+56)movq does not affect flags; + // -8 to offset add ebx + "jb up_loop \n\t" + + "cmpl $0, %%edx \n\t" // Test for bytes over mult of 64 + "jz up_end \n\t" + + + // 2 lines added by lcreeve@netins.net + // (mail 11 Jul 98 in png-implement list) + "cmpl $8, %%edx \n\t" //test for less than 8 bytes + "jb up_lt8 \n\t" + + + "addl %%edx, %%ecx \n\t" + "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8 + "subl %%edx, %%ecx \n\t" // drop over bytes from length + "jz up_lt8 \n\t" + // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously + "up_lpA: \n\t" + "movq (%%esi,%%ebx,), %%mm1 \n\t" + "movq (%%edi,%%ebx,), %%mm0 \n\t" + "addl $8, %%ebx \n\t" + "paddb %%mm1, %%mm0 \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movq %%mm0, -8(%%edi,%%ebx,) \n\t" // movq does not affect flags; -8 to offset add ebx + "jb up_lpA \n\t" + "cmpl $0, %%edx \n\t" // Test for bytes over mult of 8 + "jz up_end \n\t" + "up_lt8: \n\t" + "xorl %%eax, %%eax \n\t" + "addl %%edx, %%ecx \n\t" // move over byte count into counter + // Loop using x86 registers to update remaining bytes + "up_lp2: \n\t" + "movb (%%edi,%%ebx,), %%al \n\t" + "addb (%%esi,%%ebx,), %%al \n\t" + "incl %%ebx \n\t" + "cmpl %%ecx, %%ebx \n\t" + "movb %%al, -1(%%edi,%%ebx,) \n\t" // mov does not affect flags; -1 to offset inc ebx + "jb up_lp2 \n\t" + "up_end: \n\t" + // Conversion of filtered row completed + "emms \n\t" // End MMX instructions; prep for possible FP instrs. + + : // FIXASM: output regs/vars go here, e.g.: "=m" (memory_var) + + : // FIXASM: input regs, e.g.: "c" (count), "S" (src), "D" (dest) + + : "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi", "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" // CHECKASM: clobber list + ); +#endif /* GRR_GCC_MMX_CONVERTED */ +} + + +#if defined(PNG_HAVE_ASSEMBLER_READ_FILTER_ROW) + +// Optimized png_read_filter_row routines + +void +png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep + row, png_bytep prev_row, int filter) +{ +#ifdef PNG_DEBUG + char filnm[6]; +#endif + #define UseMMX 1 + + if (mmx_supported == 2) + mmx_supported = mmxsupport(); + +#ifdef GRR_GCC_MMX_CONVERTED + if (!mmx_supported) +#endif + { + png_read_filter_row_c(png_ptr, row_info, row, prev_row, filter); + return ; + } + +#ifdef PNG_DEBUG + png_debug(1, "in png_read_filter_row\n"); +#if (UseMMX == 1) + png_debug1(0,"%s, ", "MMX"); +#else + png_debug1(0,"%s, ", "x86"); +#endif + switch (filter) + { + case 0: sprintf(filnm, "None "); + break; + case 1: sprintf(filnm, "Sub "); + break; + case 2: sprintf(filnm, "Up "); + break; + case 3: sprintf(filnm, "Avg "); + break; + case 4: sprintf(filnm, "Paeth"); + break; + default: sprintf(filnm, "Unknw"); + break; + } + png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm); + png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth, + (int)((row_info->pixel_depth + 7) >> 3)); + png_debug1(0,"len=%8d, ", row_info->rowbytes); +#endif + + switch (filter) + { + case PNG_FILTER_VALUE_NONE: + break; + + case PNG_FILTER_VALUE_SUB: +#if (UseMMX == 1) + if ((row_info->pixel_depth > 8) && (row_info->rowbytes >= 128)) + { + png_read_filter_row_mmx_sub(row_info, row); + } + else +#endif + { + png_uint_32 i; + png_uint_32 istop = row_info->rowbytes; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + png_bytep lp = row; + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); + rp++; + } + } //end !UseMMX + break; + + case PNG_FILTER_VALUE_UP: +#if (UseMMX == 1) + if ((row_info->pixel_depth > 8) && (row_info->rowbytes >= 128)) + { + png_read_filter_row_mmx_up(row_info, row, prev_row); + } + else +#endif + { + png_bytep rp; + png_bytep pp; + png_uint_32 i; + for (i = 0, rp = row, pp = prev_row; + i < row_info->rowbytes; i++, rp++, pp++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp)) & 0xff); + } + } //end !UseMMX + break; + + case PNG_FILTER_VALUE_AVG: +#if (UseMMX == 1) + if ((row_info->pixel_depth > 8) && (row_info->rowbytes >= 128)) + { + png_read_filter_row_mmx_avg(row_info, row, prev_row); + } + else +#endif + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) >> 1)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++ + *lp++) >> 1)) & 0xff); + rp++; + } + } //end !UseMMX + break; + + case PNG_FILTER_VALUE_PAETH: +#if (UseMMX == 1) + if ((row_info->pixel_depth > 8) && (row_info->rowbytes >= 128)) + { + png_read_filter_row_mmx_paeth(row_info, row, prev_row); + } + else +#endif + { + png_uint_32 i; + png_bytep rp = row; + png_bytep pp = prev_row; + png_bytep lp = row; + png_bytep cp = prev_row; + png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3; + png_uint_32 istop=row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } + + for (i = 0; i < istop; i++) // use leftover rp,pp + { + int a, b, c, pa, pb, pc, p; + + a = *lp++; + b = *pp++; + c = *cp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + /* + if (pa <= pb && pa <= pc) + p = a; + else if (pb <= pc) + p = b; + else + p = c; + */ + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *rp = (png_byte)(((int)(*rp) + p) & 0xff); + rp++; + } + } //end !UseMMX + break; + + default: + png_error(png_ptr, "Bad adaptive filter type"); + break; + } +} + +#endif /* PNG_HAVE_ASSEMBLER_READ_FILTER_ROW */ + + +// GRR NOTES: (1) the following code assumes 386 or better (pushfl/popfl) +// (2) all instructions compile with gcc 2.7.2.3 and later +// (3) the function is moved down here to prevent gcc from +// inlining it in multiple places and then barfing be- +// cause the ".NOT_SUPPORTED" label is multiply defined +// [is there a way to signal that a *single* function should +// not be inlined? is there a way to modify the label for +// each inlined instance, e.g., by appending _1, _2, etc.? +// maybe if don't use leading "." in label name? (not tested)] + +#ifdef ORIG_THAT_USED_TO_CLOBBER_EBX + +int mmxsupport(void) +{ + int mmx_supported_local = 0; + + __asm__ ( +// ".byte 0x66 \n\t" // convert 16-bit pushf to 32-bit pushfd +// "pushf \n\t" // save Eflag to stack + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack into eax + "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx + "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) + "pushl %%eax \n\t" // save modified Eflag back to stack +// ".byte 0x66 \n\t" // convert 16-bit popf to 32-bit popfd +// "popf \n\t" // restore modified value to Eflag reg + "popfl \n\t" // restore modified value to Eflag reg + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack + "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag + "jz .NOT_SUPPORTED \n\t" // if same, CPUID instr. is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero +// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) + "cpuid \n\t" // get the CPU identification info + "cmpl $1, %%eax \n\t" // make sure eax return non-zero value + "jl .NOT_SUPPORTED \n\t" // if eax is zero, MMX is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero and... + "incl %%eax \n\t" // ...increment eax to 1. This pair is + // faster than the instruction "mov eax, 1" + "cpuid \n\t" // get the CPU identification info again + "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) + "cmpl $0, %%edx \n\t" // 0 = MMX not supported + "jz .NOT_SUPPORTED \n\t" // non-zero = yes, MMX IS supported + + "movl $1, %0 \n\t" // set return value to 1 and fall through + + ".NOT_SUPPORTED: \n\t" // target label for jump instructions + "movl %0, %%eax \n\t" // move return value to eax + // DONE + + : "=m" (mmx_supported_local) // %0 (output list: memory only) + + : // any variables used on input (none) + + : "%eax", "%ebx", // clobber list + "%ecx", "%edx" +// , "memory" // if write to a variable gcc thought was in a reg +// , "cc" // "condition codes" (flag bits) + ); + + //mmx_supported_local=0; // test code for force don't support MMX + //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local); + + return mmx_supported_local; +} + +#else /* !ORIG_THAT_USED_TO_CLOBBER_EBX */ + +int mmxsupport(void) +{ + __asm__ ( + "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction + "pushl %%ecx \n\t" // so does ecx... + "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux) +// ".byte 0x66 \n\t" // convert 16-bit pushf to 32-bit pushfd +// "pushf \n\t" // save Eflag to stack + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack into eax + "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx + "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21) + "pushl %%eax \n\t" // save modified Eflag back to stack +// ".byte 0x66 \n\t" // convert 16-bit popf to 32-bit popfd +// "popf \n\t" // restore modified value to Eflag reg + "popfl \n\t" // restore modified value to Eflag reg + "pushfl \n\t" // save Eflag to stack + "popl %%eax \n\t" // get Eflag from stack + "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag + "jz .NOT_SUPPORTED \n\t" // if same, CPUID instr. is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero +// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode) + "cpuid \n\t" // get the CPU identification info + "cmpl $1, %%eax \n\t" // make sure eax return non-zero value + "jl .NOT_SUPPORTED \n\t" // if eax is zero, MMX is not supported + + "xorl %%eax, %%eax \n\t" // set eax to zero and... + "incl %%eax \n\t" // ...increment eax to 1. This pair is + // faster than the instruction "mov eax, 1" + "cpuid \n\t" // get the CPU identification info again + "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23) + "cmpl $0, %%edx \n\t" // 0 = MMX not supported + "jz .NOT_SUPPORTED \n\t" // non-zero = yes, MMX IS supported + + "movl $1, %%eax \n\t" // set return value to 1 + "popl %%edx \n\t" // restore edx + "popl %%ecx \n\t" // restore ecx + "popl %%ebx \n\t" // restore ebx ("row" in png_do_interlace) + "ret \n\t" // DONE: have MMX support + + ".NOT_SUPPORTED: \n\t" // target label for jump instructions + "movl $0, %%eax \n\t" // set return value to 0 + "popl %%edx \n\t" // restore edx + "popl %%ecx \n\t" // restore ecx + "popl %%ebx \n\t" // restore ebx ("row" in png_do_interlace) +// "ret \n\t" // DONE: no MMX support + // (fall through to standard C "ret") + + : // "=m" (mmx_supported_local) // %0 (output list: memory only) + + : // any variables used on input (none) + + : "%eax" // clobber list +// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually +// , "memory" // if write to a variable gcc thought was in a reg +// , "cc" // "condition codes" (flag bits) + ); + + //mmx_supported_local=0; // test code for force don't support MMX + //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local); + + //return mmx_supported_local; +} + +#endif /* ?ORIG_THAT_USED_TO_CLOBBER_EBX */ + +#endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGGCCRD */ + + @@ -1,7 +1,7 @@ /* pngget.c - retrieval of values from info struct * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -150,6 +150,7 @@ png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) return (0); } +#ifdef PNG_FLOATING_POINT_SUPPORTED float png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) { @@ -167,6 +168,7 @@ png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr) #endif return ((float)0.0); } +#endif png_uint_32 png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) @@ -232,7 +234,7 @@ png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) return (0); } -#ifdef PNG_INCH_CONVERSIONS +#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED) png_uint_32 png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr) { @@ -302,7 +304,7 @@ png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr, return (retval); } #endif /* PNG_READ_pHYs_SUPPORTED */ -#endif /* PNG_INCH_CONVERSIONS */ +#endif /* PNG_INCH_CONVERSIONS $$ PNG_FLOATING_POINT_SUPPORTED */ /* png_get_channels really belongs in here, too, but it's been around longer */ @@ -343,6 +345,7 @@ png_get_bKGD(png_structp png_ptr, png_infop info_ptr, #endif #if defined(PNG_READ_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 png_get_cHRM(png_structp png_ptr, png_infop info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, @@ -372,8 +375,41 @@ png_get_cHRM(png_structp png_ptr, png_infop info_ptr, return (0); } #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 +png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) + { + png_debug1(1, "in %s retrieval function\n", "cHRM"); + if (white_x != NULL) + *white_x = info_ptr->int_x_white; + if (white_y != NULL) + *white_y = info_ptr->int_y_white; + if (red_x != NULL) + *red_x = info_ptr->int_x_red; + if (red_y != NULL) + *red_y = info_ptr->int_y_red; + if (green_x != NULL) + *green_x = info_ptr->int_x_green; + if (green_y != NULL) + *green_y = info_ptr->int_y_green; + if (blue_x != NULL) + *blue_x = info_ptr->int_x_blue; + if (blue_y != NULL) + *blue_y = info_ptr->int_y_blue; + return (PNG_INFO_cHRM); + } + return (0); +} +#endif +#endif #if defined(PNG_READ_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) { @@ -387,6 +423,22 @@ png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma) return (0); } #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 +png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point *int_file_gamma) +{ + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) + && int_file_gamma != NULL) + { + png_debug1(1, "in %s retrieval function\n", "gAMA"); + *int_file_gamma = info_ptr->int_gamma; + return (PNG_INFO_gAMA); + } + return (0); +} +#endif +#endif #if defined(PNG_READ_sRGB_SUPPORTED) png_uint_32 @@ -425,9 +477,9 @@ png_get_iCCP(png_structp png_ptr, png_infop info_ptr, } #endif -#if defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_zTXt_SUPPORTED) +#if defined(PNG_READ_sPLT_SUPPORTED) png_uint_32 -png_get_spalettes(png_structp png_ptr, png_infop info_ptr, +png_get_spalettes(png_structp png_ptr, png_infop info_ptr, png_spalette_pp spalettes) { if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) @@ -540,9 +592,10 @@ png_get_pCAL(png_structp png_ptr, png_infop info_ptr, #endif #if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 png_get_sCAL(png_structp png_ptr, png_infop info_ptr, - png_charpp unit, double *width, double *height) + int *unit, double *width, double *height) { if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_sCAL) { @@ -553,6 +606,23 @@ png_get_sCAL(png_structp png_ptr, png_infop info_ptr, } return(0); } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +png_uint_32 +png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int *unit, png_charpp width, png_charpp height) +{ + if (png_ptr != NULL && info_ptr != NULL && info_ptr->valid & PNG_INFO_sCAL) + { + *unit = info_ptr->scal_unit; + *width = info_ptr->scal_s_width; + *height = info_ptr->scal_s_height; + return (PNG_INFO_sCAL); + } + return(0); +} +#endif +#endif #endif #if defined(PNG_READ_pHYs_SUPPORTED) @@ -690,6 +760,17 @@ png_get_tRNS(png_structp png_ptr, png_infop info_ptr, } #endif +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) +png_uint_32 +png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr, + png_unknown_chunkpp unknowns) +{ + if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) + *unknowns = info_ptr->unknown_chunks; + return ((png_uint_32)info_ptr->unknown_chunks_num); +} +#endif + #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) png_byte png_get_rgb_to_gray_status (png_structp png_ptr) @@ -1,7 +1,7 @@ /* pngmem.c - stub functions for memory allocation * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger diff --git a/pngpread.c b/pngpread.c index 691936c39..cd1c82c3f 100644 --- a/pngpread.c +++ b/pngpread.c @@ -1,7 +1,7 @@ /* pngpread.c - read a png file in push mode * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -151,6 +151,12 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_hIST_SUPPORTED) PNG_hIST; #endif +#if defined(PNG_READ_iCCP_SUPPORTED) + PNG_iCCP; +#endif +#if defined(PNG_READ_iTXt_SUPPORTED) + PNG_iTXt; +#endif #if defined(PNG_READ_oFFs_SUPPORTED) PNG_oFFs; #endif @@ -163,9 +169,15 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_sBIT_SUPPORTED) PNG_sBIT; #endif +#if defined(PNG_READ_sCAL_SUPPORTED) + PNG_sCAL; +#endif #if defined(PNG_READ_sRGB_SUPPORTED) PNG_sRGB; #endif +#if defined(PNG_READ_sPLT_SUPPORTED) + PNG_sPLT; +#endif #if defined(PNG_READ_tEXt_SUPPORTED) PNG_tEXt; #endif @@ -305,6 +317,30 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif +#if defined(PNG_READ_iCCP_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } +#endif +#if defined(PNG_READ_sPLT_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } +#endif #if defined(PNG_READ_tRNS_SUPPORTED) else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4)) { @@ -377,6 +413,18 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif +#if defined(PNG_READ_sCAL_SUPPORTED) + else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4)) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } +#endif #if defined(PNG_READ_tIME_SUPPORTED) else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4)) { @@ -402,7 +450,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr) } #endif #if defined(PNG_READ_iTXt_SUPPORTED) - else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4)) + else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4)) { png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } @@ -841,30 +889,30 @@ png_read_push_finish_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ const int png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ const int png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ const int png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ const int png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; - + /* Width of interlace block. This is not currently used - if you need * it, uncomment it here and in png.h const int png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */ - + /* Height of interlace block. This is not currently used - if you need * it, uncomment it here and in png.h const int png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; */ #endif - + png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; @@ -978,6 +1026,7 @@ png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr) text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; text_ptr->lang = (char *)NULL; text_ptr->key = key; + text_ptr->lang_key = (char *)NULL; text_ptr->text = text; png_set_text(png_ptr, info_ptr, text_ptr, 1); @@ -1156,8 +1205,9 @@ png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr) text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt; - text_ptr->lang = (char *)NULL; text_ptr->key = key; + text_ptr->lang = (char *)NULL; + text_ptr->lang_key = (char *)NULL; text_ptr->text = text; png_set_text(png_ptr, info_ptr, text_ptr, 1); @@ -1201,6 +1251,7 @@ png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length void png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) { + if (png_ptr->buffer_size && png_ptr->current_text_left) { png_size_t text_size; @@ -1216,9 +1267,11 @@ png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) if (!(png_ptr->current_text_left)) { png_textp text_ptr; - png_charp text; - png_charp lang; png_charp key; + int comp_flag = 0; + png_charp lang; + png_charp lang_key; + png_charp text; if (png_ptr->buffer_size < 4) { @@ -1233,26 +1286,36 @@ png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr) return; #endif - lang = png_ptr->current_text; + key = png_ptr->current_text; png_ptr->current_text = 0; - for (key = lang; *key; key++) + for (lang = key; *lang; lang++) /* empty loop */ ; - if (key != lang + png_ptr->current_text_size) - key++; + if (lang != key + png_ptr->current_text_size) + lang++; - for (text = key; *text; text++) + comp_flag = *lang++; + lang++; /* skip comp_type, always zero */ + + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) /* empty loop */ ; if (text != key + png_ptr->current_text_size) text++; text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->lang = lang; + text_ptr->compression = comp_flag + 2; text_ptr->key = key; + text_ptr->lang = lang; + text_ptr->lang_key = lang_key; text_ptr->text = text; + text_ptr->text_length = 0; + text_ptr->itxt_length = png_strlen(text); png_set_text(png_ptr, info_ptr, text_ptr, 1); @@ -1280,6 +1343,30 @@ png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 len if(info_ptr == NULL) return; } +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; + +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, chunk.data, length); + chunk.size = length; + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + png_push_crc_skip(png_ptr, length); } @@ -1,7 +1,7 @@ /* pngread.c - read a PNG file * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -214,7 +214,7 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_sBIT_SUPPORTED) PNG_sBIT; #endif -#if defined(PNG_READ_pCAL_SUPPORTED) +#if defined(PNG_READ_sCAL_SUPPORTED) PNG_sCAL; #endif #if defined(PNG_READ_sPLT_SUPPORTED) @@ -607,7 +607,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) * not called png_set_interlace_handling(), the display_row buffer will * be ignored, so pass NULL to it. * - * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.5f. + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.5j. */ void @@ -656,7 +656,7 @@ png_read_rows(png_structp png_ptr, png_bytepp row, * only call this function once. If you desire to have an image for * each pass of a interlaced image, use png_read_rows() instead. * - * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.5f. + * [*] png_handle_alpha() does not exist yet, as of libpng version 1.0.5j. */ void png_read_image(png_structp png_ptr, png_bytepp image) @@ -743,7 +743,7 @@ png_read_end(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_sBIT_SUPPORTED) PNG_sBIT; #endif -#if defined(PNG_READ_pCAL_SUPPORTED) +#if defined(PNG_READ_sCAL_SUPPORTED) PNG_sCAL; #endif #if defined(PNG_READ_sPLT_SUPPORTED) @@ -1,7 +1,7 @@ /* pngrio.c - functions for data input * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger diff --git a/pngrtran.c b/pngrtran.c index 9215bfac7..33367c3a4 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -1,7 +1,7 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -69,7 +69,8 @@ png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action) } } -#if defined(PNG_READ_BACKGROUND_SUPPORTED) +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) /* handle alpha and tRNS via a background color */ void png_set_background(png_structp png_ptr, @@ -504,7 +505,7 @@ png_set_dither(png_structp png_ptr, png_colorp palette, } #endif -#if defined(PNG_READ_GAMMA_SUPPORTED) +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) /* Transform the image from the file_gamma to the screen_gamma. We * only do transformations on images where the file_gamma and screen_gamma * are not close reciprocals, otherwise it slows things down slightly, and @@ -581,7 +582,8 @@ png_set_gray_to_rgb(png_structp png_ptr) } #endif -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) +#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) && \ + defined(PNG_FLOATING_POINT_SUPPORTED) /* Convert a RGB image to a grayscale of the same width. This allows us, * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. */ @@ -718,7 +720,7 @@ png_init_read_transformations(png_structp png_ptr) #if defined(PNG_READ_BACKGROUND_SUPPORTED) png_ptr->background_1 = png_ptr->background; #endif -#if defined(PNG_READ_GAMMA_SUPPORTED) +#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) if (png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) { png_build_gamma_table(png_ptr); @@ -731,7 +733,6 @@ png_init_read_transformations(png_structp png_ptr) png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; - if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) { back.red = png_ptr->gamma_table[png_ptr->background.red]; @@ -789,7 +790,6 @@ png_init_read_transformations(png_structp png_ptr) back_1.blue = (png_byte)(pow( (double)png_ptr->background.blue/255, g) * 255.0 + .5); } - for (i = 0; i < num_palette; i++) { if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff) @@ -998,8 +998,15 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_READ_GAMMA_SUPPORTED) if (png_ptr->transformations & PNG_GAMMA) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED info_ptr->gamma = png_ptr->gamma; #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = png_ptr->int_gamma; +#endif + } +#endif #if defined(PNG_READ_16_TO_8_SUPPORTED) if ((png_ptr->transformations & PNG_16_TO_8) && info_ptr->bit_depth == 16) @@ -1290,7 +1297,7 @@ From Andreas Dilger e-mail to png-implement, 26 March 1998: png_ptr->row_info.channels = png_ptr->user_transform_channels; png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * png_ptr->row_info.channels); - png_ptr->row_info.rowbytes = (png_ptr->row_info.width * + png_ptr->row_info.rowbytes = (png_ptr->row_info.width * png_ptr->row_info.pixel_depth+7)>>3; } #endif @@ -1988,7 +1995,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) #endif #if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -/* reduce RGB files to grayscale, with or without alpha +/* reduce RGB files to grayscale, with or without alpha * using the equation given in Poynton's ColorFAQ at * <http://www.inforamp.net/~poynton/> * Copyright (c) 1998-01-04 Charles Poynton poynton@inforamp.net @@ -1996,7 +2003,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * * We approximate this with - * + * * Y = 0.211 * R + 0.715 * G + 0.074 * B * * which can be expressed with integers as @@ -2072,7 +2079,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) } } } - + else /* RGB bit_depth == 16 */ { #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) @@ -2097,7 +2104,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + bc*blue_1)>>8); @@ -2105,7 +2112,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } - + *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); } @@ -2194,7 +2201,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >> png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc * red_1 + gc * green_1 + bc * blue_1)>>8); @@ -2202,7 +2209,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } - + *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); *(dp++) = *(sp++); /* alpha */ @@ -2298,7 +2305,8 @@ png_correct_palette(png_structp png_ptr, png_colorp palette, int num_palette) { png_debug(1, "in png_correct_palette\n"); -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED) if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND)) { png_color back, back_1; @@ -3764,6 +3772,7 @@ png_do_dither(png_row_infop row_info, png_bytep row, } #endif +#ifdef PNG_FLOATING_POINT_SUPPORTED #if defined(PNG_READ_GAMMA_SUPPORTED) static int png_gamma_shift[] = {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0}; @@ -3814,7 +3823,7 @@ png_build_gamma_table(png_structp png_ptr) g) * 255.0 + .5); } - + png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr, (png_uint_32)256); @@ -3983,4 +3992,6 @@ png_build_gamma_table(png_structp png_ptr) } } #endif +/* To do: install integer version of png_build_gamma_table here */ +#endif diff --git a/pngrutil.c b/pngrutil.c index 4669b4ef8..94db0afe9 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -145,7 +145,7 @@ png_crc_error(png_structp png_ptr) * holding the original prefix part and an uncompressed version of the * trailing part (the malloc area passed in is freed). */ -png_charp png_decompress_chunk(png_structp png_ptr, int comp_type, +png_charp png_decompress_chunk(png_structp png_ptr, int comp_type, png_charp chunkdata, png_size_t chunklength, png_size_t prefix_size) { @@ -196,7 +196,7 @@ png_charp png_decompress_chunk(png_structp png_ptr, int comp_type, { if (text == NULL) { - text_size = prefix_size + + text_size = prefix_size + png_ptr->zbuf_size - png_ptr->zstream.avail_out; text = (png_charp)png_malloc(png_ptr, text_size + 1); png_memcpy(text + prefix_size, png_ptr->zbuf, @@ -236,7 +236,6 @@ png_charp png_decompress_chunk(png_structp png_ptr, int comp_type, } else /* if (comp_type >= PNG_TEXT_COMPRESSION_LAST) */ { - png_size_t text_size; #if !defined(PNG_NO_STDIO) char umsg[50]; @@ -496,8 +495,10 @@ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_uint_32 igamma; + png_fixed_point igamma; +#ifdef PNG_FLOATING_POINT_SUPPORTED float file_gamma; +#endif png_byte buf[4]; png_debug(1, "in png_handle_gAMA\n"); @@ -536,14 +537,14 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) if (png_crc_finish(png_ptr, 0)) return; - igamma = png_get_uint_32(buf); + igamma = (png_fixed_point)png_get_uint_32(buf); /* check for zero gamma */ if (igamma == 0) return; #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) - if(fabs((float)igamma - 45455.)>500.) + if(igamma < 45000L || igamma > 46000L) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); @@ -554,11 +555,16 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_FLOATING_POINT_SUPPORTED file_gamma = (float)igamma / (float)100000.0; #ifdef PNG_READ_GAMMA_SUPPORTED png_ptr->gamma = file_gamma; #endif png_set_gAMA(png_ptr, info_ptr, file_gamma); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_gAMA_fixed(png_ptr, info_ptr, igamma); +#endif } #endif @@ -633,8 +639,11 @@ void png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_byte buf[4]; - png_uint_32 val; +#ifdef PNG_FLOATING_POINT_SUPPORTED float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; +#endif + png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue; png_debug(1, "in png_handle_cHRM\n"); @@ -669,15 +678,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - white_x = (float)val / (float)100000.0; + int_x_white = (png_fixed_point)png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - white_y = (float)val / (float)100000.0; + int_y_white = (png_fixed_point)png_get_uint_32(buf); - if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || - white_x + white_y > 1.0) + if (int_x_white > 80000L || int_y_white > 80000L || + int_x_white + int_y_white > 100000L) { png_warning(png_ptr, "Invalid cHRM white point"); png_crc_finish(png_ptr, 24); @@ -685,15 +692,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - red_x = (float)val / (float)100000.0; + int_x_red = (png_fixed_point)png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - red_y = (float)val / (float)100000.0; + int_y_red = (png_fixed_point)png_get_uint_32(buf); - if (red_x < 0 || red_x > 0.8 || red_y < 0 || red_y > 0.8 || - red_x + red_y > 1.0) + if (int_x_red > 80000L || int_y_red > 80000L || + int_x_red + int_y_red > 100000L) { png_warning(png_ptr, "Invalid cHRM red point"); png_crc_finish(png_ptr, 16); @@ -701,15 +706,13 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - green_x = (float)val / (float)100000.0; + int_x_green = (png_fixed_point)png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - green_y = (float)val / (float)100000.0; + int_y_green = (png_fixed_point)png_get_uint_32(buf); - if (green_x < 0 || green_x > 0.8 || green_y < 0 || green_y > 0.8 || - green_x + green_y > 1.0) + if (int_x_green > 80000L || int_y_green > 80000L || + int_x_green + int_y_green > 100000L) { png_warning(png_ptr, "Invalid cHRM green point"); png_crc_finish(png_ptr, 8); @@ -717,52 +720,74 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - blue_x = (float)val / (float)100000.0; + int_x_blue = (png_fixed_point)png_get_uint_32(buf); png_crc_read(png_ptr, buf, 4); - val = png_get_uint_32(buf); - blue_y = (float)val / (float)100000.0; + int_y_blue = (png_fixed_point)png_get_uint_32(buf); - if (blue_x < (float)0 || blue_x > (float)0.8 || blue_y < (float)0 || - blue_y > (float)0.8 || blue_x + blue_y > (float)1.0) + if (int_x_blue > 80000L || int_y_blue > 80000L || + int_x_blue + int_y_blue > 100000L) { png_warning(png_ptr, "Invalid cHRM blue point"); png_crc_finish(png_ptr, 0); return; } - - if (png_crc_finish(png_ptr, 0)) - return; +#ifdef PNG_FLOATING_POINT_SUPPORTED + white_x = (float)int_x_white / (float)100000.0; + white_y = (float)int_y_white / (float)100000.0; + red_x = (float)int_x_red / (float)100000.0; + red_y = (float)int_y_red / (float)100000.0; + green_x = (float)int_x_green / (float)100000.0; + green_y = (float)int_y_green / (float)100000.0; + blue_x = (float)int_x_blue / (float)100000.0; + blue_y = (float)int_y_blue / (float)100000.0; +#endif #if defined(PNG_READ_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) { - if (fabs(white_x - (float).3127) > (float).001 || - fabs(white_y - (float).3290) > (float).001 || - fabs( red_x - (float).6400) > (float).001 || - fabs( red_y - (float).3300) > (float).001 || - fabs(green_x - (float).3000) > (float).001 || - fabs(green_y - (float).6000) > (float).001 || - fabs( blue_x - (float).1500) > (float).001 || - fabs( blue_y - (float).0600) > (float).001) + if (abs(int_x_white - 31270L) > 1000 || + abs(int_y_white - 32900L) > 1000 || + abs( int_x_red - 64000L) > 1000 || + abs( int_y_red - 33000L) > 1000 || + abs(int_x_green - 30000L) > 1000 || + abs(int_y_green - 60000L) > 1000 || + abs( int_x_blue - 15000L) > 1000 || + abs( int_y_blue - 6000L) > 1000) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); #ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n", white_x, white_y, red_x, red_y); fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n", green_x, green_y, blue_x, blue_y); +#else + fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n", + int_x_white, int_y_white, int_x_red, int_y_red); + fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n", + int_x_green, int_y_green, int_x_blue, int_y_blue); #endif +#endif /* PNG_NO_CONSOLE_IO */ } + png_crc_finish(png_ptr, 0); return; } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_FLOATING_POINT_SUPPORTED png_set_cHRM(png_ptr, info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_cHRM_fixed(png_ptr, info_ptr, + int_x_white, int_y_white, int_x_red, int_y_red, int_x_green, + int_y_green, int_x_blue, int_y_blue); +#endif + if (png_crc_finish(png_ptr, 0)) + return; } #endif @@ -771,6 +796,9 @@ void png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { int intent; +#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) + int igamma; +#endif png_byte buf[1]; png_debug(1, "in png_handle_sRGB\n"); @@ -814,27 +842,38 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) } #if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED + igamma=png_ptr->gamma * 100000.; +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + igamma=(int)png_ptr->int_gamma; +# endif +#endif if ((info_ptr->valid & PNG_INFO_gAMA)) - if(fabs((png_ptr->gamma*(float)100000.+.5)-45455.) > 500.) + if(igamma < 45000L || igamma > 46000L) { png_warning(png_ptr, "Ignoring incorrect gAMA value when sRGB is also present"); #ifndef PNG_NO_CONSOLE_IO +#ifdef PNG_FLOATING_POINT_SUPPORTED fprintf(stderr,"gamma=%f\n",png_ptr->gamma); +#else + fprintf(stderr,"gamma=(%lu/100000)\n",png_ptr->int_gamma); +#endif #endif } #endif /* PNG_READ_gAMA_SUPPORTED */ #ifdef PNG_READ_cHRM_SUPPORTED if (info_ptr->valid & PNG_INFO_cHRM) - if (fabs(info_ptr->x_white - (float).3127) > (float).001 || - fabs(info_ptr->y_white - (float).3290) > (float).001 || - fabs( info_ptr->x_red - (float).6400) > (float).001 || - fabs( info_ptr->y_red - (float).3300) > (float).001 || - fabs(info_ptr->x_green - (float).3000) > (float).001 || - fabs(info_ptr->y_green - (float).6000) > (float).001 || - fabs( info_ptr->x_blue - (float).1500) > (float).001 || - fabs( info_ptr->y_blue - (float).0600) > (float).001) + if (abs(info_ptr->int_x_white - 31270L) > 1000 || + abs(info_ptr->int_y_white - 32900L) > 1000 || + abs( info_ptr->int_x_red - 64000L) > 1000 || + abs( info_ptr->int_y_red - 33000L) > 1000 || + abs(info_ptr->int_x_green - 30000L) > 1000 || + abs(info_ptr->int_y_green - 60000L) > 1000 || + abs( info_ptr->int_x_blue - 15000L) > 1000 || + abs( info_ptr->int_y_blue - 6000L) > 1000) { png_warning(png_ptr, "Ignoring incorrect cHRM value when sRGB is also present"); @@ -851,7 +890,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { png_charp chunkdata; - png_byte compression_type; + png_byte compression_type; png_charp profile; png_uint_32 skip = 0; png_size_t slength, prefix_length; @@ -1480,8 +1519,15 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) void png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { - png_charp unit, ep, vp; - double width, height; + png_charp buffer, ep; +#ifdef PNG_FLOATING_POINT_SUPPORTED + double width=0., height=0.; + png_charp vp; +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_charp swidth, sheight; +#endif +#endif png_size_t slength; png_debug(1, "in png_handle_sCAL\n"); @@ -1503,46 +1549,75 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug1(2, "Allocating and reading sCAL chunk data (%d bytes)\n", length + 1); - unit = (png_charp)png_malloc(png_ptr, length + 1); + buffer = (png_charp)png_malloc(png_ptr, length + 1); slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)unit, slength); + png_crc_read(png_ptr, (png_bytep)buffer, slength); if (png_crc_finish(png_ptr, 0)) { - png_free(png_ptr, unit); + png_free(png_ptr, buffer); return; } - unit[slength] = 0x00; /* null terminate the last string */ + buffer[slength] = 0x00; /* null terminate the last string */ - png_debug(3, "Finding end of sCAL unit string\n"); - for (ep = unit; *ep; ep++) - /* empty loop */ ; - ep++; + ep = buffer + 1; /* skip unit byte */ +#ifdef PNG_FLOATING_POINT_SUPPORTED width = strtod(ep, &vp); if (*vp) png_error(png_ptr, "malformed width string in sCAL chunk"); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + swidth = (png_charp)png_malloc(png_ptr, strlen(ep) + 1); + png_memcpy(swidth, ep, (png_size_t)strlen(ep)); +#endif +#endif - for (ep = unit; *ep; ep++) + for (ep = buffer; *ep; ep++) /* empty loop */ ; ep++; +#ifdef PNG_FLOATING_POINT_SUPPORTED height = strtod(ep, &vp); if (*vp) png_error(png_ptr, "malformed height string in sCAL chunk"); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + sheight = (png_charp)png_malloc(png_ptr, strlen(ep) + 1); + png_memcpy(sheight, ep, (png_size_t)strlen(ep)); +#endif +#endif - if (unit + slength < ep || width <= 0. || height <= 0.) + if (buffer + slength < ep +#ifdef PNG_FLOATING_POINT_SUPPORTED + || width <= 0. || height <= 0. +#endif + ) { png_warning(png_ptr, "Invalid sCAL data"); - png_free(png_ptr, unit); + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED)&& !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif return; } - png_set_sCAL(png_ptr, info_ptr, unit, width, height); +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight); +#endif +#endif - png_free(png_ptr, unit); + png_free(png_ptr, buffer); +#if defined(PNG_FIXED_POINT_SUPPORTED)&& !defined(PNG_FLOATING_POINT_SUPPORTED) + png_free(png_ptr, swidth); + png_free(png_ptr, sheight); +#endif } #endif @@ -1637,9 +1712,12 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->lang = NULL; text_ptr->key = key; + text_ptr->lang = NULL; + text_ptr->lang_key = NULL; text_ptr->text = text; + text_ptr->text_length = png_strlen(text); + text_ptr->itxt_length = 0; png_set_text(png_ptr, info_ptr, text_ptr, 1); @@ -1700,7 +1778,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) else { comp_type = *(++text); - text++; /* skip the compression byte */ + text++; /* skip the compression_method byte */ } prefix_len = text - chunkdata; @@ -1711,7 +1789,10 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) text_ptr->compression = comp_type; text_ptr->lang = NULL; text_ptr->key = chunkdata; + text_ptr->lang_key = NULL; text_ptr->text = chunkdata + prefix_len; + text_ptr->text_length = png_strlen(text); + text_ptr->itxt_length = 0; png_set_text(png_ptr, info_ptr, text_ptr, 1); @@ -1727,9 +1808,9 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_textp text_ptr; png_charp chunkdata; - png_charp lang, text; - int comp_type = PNG_TEXT_COMPRESSION_NONE; - int comp_flag = 0; + png_charp key, lang, text, lang_key; + int comp_flag = PNG_TEXT_COMPRESSION_NONE; + int comp_type = 0; png_size_t slength, prefix_len; png_debug(1, "in png_handle_iTXt\n"); @@ -1766,10 +1847,13 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* empty loop */ ; lang++; /* skip NUL separator */ - /* iTXt must have a language tag and some text after the keyword */ + /* iTXt must have a language tag (possibly empty), two compression bytes, + translated keyword (possibly empty), and possibly some text after the + keyword */ + if (lang >= chunkdata + slength) { - comp_type = PNG_TEXT_COMPRESSION_NONE; + comp_flag = PNG_TEXT_COMPRESSION_NONE; png_warning(png_ptr, "Zero length iTXt chunk"); } else @@ -1778,25 +1862,31 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) comp_type = *lang++; } - for (text = lang; *text; text++) + for (lang_key = lang; *lang_key; lang_key++) + /* empty loop */ ; + lang_key++; /* skip NUL separator */ + + for (text = lang_key; *text; text++) /* empty loop */ ; text++; /* skip NUL separator */ prefix_len = text - chunkdata; + key=chunkdata; if (comp_flag) chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata, - (size_t)length, prefix_len); - + (size_t)length, prefix_len); text_ptr = (png_textp)png_malloc(png_ptr, (png_uint_32)sizeof(png_text)); - text_ptr->compression = (png_byte)comp_type; - text_ptr->lang = NULL; + text_ptr->compression = (int)comp_flag + 1; + text_ptr->lang_key = chunkdata+(lang_key-key); + text_ptr->lang = chunkdata+(lang-key); text_ptr->key = chunkdata; text_ptr->text = chunkdata + prefix_len; + text_ptr->text_length = 0; + text_ptr->itxt_length = png_strlen(text_ptr->text); png_set_text(png_ptr, info_ptr, text_ptr, 1); - png_free(png_ptr, text_ptr->key); png_free(png_ptr, text_ptr); png_free(png_ptr, chunkdata); } @@ -1804,12 +1894,19 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* This function is called when we haven't found a handler for a chunk. If there isn't a problem with the chunk itself (ie bad - chunk name, CRC, or a critical chunk), the chunk is silently ignored. */ + chunk name, CRC, or a critical chunk), the chunk is silently ignored + -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which + case it will be saved away to be written out later. */ void png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { + png_uint_32 skip = 0; + png_debug(1, "in png_handle_unknown\n"); + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + /* In the future we can have code here that calls user-supplied * callback functions for unknown chunks before they are ignored or * cause an error. @@ -1825,11 +1922,33 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - if (png_ptr->mode & PNG_HAVE_IDAT) - png_ptr->mode |= PNG_AFTER_IDAT; +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) + { + png_unknown_chunk chunk; - png_crc_finish(png_ptr, length); +#ifdef PNG_MAX_MALLOC_64K + if (length > (png_uint_32)65535L) + { + png_warning(png_ptr, "unknown chunk too large to fit in memory"); + skip = length - (png_uint_32)65535L; + length = (png_uint_32)65535L; + } +#endif + + strcpy((png_charp)chunk.name, (png_charp)png_ptr->chunk_name); + chunk.data = (png_bytep)png_malloc(png_ptr, length); + png_crc_read(png_ptr, chunk.data, length); + chunk.size = length; + png_set_unknown_chunks(png_ptr, info_ptr, &chunk, 1); + png_free(png_ptr, chunk.data); + } + else +#endif + skip = length; + + png_crc_finish(png_ptr, skip); } /* This function is called to verify that a chunk name is valid. @@ -2080,11 +2199,11 @@ png_do_read_interlace { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; #endif - + png_debug(1,"in png_do_read_interlace\n"); if (row != NULL && row_info != NULL) { @@ -2425,20 +2544,20 @@ png_read_finish_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + png_debug(1, "in png_read_finish_row\n"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) @@ -2547,20 +2666,20 @@ png_read_start_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ const int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ const int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ const int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ const int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + int max_pixel_depth; png_uint_32 row_bytes; @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -30,6 +30,7 @@ png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background) #endif #if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED void png_set_cHRM(png_structp png_ptr, png_infop info_ptr, double white_x, double white_y, double red_x, double red_y, @@ -47,11 +48,55 @@ png_set_cHRM(png_structp png_ptr, png_infop info_ptr, info_ptr->y_green = (float)green_y; info_ptr->x_blue = (float)blue_x; info_ptr->y_blue = (float)blue_y; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5); + info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5); + info_ptr->int_x_red = (png_fixed_point)(red_x*100000.+0.5); + info_ptr->int_y_red = (png_fixed_point)(red_y*100000.+0.5); + info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5); + info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5); + info_ptr->int_x_blue = (png_fixed_point)(blue_x*100000.+0.5); + info_ptr->int_y_blue = (png_fixed_point)(blue_y*100000.+0.5); +#endif + info_ptr->valid |= PNG_INFO_cHRM; +} +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void +png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, + png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, + png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, + png_fixed_point blue_x, png_fixed_point blue_y) +{ + png_debug1(1, "in %s storage function\n", "cHRM"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->int_x_white = white_x; + info_ptr->int_y_white = white_y; + info_ptr->int_x_red = red_x; + info_ptr->int_y_red = red_y; + info_ptr->int_x_green = green_x; + info_ptr->int_y_green = green_y; + info_ptr->int_x_blue = blue_x; + info_ptr->int_y_blue = blue_y; +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->x_white = (float)white_x/100000.; + info_ptr->y_white = (float)white_y/100000.; + info_ptr->x_red = (float)red_x/100000.; + info_ptr->y_red = (float)red_y/100000.; + info_ptr->x_green = (float)green_x/100000.; + info_ptr->y_green = (float)green_y/100000.; + info_ptr->x_blue = (float)blue_x/100000.; + info_ptr->y_blue = (float)blue_y/100000.; +#endif info_ptr->valid |= PNG_INFO_cHRM; } #endif +#endif #if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED void png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) { @@ -60,6 +105,26 @@ png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) return; info_ptr->gamma = (float)file_gamma; +#ifdef PNG_FIXED_POINT_SUPPORTED + info_ptr->int_gamma = (int)(file_gamma*100000.+.5); +#endif + info_ptr->valid |= PNG_INFO_gAMA; +} +#endif +#endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void +png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point + int_gamma) +{ + png_debug1(1, "in %s storage function\n", "gAMA"); + if (png_ptr == NULL || info_ptr == NULL) + return; + +#ifdef PNG_FLOATING_POINT_SUPPORTED + info_ptr->gamma = (float)int_gamma/100000.; +#endif + info_ptr->int_gamma = int_gamma; info_ptr->valid |= PNG_INFO_gAMA; } #endif @@ -72,7 +137,8 @@ png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist) if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->hist = hist; + info_ptr->hist = png_malloc(png_ptr, sizeof(png_uint_16) * info_ptr->num_palette); + memcpy(info_ptr->hist, hist, sizeof(png_uint_16) * info_ptr->num_palette); info_ptr->valid |= PNG_INFO_hIST; } #endif @@ -179,9 +245,26 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr, #endif #if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED void png_set_sCAL(png_structp png_ptr, png_infop info_ptr, - png_charp unit, double width, double height) + int unit, double width, double height) +{ + png_debug1(1, "in %s storage function\n", "sCAL"); + if (png_ptr == NULL || info_ptr == NULL) + return; + + info_ptr->scal_unit = (png_byte)unit; + info_ptr->scal_pixel_width = width; + info_ptr->scal_pixel_height = height; + + info_ptr->valid |= PNG_INFO_sCAL; +} +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void +png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, + int unit, png_charp swidth, png_charp sheight) { png_uint_32 length; @@ -189,16 +272,23 @@ png_set_sCAL(png_structp png_ptr, png_infop info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - length = png_strlen(unit) + 1; + info_ptr->scal_unit = (png_byte)unit; + + length = png_strlen(swidth) + 1; png_debug1(3, "allocating unit for info (%d bytes)\n", length); - info_ptr->scal_unit = (png_charp)png_malloc(png_ptr, length); - png_memcpy(info_ptr->scal_unit, unit, (png_size_t)length); - info_ptr->scal_pixel_width = width; - info_ptr->scal_pixel_height = height; + info_ptr->scal_s_width = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length); + + length = png_strlen(sheight) + 1; + png_debug1(3, "allocating unit for info (%d bytes)\n", length); + info_ptr->scal_s_width = (png_charp)png_malloc(png_ptr, length); + png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length); info_ptr->valid |= PNG_INFO_sCAL; } #endif +#endif +#endif #if defined(PNG_pHYs_SUPPORTED) void @@ -254,16 +344,28 @@ png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent) info_ptr->srgb_intent = (png_byte)intent; info_ptr->valid |= PNG_INFO_sRGB; } + void png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, int intent) { #if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED float file_gamma; #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_file_gamma; +#endif +#endif #if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, + int_green_y, int_blue_x, int_blue_y; +#endif +#endif png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM"); if (png_ptr == NULL || info_ptr == NULL) return; @@ -271,11 +373,32 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, png_set_sRGB(png_ptr, info_ptr, intent); #if defined(PNG_gAMA_SUPPORTED) +#ifdef PNG_FLOATING_POINT_SUPPORTED file_gamma = (float).45455; png_set_gAMA(png_ptr, info_ptr, file_gamma); #endif +#ifdef PNG_FIXED_POINT_SUPPORTED + int_file_gamma = 45455L; + png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma); +#endif +#endif #if defined(PNG_cHRM_SUPPORTED) +#ifdef PNG_FIXED_POINT_SUPPORTED + int_white_x = 31270L; + int_white_y = 32900L; + int_red_x = 64000L; + int_red_y = 33000L; + int_green_x = 30000L; + int_green_y = 60000L; + int_blue_x = 15000L; + int_blue_y = 6000L; + + png_set_cHRM_fixed(png_ptr, info_ptr, + int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y, + int_blue_x, int_blue_y); +#endif +#ifdef PNG_FLOATING_POINT_SUPPORTED white_x = (float).3127; white_y = (float).3290; red_x = (float).64; @@ -287,11 +410,12 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, png_set_cHRM(png_ptr, info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); - +#endif #endif } #endif + #if defined(PNG_iCCP_SUPPORTED) void png_set_iCCP(png_structp png_ptr, png_infop info_ptr, @@ -359,52 +483,87 @@ png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr, for (i = 0; i < num_text; i++) { + png_size_t text_length,key_len,lang_len,lang_key_len; png_textp textp = &(info_ptr->text[info_ptr->num_text]); - png_charp key,text; if (text_ptr[i].key == (png_charp)NULL) continue; -#ifdef PNG_iTXt_SUPPORTED - textp->lang = text_ptr[i].lang; -#else - textp->lang = NULL; -#endif + key_len = png_strlen(text_ptr[i].key); + + if(text_ptr[i].compression > 0) + { + /* set iTXt data */ + lang_len = png_strlen(text_ptr[i].lang); + lang_key_len = png_strlen(text_ptr[i].lang_key); + } + else + { + lang_len = 0; + lang_key_len = 0; + } if (text_ptr[i].text[0] == '\0') { - textp->text_length = 0; - textp->compression = PNG_TEXT_COMPRESSION_NONE; + text_length = 0; + if(text_ptr[i].compression > 0) + textp->compression = PNG_ITXT_COMPRESSION_NONE; + else + textp->compression = PNG_TEXT_COMPRESSION_NONE; } else { - textp->text_length = png_strlen(text_ptr[i].text); + text_length = png_strlen(text_ptr[i].text); textp->compression = text_ptr[i].compression; } - key=text_ptr[i].key; - for (text = key; *text++;) - /* empty loop to find the byte after the zero byte after the - end of key */ ; textp->key = (png_charp)png_malloc(png_ptr, - (png_uint_32)(text+textp->text_length - key)+1); + (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4)); /* Caution: the calling program, not libpng, is responsible for freeing this, if libpng wasn't the caller. */ png_debug2(2, "Allocated %d bytes at %x in png_set_text\n", - text+textp->text_length-key+1, textp->key); + key_len + lang_len + lang_key_len + text_length + 4, textp->key); png_memcpy(textp->key, text_ptr[i].key, - (png_size_t)(text - key)); /* includes the zero-byte separator */ + (png_size_t)(key_len)); + *(textp->key+key_len) = '\0'; + if (text_ptr[i].compression > 0) + { + textp->lang=textp->key + key_len + 1; + png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + *(textp->lang+lang_len) = '\0'; + textp->lang_key=textp->lang + lang_len + 1; + png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + *(textp->lang_key+lang_key_len) = '\0'; + textp->text=textp->lang_key + lang_key_len + 1; + } + else + { + textp->lang=NULL; + textp->lang_key=NULL; + textp->text=textp->key + key_len + 1; + } - textp->text = textp->key + (text-key); - if(textp->text_length) + if(text_length) { png_memcpy(textp->text, text_ptr[i].text, - (png_size_t)(textp->text_length)); - *(textp->text+textp->text_length) = '\0'; + (png_size_t)(text_length)); + *(textp->text+text_length) = '\0'; } else textp->text--; + + if(textp->compression > 0) + { + textp->text_length = 0; + textp->itxt_length = text_length; + } + else + { + textp->text_length = text_length; + textp->itxt_length = 0; + } + info_ptr->text[info_ptr->num_text]= *textp; info_ptr->num_text++; png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text); @@ -463,13 +622,13 @@ png_set_spalettes(png_structp png_ptr, np = (png_spalette_p)png_malloc(png_ptr, (info_ptr->splt_palettes_num + nentries) * sizeof(png_spalette)); - memcpy(np, info_ptr->splt_palettes, + memcpy(np, info_ptr->splt_palettes, info_ptr->splt_palettes_num * sizeof(png_spalette)); png_free(png_ptr, info_ptr->splt_palettes); for (i = 0; i < nentries; i++) { - png_spalette_p to = np + i; + png_spalette_p to = np + info_ptr->splt_palettes_num + i; png_spalette_p from = entries + i; to->name = (png_charp)png_malloc(png_ptr, @@ -477,15 +636,56 @@ png_set_spalettes(png_structp png_ptr, png_strcpy(to->name, from->name); to->entries = (png_spalette_entryp)png_malloc(png_ptr, from->nentries * sizeof(png_spalette)); - memcpy(to->entries, from->entries, + memcpy(to->entries, from->entries, from->nentries * sizeof(png_spalette)); + to->nentries = from->nentries; + to->depth = from->depth; } info_ptr->splt_palettes = np; info_ptr->splt_palettes_num += nentries; + info_ptr->valid |= PNG_INFO_sPLT; } #endif /* PNG_sPLT_SUPPORTED */ +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) +void +png_set_unknown_chunks(png_structp png_ptr, + png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns) +{ + png_unknown_chunkp np; + int i; + + if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + return; + + np = (png_unknown_chunkp)png_malloc(png_ptr, + (info_ptr->unknown_chunks_num + num_unknowns) * + sizeof(png_unknown_chunk)); + + memcpy(np, info_ptr->unknown_chunks, + info_ptr->unknown_chunks_num * sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + + for (i = 0; i < num_unknowns; i++) + { + png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; + png_unknown_chunkp from = unknowns + i; + + png_strcpy((png_charp)to->name, (png_charp)from->name); + to->data = (png_bytep)png_malloc(png_ptr, from->size); + memcpy(to->data, from->data, from->size); + to->size = from->size; + + /* note our location in the read or write sequence */ + to->location = (png_byte)(png_ptr->mode & 0xff); + } + + info_ptr->unknown_chunks = np; + info_ptr->unknown_chunks_num += num_unknowns; +} +#endif + #if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) void png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) @@ -497,9 +697,45 @@ png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted) } #endif +#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) +void +png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep chunk_list, + int num_chunks) +{ +/* + png_set_keep_unknown_chunks(png_ptr, keep, chunk_list, + num_chunks); + keep - 0: do not keep + 1: keep only if safe-to-copy + 2: keep even if unsafe-to-copy + The following are not yet implemented + in libpng version 1.0.5j: + chunk_list - list of chunks affected, NULL if + num_chunks is 0. + num_chunks - number of chunks affected. If 0, all + unknown chunks are affected. +*/ + + if (num_chunks == 0) + { + if(keep) + png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; - - - - + if(keep == 2) + png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else + png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + } + else + { + /* to do: set up chunk_list processing */ + png_warning(png_ptr, + "chunk_list not yet implemented in png_set_keep_unknown_chunks"); + if (chunk_list == NULL || num_chunks == 0) + /* do nothing right now */ ; + } +} +#endif diff --git a/pngtrans.c b/pngtrans.c index c0f29fced..eabd096ba 100644 --- a/pngtrans.c +++ b/pngtrans.c @@ -1,7 +1,7 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -2,7 +2,7 @@ * * For Intel x86 CPU and Microsoft Visual C++ compiler * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998, Intel Corporation * Copyright (c) 1998, 1999 Glenn Randers-Pehrson @@ -3653,7 +3653,7 @@ png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep #ifdef PNG_DEBUG char filnm[6]; #endif - #define UseMMX 1 +#define UseMMX 1 if (mmx_supported == 2) mmx_supported = mmxsupport(); @@ -1,7 +1,7 @@ /* pngwio.c - functions for data output * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger diff --git a/pngwrite.c b/pngwrite.c index 1f836ad1b..62ec55a19 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1,7 +1,7 @@ /* pngwrite.c - general routines to write a PNG file * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -24,9 +24,6 @@ void png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) { -#if defined(PNG_WRITE_sPLT_SUPPORTED) - int i; -#endif png_debug(1, "in png_write_info_before_PLTE\n"); if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) { @@ -44,7 +41,15 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) flag set, and if it does, writes the chunk. */ #if defined(PNG_WRITE_gAMA_SUPPORTED) if (info_ptr->valid & PNG_INFO_gAMA) + { +# ifdef PNG_FLOATING_POINT_SUPPORTED png_write_gAMA(png_ptr, info_ptr->gamma); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma); +# endif +#endif + } #endif #if defined(PNG_WRITE_sRGB_SUPPORTED) if (info_ptr->valid & PNG_INFO_sRGB) @@ -55,22 +60,49 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_TEXT_COMPRESSION_NONE, info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); #endif -#if defined(PNG_WRITE_sPLT_SUPPORTED) - if (info_ptr->valid & PNG_INFO_sPLT) - for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) - png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); -#endif #if defined(PNG_WRITE_sBIT_SUPPORTED) if (info_ptr->valid & PNG_INFO_sBIT) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif #if defined(PNG_WRITE_cHRM_SUPPORTED) if (info_ptr->valid & PNG_INFO_cHRM) + { +#ifdef PNG_FLOATING_POINT_SUPPORTED png_write_cHRM(png_ptr, info_ptr->x_white, info_ptr->y_white, info_ptr->x_red, info_ptr->y_red, info_ptr->x_green, info_ptr->y_green, info_ptr->x_blue, info_ptr->y_blue); +#else +# ifdef PNG_FIXED_POINT_SUPPORTED + png_write_cHRM_fixed(png_ptr, + info_ptr->int_x_white, info_ptr->int_y_white, + info_ptr->int_x_red, info_ptr->int_y_red, + info_ptr->int_x_green, info_ptr->int_y_green, + info_ptr->int_x_blue, info_ptr->int_y_blue); +# endif +#endif + } +#endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + if (up->location && (!(up->location & PNG_HAVE_PLTE)) && + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS || + up->name[3] & 0x20)) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } #endif png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } @@ -79,7 +111,7 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) void png_write_info(png_structp png_ptr, png_infop info_ptr) { -#if defined(PNG_WRITE_TEXT_SUPPORTED) +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; #endif @@ -131,8 +163,15 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #endif #if defined(PNG_WRITE_sCAL_SUPPORTED) if (info_ptr->valid & PNG_INFO_sCAL) - png_write_sCAL(png_ptr, info_ptr->scal_unit, +#ifdef PNG_FLOATING_POINT_SUPPORTED + png_write_sCAL(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_pixel_width, info_ptr->scal_pixel_height); +#else +#ifdef PNG_FIXED_POINT_SUPPORTED + png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, + info_ptr->scal_s_width, info_ptr->scal_s_height); +#endif +#endif #endif #if defined(PNG_WRITE_pHYs_SUPPORTED) if (info_ptr->valid & PNG_INFO_pHYs) @@ -146,6 +185,11 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) png_ptr->mode |= PNG_WROTE_tIME; } #endif +#if defined(PNG_WRITE_sPLT_SUPPORTED) + if (info_ptr->valid & PNG_INFO_sPLT) + for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) + png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); +#endif #if defined(PNG_WRITE_TEXT_SUPPORTED) /* Check to see if we need to write text chunks */ for (i = 0; i < info_ptr->num_text; i++) @@ -153,14 +197,15 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) png_debug2(2, "Writing header text chunk %d, type %d\n", i, info_ptr->text[i].compression); /* an internationalized chunk? */ - if (info_ptr->text[i].lang) + if (info_ptr->text[i].compression > 0) { #if defined(PNG_WRITE_iTXt_SUPPORTED) /* write international chunk */ - png_write_iTXt(png_ptr, + png_write_iTXt(png_ptr, info_ptr->text[i].compression, - info_ptr->text[i].lang, info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, info_ptr->text[i].text); #else png_warning(png_ptr, "Unable to write international text\n"); @@ -169,12 +214,12 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } /* If we want a compressed text chunk */ - else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) { #if defined(PNG_WRITE_zTXt_SUPPORTED) /* write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, info_ptr->text[i].text_length, + info_ptr->text[i].text, 0, info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text\n"); @@ -187,8 +232,8 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_WRITE_tEXt_SUPPORTED) /* write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, - info_ptr->text[i].text_length); + info_ptr->text[i].text, + 0); #else png_warning(png_ptr, "Unable to write uncompressed text\n"); #endif @@ -197,6 +242,27 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) } } #endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + if (up->location && (up->location& PNG_HAVE_PLTE) && + !(up->location& PNG_HAVE_IDAT) && + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS || + up->name[3] & 0x20)) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif } /* Writes the end of the PNG file. If you don't want to write comments or @@ -229,12 +295,29 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) { png_debug2(2, "Writing trailer text chunk %d, type %d\n", i, info_ptr->text[i].compression); - if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) + /* an internationalized chunk? */ + if (info_ptr->text[i].compression > 0) + { +#if defined(PNG_WRITE_iTXt_SUPPORTED) + /* write international chunk */ + png_write_iTXt(png_ptr, + info_ptr->text[i].compression, + info_ptr->text[i].key, + info_ptr->text[i].lang, + info_ptr->text[i].lang_key, + info_ptr->text[i].text); +#else + png_warning(png_ptr, "Unable to write international text\n"); +#endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + } + else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) { #if defined(PNG_WRITE_zTXt_SUPPORTED) /* write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, info_ptr->text[i].text_length, + info_ptr->text[i].text, 0, info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text\n"); @@ -247,7 +330,7 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) #if defined(PNG_WRITE_tEXt_SUPPORTED) /* write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, info_ptr->text[i].text_length); + info_ptr->text[i].text, 0); #else png_warning(png_ptr, "Unable to write uncompressed text\n"); #endif @@ -257,6 +340,26 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) } } #endif +#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) + if (info_ptr->unknown_chunks_num) + { + png_unknown_chunk *up; + + png_debug(5, "writing extra chunks\n"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + up++) + { + if ((up->location && (up->location & PNG_AFTER_IDAT)) && + (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS || + up->name[3] & 0x20)) + { + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +#endif } png_ptr->mode |= PNG_AFTER_IDAT; @@ -679,40 +782,27 @@ png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) if (info_ptr != NULL) { #if defined(PNG_WRITE_TEXT_SUPPORTED) - png_debug(1, "in png_info_destroy\n"); - if (info_ptr->text != NULL) - { - int i; - for (i = 0; i < info_ptr->num_text; i++) - { - if(info_ptr->text[i].key != NULL) - { - png_free(png_ptr, info_ptr->text[i].key); - info_ptr->text[i].key = NULL; - } - if(info_ptr->text[i].lang != NULL) - { - png_free(png_ptr, info_ptr->text[i].lang); - info_ptr->text[i].lang = NULL; - } - } - png_free(png_ptr, info_ptr->text); - info_ptr->text = NULL; - } + png_free_text(png_ptr, info_ptr, -1); #endif -#if defined(PNG_READ_pCAL_SUPPORTED) - png_free(png_ptr, info_ptr->pcal_purpose); - png_free(png_ptr, info_ptr->pcal_units); - if (info_ptr->pcal_params != NULL) - { - int i; - for (i = 0; i < (int)info_ptr->pcal_nparams; i++) - { - png_free(png_ptr, info_ptr->pcal_params[i]); - } - png_free(png_ptr, info_ptr->pcal_params); - } +#if defined(PNG_WRITE_sCAL_SUPPORTED) + png_free_sCAL(png_ptr, info_ptr); #endif +#if defined(PNG_WRITE_pCAL_SUPPORTED) + png_free_pCAL(png_ptr, info_ptr); +#endif +#if defined(PNG_WRITE_iCCP_SUPPORTED) + png_free_iCCP(png_ptr, info_ptr); +#endif +#if defined(PNG_WRITE_sPLT_SUPPORTED) + png_free_spalettes(png_ptr, info_ptr, -1); +#endif +#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + png_free_unknown_chunks(png_ptr, info_ptr, -1); +#endif +#if defined(PNG_hIST_SUPPORTED) + png_free_hIST(png_ptr, info_ptr); +#endif + #ifdef PNG_USER_MEM_SUPPORTED png_destroy_struct_2((png_voidp)info_ptr, free_fn); #else @@ -1042,6 +1132,14 @@ png_set_compression_window_bits(png_structp png_ptr, int window_bits) png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); else if (window_bits < 8) png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); +#ifndef WBITS_8_OK + /* avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Compression window is being reset to 512"); + window_bits=9; + } +#endif png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; png_ptr->zlib_window_bits = window_bits; } diff --git a/pngwtran.c b/pngwtran.c index 310064ea0..66282a287 100644 --- a/pngwtran.c +++ b/pngwtran.c @@ -1,7 +1,7 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger diff --git a/pngwutil.c b/pngwutil.c index 37a4f50c3..050f1a811 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1,7 +1,7 @@ /* pngwutil.c - utilities to write a PNG file * - * libpng 1.0.5f - December 6, 1999 + * libpng 1.0.5j - December 21, 1999 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. * Copyright (c) 1996, 1997 Andreas Dilger @@ -133,7 +133,7 @@ png_write_sig(png_structp png_ptr) (png_size_t)8 - png_ptr->sig_bytes); } -#if defined(PNG_WRITE_TEXT_SUPPORTED) +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) /* * This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. @@ -151,8 +151,8 @@ typedef struct } compression_state; /* compress given text into storage in the png_ptr structure */ -static int -png_text_compress(png_structp png_ptr, +static int +png_text_compress(png_structp png_ptr, png_charp text, png_size_t text_len, int compression, compression_state *comp) { @@ -233,7 +233,7 @@ png_text_compress(png_structp png_ptr, old_ptr = comp->output_ptr; comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); - png_memcpy(comp->output_ptr, old_ptr, + png_memcpy(comp->output_ptr, old_ptr, old_max * sizeof (png_charp)); png_free(png_ptr, old_ptr); } @@ -288,7 +288,7 @@ png_text_compress(png_structp png_ptr, /* This could be optimized to realloc() */ comp->output_ptr = (png_charpp)png_malloc(png_ptr, (png_uint_32)(comp->max_output_ptr * sizeof (png_charpp))); - png_memcpy(comp->output_ptr, old_ptr, + png_memcpy(comp->output_ptr, old_ptr, old_max * sizeof (png_charp)); png_free(png_ptr, old_ptr); } @@ -319,7 +319,7 @@ png_text_compress(png_structp png_ptr, } /* ship the compressed text out via chunk writes */ -static void +static void png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) { int i; @@ -334,7 +334,8 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) /* write saved output buffers, if any */ for (i = 0; i < comp->num_output_ptr; i++) { - png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],png_ptr->zbuf_size); + png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i], + png_ptr->zbuf_size); png_free(png_ptr, comp->output_ptr[i]); } if (comp->max_output_ptr != 0) @@ -566,6 +567,7 @@ png_write_IEND(png_structp png_ptr) #if defined(PNG_WRITE_gAMA_SUPPORTED) /* write a gAMA chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED void png_write_gAMA(png_structp png_ptr, double file_gamma) { @@ -576,12 +578,28 @@ png_write_gAMA(png_structp png_ptr, double file_gamma) png_byte buf[4]; png_debug(1, "in png_write_gAMA\n"); - /* file_gamma is saved in 1/1000000ths */ + /* file_gamma is saved in 1/100,000ths */ igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5); png_save_uint_32(buf, igamma); png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); } #endif +void +#ifdef PNG_FIXED_POINT_SUPPORTED +png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_gAMA; +#endif + png_byte buf[4]; + + png_debug(1, "in png_write_gAMA\n"); + /* file_gamma is saved in 1/100,000ths */ + png_save_uint_32(buf, file_gamma); + png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4); +} +#endif +#endif #if defined(PNG_WRITE_sRGB_SUPPORTED) /* write a sRGB chunk */ @@ -634,7 +652,7 @@ png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type, PNG_TEXT_COMPRESSION_zTXt, &comp); /* make sure we include the NULL after the name and the compression type */ - png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, + png_write_chunk_start(png_ptr, (png_bytep)png_iCCP, (png_uint_32)name_len+profile_len+2); png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2); @@ -669,9 +687,10 @@ png_write_sPLT(png_structp png_ptr, png_spalette_p spalette) } /* make sure we include the NULL after the name */ - png_write_chunk_start(png_ptr, (png_bytep) png_sPLT, - (png_uint_32)(name_len + 1 + palette_size)); + png_write_chunk_start(png_ptr, (png_bytep) png_sPLT, + (png_uint_32)(name_len + 2 + palette_size)); png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1); + png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1); /* loop through each palette entry, writing appropriately */ for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++) @@ -758,6 +777,7 @@ png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type) #if defined(PNG_WRITE_cHRM_SUPPORTED) /* write the cHRM chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED void png_write_cHRM(png_structp png_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, @@ -766,15 +786,16 @@ png_write_cHRM(png_structp png_ptr, double white_x, double white_y, #ifdef PNG_USE_LOCAL_ARRAYS PNG_cHRM; #endif - png_uint_32 itemp; png_byte buf[32]; + png_uint_32 itemp; png_debug(1, "in png_write_cHRM\n"); - /* each value is saved int 1/1000000ths */ + /* each value is saved in 1/100,000ths */ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 || white_x + white_y > 1.0) { png_warning(png_ptr, "Invalid cHRM white point specified"); + printf("white_x=%f, white_y=%f\n",white_x, white_y); return; } itemp = (png_uint_32)(white_x * 100000.0 + 0.5); @@ -818,6 +839,57 @@ png_write_cHRM(png_structp png_ptr, double white_x, double white_y, png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); } #endif +#ifdef PNG_FIXED_POINT_SUPPORTED +void +png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, + png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, + png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, + png_fixed_point blue_y) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_cHRM; +#endif + png_byte buf[32]; + + png_debug(1, "in png_write_cHRM\n"); + /* each value is saved in 1/100,000ths */ + if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM white point specified"); + printf("white_x=%ld, white_y=%ld\n",white_x, white_y); + return; + } + png_save_uint_32(buf, white_x); + png_save_uint_32(buf + 4, white_y); + + if (red_x > 80000L || red_y > 80000L || red_x + red_y > 100000L) + { + png_warning(png_ptr, "Invalid cHRM fixed red point specified"); + return; + } + png_save_uint_32(buf + 8, red_x); + png_save_uint_32(buf + 12, red_y); + + if (green_x > 80000L || green_y > 80000L || green_x + green_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM green point specified"); + return; + } + png_save_uint_32(buf + 16, green_x); + png_save_uint_32(buf + 20, green_y); + + if (blue_x > 80000L || blue_y > 80000L || blue_x + blue_y > 100000L) + { + png_warning(png_ptr, "Invalid fixed cHRM blue point specified"); + return; + } + png_save_uint_32(buf + 24, blue_x); + png_save_uint_32(buf + 28, blue_y); + + png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32); +} +#endif +#endif #if defined(PNG_WRITE_tRNS_SUPPORTED) /* write the tRNS chunk */ @@ -1039,7 +1111,7 @@ png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key) { png_free(png_ptr, *new_key); *new_key=NULL; - png_chunk_warning(png_ptr, "zero length keyword"); + png_chunk_warning(png_ptr, "Zero length keyword"); } if (key_len > 79) @@ -1074,6 +1146,8 @@ png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text, if (text == NULL || *text == '\0') text_len = 0; + else + text_len = png_strlen(text); /* make sure we include the 0 after the key */ png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1); @@ -1120,10 +1194,12 @@ png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, png_free(png_ptr, new_key); return; } + + text_len = png_strlen(text); png_free(png_ptr, new_key); - /* compute the compressed data; do it now for the length */ + /* compute the compressed data; do it now for the length */ text_len = png_text_compress(png_ptr, text, text_len, compression, &comp); /* write start of chunk */ @@ -1145,53 +1221,49 @@ png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text, #if defined(PNG_WRITE_iTXt_SUPPORTED) /* write an iTXt chunk */ void -png_write_iTXt(png_structp png_ptr, int compression, - png_charp key, png_charp lang, png_charp text) +png_write_iTXt(png_structp png_ptr, int compression, png_charp key, + png_charp lang, png_charp lang_key, png_charp text) { #ifdef PNG_USE_LOCAL_ARRAYS PNG_iTXt; #endif - png_size_t lang_len, key_len, text_len = png_strlen(text); + png_size_t lang_len, key_len, lang_key_len, text_len; png_charp new_lang, new_key; png_byte cbuf[2]; compression_state comp; png_debug(1, "in png_write_iTXt\n"); - if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, - &new_lang))==0) + + if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) { - png_warning(png_ptr, "Empty language field in iTXt chunk"); + png_warning(png_ptr, "Empty keyword in iTXt chunk"); return; } - if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0) + if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, + &new_lang))==0) { - png_warning(png_ptr, "Empty keyword in iTXt chunk"); + png_warning(png_ptr, "Empty language field in iTXt chunk"); return; } + lang_key_len = png_strlen(lang_key); + text_len = png_strlen(text); if (text == NULL || *text == '\0') text_len = 0; - /* compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression, &comp); + /* compute the compressed data; do it now for the length */ + text_len = png_text_compress(png_ptr, text, text_len, compression-2, &comp); - /* make sure we include the compression flag, the compression byte, - * and the NULs after the lang and key parts */ - png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, - (png_uint_32)(2 + lang_len+1 + key_len+1 + text_len)); + /* make sure we include the compression flag, the compression byte, + * and the NULs after the key, lang, and lang_key parts */ - /* set the compression bits */ - if (compression == PNG_TEXT_COMPRESSION_NONE) - { - cbuf[0] = 0; - cbuf[1] = 0; - } - else /* compression == PNG_TEXT_COMPRESSION_zTXt */ - { - cbuf[0] = 1; - cbuf[1] = 0; - } - png_write_chunk_data(png_ptr, cbuf, 2); + png_write_chunk_start(png_ptr, (png_bytep)png_iTXt, + (png_uint_32)( + 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ + + key_len + + lang_len + + lang_key_len + + text_len)); /* * We leave it to the application to meet PNG-1.0 requirements on the @@ -1199,9 +1271,22 @@ png_write_iTXt(png_structp png_ptr, int compression, * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. */ - png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1); png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1); + /* set the compression flag */ + if (compression == PNG_ITXT_COMPRESSION_NONE || \ + compression == PNG_TEXT_COMPRESSION_NONE) + cbuf[0] = 0; + else /* compression == PNG_ITXT_COMPRESSION_zTXt */ + cbuf[0] = 1; + /* set the compression method */ + cbuf[1] = 0; + png_write_chunk_data(png_ptr, cbuf, 2); + + png_write_chunk_data(png_ptr, (png_bytep)new_lang, lang_len + 1); + png_write_chunk_data(png_ptr, (png_bytep)lang_key, lang_key_len+1); + png_write_chunk_data(png_ptr, '\0', 1); + png_write_compressed_data_out(png_ptr, &comp); png_write_chunk_end(png_ptr); @@ -1296,8 +1381,9 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, #if defined(PNG_WRITE_sCAL_SUPPORTED) /* write the sCAL chunk */ +#ifdef PNG_FLOATING_POINT_SUPPORTED void -png_write_sCAL(png_structp png_ptr, png_charp unit, double width,double height) +png_write_sCAL(png_structp png_ptr, int unit, double width,double height) { #ifdef PNG_USE_LOCAL_ARRAYS PNG_sCAL; @@ -1309,16 +1395,44 @@ png_write_sCAL(png_structp png_ptr, png_charp unit, double width,double height) sprintf(wbuf, "%12.12e", width); sprintf(hbuf, "%12.12e", height); - total_len = png_strlen(unit)+1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); png_debug1(3, "sCAL total length = %d\n", total_len); png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_bytep)unit, png_strlen(unit)+1); + png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1); png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf)); png_write_chunk_end(png_ptr); } +#else +#ifdef PNG_FIXED_POINT_SUPPORTED +void +png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width, + png_charp height) +{ +#ifdef PNG_USE_LOCAL_ARRAYS + PNG_sCAL; +#endif + png_size_t total_len; + char wbuf[32], hbuf[32]; + + png_debug(1, "in png_write_sCAL\n"); + + sprintf(wbuf, "%s", width); + sprintf(hbuf, "%s", height); + total_len = 1 + png_strlen(wbuf)+1 + png_strlen(hbuf); + + png_debug1(3, "sCAL total length = %d\n", total_len); + png_write_chunk_start(png_ptr, (png_bytep)png_sCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, (png_bytep)&unit, 1); + png_write_chunk_data(png_ptr, (png_bytep)wbuf, strlen(wbuf)+1); + png_write_chunk_data(png_ptr, (png_bytep)hbuf, strlen(hbuf)); + + png_write_chunk_end(png_ptr); +} +#endif +#endif #endif #if defined(PNG_WRITE_pHYs_SUPPORTED) @@ -1383,20 +1497,20 @@ png_write_start_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + png_size_t buf_size; png_debug(1, "in png_write_start_row\n"); @@ -1477,20 +1591,20 @@ png_write_finish_row(png_structp png_ptr) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; - + /* start of interlace block in the y direction */ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; - + /* offset to next interlace block in the y direction */ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - + int ret; png_debug(1, "in png_write_finish_row\n"); @@ -1591,14 +1705,14 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { #ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ - + /* start of interlace block */ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; - + /* offset to next interlace block */ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; #endif - + png_debug(1, "in png_do_write_interlace\n"); /* we don't have to do anything on the last pass (6) */ #if defined(PNG_USELESS_TESTS_SUPPORTED) diff --git a/uncompr.c b/uncompr.c new file mode 100644 index 000000000..d10332137 --- /dev/null +++ b/uncompr.c @@ -0,0 +1,58 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} |