update libpng

update libpng, the repo now requires a vcpkg setup for integrating but skipping the install step should allow it to work for windows an linux, mac might need more
This commit is contained in:
marauder2k7 2025-12-31 20:11:14 +00:00
parent c593d860a0
commit 5d644b4ffb
300 changed files with 25573 additions and 17698 deletions

View file

@ -0,0 +1,9 @@
# https://editorconfig.org
root = false
[*.[ch]]
indent_size = unset
indent_style = unset
max_doc_length = unset
max_line_length = unset

View file

@ -1,3 +1,5 @@
External contributions to libpng
--------------------------------
This "contrib" directory contains contributions which are not necessarily under
the libpng license, although all are open source. They are not part of

View file

@ -2,7 +2,6 @@
*
* Copyright (c) 2014 Glenn Randers-Pehrson
* Written by John Bowler, 2014.
* Last changed in libpng 1.6.10 [March 6, 2014]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -24,6 +23,7 @@
* has been compiled only, not linked: no version of the library has been found,
* only the header files exist in the NDK.
*/
#include <cpu-features.h>
static int

View file

@ -2,7 +2,6 @@
*
* Copyright (c) 2014 Glenn Randers-Pehrson
* Written by Mans Rullgard, 2011.
* Last changed in libpng 1.6.10 [March 6, 2014]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -22,6 +21,7 @@
* This generic __linux__ implementation requires reading /proc/self/auxv and
* looking at each element for one that records NEON capabilities.
*/
#include <unistd.h> /* for POSIX 1003.1 */
#include <errno.h> /* for EINTR */

View file

@ -1,6 +1,5 @@
/* contrib/arm-neon/linux.c
*
* Last changed in libpng 1.6.31 [July 27, 2017]
* Copyright (c) 2014, 2017 Glenn Randers-Pehrson
* Written by John Bowler, 2014, 2017.
*
@ -19,6 +18,7 @@
* This code is strict ANSI-C and is probably moderately portable; it does
* however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
*/
#include <stdio.h>
static int

View file

@ -0,0 +1,133 @@
# basic.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2024
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Build libpng with basic read and write support. This enables the lowest
# level libpng read and write APIs - the "row-by-row" ones.
#
# Support is enabled only for those transformations that are observed to be
# required by widely used apps or are in the v3 specification.
#
everything = off
# The sequential read code is enabled here; the progressive code can be used
# instead but there is no point enabling both.
option READ on
option SEQUENTIAL_READ on
option EASY_ACCESS on
option SET_USER_LIMITS on
option INFO_IMAGE on
option READ_16BIT on
# Errors: these can be disabled but then there won't be any error messages
# just failures and the error messages are really needed for apps:
option WARNINGS on
option ERROR_TEXT on
option BENIGN_READ_ERRORS on
# Required for many display programs such as web browsers:
option PROGRESSIVE_READ on
# Switch on the write code - this makes a minimalist encoder but with
# interlace support turned on; otherwise png_read_png..png_write_png will
# fail on an interlaced image.
option WRITE on
option WRITE_INTERLACING on
option WRITE_16BIT on
# Usages of the 'fixed' APIs are relatively rare but they do occur
# one or the other for both the API and the internal math.
#Fixed point:
option FIXED_POINT on
#Floating point:
option FLOATING_POINT on
option FLOATING_ARITHMETIC on
# Basic error handling, IO and user memory support. The latter allows the
# application program to provide its own implementations of 'malloc' and 'free'.
option SETJMP on
option STDIO on
option USER_MEM on
# Gamma handling: this needs to be on for the gamma handling
option READ_GAMMA on
# The supported chunks
chunk bKGD on
chunk cHRM on
chunk eXIf on
chunk gAMA on
chunk iCCP on
chunk iTXt on
chunk pHYs on
chunk sBIT on
chunk sRGB on
chunk tEXt on
chunk tIME on
chunk tRNS on
chunk zTXt on
# These don't seem to be used anywhere:
# chunk pCAL
# chunk sCAL
# chunk sPLT
# The rest of this is app dependent: none of these options are required for
# read/write of the full range of PNG files and the normal chunk handling on
# read.
option WRITE_CUSTOMIZE_ZTXT_COMPRESSION on
option WRITE_CUSTOMIZE_COMPRESSION on
option READ_EXPAND on
option READ_FILLER on
option READ_GRAY_TO_RGB on
option READ_INVERT on
option READ_PACK on
option READ_RGB_TO_GRAY on
option READ_SCALE_16_TO_8 on
option READ_SHIFT on
option READ_STRIP_16_TO_8 on
option READ_STRIP_ALPHA on
option READ_SWAP on
option CONVERT_tIME on
# optipng
option IO_STATE on
option STORE_UNKNOWN_CHUNKS on
option HANDLE_AS_UNKNOWN on
# pngcrush
option READ_USER_TRANSFORM on
option WRITE_FLUSH on
# pnmtopng
chunk hIST on
# cairo
option WRITE_PACKSWAP on
option WRITE_USER_TRANSFORM on
# graphicsmagick
option READ_USER_CHUNKS on
# Qt5.15 qtgui (gentoo package split) Qt6.6 qtbase
option READ_BGR on
option WRITE_BGR on
option READ_SWAP_ALPHA on
option WRITE_SWAP_ALPHA on
chunk oFFs on
# ghostscript-gpl
option WRITE_INVERT_ALPHA on
option WRITE_INVERT on

View file

@ -0,0 +1,15 @@
# fixed.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Test the standard libpng configuration without floating point (the internal
# fixed point implementations are used instead).
#
option FLOATING_ARITHMETIC off
option FLOATING_POINT off

View file

@ -0,0 +1,14 @@
# fixed-float.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Test the standard libpng configuration with the fixed point internal
# implementation in place of the default floating point
#
option FLOATING_ARITHMETIC off

View file

@ -0,0 +1,21 @@
# nolimits.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
#
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Build libpng without any limits and without run-time settable limits. Turning
# USER_LIMITS off reduces libpng code size by allowing compile-time elimination
# of some checking code.
#
option USER_LIMITS off
@# define PNG_USER_WIDTH_MAX PNG_UINT_31_MAX
@# define PNG_USER_HEIGHT_MAX PNG_UINT_31_MAX
@# define PNG_USER_CHUNK_CACHE_MAX 0
@# define PNG_USER_CHUNK_MALLOC_MAX 0

View file

@ -0,0 +1,19 @@
# nolimits.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
#
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Build libpng without any limits. With these settigs run-time limits are still
# possible.
#
@# define PNG_USER_WIDTH_MAX PNG_UINT_31_MAX
@# define PNG_USER_HEIGHT_MAX PNG_UINT_31_MAX
@# define PNG_USER_CHUNK_CACHE_MAX 0
@# define PNG_USER_CHUNK_MALLOC_MAX 0

View file

@ -0,0 +1,13 @@
# read-full.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Build libpng with no write support and full read support.
#
option WRITE off

View file

@ -0,0 +1,13 @@
# write-full.dfa
# Build time configuration of libpng
#
# Author: John Bowler
# Copyright: (c) John Bowler, 2025
# Usage rights:
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Build libpng with no read support and full write support.
#
option READ off

View file

@ -0,0 +1,143 @@
---
Language: Cpp
AccessModifierOffset: -3
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AlignConsecutiveBitFields:
Enabled: false
AlignConsecutiveDeclarations:
Enabled: false
AlignConsecutiveMacros:
Enabled: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AlignEscapedNewlines: DontAlign
AlignOperands: false
AlignTrailingComments:
Kind: Never
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: true
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterExternBlock: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: TopLevel
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: false
BreakStringLiterals: false
BreakTemplateDeclarations: MultiLine
ColumnLimit: 79
ContinuationIndentWidth: 3
DerivePointerAlignment: true
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: false
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 3
IndentWrappedFunctionNames: false
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: false
AtStartOfFile: false
KeepFormFeed: false
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
PackConstructorInitializers: Never
PointerAlignment: Left
QualifierAlignment: Custom
QualifierOrder: [static, inline, constexpr, const, volatile, restrict, type]
ReferenceAlignment: Pointer
ReflowComments: Never
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SortIncludes: false
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 8
UseTab: Never
WrapNamespaceBodyWithEmptyLines: Leave
...

View file

@ -1,4 +1,3 @@
This directory (contrib/examples) contains examples of libpng usage.
NO COPYRIGHT RIGHTS ARE CLAIMED TO ANY OF THE FILES IN THIS DIRECTORY.

View file

@ -26,8 +26,9 @@
#include <png.h>
#if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \
defined (PNG_iCCP_SUPPORTED)
#if !defined(PNG_iCCP_SUPPORTED) || !defined(PNG_READ_SUPPORTED)
#error This program requires libpng supporting the iCCP chunk and the read API
#endif
static int verbose = 1;
@ -36,7 +37,8 @@ static png_byte no_profile[] = "no profile";
static png_bytep
extract(FILE *fp, png_uint_32 *proflen)
{
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
png_structp png_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = NULL;
png_bytep result = NULL;
@ -69,7 +71,7 @@ extract(FILE *fp, png_uint_32 *proflen)
png_bytep profile;
if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
proflen) & PNG_INFO_iCCP)
proflen) & PNG_INFO_iCCP)
{
result = malloc(*proflen);
if (result != NULL)
@ -80,7 +82,7 @@ extract(FILE *fp, png_uint_32 *proflen)
}
else
result = no_profile;
result = no_profile;
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
@ -107,7 +109,7 @@ extract_one_file(const char *filename)
const char *ep = strrchr(filename, '.');
if (ep != NULL)
len = ep-filename;
len = ep - filename;
else
len = strlen(filename);
@ -119,14 +121,14 @@ extract_one_file(const char *filename)
FILE *of;
memcpy(output, filename, len);
strcpy(output+len, ".icc");
strcpy(output + len, ".icc");
of = fopen(output, "wb");
if (of != NULL)
{
if (fwrite(profile, proflen, 1, of) == 1 &&
fflush(of) == 0 &&
fclose(of) == 0)
fflush(of) == 0 &&
fclose(of) == 0)
{
if (verbose)
printf("%s -> %s\n", filename, output);
@ -155,12 +157,15 @@ extract_one_file(const char *filename)
}
else if (verbose && profile == no_profile)
printf("%s has no profile\n", filename);
printf("%s has no profile\n", filename);
}
else
fprintf(stderr, "%s: could not open file\n", filename);
if (fp != NULL)
fclose(fp);
return result;
}
@ -170,7 +175,7 @@ main(int argc, char **argv)
int i;
int extracted = 0;
for (i=1; i<argc; ++i)
for (i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "-q") == 0)
verbose = 0;
@ -182,4 +187,3 @@ main(int argc, char **argv)
/* Exit code is true if any extract succeeds */
return extracted == 0;
}
#endif /* READ && STDIO && iCCP */

View file

@ -15,8 +15,8 @@
* images. Normally you would call png_set_interlace_handling() to have libpng
* deal with the interlace for you, but that obliges you to buffer half of the
* image to assemble the interlaced rows. In this code
* png_set_interlace_handling() is not called and, instead, the code handles the
* interlace passes directly looking for the required pixel.
* png_set_interlace_handling() is not called and, instead, the code handles
* the interlace passes directly looking for the required pixel.
*/
#include <stdlib.h>
#include <stdio.h>
@ -27,34 +27,37 @@
*/
#include "../../png.h"
#if defined(PNG_READ_SUPPORTED) && defined(PNG_SEQUENTIAL_READ_SUPPORTED)
#if !defined(PNG_READ_SUPPORTED) || !defined(PNG_SEQUENTIAL_READ_SUPPORTED)
#error This program requires libpng supporting the read and sequential read API
#endif
/* Return component 'c' of pixel 'x' from the given row. */
static unsigned int
component(png_const_bytep row, png_uint_32 x, unsigned int c,
unsigned int bit_depth, unsigned int channels)
unsigned int bit_depth, unsigned int channels)
{
/* PNG images can be up to 2^31 pixels wide, but this means they can be up to
* 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence 2^34
* bytes wide. Since the row fitted into memory, however, the following must
/* PNG images can be up to 2^31 pixels wide, which means they can be up to
* 2^37 bits wide (for a 64-bit pixel - the largest possible) and hence
* 2^34 bytes wide. Since the row fitted into memory, the following must
* work:
*/
png_uint_32 bit_offset_hi = bit_depth * ((x >> 6) * channels);
png_uint_32 bit_offset_lo = bit_depth * ((x & 0x3f) * channels + c);
row = (png_const_bytep)(((const png_byte (*)[8])row) + bit_offset_hi);
row = (png_const_bytep)(((const png_byte(*)[8])row) + bit_offset_hi);
row += bit_offset_lo >> 3;
bit_offset_lo &= 0x07;
/* PNG pixels are packed into bytes to put the first pixel in the highest
* bits of the byte and into two bytes for 16-bit values with the high 8 bits
* first, so:
* bits of the byte, and into two bytes for 16-bit values with the high
* 8 bits first, so:
*/
switch (bit_depth)
{
case 1: return (row[0] >> (7-bit_offset_lo)) & 0x01;
case 2: return (row[0] >> (6-bit_offset_lo)) & 0x03;
case 4: return (row[0] >> (4-bit_offset_lo)) & 0x0f;
case 1: return (row[0] >> (7 - bit_offset_lo)) & 0x01;
case 2: return (row[0] >> (6 - bit_offset_lo)) & 0x03;
case 4: return (row[0] >> (4 - bit_offset_lo)) & 0x0f;
case 8: return row[0];
case 16: return (row[0] << 8) + row[1];
default:
@ -71,7 +74,7 @@ component(png_const_bytep row, png_uint_32 x, unsigned int c,
*/
static void
print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
png_uint_32 x)
png_uint_32 x)
{
unsigned int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
@ -92,22 +95,24 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
int num_palette = 0;
if ((png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette) &
PNG_INFO_PLTE) && num_palette > 0 && palette != NULL)
PNG_INFO_PLTE) &&
(num_palette > 0) &&
(palette != NULL))
{
png_bytep trans_alpha = NULL;
int num_trans = 0;
if ((png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans,
NULL) & PNG_INFO_tRNS) && num_trans > 0 &&
trans_alpha != NULL)
NULL) & PNG_INFO_tRNS) &&
(num_trans > 0) &&
(trans_alpha != NULL))
printf("INDEXED %u = %d %d %d %d\n", index,
palette[index].red, palette[index].green,
palette[index].blue,
index < num_trans ? trans_alpha[index] : 255);
palette[index].red, palette[index].green,
palette[index].blue,
index < num_trans ? trans_alpha[index] : 255);
else /* no transparency */
printf("INDEXED %u = %d %d %d\n", index,
palette[index].red, palette[index].green,
palette[index].blue);
printf("INDEXED %u = %d %d %d\n", index, palette[index].red,
palette[index].green, palette[index].blue);
}
else
@ -117,20 +122,20 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
case PNG_COLOR_TYPE_RGB:
printf("RGB %u %u %u\n", component(row, x, 0, bit_depth, 3),
component(row, x, 1, bit_depth, 3),
component(row, x, 2, bit_depth, 3));
component(row, x, 1, bit_depth, 3),
component(row, x, 2, bit_depth, 3));
return;
case PNG_COLOR_TYPE_GRAY_ALPHA:
printf("GRAY+ALPHA %u %u\n", component(row, x, 0, bit_depth, 2),
component(row, x, 1, bit_depth, 2));
component(row, x, 1, bit_depth, 2));
return;
case PNG_COLOR_TYPE_RGB_ALPHA:
printf("RGBA %u %u %u %u\n", component(row, x, 0, bit_depth, 4),
component(row, x, 1, bit_depth, 4),
component(row, x, 2, bit_depth, 4),
component(row, x, 3, bit_depth, 4));
component(row, x, 1, bit_depth, 4),
component(row, x, 2, bit_depth, 4),
component(row, x, 3, bit_depth, 4));
return;
default:
@ -138,7 +143,8 @@ print_pixel(png_structp png_ptr, png_infop info_ptr, png_const_bytep row,
}
}
int main(int argc, const char **argv)
int
main(int argc, const char **argv)
{
/* This program uses the default, <setjmp.h> based, libpng error handling
* mechanism, therefore any local variable that exists before the call to
@ -146,7 +152,7 @@ int main(int argc, const char **argv)
* be declared with 'volatile' to ensure that their values don't get
* destroyed by longjmp:
*/
volatile int result = 1/*fail*/;
volatile int result = 1 /*fail*/;
if (argc == 4)
{
@ -163,8 +169,8 @@ int main(int argc, const char **argv)
* writes error messages to stderr. Creating the png_struct is a
* little tricky; just copy the following code.
*/
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
png_structp png_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr != NULL)
{
@ -184,11 +190,11 @@ int main(int argc, const char **argv)
compression_method, filter_method;
png_bytep row_tmp;
/* Now associate the recently opened (FILE*) with the default
* libpng initialization functions. Sometimes libpng is
* compiled without stdio support (it can be difficult to do
* in some environments); in that case you will have to write
* your own read callback to read data from the (FILE*).
/* Now associate the recently opened FILE object with the
* default libpng initialization functions. Sometimes libpng
* is compiled without stdio support (it can be difficult to
* do in some environments); in that case you will have to
* write your own read callback to read data from the stream.
*/
png_init_io(png_ptr, f);
@ -202,21 +208,21 @@ int main(int argc, const char **argv)
* space. In this case png_malloc is used - it will not
* return if memory isn't available.
*/
row = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
info_ptr));
row =
png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
/* To avoid the overhead of using a volatile auto copy row_tmp
/* Avoid the overhead of using a volatile auto copy row_tmp
* to a local here - just use row for the png_free below.
*/
row_tmp = row;
/* All the information we need is in the header is returned by
* png_get_IHDR, if this fails we can now use 'png_error' to
/* All the information we need is in the header returned by
* png_get_IHDR. If this fails, we can use 'png_error' to
* signal the error and return control to the setjmp above.
*/
if (png_get_IHDR(png_ptr, info_ptr, &width, &height,
&bit_depth, &color_type, &interlace_method,
&compression_method, &filter_method))
&bit_depth, &color_type, &interlace_method,
&compression_method, &filter_method))
{
int passes, pass;
@ -242,7 +248,7 @@ int main(int argc, const char **argv)
/* Now read the pixels, pass-by-pass, row-by-row: */
png_start_read_image(png_ptr);
for (pass=0; pass<passes; ++pass)
for (pass = 0; pass < passes; ++pass)
{
png_uint_32 ystart, xstart, ystep, xstep;
png_uint_32 py;
@ -299,19 +305,27 @@ int main(int argc, const char **argv)
* are, of course, much better ways of doing this
* than using a for loop:
*/
if (y == py) for (px = xstart, ppx = 0;
px < width; px += xstep, ++ppx) if (x == px)
if (y == py)
{
/* 'ppx' is the index of the pixel in the row
* buffer.
*/
print_pixel(png_ptr, info_ptr, row_tmp, ppx);
for (px = xstart, ppx = 0;
px < width;
px += xstep, ++ppx)
{
if (x == px)
{
/* 'ppx' is the index of the pixel in the
* row buffer.
*/
print_pixel(png_ptr, info_ptr, row_tmp,
ppx);
/* Now terminate the loops early - we have
* found and handled the required data.
*/
goto pass_loop_end;
} /* x loop */
/* Now terminate the loops early - we have
* found and handled the required data.
*/
goto pass_loop_end;
} /* x loop */
}
}
} /* y loop */
} /* pass loop */
@ -323,7 +337,6 @@ int main(int argc, const char **argv)
else
png_error(png_ptr, "pngpixel: png_get_IHDR failed");
}
else
@ -349,7 +362,8 @@ int main(int argc, const char **argv)
}
else
fprintf(stderr, "pngpixel: out of memory allocating png_info\n");
fprintf(stderr,
"pngpixel: out of memory allocating png_info\n");
png_destroy_read_struct(&png_ptr, NULL, NULL);
}
@ -368,4 +382,3 @@ int main(int argc, const char **argv)
return result;
}
#endif /* READ && SEQUENTIAL_READ */

View file

@ -5,13 +5,11 @@
* related or neighboring rights to this work. This work is published from:
* United States.
*
* Last changed in libpng 1.6.29 [March 16, 2017]
*
* Read a PNG and write it out in a fixed format, using the 'simplified API'
* that was introduced in libpng-1.6.0.
*
* This sample code is just the code from the top of 'example.c' with some error
* handling added. See example.c for more comments.
* This sample code is just the code from 'example.c' with some error handling
* added. See example.c in the top-level libpng directory for more comments.
*/
#include <stddef.h>
#include <stdlib.h>
@ -22,10 +20,15 @@
* ensure the code picks up the local libpng implementation:
*/
#include "../../png.h"
#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && \
defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
int main(int argc, const char **argv)
#if !defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \
!defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
#error This program requires libpng supporting the simplified read/write API
#endif
int
main(int argc, const char **argv)
{
int result = 1;
@ -50,22 +53,22 @@ int main(int argc, const char **argv)
if (buffer != NULL)
{
if (png_image_finish_read(&image, NULL/*background*/, buffer,
0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */))
if (png_image_finish_read(&image, NULL /*background*/, buffer,
0 /*row_stride*/, NULL /*colormap */))
{
if (png_image_write_to_file(&image, argv[2],
0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
NULL/*colormap*/))
if (png_image_write_to_file(
&image, argv[2], 0 /*convert_to_8bit*/, buffer,
0 /*row_stride*/, NULL /*colormap*/))
result = 0;
else
fprintf(stderr, "pngtopng: write %s: %s\n", argv[2],
image.message);
image.message);
}
else
fprintf(stderr, "pngtopng: read %s: %s\n", argv[1],
image.message);
image.message);
free(buffer);
}
@ -73,7 +76,7 @@ int main(int argc, const char **argv)
else
{
fprintf(stderr, "pngtopng: out of memory: %lu bytes\n",
(unsigned long)PNG_IMAGE_SIZE(image));
(unsigned long)PNG_IMAGE_SIZE(image));
/* This is the only place where a 'free' is required; libpng does
* the cleanup on error and success, but in this case we couldn't
@ -95,4 +98,3 @@ int main(int argc, const char **argv)
return result;
}
#endif /* READ && WRITE */

View file

@ -6,9 +6,9 @@
* United States.
*
* Read several PNG files, which should have an alpha channel or transparency
* information, and composite them together to produce one or more 16-bit linear
* RGBA intermediates. This involves doing the correct 'over' composition to
* combine the alpha channels and corresponding data.
* information, and composite them together to produce one or more 16-bit
* linear RGBA intermediates. This involves doing the 'over' compositing
* operation to combine the alpha channels and corresponding data.
*
* Finally read an output (background) PNG using the 24-bit RGB format (the
* PNG will be composited on green (#00ff00) by default if it has an alpha
@ -28,8 +28,8 @@
* correctly. Apart from the libpng Simplified API the only work done in here
* is to combine multiple input PNG images into a single sprite; this involves
* a Porter-Duff 'over' operation and the input PNG images may, as a result,
* be regarded as being layered one on top of the other with the first (leftmost
* on the command line) being at the bottom and the last on the top.
* be regarded as being layered one on top of the other with the first
* (leftmost on the command line) being at the bottom and the last on the top.
*/
#include <stddef.h>
#include <stdlib.h>
@ -44,54 +44,61 @@
*/
#include "../../png.h"
#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
#if !defined(PNG_SIMPLIFIED_READ_SUPPORTED)
#error This program requires libpng supporting the simplified read API
#endif
#define sprite_name_chars 15
struct sprite {
FILE *file;
png_uint_16p buffer;
unsigned int width;
unsigned int height;
char name[sprite_name_chars+1];
struct sprite
{
FILE *file;
png_uint_16p buffer;
unsigned int width;
unsigned int height;
char name[sprite_name_chars + 1];
};
#if 0 /* div by 65535 test program */
#include <math.h>
#include <stdio.h>
int main(void) {
int
main(void)
{
double err = 0;
unsigned int xerr = 0;
unsigned int r = 32769;
unsigned int x = 0;
do
{
unsigned int x = 0;
unsigned int t = x + (x >> 16) /*+ (x >> 31)*/ + r;
double v = x, errtest;
do {
unsigned int t = x + (x >> 16) /*+ (x >> 31)*/ + r;
double v = x, errtest;
if (t < x)
{
fprintf(stderr, "overflow: %u+%u -> %u\n", x, r, t);
return 1;
}
if (t < x) {
fprintf(stderr, "overflow: %u+%u -> %u\n", x, r, t);
return 1;
v /= 65535;
errtest = v;
t >>= 16;
errtest -= t;
if (errtest > err)
{
err = errtest;
xerr = x;
if (errtest >= .5)
{
fprintf(stderr, "error: %u/65535 = %f, not %u, error %f\n",
x, v, t, errtest);
return 0;
}
v /= 65535;
errtest = v;
t >>= 16;
errtest -= t;
if (errtest > err) {
err = errtest;
xerr = x;
if (errtest >= .5) {
fprintf(stderr, "error: %u/65535 = %f, not %u, error %f\n",
x, v, t, errtest);
return 0;
}
}
} while (++x <= 65535U*65535U);
}
}
} while (++x <= 65535U * 65535U);
printf("error %f @ %u\n", err, xerr);
@ -101,7 +108,7 @@ int main(void) {
static void
sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
png_imagep image, const png_uint_16 *buffer)
png_imagep image, const png_uint_16 *buffer)
{
/* This is where the Porter-Duff 'Over' operator is evaluated; change this
* code to change the operator (this could be parameterized). Any other
@ -112,8 +119,8 @@ sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
/* Check for an x or y offset that pushes any part of the image beyond the
* right or bottom of the sprite:
*/
if ((y_offset < 0 || (unsigned)/*SAFE*/y_offset < sprite->height) &&
(x_offset < 0 || (unsigned)/*SAFE*/x_offset < sprite->width))
if ((y_offset < 0 || /*SAFE*/ (unsigned)y_offset < sprite->height) &&
(x_offset < 0 || /*SAFE*/ (unsigned)x_offset < sprite->width))
{
unsigned int y = 0;
@ -130,7 +137,7 @@ sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
do
{
/* In and out are RGBA values, so: */
const png_uint_16 *in_pixel = buffer + (y * image->width + x)*4;
const png_uint_16 *in_pixel = buffer + (y * image->width + x) * 4;
png_uint_32 in_alpha = in_pixel[3];
/* This is the optimized Porter-Duff 'Over' operation, when the
@ -139,10 +146,10 @@ sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
if (in_alpha > 0)
{
png_uint_16 *out_pixel = sprite->buffer +
((y+y_offset) * sprite->width + (x+x_offset))*4;
((y + y_offset) * sprite->width + (x + x_offset)) * 4;
/* This is the weight to apply to the output: */
in_alpha = 65535-in_alpha;
in_alpha = 65535 - in_alpha;
if (in_alpha > 0)
{
@ -159,9 +166,9 @@ sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
*/
png_uint_32 tmp;
# define compose(c)\
tmp = out_pixel[c] * in_alpha;\
tmp = (tmp + (tmp >> 16) + 32769) >> 16;\
# define compose(c) \
tmp = out_pixel[c] * in_alpha; \
tmp = (tmp + (tmp >> 16) + 32769) >> 16; \
out_pixel[c] = tmp + in_pixel[c]
/* The following is very vectorizable... */
@ -172,15 +179,15 @@ sprite_op(const struct sprite *sprite, int x_offset, int y_offset,
}
else
out_pixel[0] = in_pixel[0],
out_pixel[1] = in_pixel[1],
out_pixel[2] = in_pixel[2],
{
out_pixel[0] = in_pixel[0];
out_pixel[1] = in_pixel[1];
out_pixel[2] = in_pixel[2];
out_pixel[3] = in_pixel[3];
}
}
}
while (++x < image->width);
}
while (++y < image->height);
} while (++x < image->width);
} while (++y < image->height);
}
}
@ -224,9 +231,8 @@ create_sprite(struct sprite *sprite, int *argc, const char ***argv)
if (buffer != NULL)
{
if (png_image_finish_read(&image, NULL/*background*/, buffer,
0/*row_stride*/,
NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
if (png_image_finish_read(&image, NULL /*background*/, buffer,
0 /*row_stride*/, NULL /*colormap*/))
{
/* This is the place where the Porter-Duff 'Over' operator
* needs to be done by this code. In fact, any image
@ -245,14 +251,14 @@ create_sprite(struct sprite *sprite, int *argc, const char ***argv)
{
free(buffer);
fprintf(stderr, "simpleover: read %s: %s\n", (*argv)[0],
image.message);
image.message);
}
}
else
{
fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
(unsigned long)PNG_IMAGE_SIZE(image));
(unsigned long)PNG_IMAGE_SIZE(image));
/* png_image_free must be called if we abort the Simplified API
* read because of a problem detected in this code. If problems
@ -290,8 +296,9 @@ create_sprite(struct sprite *sprite, int *argc, const char ***argv)
save.flags = PNG_IMAGE_FLAG_FAST;
save.colormap_entries = 0;
if (png_image_write_to_stdio(&save, sprite->file, 1/*convert_to_8_bit*/,
sprite->buffer, 0/*row_stride*/, NULL/*colormap*/))
if (png_image_write_to_stdio(&save, sprite->file, 1 /*convert_to_8_bit*/,
sprite->buffer, 0 /*row_stride*/,
NULL /*colormap*/))
{
/* Success; the buffer is no longer needed: */
free(sprite->buffer);
@ -301,19 +308,20 @@ create_sprite(struct sprite *sprite, int *argc, const char ***argv)
else
fprintf(stderr, "simpleover: write sprite %s: %s\n", sprite->name,
save.message);
save.message);
}
else
fprintf(stderr, "simpleover: sprite %s: could not allocate tmpfile: %s\n",
sprite->name, strerror(errno));
fprintf(stderr,
"simpleover: sprite %s: could not allocate tmpfile: %s\n",
sprite->name, strerror(errno));
return 0; /* fail */
}
static int
add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
int *argc, const char ***argv)
int *argc, const char ***argv)
{
/* Given a --add argument naming this sprite, perform the operations listed
* in the following arguments. The arguments are expected to have the form
@ -334,13 +342,13 @@ add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
* will fit.
*/
if (x < 0 || y < 0 ||
(unsigned)/*SAFE*/x >= output->width ||
(unsigned)/*SAFE*/y >= output->height ||
sprite->width > output->width-x ||
sprite->height > output->height-y)
/*SAFE*/ (unsigned)x >= output->width ||
/*SAFE*/ (unsigned)y >= output->height ||
sprite->width > output->width - x ||
sprite->height > output->height - y)
{
fprintf(stderr, "simpleover: sprite %s @ (%d,%d) outside image\n",
sprite->name, x, y);
sprite->name, x, y);
/* Could just skip this, but for the moment it is an error */
return 0; /* error */
}
@ -359,10 +367,10 @@ add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
{
in.format = PNG_FORMAT_RGB; /* force compose */
if (png_image_finish_read(&in, NULL/*background*/,
out_buf + (y*output->width + x)*3/*RGB*/,
output->width*3/*row_stride*/,
NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP*/))
if (png_image_finish_read(
&in, NULL /*background*/,
out_buf + (y * output->width + x) * 3 /*RGB*/,
output->width * 3 /*row_stride*/, NULL /*colormap*/))
{
++*argv, --*argc;
continue;
@ -371,7 +379,7 @@ add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
/* The read failed: */
fprintf(stderr, "simpleover: add sprite %s: %s\n", sprite->name,
in.message);
in.message);
return 0; /* error */
}
}
@ -379,7 +387,7 @@ add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
else
{
fprintf(stderr, "simpleover: --add='%s': invalid position %s\n",
sprite->name, (*argv)[0]);
sprite->name, (*argv)[0]);
return 0; /* error */
}
}
@ -389,10 +397,10 @@ add_sprite(png_imagep output, png_bytep out_buf, struct sprite *sprite,
static int
simpleover_process(png_imagep output, png_bytep out_buf, int argc,
const char **argv)
const char **argv)
{
int result = 1; /* success */
# define csprites 10/*limit*/
# define csprites 10 /*limit*/
# define str(a) #a
int nsprites = 0;
struct sprite sprites[csprites];
@ -412,23 +420,25 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
sprites[nsprites].width = sprites[nsprites].height = 0;
sprites[nsprites].name[0] = 0;
n = sscanf(argv[0], "--sprite=%u,%u,%" str(sprite_name_chars) "s%c",
&sprites[nsprites].width, &sprites[nsprites].height,
sprites[nsprites].name, &tombstone);
n = sscanf(argv[0],
"--sprite=%u,%u,%" str(sprite_name_chars) "s%c",
&sprites[nsprites].width, &sprites[nsprites].height,
sprites[nsprites].name, &tombstone);
if ((n == 2 || n == 3) &&
sprites[nsprites].width > 0 && sprites[nsprites].height > 0)
(sprites[nsprites].width > 0) &&
(sprites[nsprites].height > 0))
{
size_t buf_size, tmp;
/* Default a name if not given. */
if (sprites[nsprites].name[0] == 0)
sprintf(sprites[nsprites].name, "sprite-%d", nsprites+1);
sprintf(sprites[nsprites].name, "sprite-%d", nsprites + 1);
/* Allocate a buffer for the sprite and calculate the buffer
* size:
*/
buf_size = sizeof (png_uint_16 [4]);
buf_size = sizeof(png_uint_16[4]);
buf_size *= sprites[nsprites].width;
buf_size *= sprites[nsprites].height;
@ -437,7 +447,7 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
tmp /= sprites[nsprites].width;
tmp /= sprites[nsprites].height;
if (tmp == sizeof (png_uint_16 [4]))
if (tmp == sizeof(png_uint_16[4]))
{
sprites[nsprites].buffer = malloc(buf_size);
/* This buffer must be initialized to transparent: */
@ -448,7 +458,7 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
sprites[nsprites].file = NULL;
++argv, --argc;
if (create_sprite(sprites+nsprites++, &argc, &argv))
if (create_sprite(sprites + nsprites++, &argc, &argv))
{
result = 1; /* still ok */
continue;
@ -466,7 +476,8 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
else
{
fprintf(stderr, "simpleover: %s: invalid sprite (%u,%u)\n",
argv[0], sprites[nsprites].width, sprites[nsprites].height);
argv[0],
sprites[nsprites].width, sprites[nsprites].height);
break;
}
}
@ -480,7 +491,7 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
else if (strncmp(argv[0], "--add=", 6) == 0)
{
const char *name = argv[0]+6;
const char *name = argv[0] + 6;
int isprite = nsprites;
++argv, --argc;
@ -489,7 +500,8 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
{
if (strcmp(sprites[isprite].name, name) == 0)
{
if (!add_sprite(output, out_buf, sprites+isprite, &argc, &argv))
if (!add_sprite(output, out_buf, sprites + isprite,
&argc, &argv))
goto out; /* error in add_sprite */
break;
@ -498,7 +510,8 @@ simpleover_process(png_imagep output, png_bytep out_buf, int argc,
if (isprite < 0) /* sprite not found */
{
fprintf(stderr, "simpleover: --add='%s': sprite not found\n", name);
fprintf(stderr, "simpleover: --add='%s': sprite not found\n",
name);
break;
}
}
@ -526,7 +539,8 @@ out:
return result;
}
int main(int argc, const char **argv)
int
main(int argc, const char **argv)
{
int result = 1; /* default to fail */
@ -536,7 +550,7 @@ int main(int argc, const char **argv)
const char *output = NULL;
png_image image;
if (argc > 2 && argv[2][0] != '-'/*an operation*/)
if (argc > 2 && argv[2][0] != '-' /*an operation*/)
{
output = argv[2];
argi = 3;
@ -558,7 +572,7 @@ int main(int argc, const char **argv)
png_color background = {0, 0xff, 0}; /* fully saturated green */
if (png_image_finish_read(&image, &background, buffer,
0/*row_stride*/, NULL/*colormap for PNG_FORMAT_FLAG_COLORMAP */))
0 /*row_stride*/, NULL /*colormap*/))
{
/* At this point png_image_finish_read has cleaned up the
* allocated data in png_image, and only the buffer needs to be
@ -566,22 +580,24 @@ int main(int argc, const char **argv)
*
* Perform the remaining operations:
*/
if (simpleover_process(&image, buffer, argc-argi, argv+argi))
if (simpleover_process(&image, buffer,
argc - argi, argv + argi))
{
/* Write the output: */
if ((output != NULL &&
png_image_write_to_file(&image, output,
0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
NULL/*colormap*/)) ||
png_image_write_to_file(
&image, output, 0 /*convert_to_8bit*/, buffer,
0 /*row_stride*/, NULL /*colormap*/)) ||
(output == NULL &&
png_image_write_to_stdio(&image, stdout,
0/*convert_to_8bit*/, buffer, 0/*row_stride*/,
NULL/*colormap*/)))
png_image_write_to_stdio(
&image, stdout, 0 /*convert_to_8bit*/, buffer,
0 /*row_stride*/, NULL /*colormap*/)))
result = 0;
else
fprintf(stderr, "simpleover: write %s: %s\n",
output == NULL ? "stdout" : output, image.message);
output == NULL ? "stdout" : output,
image.message);
}
/* else simpleover_process writes an error message */
@ -589,7 +605,7 @@ int main(int argc, const char **argv)
else
fprintf(stderr, "simpleover: read %s: %s\n", argv[1],
image.message);
image.message);
free(buffer);
}
@ -597,7 +613,7 @@ int main(int argc, const char **argv)
else
{
fprintf(stderr, "simpleover: out of memory: %lu bytes\n",
(unsigned long)PNG_IMAGE_SIZE(image));
(unsigned long)PNG_IMAGE_SIZE(image));
/* This is the only place where a 'free' is required; libpng does
* the cleanup on error and success, but in this case we couldn't
@ -617,7 +633,8 @@ int main(int argc, const char **argv)
else
{
/* Usage message */
fprintf(stderr,
fprintf(
stderr,
"simpleover: usage: simpleover background.png [output.png]\n"
" Output 'background.png' as a 24-bit RGB PNG file in 'output.png'\n"
" or, if not given, stdout. 'background.png' will be composited\n"
@ -628,13 +645,13 @@ int main(int argc, const char **argv)
" --sprite=width,height,name {[--at=x,y] {sprite.png}}\n"
" Produce a transparent sprite of size (width,height) and with\n"
" name 'name'.\n"
" For each sprite.png composite it using a Porter-Duff 'Over'\n"
" operation at offset (x,y) in the sprite (defaulting to (0,0)).\n"
" For each sprite.png composite it is using a Porter-Duff 'Over'\n"
" operation at offset (x,y) in the sprite, defaulting to (0,0).\n"
" Input PNGs will be truncated to the area of the sprite.\n"
"\n"
" --add='name' {x,y}\n"
" Optionally, before output, composite a sprite, 'name', which\n"
" must have been previously produced using --sprite, at each\n"
" must have been previously produced using --sprite at each\n"
" offset (x,y) in the output image. Each sprite must fit\n"
" completely within the output image.\n"
"\n"
@ -645,4 +662,3 @@ int main(int argc, const char **argv)
return result;
}
#endif /* SIMPLIFIED_READ */

View file

@ -21,7 +21,7 @@
- 1.10: added support for non-default visuals; fixed X pixel-conversion
- 1.11: added extra set of parentheses to png_jmpbuf() macro; fixed
command-line parsing bug
- 1.12: fixed some small X memory leaks (thanks to François Petitjean)
- 1.12: fixed some small X memory leaks (thanks to François Petitjean)
- 1.13: fixed XFreeGC() crash bug (thanks to Patrick Welche)
- 1.14: added support for X resources (thanks to Gerhard Niklasch)
- 2.00: dual-licensed (added GNU GPL)

View file

@ -27,7 +27,7 @@
- 1.11: added -usleep option for demos; fixed command-line parsing bug
- 1.12: added -pause option for demos and testing
- 1.20: added runtime MMX-enabling/disabling and new -mmx* options
- 1.21: fixed some small X memory leaks (thanks to François Petitjean)
- 1.21: fixed some small X memory leaks (thanks to François Petitjean)
- 1.22: fixed XFreeGC() crash bug (thanks to Patrick Welche)
- 1.23: added -bgpat 0 mode (std white/gray checkerboard, 8x8 squares)
- 1.30: added -loop option for -bgpat (ifdef FEATURE_LOOP); fixed bpp =

View file

@ -2,8 +2,6 @@
#
# Copyright (c) 2013 John Cunningham Bowler
#
# Last changed in libpng 1.6.0 [February 14, 2013]
#
# This code is released under the libpng license.
# For conditions of distribution and use, see the disclaimer
# and license in png.h

View file

@ -3,8 +3,6 @@
/* Copyright: */
#define COPYRIGHT "\251 2013,2015 John Cunningham Bowler"
/*
* Last changed in libpng 1.6.20 [November 24, 2015]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@ -299,25 +297,28 @@ generate_palette(png_colorp palette, png_bytep trans, int bit_depth,
unsigned int x, y;
volatile unsigned int ip = 0;
for (x=0; x<size; ++x) for (y=0; y<size; ++y)
for (x=0; x<size; ++x)
{
ip = x + (size * y);
for (y=0; y<size; ++y)
{
ip = x + (size * y);
/* size is at most 16, so the scaled value below fits in 16 bits
*/
# define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
# define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
(interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
(size*size))
/* size is at most 16, so the scaled value below fits in 16 bits
*/
# define interp(pos, c1, c2) ((pos * c1) + ((size-pos) * c2))
# define xyinterp(x, y, c1, c2, c3, c4) (((size * size / 2) +\
(interp(x, c1, c2) * y + (size-y) * interp(x, c3, c4))) /\
(size*size))
set_color(palette+ip, trans+ip,
/* color: green, red,blue,white */
xyinterp(x, y, 0, 255, 0, 255),
xyinterp(x, y, 255, 0, 0, 255),
xyinterp(x, y, 0, 0, 255, 255),
/* alpha: 0, 102, 204, 255) */
xyinterp(x, y, 0, 102, 204, 255),
gamma_table);
set_color(palette+ip, trans+ip,
/* color: green, red,blue,white */
xyinterp(x, y, 0, 255, 0, 255),
xyinterp(x, y, 255, 0, 0, 255),
xyinterp(x, y, 0, 0, 255, 255),
/* alpha: 0, 102, 204, 255) */
xyinterp(x, y, 0, 102, 204, 255),
gamma_table);
}
}
return ip+1;
@ -396,7 +397,7 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
image_size_of_type(color_type, bit_depth, colors, small)-1;
png_uint_32 depth_max = (1U << bit_depth)-1; /* up to 65536 */
if (colors[0] == 0) if (small)
if (colors[0] == 0 && small)
{
unsigned int pixel_depth = pixel_depth_of_type(color_type, bit_depth);
@ -495,7 +496,7 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type,
case 32:
case 48:
case 64:
/* The rows are filled by an alogorithm similar to the above, in the
/* The rows are filled by an algorithm similar to the above, in the
* first row pixel bytes are all equal, increasing from 0 by 1 for
* each pixel. In the second row the bytes within a pixel are
* incremented 1,3,5,7,... from the previous row byte. Using an odd
@ -858,10 +859,13 @@ write_png(const char **name, FILE *fp, int color_type, int bit_depth,
{
unsigned int i;
if (real_gamma == 45455) for (i=0; i<256; ++i)
if (real_gamma == 45455)
{
gamma_table[i] = (png_byte)i;
conv = 1.;
for (i=0; i<256; ++i)
{
gamma_table[i] = (png_byte)i;
conv = 1.;
}
}
else
@ -1430,10 +1434,13 @@ find_parameters(png_const_charp what, png_charp param, png_charp *list,
for (i=0; *param && i<nparams; ++i)
{
list[i] = param;
while (*++param) if (*param == '\n' || *param == ':')
while (*++param)
{
*param++ = 0; /* Terminate last parameter */
break; /* And start a new one. */
if (*param == '\n' || *param == ':')
{
*param++ = 0; /* Terminate last parameter */
break; /* And start a new one. */
}
}
}
@ -1869,7 +1876,7 @@ main(int argc, char **argv)
}
}
/* small and colors are incomparible (will probably crash if both are used at
/* small and colors are incompatible (will probably crash if both are used at
* the same time!)
*/
if (small && colors[0] != 0)

View file

@ -1,9 +1,8 @@
/* pngimage.c
*
* Copyright (c) 2021-2025 Cosmin Truta
* Copyright (c) 2015,2016 John Cunningham Bowler
*
* Last changed in libpng 1.6.24 [August 4, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@ -12,6 +11,7 @@
* using png_read_png and then write with png_write_png. Test all possible
* transforms.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@ -39,7 +39,7 @@
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
* a skipped test, in earlier versions we need to succeed on a skipped test, so:
*/
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#if defined(HAVE_CONFIG_H)
# define SKIP 77
#else
# define SKIP 0
@ -317,11 +317,10 @@ transform_name(int t)
t &= -t; /* first set bit */
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
{
if ((transform_info[i].transform & t) != 0)
return transform_info[i].name;
}
for (i=0; i<TTABLE_SIZE; ++i)
if (transform_info[i].name != NULL)
if ((transform_info[i].transform & t) != 0)
return transform_info[i].name;
return "invalid transform";
}
@ -338,13 +337,16 @@ validate_T(void)
{
unsigned int i;
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
for (i=0; i<TTABLE_SIZE; ++i)
{
if (transform_info[i].when & TRANSFORM_R)
read_transforms |= transform_info[i].transform;
if (transform_info[i].name != NULL)
{
if (transform_info[i].when & TRANSFORM_R)
read_transforms |= transform_info[i].transform;
if (transform_info[i].when & TRANSFORM_W)
write_transforms |= transform_info[i].transform;
if (transform_info[i].when & TRANSFORM_W)
write_transforms |= transform_info[i].transform;
}
}
/* Reversible transforms are those which are supported on both read and
@ -540,6 +542,7 @@ typedef enum
struct display
{
jmp_buf error_return; /* Where to go to on error */
error_level error_code; /* Set before longjmp */
const char *filename; /* The name of the original file */
const char *operation; /* Operation being performed */
@ -760,7 +763,10 @@ display_log(struct display *dp, error_level level, const char *fmt, ...)
/* Errors cause this routine to exit to the fail code */
if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
{
dp->error_code = level;
longjmp(dp->error_return, level);
}
}
/* error handler callbacks for libpng */
@ -962,21 +968,24 @@ update_display(struct display *dp)
int bd = dp->bit_depth;
unsigned int i;
for (i=0; i<TTABLE_SIZE; ++i) if (transform_info[i].name != NULL)
for (i=0; i<TTABLE_SIZE; ++i)
{
int transform = transform_info[i].transform;
if (transform_info[i].name != NULL)
{
int transform = transform_info[i].transform;
if ((transform_info[i].valid_chunks == 0 ||
(transform_info[i].valid_chunks & chunks) != 0) &&
(transform_info[i].color_mask_required & ct) ==
transform_info[i].color_mask_required &&
(transform_info[i].color_mask_absent & ct) == 0 &&
(transform_info[i].bit_depths & bd) != 0 &&
(transform_info[i].when & TRANSFORM_R) != 0)
active |= transform;
if ((transform_info[i].valid_chunks == 0 ||
(transform_info[i].valid_chunks & chunks) != 0) &&
(transform_info[i].color_mask_required & ct) ==
transform_info[i].color_mask_required &&
(transform_info[i].color_mask_absent & ct) == 0 &&
(transform_info[i].bit_depths & bd) != 0 &&
(transform_info[i].when & TRANSFORM_R) != 0)
active |= transform;
else if ((transform_info[i].when & TRANSFORM_R) != 0)
inactive |= transform;
else if ((transform_info[i].when & TRANSFORM_R) != 0)
inactive |= transform;
}
}
/* Some transforms appear multiple times in the table; the 'active' status
@ -1000,8 +1009,9 @@ compare_read(struct display *dp, int applied_transforms)
int interlace_method, compression_method, filter_method;
const char *e = NULL;
png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth,
&color_type, &interlace_method, &compression_method, &filter_method);
if (!png_get_IHDR(dp->read_pp, dp->read_ip, &width, &height, &bit_depth,
&color_type, &interlace_method, &compression_method, &filter_method))
display_log(dp, LIBPNG_BUG, "png_get_IHDR failed");
# define C(item) if (item != dp->item) \
display_log(dp, APP_WARNING, "IHDR " #item "(%lu) changed to %lu",\
@ -1012,7 +1022,12 @@ compare_read(struct display *dp, int applied_transforms)
C(height);
C(bit_depth);
C(color_type);
C(interlace_method);
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* If write interlace has been disabled, the PNG file is still
* written correctly, but as a regular (not-interlaced) PNG.
*/
C(interlace_method);
# endif
C(compression_method);
C(filter_method);
@ -1081,8 +1096,9 @@ compare_read(struct display *dp, int applied_transforms)
size_t x;
/* Find the first error */
for (x=0; x<rowbytes-1; ++x) if (row[x] != orig[x])
break;
for (x=0; x<rowbytes-1; ++x)
if (row[x] != orig[x])
break;
display_log(dp, APP_FAIL,
"byte(%lu,%lu) changed 0x%.2x -> 0x%.2x",
@ -1137,6 +1153,7 @@ compare_read(struct display *dp, int applied_transforms)
display_log(dp, LIBPNG_ERROR, "invalid colour type %d",
color_type);
/*NOTREACHED*/
memset(sig_bits, 0, sizeof(sig_bits));
bpp = 0;
break;
}
@ -1198,7 +1215,7 @@ compare_read(struct display *dp, int applied_transforms)
sig_bits[0] = (png_byte)b;
break;
case 4: /* Relicate twice */
case 4: /* Replicate twice */
/* Value is 1, 2, 3 or 4 */
b = 0xf & ((0xf << 4) >> sig_bits[0]);
b |= b << 4;
@ -1557,18 +1574,19 @@ static int
do_test(struct display *dp, const char *file)
/* Exists solely to isolate the setjmp clobbers */
{
int ret = setjmp(dp->error_return);
dp->error_code = VERBOSE; /* The "lowest" level */
if (ret == 0)
if (setjmp(dp->error_return) == 0)
{
test_one_file(dp, file);
return 0;
}
else if (ret < ERRORS) /* shouldn't longjmp on warnings */
display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
else if (dp->error_code < ERRORS) /* shouldn't longjmp on warnings */
display_log(dp, INTERNAL_ERROR, "unexpected return code %d",
dp->error_code);
return ret;
return dp->error_code;
}
int
@ -1668,7 +1686,11 @@ main(int argc, char **argv)
int ret = do_test(&d, argv[i]);
if (ret > QUIET) /* abort on user or internal error */
{
display_clean(&d);
display_destroy(&d);
return 99;
}
}
/* Here on any return, including failures, except user/internal issues
@ -1686,8 +1708,9 @@ main(int argc, char **argv)
printf("%s: pngimage ", pass ? "PASS" : "FAIL");
for (j=1; j<option_end; ++j) if (j != ilog)
printf("%s ", argv[j]);
for (j=1; j<option_end; ++j)
if (j != ilog)
printf("%s ", argv[j]);
printf("%s\n", d.filename);
}

View file

@ -1,7 +1,6 @@
/*-
* pngstest.c
/* pngstest.c
*
* Last changed in libpng 1.6.31 [July 27, 2017]
* Copyright (c) 2021-2025 Cosmin Truta
* Copyright (c) 2013-2017 John Cunningham Bowler
*
* This code is released under the libpng license.
@ -10,8 +9,9 @@
*
* Test for the PNG 'simplified' APIs.
*/
#define _ISOC90_SOURCE 1
#define MALLOC_CHECK_ 2/*glibc facility: turn on debugging*/
#define MALLOC_CHECK_ 2 /*glibc facility: turn on debugging*/
#include <stddef.h>
#include <stdlib.h>
@ -37,7 +37,7 @@
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
* a skipped test, in earlier versions we need to succeed on a skipped test, so:
*/
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#if defined(HAVE_CONFIG_H)
# define SKIP 77
#else
# define SKIP 0
@ -595,7 +595,8 @@ newimage(Image *image)
memset(image, 0, sizeof *image);
}
/* Reset the image to be read again - only needs to rewind the FILE* at present.
/* Reset the image to be read again - only needs to rewind the FILE object at
* present.
*/
static void
resetimage(Image *image)
@ -1150,7 +1151,7 @@ get_pixel(png_uint_32 format))(Pixel *p, png_const_voidp pb)
*
* 2) Remove color by mapping to grayscale. (Grayscale to color is a no-op.)
*
* 3) Convert between 8-bit and 16-bit components. (Both directtions are
* 3) Convert between 8-bit and 16-bit components. (Both directions are
* relevant.)
*
* This gives the following base format conversion matrix:
@ -2701,7 +2702,7 @@ compare_two_images(Image *a, Image *b, int via_linear,
{
if ((a->opts & ACCUMULATE) == 0)
{
char pindex[9];
char pindex[16];
sprintf(pindex, "%lu[%lu]", (unsigned long)y,
(unsigned long)a->image.colormap_entries);
logerror(a, a->file_name, ": bad pixel index: ", pindex);
@ -2712,12 +2713,12 @@ compare_two_images(Image *a, Image *b, int via_linear,
else if (y >= b->image.colormap_entries)
{
if ((b->opts & ACCUMULATE) == 0)
{
char pindex[9];
{
char pindex[16];
sprintf(pindex, "%lu[%lu]", (unsigned long)y,
(unsigned long)b->image.colormap_entries);
logerror(b, b->file_name, ": bad pixel index: ", pindex);
}
}
result = 0;
}
@ -2820,8 +2821,11 @@ compare_two_images(Image *a, Image *b, int via_linear,
bchannels = component_loc(bloc, formatb);
/* Hence the btoa array. */
for (i=0; i<4; ++i) if (bloc[i] < 4)
btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */
for (i=0; i<4; ++i)
{
if (bloc[i] < 4)
btoa[bloc[i]] = aloc[i]; /* may be '4' for alpha */
}
if (alpha_added)
alpha_added = bloc[0]; /* location of alpha channel in image b */
@ -3209,10 +3213,10 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
else if (image->opts & USE_FILE)
{
#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
static int counter = 0;
static unsigned int counter = 0;
char name[32];
sprintf(name, "%s%d.png", tmpf, ++counter);
sprintf(name, "%s%u.png", tmpf, ++counter);
if (png_image_write_to_file(&image->image, name, convert_to_8bit,
image->buffer+16, (png_int_32)image->stride, image->colormap))
@ -3496,7 +3500,7 @@ main(int argc, char **argv)
int retval = 0;
int c;
#if PNG_LIBPNG_VER >= 10700
#if PNG_LIBPNG_VER == 10700
/* This error should not exist in 1.7 or later: */
opts |= GBG_ERROR;
#endif

View file

@ -1,7 +1,6 @@
/* pngunknown.c - test the read side unknown chunk handling
*
* Last changed in libpng 1.6.32 [August 24, 2017]
* Copyright (c) 2021-2025 Cosmin Truta
* Copyright (c) 2015,2017 Glenn Randers-Pehrson
* Written by John Cunningham Bowler
*
@ -33,7 +32,7 @@
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
* a skipped test, in earlier versions we need to succeed on a skipped test, so:
*/
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#if defined(HAVE_CONFIG_H)
# define SKIP 77
#else
# define SKIP 0
@ -55,48 +54,7 @@
#if defined(PNG_READ_USER_CHUNKS_SUPPORTED) ||\
defined(PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED)
#if PNG_LIBPNG_VER < 10500
/* This deliberately lacks the const. */
typedef png_byte *png_const_bytep;
/* This is copied from 1.5.1 png.h: */
#define PNG_INTERLACE_ADAM7_PASSES 7
#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7)
#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7)
#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)
#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)
#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\
-1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass))
#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\
-1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass))
#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \
(((yIn)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass))
#define PNG_COL_FROM_PASS_COL(xIn, pass) \
(((xIn)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass))
#define PNG_PASS_MASK(pass,off) ( \
((0x110145AFU>>(((7-(off))-(pass))<<2)) & 0xFU) | \
((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U))
#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \
((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)
#define PNG_COL_IN_INTERLACE_PASS(x, pass) \
((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
/* These are needed too for the default build: */
#define PNG_WRITE_16BIT_SUPPORTED
#define PNG_READ_16BIT_SUPPORTED
/* This comes from pnglibconf.h after 1.5: */
#define PNG_FP_1 100000
#define PNG_GAMMA_THRESHOLD_FIXED\
((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1))
#endif
#if PNG_LIBPNG_VER < 10600
/* 1.6.0 constifies many APIs. The following exists to allow pngvalid to be
* compiled against earlier versions.
*/
# define png_const_structp png_structp
#endif
#if PNG_LIBPNG_VER < 10700
/* Copied from libpng 1.7.0 png.h */
@ -114,6 +72,8 @@ typedef png_byte *png_const_bytep;
#define png_PLTE PNG_U32( 80, 76, 84, 69)
#define png_bKGD PNG_U32( 98, 75, 71, 68)
#define png_cHRM PNG_U32( 99, 72, 82, 77)
#define png_cICP PNG_U32( 99, 73, 67, 80) /* PNGv3 */
#define png_cLLI PNG_U32( 99, 76, 76, 73) /* PNGv3 */
#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */
#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */
#define png_gAMA PNG_U32(103, 65, 77, 65)
@ -123,6 +83,7 @@ typedef png_byte *png_const_bytep;
#define png_hIST PNG_U32(104, 73, 83, 84)
#define png_iCCP PNG_U32(105, 67, 67, 80)
#define png_iTXt PNG_U32(105, 84, 88, 116)
#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */
#define png_oFFs PNG_U32(111, 70, 70, 115)
#define png_pCAL PNG_U32(112, 67, 65, 76)
#define png_pHYs PNG_U32(112, 72, 89, 115)
@ -209,6 +170,20 @@ static struct
0,
# else
1,
# endif
1, START, 0 },
{ "cICP", PNG_INFO_cICP, png_cICP,
# ifdef PNG_READ_cICP_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "cLLI", PNG_INFO_cLLI, png_cLLI,
# ifdef PNG_READ_cLLI_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "eXIf", PNG_INFO_eXIf, png_eXIf,
@ -246,6 +221,13 @@ static struct
1,
# endif
1, ABSENT, 0 },
{ "mDCV", PNG_INFO_mDCV, png_mDCV,
# ifdef PNG_READ_mDCV_SUPPORTED
0,
# else
1,
# endif
1, START, 0 },
{ "oFFs", PNG_INFO_oFFs, png_oFFs,
# ifdef PNG_READ_oFFs_SUPPORTED
0,
@ -370,7 +352,9 @@ find_by_flag(png_uint_32 flag)
{
int i = NINFO;
while (--i >= 0) if (chunk_info[i].flag == flag) return i;
while (--i >= 0)
if (chunk_info[i].flag == flag)
return i;
fprintf(stderr, "pngunknown: internal error\n");
exit(4);
@ -547,27 +531,30 @@ read_callback(png_structp pp, png_unknown_chunkp pc)
case PNG_HANDLE_CHUNK_AS_DEFAULT:
case PNG_HANDLE_CHUNK_NEVER:
discard = 1/*handled; discard*/;
discard = 1; /*handled; discard*/
break;
case PNG_HANDLE_CHUNK_IF_SAFE:
case PNG_HANDLE_CHUNK_ALWAYS:
discard = 0/*not handled; keep*/;
discard = 0; /*not handled; keep*/
break;
}
/* Also store information about this chunk in the display, the relevant flag
* is set if the chunk is to be kept ('not handled'.)
*/
if (chunk >= 0) if (!discard) /* stupidity to stop a GCC warning */
if (chunk >= 0)
{
png_uint_32 flag = chunk_info[chunk].flag;
if (!discard) /* stupidity to stop a GCC warning */
{
png_uint_32 flag = chunk_info[chunk].flag;
if (pc->location & PNG_AFTER_IDAT)
d->after_IDAT |= flag;
if (pc->location & PNG_AFTER_IDAT)
d->after_IDAT |= flag;
else
d->before_IDAT |= flag;
else
d->before_IDAT |= flag;
}
}
/* However if there is no support to store unknown chunks don't ask libpng to
@ -841,8 +828,9 @@ check(FILE *fp, int argc, const char **argv, png_uint_32p flags/*out*/,
{
png_uint_32 y;
for (y=0; y<height; ++y) if (PNG_ROW_IN_INTERLACE_PASS(y, ipass))
png_read_row(d->png_ptr, NULL, NULL);
for (y=0; y<height; ++y)
if (PNG_ROW_IN_INTERLACE_PASS(y, ipass))
png_read_row(d->png_ptr, NULL, NULL);
}
}
} /* interlaced */
@ -1091,15 +1079,15 @@ perform_one_test_safe(FILE *fp, int argc, const char **argv,
static const char *standard_tests[] =
{
"discard", "default=discard", 0,
"save", "default=save", 0,
"if-safe", "default=if-safe", 0,
"vpAg", "vpAg=if-safe", 0,
"sTER", "sTER=if-safe", 0,
"IDAT", "default=discard", "IDAT=save", 0,
"sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save",
"sBIT=save", "sRGB=save", "eXIf=save", 0,
0/*end*/
"discard", "default=discard", NULL,
"save", "default=save", NULL,
"if-safe", "default=if-safe", NULL,
"vpAg", "vpAg=if-safe", NULL,
"sTER", "sTER=if-safe", NULL,
"IDAT", "default=discard", "IDAT=save", NULL,
"sAPI", "bKGD=save", "cHRM=save", "gAMA=save", "all=discard", "iCCP=save",
"sBIT=save", "sRGB=save", "eXIf=save", NULL,
NULL /*end*/
};
static PNG_NORETURN void
@ -1115,7 +1103,7 @@ int
main(int argc, const char **argv)
{
FILE *fp;
png_uint_32 default_flags[4/*valid,unknown{before,after}*/];
png_uint_32 default_flags[4]; /*valid,unknown{before,after}*/
int strict = 0, default_tests = 0;
const char *count_argv = "default=save";
const char *touch_file = NULL;
@ -1153,8 +1141,9 @@ main(int argc, const char **argv)
/* GCC BUG: if (default_tests && argc != 1) triggers some weird GCC argc
* optimization which causes warnings with -Wstrict-overflow!
*/
else if (default_tests) if (argc != 1)
usage(d.program, "extra arguments");
else if (default_tests)
if (argc != 1)
usage(d.program, "extra arguments");
/* The name of the test file is the last argument; remove it. */
d.file = argv[--argc];
@ -1216,7 +1205,11 @@ main(int argc, const char **argv)
const char *result;
int arg_count = 0;
while (*next) ++next, ++arg_count;
while (*next != NULL)
{
++next;
++arg_count;
}
perform_one_test_safe(fp, arg_count, test, default_flags, &d,
this_test);

View file

@ -1,7 +1,6 @@
/* pngvalid.c - validate libpng by constructing then reading png files.
*
* Last changed in libpng 1.6.31 [July 27, 2017]
* Copyright (c) 2021-2025 Cosmin Truta
* Copyright (c) 2014-2017 John Cunningham Bowler
*
* This code is released under the libpng license.
@ -22,6 +21,7 @@
#define _ISOC99_SOURCE 1 /* For floating point */
#define _GNU_SOURCE 1 /* For the floating point exception extension */
#define _BSD_SOURCE 1 /* For the floating point exception extension */
#define _DEFAULT_SOURCE 1 /* For the floating point exception extension */
#include <signal.h>
#include <stdio.h>
@ -62,59 +62,21 @@
/* 1.6.1 added support for the configure test harness, which uses 77 to indicate
* a skipped test, in earlier versions we need to succeed on a skipped test, so:
*/
#if PNG_LIBPNG_VER >= 10601 && defined(HAVE_CONFIG_H)
#if defined(HAVE_CONFIG_H)
# define SKIP 77
#else
# define SKIP 0
#endif
/* pngvalid requires write support and one of the fixed or floating point APIs.
* progressive read is also required currently as the progressive read pointer
* is used to record the 'display' structure.
*/
#if defined(PNG_WRITE_SUPPORTED) &&\
(defined(PNG_FIXED_POINT_SUPPORTED) || defined(PNG_FLOATING_POINT_SUPPORTED))
#if defined PNG_WRITE_SUPPORTED &&\
(defined PNG_PROGRESSIVE_READ_SUPPORTED) &&\
(defined PNG_FIXED_POINT_SUPPORTED || defined PNG_FLOATING_POINT_SUPPORTED)
#if PNG_LIBPNG_VER < 10500
/* This deliberately lacks the const. */
typedef png_byte *png_const_bytep;
/* This is copied from 1.5.1 png.h: */
#define PNG_INTERLACE_ADAM7_PASSES 7
#define PNG_PASS_START_ROW(pass) (((1U&~(pass))<<(3-((pass)>>1)))&7)
#define PNG_PASS_START_COL(pass) (((1U& (pass))<<(3-(((pass)+1)>>1)))&7)
#define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3)
#define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3)
#define PNG_PASS_ROWS(height, pass) (((height)+(((1<<PNG_PASS_ROW_SHIFT(pass))\
-1)-PNG_PASS_START_ROW(pass)))>>PNG_PASS_ROW_SHIFT(pass))
#define PNG_PASS_COLS(width, pass) (((width)+(((1<<PNG_PASS_COL_SHIFT(pass))\
-1)-PNG_PASS_START_COL(pass)))>>PNG_PASS_COL_SHIFT(pass))
#define PNG_ROW_FROM_PASS_ROW(yIn, pass) \
(((yIn)<<PNG_PASS_ROW_SHIFT(pass))+PNG_PASS_START_ROW(pass))
#define PNG_COL_FROM_PASS_COL(xIn, pass) \
(((xIn)<<PNG_PASS_COL_SHIFT(pass))+PNG_PASS_START_COL(pass))
#define PNG_PASS_MASK(pass,off) ( \
((0x110145AFU>>(((7-(off))-(pass))<<2)) & 0xFU) | \
((0x01145AF0U>>(((7-(off))-(pass))<<2)) & 0xF0U))
#define PNG_ROW_IN_INTERLACE_PASS(y, pass) \
((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1)
#define PNG_COL_IN_INTERLACE_PASS(x, pass) \
((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1)
/* These are needed too for the default build: */
#define PNG_WRITE_16BIT_SUPPORTED
#define PNG_READ_16BIT_SUPPORTED
/* This comes from pnglibconf.h after 1.5: */
#define PNG_FP_1 100000
#define PNG_GAMMA_THRESHOLD_FIXED\
((png_fixed_point)(PNG_GAMMA_THRESHOLD * PNG_FP_1))
#endif
#if PNG_LIBPNG_VER < 10600
/* 1.6.0 constifies many APIs, the following exists to allow pngvalid to be
* compiled against earlier versions.
*/
# define png_const_structp png_structp
#endif
#ifndef RELEASE_BUILD
/* RELEASE_BUILD is true for releases and release candidates: */
@ -300,20 +262,20 @@ make_four_random_bytes(png_uint_32* seed, png_bytep bytes)
#if defined PNG_READ_SUPPORTED || defined PNG_WRITE_tRNS_SUPPORTED ||\
defined PNG_WRITE_FILTER_SUPPORTED
static void
randomize(void *pv, size_t size)
randomize_bytes(void *pv, size_t size)
{
static png_uint_32 random_seed[2] = {0x56789abc, 0xd};
make_random_bytes(random_seed, pv, size);
}
#define R8(this) randomize(&(this), sizeof (this))
#define R8(this) randomize_bytes(&(this), sizeof (this))
#ifdef PNG_READ_SUPPORTED
static png_byte
random_byte(void)
{
unsigned char b1[1];
randomize(b1, sizeof b1);
randomize_bytes(b1, sizeof b1);
return b1[0];
}
#endif /* READ */
@ -322,7 +284,7 @@ static png_uint_16
random_u16(void)
{
unsigned char b2[2];
randomize(b2, sizeof b2);
randomize_bytes(b2, sizeof b2);
return png_get_uint_16(b2);
}
@ -332,7 +294,7 @@ static png_uint_32
random_u32(void)
{
unsigned char b4[4];
randomize(b4, sizeof b4);
randomize_bytes(b4, sizeof b4);
return png_get_uint_32(b4);
}
#endif /* READ_FILLER || READ_RGB_TO_GRAY */
@ -644,34 +606,8 @@ row_copy(png_bytep toBuffer, png_const_bytep fromBuffer, unsigned int bitWidth,
static int
pixel_cmp(png_const_bytep pa, png_const_bytep pb, png_uint_32 bit_width)
{
#if PNG_LIBPNG_VER < 10506
if (memcmp(pa, pb, bit_width>>3) == 0)
{
png_uint_32 p;
if ((bit_width & 7) == 0) return 0;
/* Ok, any differences? */
p = pa[bit_width >> 3];
p ^= pb[bit_width >> 3];
if (p == 0) return 0;
/* There are, but they may not be significant, remove the bits
* after the end (the low order bits in PNG.)
*/
bit_width &= 7;
p >>= 8-bit_width;
if (p == 0) return 0;
}
#else
/* From libpng-1.5.6 the overwrite should be fixed, so compare the trailing
* bits too:
*/
if (memcmp(pa, pb, (bit_width+7)>>3) == 0)
return 0;
#endif
/* Return the index of the changed byte. */
{
@ -2570,7 +2506,7 @@ modifier_init(png_modifier *pm)
* in the rgb_to_gray check, replacing it with an exact copy of the libpng 1.5
* algorithm.
*/
#define DIGITIZE PNG_LIBPNG_VER < 10700
#define DIGITIZE PNG_LIBPNG_VER != 10700
/* If pm->calculations_use_input_precision is set then operations will happen
* with the precision of the input, not the precision of the output depth.
@ -3982,7 +3918,7 @@ transform_row(png_const_structp pp, png_byte buffer[TRANSFORM_ROWMAX],
# define check_interlace_type(type) ((void)(type))
# define set_write_interlace_handling(pp,type) png_set_interlace_handling(pp)
# define do_own_interlace 0
#elif PNG_LIBPNG_VER < 10700
#elif PNG_LIBPNG_VER != 10700
# define set_write_interlace_handling(pp,type) (1)
static void
check_interlace_type(int const interlace_type)
@ -4010,7 +3946,7 @@ check_interlace_type(int const interlace_type)
# define do_own_interlace 1
#endif /* WRITE_INTERLACING tests */
#if PNG_LIBPNG_VER >= 10700 || defined PNG_WRITE_INTERLACING_SUPPORTED
#if PNG_LIBPNG_VER == 10700 || defined PNG_WRITE_INTERLACING_SUPPORTED
# define CAN_WRITE_INTERLACE 1
#else
# define CAN_WRITE_INTERLACE 0
@ -4629,10 +4565,10 @@ static const struct
{
/* no warnings makes these errors undetectable prior to 1.7.0 */
{ sBIT0_error_fn, "sBIT(0): failed to detect error",
PNG_LIBPNG_VER < 10700 },
PNG_LIBPNG_VER != 10700 },
{ sBIT_error_fn, "sBIT(too big): failed to detect error",
PNG_LIBPNG_VER < 10700 },
PNG_LIBPNG_VER != 10700 },
};
static void
@ -4848,9 +4784,7 @@ perform_formatting_test(png_store *ps)
{
png_const_charp correct = "29 Aug 2079 13:53:60 +0000";
png_const_charp result;
# if PNG_LIBPNG_VER >= 10600
char timestring[29];
# endif
char timestring[29];
png_structp pp;
png_time pt;
@ -5822,8 +5756,9 @@ test_standard(png_modifier* const pm, png_byte const colour_type,
for (interlace_type = PNG_INTERLACE_NONE;
interlace_type < INTERLACE_LAST; ++interlace_type)
{
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
interlace_type, 0, 0, 0), do_read_interlace, pm->use_update_info);
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, interlace_type, 0, 0, 0), do_read_interlace,
pm->use_update_info);
if (fail(pm))
return 0;
@ -5876,47 +5811,50 @@ test_size(png_modifier* const pm, png_byte const colour_type,
{
png_uint_32 h, w;
for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo])
for (h=1; h<=16; h+=hinc[bdlo])
{
/* First test all the 'size' images against the sequential
* reader using libpng to deinterlace (where required.) This
* validates the write side of libpng. There are four possibilities
* to validate.
*/
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/,
pm->use_update_info);
for (w=1; w<=16; w+=winc[bdlo])
{
/* First test all the 'size' images against the sequential
* reader using libpng to deinterlace (where required.) This
* validates the write side of libpng. There are four possibilities
* to validate.
*/
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_NONE, w, h, 0), 0/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
if (fail(pm))
return 0;
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/,
pm->use_update_info);
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_NONE, w, h, 1), 0/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
if (fail(pm))
return 0;
/* Now validate the interlaced read side - do_interlace true,
* in the progressive case this does actually make a difference
* to the code used in the non-interlaced case too.
*/
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/,
pm->use_update_info);
/* Now validate the interlaced read side - do_interlace true,
* in the progressive case this does actually make a difference
* to the code used in the non-interlaced case too.
*/
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_NONE, w, h, 0), 1/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
if (fail(pm))
return 0;
# if CAN_WRITE_INTERLACE
/* Validate the pngvalid code itself: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_ADAM7, w, h, 1), 1/*do_interlace*/,
pm->use_update_info);
# if CAN_WRITE_INTERLACE
/* Validate the pngvalid code itself: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_ADAM7, w, h, 1), 1/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
# endif
if (fail(pm))
return 0;
# endif
}
}
}
@ -5927,45 +5865,48 @@ test_size(png_modifier* const pm, png_byte const colour_type,
{
png_uint_32 h, w;
for (h=1; h<=16; h+=hinc[bdlo]) for (w=1; w<=16; w+=winc[bdlo])
for (h=1; h<=16; h+=hinc[bdlo])
{
# ifdef PNG_READ_INTERLACING_SUPPORTED
/* Test with pngvalid generated interlaced images first; we have
* already verify these are ok (unless pngvalid has self-consistent
* read/write errors, which is unlikely), so this detects errors in the
* read side first:
*/
# if CAN_WRITE_INTERLACE
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/,
pm->use_update_info);
for (w=1; w<=16; w+=winc[bdlo])
{
# ifdef PNG_READ_INTERLACING_SUPPORTED
/* Test with pngvalid generated interlaced images first; we have
* already verify these are ok (unless pngvalid has self-consistent
* read/write errors, which is unlikely), so this detects errors in
* the read side first:
*/
# if CAN_WRITE_INTERLACE
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_ADAM7, w, h, 1), 0/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
# endif
# endif /* READ_INTERLACING */
if (fail(pm))
return 0;
# endif
# endif /* READ_INTERLACING */
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Test the libpng write side against the pngvalid read side: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/,
pm->use_update_info);
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Test the libpng write side against the pngvalid read side: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_ADAM7, w, h, 0), 1/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
# endif
if (fail(pm))
return 0;
# endif
# ifdef PNG_READ_INTERLACING_SUPPORTED
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Test both together: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo), 0/*palette*/,
PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/,
pm->use_update_info);
# ifdef PNG_READ_INTERLACING_SUPPORTED
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Test both together: */
standard_test(&pm->this, FILEID(colour_type, DEPTH(bdlo),
0/*palette*/, PNG_INTERLACE_ADAM7, w, h, 0), 0/*do_interlace*/,
pm->use_update_info);
if (fail(pm))
return 0;
# endif
# endif /* READ_INTERLACING */
if (fail(pm))
return 0;
# endif
# endif /* READ_INTERLACING */
}
}
}
@ -6225,7 +6166,7 @@ image_pixel_add_alpha(image_pixel *this, const standard_display *display,
{
if (this->colour_type == PNG_COLOR_TYPE_GRAY)
{
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
if (!for_background && this->bit_depth < 8)
this->bit_depth = this->sample_depth = 8;
# endif
@ -6235,7 +6176,7 @@ image_pixel_add_alpha(image_pixel *this, const standard_display *display,
/* After 1.7 the expansion of bit depth only happens if there is a
* tRNS chunk to expand at this point.
*/
# if PNG_LIBPNG_VER >= 10700
# if PNG_LIBPNG_VER == 10700
if (!for_background && this->bit_depth < 8)
this->bit_depth = this->sample_depth = 8;
# endif
@ -6711,7 +6652,7 @@ transform_range_check(png_const_structp pp, unsigned int r, unsigned int g,
unsigned int out, png_byte sample_depth, double err, double limit,
const char *name, double digitization_error)
{
/* Compare the scaled, digitzed, values of our local calculation (in+-err)
/* Compare the scaled, digitized, values of our local calculation (in+-err)
* with the digitized values libpng produced; 'sample_depth' is the actual
* digitization depth of the libpng output colors (the bit depth except for
* palette images where it is always 8.) The check on 'err' is to detect
@ -7116,7 +7057,7 @@ image_transform_png_set_tRNS_to_alpha_mod(const image_transform *this,
image_pixel *that, png_const_structp pp,
const transform_display *display)
{
#if PNG_LIBPNG_VER < 10700
#if PNG_LIBPNG_VER != 10700
/* LIBPNG BUG: this always forces palette images to RGB. */
if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(that);
@ -7126,13 +7067,13 @@ image_transform_png_set_tRNS_to_alpha_mod(const image_transform *this,
* convert to an alpha channel.
*/
if (that->have_tRNS)
# if PNG_LIBPNG_VER >= 10700
# if PNG_LIBPNG_VER == 10700
if (that->colour_type != PNG_COLOR_TYPE_PALETTE &&
(that->colour_type & PNG_COLOR_MASK_ALPHA) == 0)
# endif
image_pixel_add_alpha(that, &display->this, 0/*!for background*/);
#if PNG_LIBPNG_VER < 10700
#if PNG_LIBPNG_VER != 10700
/* LIBPNG BUG: otherwise libpng still expands to 8 bits! */
else
{
@ -7161,7 +7102,7 @@ image_transform_png_set_tRNS_to_alpha_add(image_transform *this,
* any action on a palette image.
*/
return
# if PNG_LIBPNG_VER >= 10700
# if PNG_LIBPNG_VER == 10700
colour_type != PNG_COLOR_TYPE_PALETTE &&
# endif
(colour_type & PNG_COLOR_MASK_ALPHA) == 0;
@ -7302,7 +7243,7 @@ image_transform_png_set_expand_gray_1_2_4_to_8_mod(
const image_transform *this, image_pixel *that, png_const_structp pp,
const transform_display *display)
{
#if PNG_LIBPNG_VER < 10700
#if PNG_LIBPNG_VER != 10700
image_transform_png_set_expand_mod(this, that, pp, display);
#else
/* Only expand grayscale of bit depth less than 8: */
@ -7318,7 +7259,7 @@ static int
image_transform_png_set_expand_gray_1_2_4_to_8_add(image_transform *this,
const image_transform **that, png_byte colour_type, png_byte bit_depth)
{
#if PNG_LIBPNG_VER < 10700
#if PNG_LIBPNG_VER != 10700
return image_transform_png_set_expand_add(this, that, colour_type,
bit_depth);
#else
@ -7348,7 +7289,7 @@ image_transform_png_set_expand_16_set(const image_transform *this,
png_set_expand_16(pp);
/* NOTE: prior to 1.7 libpng does SET_EXPAND as well, so tRNS is expanded. */
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
if (that->this.has_tRNS)
that->this.is_transparent = 1;
# endif
@ -7401,7 +7342,7 @@ image_transform_png_set_scale_16_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_scale_16(pp);
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
/* libpng will limit the gamma table size: */
that->max_gamma_8 = PNG_MAX_GAMMA_8;
# endif
@ -7449,7 +7390,7 @@ image_transform_png_set_strip_16_set(const image_transform *this,
transform_display *that, png_structp pp, png_infop pi)
{
png_set_strip_16(pp);
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
/* libpng will limit the gamma table size: */
that->max_gamma_8 = PNG_MAX_GAMMA_8;
# endif
@ -7474,22 +7415,7 @@ image_transform_png_set_strip_16_mod(const image_transform *this,
* 'scale' API (above) must be used.
*/
# ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED
# if PNG_LIBPNG_VER >= 10504
# error PNG_READ_ACCURATE_SCALE should not be set
# endif
/* The strip 16 algorithm drops the low 8 bits rather than calculating
* 1/257, so we need to adjust the permitted errors appropriately:
* Notice that this is only relevant prior to the addition of the
* png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!)
*/
{
const double d = (255-128.5)/65535;
that->rede += d;
that->greene += d;
that->bluee += d;
that->alphae += d;
}
# error PNG_READ_ACCURATE_SCALE should not be set
# endif
}
@ -7635,8 +7561,8 @@ image_transform_png_set_rgb_to_gray_ini(const image_transform *this,
else
{
/* The default (built in) coeffcients, as above: */
# if PNG_LIBPNG_VER < 10700
/* The default (built in) coefficients, as above: */
# if PNG_LIBPNG_VER != 10700
data.red_coefficient = 6968 / 32768.;
data.green_coefficient = 23434 / 32768.;
data.blue_coefficient = 2366 / 32768.;
@ -7719,7 +7645,7 @@ image_transform_png_set_rgb_to_gray_ini(const image_transform *this,
* conversion adds another +/-2 in the 16-bit case and
* +/-(1<<(15-PNG_MAX_GAMMA_8)) in the 8-bit case.
*/
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
if (that->this.bit_depth < 16)
that->max_gamma_8 = PNG_MAX_GAMMA_8;
# endif
@ -7896,7 +7822,7 @@ image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
{
double gray, err;
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
if (that->colour_type == PNG_COLOR_TYPE_PALETTE)
image_pixel_convert_PLTE(that);
# endif
@ -8083,7 +8009,7 @@ image_transform_png_set_rgb_to_gray_mod(const image_transform *this,
double b = that->bluef;
double be = that->bluee;
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
/* The true gray case involves no math in earlier versions (not
* true, there was some if gamma correction was happening too.)
*/
@ -9057,7 +8983,7 @@ image_transform_reset_count(void)
static int
image_transform_test_counter(png_uint_32 counter, unsigned int max)
{
/* Test the list to see if there is any point contining, given a current
/* Test the list to see if there is any point continuing, given a current
* counter and a 'max' value.
*/
image_transform *next = image_transform_first;
@ -9862,7 +9788,7 @@ gamma_component_validate(const char *name, const validate_info *vi,
* lost. This can result in up to a +/-1 error in the presence of
* an sbit less than the bit depth.
*/
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
# define SBIT_ERROR .5
# else
# define SBIT_ERROR 1.
@ -9922,47 +9848,6 @@ gamma_component_validate(const char *name, const validate_info *vi,
* (chop) method of scaling was used.
*/
# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
# if PNG_LIBPNG_VER < 10504
/* This may be required for other components in the future,
* but at present the presence of gamma correction effectively
* prevents the errors in the component scaling (I don't quite
* understand why, but since it's better this way I care not
* to ask, JB 20110419.)
*/
if (pass == 0 && alpha < 0 && vi->scale16 && vi->sbit > 8 &&
vi->sbit + vi->isbit_shift == 16)
{
tmp = ((id >> 8) - .5)/255;
if (tmp > 0)
{
is_lo = ceil(outmax * tmp - vi->maxout_total);
if (is_lo < 0) is_lo = 0;
}
else
is_lo = 0;
tmp = ((id >> 8) + .5)/255;
if (tmp < 1)
{
is_hi = floor(outmax * tmp + vi->maxout_total);
if (is_hi > outmax) is_hi = outmax;
}
else
is_hi = outmax;
if (!(od < is_lo || od > is_hi))
{
if (encoded_error < vi->outlog)
return i;
pass = "within 8 bit limits:\n";
}
}
# endif
# endif
}
else /* !use_input_precision */
@ -10001,9 +9886,12 @@ gamma_component_validate(const char *name, const validate_info *vi,
case ALPHA_MODE_OFFSET + PNG_ALPHA_BROKEN:
case ALPHA_MODE_OFFSET + PNG_ALPHA_OPTIMIZED:
# endif /* ALPHA_MODE_SUPPORTED */
# if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
(defined PNG_READ_ALPHA_MODE_SUPPORTED)
do_compose = (alpha > 0 && alpha < 1);
use_input = (alpha != 0);
break;
# endif
default:
break;
@ -10649,16 +10537,21 @@ static void perform_gamma_transform_tests(png_modifier *pm)
{
unsigned int i, j;
for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j)
if (i != j)
for (i=0; i<pm->ngamma_tests; ++i)
{
for (j=0; j<pm->ngamma_tests; ++j)
{
gamma_transform_test(pm, colour_type, bit_depth, palette_number,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j], 0/*sBIT*/,
pm->use_input_precision, 0 /*do not scale16*/);
if (i != j)
{
gamma_transform_test(pm, colour_type, bit_depth, palette_number,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
0/*sBIT*/, pm->use_input_precision, 0/*do not scale16*/);
if (fail(pm))
return;
if (fail(pm))
return;
}
}
}
}
}
@ -10687,14 +10580,17 @@ static void perform_gamma_sbit_tests(png_modifier *pm)
{
unsigned int j;
for (j=0; j<pm->ngamma_tests; ++j) if (i != j)
for (j=0; j<pm->ngamma_tests; ++j)
{
gamma_transform_test(pm, colour_type, bit_depth, npalette,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
sbit, pm->use_input_precision_sbit, 0 /*scale16*/);
if (i != j)
{
gamma_transform_test(pm, colour_type, bit_depth, npalette,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
sbit, pm->use_input_precision_sbit, 0 /*scale16*/);
if (fail(pm))
return;
if (fail(pm))
return;
}
}
}
}
@ -10711,7 +10607,7 @@ static void perform_gamma_scale16_tests(png_modifier *pm)
# ifndef PNG_MAX_GAMMA_8
# define PNG_MAX_GAMMA_8 11
# endif
# if defined PNG_MAX_GAMMA_8 || PNG_LIBPNG_VER < 10700
# if defined PNG_MAX_GAMMA_8 || PNG_LIBPNG_VER != 10700
# define SBIT_16_TO_8 PNG_MAX_GAMMA_8
# else
# define SBIT_16_TO_8 16
@ -10946,14 +10842,17 @@ perform_gamma_composition_tests(png_modifier *pm, int do_background,
unsigned int i, j;
/* Don't skip the i==j case here - it's relevant. */
for (i=0; i<pm->ngamma_tests; ++i) for (j=0; j<pm->ngamma_tests; ++j)
for (i=0; i<pm->ngamma_tests; ++i)
{
gamma_composition_test(pm, colour_type, bit_depth, palette_number,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
pm->use_input_precision, do_background, expand_16);
for (j=0; j<pm->ngamma_tests; ++j)
{
gamma_composition_test(pm, colour_type, bit_depth, palette_number,
pm->interlace_type, 1/pm->gammas[i], pm->gammas[j],
pm->use_input_precision, do_background, expand_16);
if (fail(pm))
return;
if (fail(pm))
return;
}
}
}
}
@ -11056,7 +10955,7 @@ perform_gamma_test(png_modifier *pm, int summary)
pm->calculations_use_input_precision = 0;
if (summary)
summarize_gamma_errors(pm, 0/*who*/, 1/*low bit depth*/, 1/*indexed*/);
summarize_gamma_errors(pm, NULL/*who*/, 1/*low bit depth*/, 1/*indexed*/);
if (fail(pm))
return;
@ -11182,8 +11081,10 @@ png_pass_start_row(int pass)
{
int x, y;
++pass;
for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass)
return y;
for (y=0; y<8; ++y)
for (x=0; x<8; ++x)
if (adam7[y][x] == pass)
return y;
return 0xf;
}
@ -11192,8 +11093,10 @@ png_pass_start_col(int pass)
{
int x, y;
++pass;
for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass)
return x;
for (x=0; x<8; ++x)
for (y=0; y<8; ++y)
if (adam7[y][x] == pass)
return x;
return 0xf;
}
@ -11202,18 +11105,24 @@ png_pass_row_shift(int pass)
{
int x, y, base=(-1), inc=8;
++pass;
for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass)
for (y=0; y<8; ++y)
{
if (base == (-1))
base = y;
else if (base == y)
{}
else if (inc == y-base)
base=y;
else if (inc == 8)
inc = y-base, base=y;
else if (inc != y-base)
return 0xff; /* error - more than one 'inc' value! */
for (x=0; x<8; ++x)
{
if (adam7[y][x] == pass)
{
if (base == (-1))
base = y;
else if (base == y)
{}
else if (inc == y-base)
base=y;
else if (inc == 8)
inc = y-base, base=y;
else if (inc != y-base)
return 0xff; /* error - more than one 'inc' value! */
}
}
}
if (base == (-1)) return 0xfe; /* error - no row in pass! */
@ -11236,18 +11145,24 @@ png_pass_col_shift(int pass)
{
int x, y, base=(-1), inc=8;
++pass;
for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass)
for (x=0; x<8; ++x)
{
if (base == (-1))
base = x;
else if (base == x)
{}
else if (inc == x-base)
base=x;
else if (inc == 8)
inc = x-base, base=x;
else if (inc != x-base)
return 0xff; /* error - more than one 'inc' value! */
for (y=0; y<8; ++y)
{
if (adam7[y][x] == pass)
{
if (base == (-1))
base = x;
else if (base == x)
{}
else if (inc == x-base)
base=x;
else if (inc == 8)
inc = x-base, base=x;
else if (inc != x-base)
return 0xff; /* error - more than one 'inc' value! */
}
}
}
if (base == (-1)) return 0xfe; /* error - no row in pass! */
@ -11311,8 +11226,9 @@ png_row_in_interlace_pass(png_uint_32 y, int pass)
int x;
y &= 7;
++pass;
for (x=0; x<8; ++x) if (adam7[y][x] == pass)
return 1;
for (x=0; x<8; ++x)
if (adam7[y][x] == pass)
return 1;
return 0;
}
@ -11324,8 +11240,9 @@ png_col_in_interlace_pass(png_uint_32 x, int pass)
int y;
x &= 7;
++pass;
for (y=0; y<8; ++y) if (adam7[y][x] == pass)
return 1;
for (y=0; y<8; ++y)
if (adam7[y][x] == pass)
return 1;
return 0;
}
@ -11339,11 +11256,17 @@ png_pass_rows(png_uint_32 height, int pass)
height &= 7;
++pass;
for (y=0; y<8; ++y) for (x=0; x<8; ++x) if (adam7[y][x] == pass)
for (y=0; y<8; ++y)
{
rows += tiles;
if (y < height) ++rows;
break; /* i.e. break the 'x', column, loop. */
for (x=0; x<8; ++x)
{
if (adam7[y][x] == pass)
{
rows += tiles;
if (y < height) ++rows;
break; /* i.e. break the 'x', column, loop. */
}
}
}
return rows;
@ -11358,11 +11281,17 @@ png_pass_cols(png_uint_32 width, int pass)
width &= 7;
++pass;
for (x=0; x<8; ++x) for (y=0; y<8; ++y) if (adam7[y][x] == pass)
for (x=0; x<8; ++x)
{
cols += tiles;
if (x < width) ++cols;
break; /* i.e. break the 'y', row, loop. */
for (y=0; y<8; ++y)
{
if (adam7[y][x] == pass)
{
cols += tiles;
if (x < width) ++cols;
break; /* i.e. break the 'y', row, loop. */
}
}
}
return cols;
@ -11681,7 +11610,7 @@ int main(int argc, char **argv)
* code that 16-bit arithmetic is used for 8-bit samples when it would make a
* difference.
*/
pm.assume_16_bit_calculations = PNG_LIBPNG_VER >= 10700;
pm.assume_16_bit_calculations = PNG_LIBPNG_VER == 10700;
/* Currently 16 bit expansion happens at the end of the pipeline, so the
* calculations are done in the input bit depth not the output.
@ -11701,17 +11630,17 @@ int main(int argc, char **argv)
# ifdef PNG_WRITE_tRNS_SUPPORTED
pm.test_tRNS = 1;
# endif
pm.test_lbg = PNG_LIBPNG_VER >= 10600;
pm.test_lbg = 1; /* PNG_LIBPNG_VER >= 10600 */
pm.test_lbg_gamma_threshold = 1;
pm.test_lbg_gamma_transform = PNG_LIBPNG_VER >= 10600;
pm.test_lbg_gamma_transform = 1; /* PNG_LIBPNG_VER >= 10600 */
pm.test_lbg_gamma_sbit = 1;
pm.test_lbg_gamma_composition = PNG_LIBPNG_VER >= 10700;
pm.test_lbg_gamma_composition = PNG_LIBPNG_VER == 10700;
/* And the test encodings */
pm.encodings = test_encodings;
pm.nencodings = ARRAY_SIZE(test_encodings);
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
pm.sbitlow = 8U; /* because libpng doesn't do sBIT below 8! */
# else
pm.sbitlow = 1U;
@ -11719,7 +11648,7 @@ int main(int argc, char **argv)
/* The following allows results to pass if they correspond to anything in the
* transformed range [input-.5,input+.5]; this is is required because of the
* way libpng treates the 16_TO_8 flag when building the gamma tables in
* way libpng treats the 16_TO_8 flag when building the gamma tables in
* releases up to 1.6.0.
*
* TODO: review this
@ -11741,7 +11670,7 @@ int main(int argc, char **argv)
pm.maxout16 = .499; /* Error in *encoded* value */
pm.maxabs16 = .00005;/* 1/20000 */
pm.maxcalc16 =1./65535;/* +/-1 in 16 bits for compose errors */
# if PNG_LIBPNG_VER < 10700
# if PNG_LIBPNG_VER != 10700
pm.maxcalcG = 1./((1<<PNG_MAX_GAMMA_8)-1);
# else
pm.maxcalcG = 1./((1<<16)-1);
@ -11810,21 +11739,21 @@ int main(int argc, char **argv)
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
else if (strncmp(*argv, "--transform-disable=",
sizeof "--transform-disable") == 0)
{
{
pm.test_transform = 1;
transform_disable(*argv + sizeof "--transform-disable");
}
}
else if (strncmp(*argv, "--transform-enable=",
sizeof "--transform-enable") == 0)
{
{
pm.test_transform = 1;
transform_enable(*argv + sizeof "--transform-enable");
}
}
#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
else if (strcmp(*argv, "--gamma") == 0)
{
{
/* Just do two gamma tests here (2.2 and linear) for speed: */
pm.ngamma_tests = 2U;
pm.test_gamma_threshold = 1;
@ -11833,7 +11762,7 @@ int main(int argc, char **argv)
pm.test_gamma_scale16 = 1;
pm.test_gamma_background = 1; /* composition */
pm.test_gamma_alpha_mode = 1;
}
}
else if (strcmp(*argv, "--nogamma") == 0)
pm.ngamma_tests = 0;
@ -11875,7 +11804,14 @@ int main(int argc, char **argv)
pm.test_gamma_alpha_mode = 0;
else if (strcmp(*argv, "--expand16") == 0)
pm.test_gamma_expand16 = 1;
{
# ifdef PNG_READ_EXPAND_16_SUPPORTED
pm.test_gamma_expand16 = 1;
# else
fprintf(stderr, "pngvalid: --expand16: no read support\n");
return SKIP;
# endif
}
else if (strcmp(*argv, "--noexpand16") == 0)
pm.test_gamma_expand16 = 0;
@ -11890,10 +11826,15 @@ int main(int argc, char **argv)
pm.test_lbg_gamma_transform = pm.test_lbg_gamma_sbit =
pm.test_lbg_gamma_composition = 0;
# ifdef PNG_WRITE_tRNS_SUPPORTED
else if (strcmp(*argv, "--tRNS") == 0)
else if (strcmp(*argv, "--tRNS") == 0)
{
# ifdef PNG_WRITE_tRNS_SUPPORTED
pm.test_tRNS = 1;
# endif
# else
fprintf(stderr, "pngvalid: --tRNS: no write support\n");
return SKIP;
# endif
}
else if (strcmp(*argv, "--notRNS") == 0)
pm.test_tRNS = 0;
@ -12147,7 +12088,7 @@ int main(int argc, char **argv)
(pm.this.nerrors || (pm.this.treat_warnings_as_errors &&
pm.this.nwarnings)) ? "FAIL" : "PASS",
command,
#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || PNG_LIBPNG_VER < 10500
#if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)
"floating"
#else
"fixed"

View file

@ -2,8 +2,6 @@
*
* Copyright (c) 2013 John Cunningham Bowler
*
* Last changed in libpng 1.6.1 [March 28, 2013]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h

View file

@ -1,10 +1,8 @@
/* tarith.c
*
* Copyright (c) 2021 Cosmin Truta
* Copyright (c) 2011-2013 John Cunningham Bowler
*
* Last changed in libpng 1.6.0 [February 14, 2013]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@ -88,6 +86,7 @@ int validation_ascii_to_fp(int count, int argc, char **argv)
int minorarith = 0;
while (--argc > 0)
{
if (strcmp(*++argv, "-a") == 0)
showall = 1;
else if (strcmp(*argv, "-e") == 0 && argc > 0)
@ -105,6 +104,7 @@ int validation_ascii_to_fp(int count, int argc, char **argv)
fprintf(stderr, "unknown argument %s\n", *argv);
return 1;
}
}
do
{
@ -130,8 +130,8 @@ int validation_ascii_to_fp(int count, int argc, char **argv)
*/
if (buffer[precision+7] != 71)
{
fprintf(stderr, "%g[%d] -> '%s'[%lu] buffer overflow\n", test,
precision, buffer, (unsigned long)strlen(buffer));
fprintf(stderr, "%g[%d] -> '%s'[%lu] buffer overflow\n",
test, precision, buffer, (unsigned long)strlen(buffer));
failed = 1;
}
@ -146,16 +146,16 @@ int validation_ascii_to_fp(int count, int argc, char **argv)
if (test >= 0 && strcmp(buffer, "inf") ||
test < 0 && strcmp(buffer, "-inf"))
{
fprintf(stderr, "%g[%d] -> '%s' but expected 'inf'\n", test,
precision, buffer);
fprintf(stderr, "%g[%d] -> '%s' but expected 'inf'\n",
test, precision, buffer);
failed = 1;
}
}
else if (!png_check_fp_number(buffer, precision+10, &state, &index) ||
buffer[index] != 0)
{
fprintf(stderr, "%g[%d] -> '%s' but has bad format ('%c')\n", test,
precision, buffer, buffer[index]);
fprintf(stderr, "%g[%d] -> '%s' but has bad format ('%c')\n",
test, precision, buffer, buffer[index]);
failed = 1;
}
else if (PNG_FP_IS_NEGATIVE(state) && !(test < 0))
@ -187,7 +187,7 @@ int validation_ascii_to_fp(int count, int argc, char **argv)
/* Check the result against the original. */
double out = atof(buffer);
double change = fabs((out - test)/test);
double allow = .5/pow(10,
double allow = .5 / pow(10,
(precision >= DBL_DIG) ? DBL_DIG-1 : precision-1);
/* NOTE: if you hit this error case are you compiling with gcc
@ -257,8 +257,9 @@ skip:
}
while (--count);
printf("Tested %d finite values, %d non-finite, %d OK (%d failed) %d minor "
"arithmetic errors\n", finite, nonfinite, ok, failcount, minorarith);
printf("Tested %d finite values, %d non-finite, %d OK (%d failed) "
"%d minor arithmetic errors\n",
finite, nonfinite, ok, failcount, minorarith);
printf(" Error with >=%d digit precision %.2f%%\n", DBL_DIG, max_abs);
printf(" Error with < %d digit precision %.2f%%\n", DBL_DIG, max);
@ -371,8 +372,8 @@ static int check_one_character(checkfp_command *co, checkfp_control c, int ch)
/* This should never fail (it's a serious bug if it does): */
if (index != 0 && index != 1)
{
fprintf(stderr, "%s: read beyond end of string (%lu)\n", co->number,
(unsigned long)index);
fprintf(stderr, "%s: read beyond end of string (%lu)\n",
co->number, (unsigned long)index);
return 0;
}
@ -503,8 +504,8 @@ static int check_one_character(checkfp_command *co, checkfp_control c, int ch)
if (number_is_valid != c.number_was_valid)
{
fprintf(stderr,
"%s: character '%c' [0x%.2x] changed number validity\n", co->number,
ch, ch);
"%s: character '%c' [0x%.2x] changed number validity\n",
co->number, ch, ch);
return 0;
}
@ -521,10 +522,13 @@ static int check_all_characters(checkfp_command *co, checkfp_control c)
{
int ch;
if (c.cnumber+4 < sizeof co->number) for (ch=0; ch<256; ++ch)
if (c.cnumber+4 < sizeof co->number)
{
if (!check_one_character(co, c, ch))
return 0;
for (ch=0; ch<256; ++ch)
{
if (!check_one_character(co, c, ch))
return 0;
}
}
return 1;
@ -539,10 +543,13 @@ static int check_some_characters(checkfp_command *co, checkfp_control c,
if (c.cnumber+4 < sizeof co->number && c.limit >= 0)
{
if (c.limit > 0) for (i=0; tests[i]; ++i)
if (c.limit > 0)
{
if (!check_one_character(co, c, tests[i]))
return 0;
for (i=0; tests[i]; ++i)
{
if (!check_one_character(co, c, tests[i]))
return 0;
}
}
/* At the end check all the characters. */
@ -616,10 +623,10 @@ int validation_muldiv(int count, int argc, char **argv)
png_int_32 times, div;
while (--argc > 0)
{
fprintf(stderr, "unknown argument %s\n", *++argv);
return 1;
}
{
fprintf(stderr, "unknown argument %s\n", *++argv);
return 1;
}
/* Find out about the random number generator. */
randbuffer = RAND_MAX;
@ -687,25 +694,25 @@ int validation_muldiv(int count, int argc, char **argv)
ok = 0, ++overflow, fpround = fp/*misleading*/;
if (verbose)
fprintf(stderr, "TEST %d * %d / %d -> %lld (%s)\n", a, times, div,
fp, ok ? "ok" : "overflow");
fprintf(stderr, "TEST %d * %d / %d -> %lld (%s)\n",
a, times, div, fp, ok ? "ok" : "overflow");
++tested;
if (png_muldiv(&result, a, times, div) != ok)
{
++error;
if (ok)
fprintf(stderr, "%d * %d / %d -> overflow (expected %lld)\n", a,
times, div, fp);
fprintf(stderr, "%d * %d / %d -> overflow (expected %lld)\n",
a, times, div, fp);
else
fprintf(stderr, "%d * %d / %d -> %d (expected overflow %lld)\n", a,
times, div, result, fp);
fprintf(stderr, "%d * %d / %d -> %d (expected overflow %lld)\n",
a, times, div, result, fp);
}
else if (ok && result != fpround)
{
++error;
fprintf(stderr, "%d * %d / %d -> %d not %lld\n", a, times, div, result,
fp);
fprintf(stderr, "%d * %d / %d -> %d not %lld\n",
a, times, div, result, fp);
}
else
++passed;
@ -721,8 +728,8 @@ int validation_muldiv(int count, int argc, char **argv)
}
while (--count > 0);
printf("%d tests including %d overflows, %d passed, %d failed (%d 64-bit "
"errors)\n", tested, overflow, passed, error, error64);
printf("%d tests including %d overflows, %d passed, %d failed "
"(%d 64-bit errors)\n", tested, overflow, passed, error, error64);
return 0;
}
@ -821,8 +828,9 @@ int validation_gamma(int argc, char **argv)
{
if (error > .68) /* By experiment error is less than .68 */
{
fprintf(stderr, "16-bit log error: %d: got %u, expected %f"
" error: %f\n", i, png_log16bit(i), correct, error);
fprintf(stderr,
"16-bit log error: %d: got %u, expected %f error: %f\n",
i, png_log16bit(i), correct, error);
}
}
}
@ -841,8 +849,9 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > 1883) /* By experiment. */
{
fprintf(stderr, "32-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp(i), correct, error);
fprintf(stderr,
"32-bit exp error: %d: got %u, expected %f error: %f\n",
i, png_exp(i), correct, error);
}
}
@ -859,8 +868,9 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > .50002) /* By experiment */
{
fprintf(stderr, "8-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp8bit(i), correct, error);
fprintf(stderr,
"8-bit exp error: %d: got %u, expected %f error: %f\n",
i, png_exp8bit(i), correct, error);
}
}
@ -877,8 +887,9 @@ int validation_gamma(int argc, char **argv)
maxerr = fabs(error);
if (fabs(error) > .524) /* By experiment */
{
fprintf(stderr, "16-bit exp error: %d: got %u, expected %f"
" error: %f\n", i, png_exp16bit(i), correct, error);
fprintf(stderr,
"16-bit exp error: %d: got %u, expected %f error: %f\n",
i, png_exp16bit(i), correct, error);
}
}
@ -940,7 +951,7 @@ int validation_gamma(int argc, char **argv)
/**************************** VALIDATION TESTS ********************************/
/* Various validation routines are included herein, they require some
* definition for png_warning and png_error, seetings of VALIDATION:
* definition for png_warning and png_error, settings of VALIDATION:
*
* 1: validates the ASCII to floating point conversions
* 2: validates png_muldiv

View file

@ -2,8 +2,6 @@
*
* Copyright (c) 2013,2016 John Cunningham Bowler
*
* Last changed in libpng 1.6.22 [May 26, 2016]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@ -528,7 +526,7 @@ int main(int argc, char **argv)
}
}
else if (nfiles == 0) /* Read from stdin withoout --dissemble */
else if (nfiles == 0) /* Read from stdin without --dissemble */
{
char filename[FILENAME_MAX+1];

View file

@ -0,0 +1,141 @@
/* contrib/mips-mmi/linux.c
*
* Copyright (c) 2024 Cosmin Truta
* Written by guxiwei, 2023
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/auxv.h>
/*
* parse_r var, r - Helper assembler macro for parsing register names.
*
* This converts the register name in $n form provided in \r to the
* corresponding register number, which is assigned to the variable \var. It is
* needed to allow explicit encoding of instructions in inline assembly where
* registers are chosen by the compiler in $n form, allowing us to avoid using
* fixed register numbers.
*
* It also allows newer instructions (not implemented by the assembler) to be
* transparently implemented using assembler macros, instead of needing separate
* cases depending on toolchain support.
*
* Simple usage example:
* __asm__ __volatile__("parse_r __rt, %0\n\t"
* ".insn\n\t"
* "# di %0\n\t"
* ".word (0x41606000 | (__rt << 16))"
* : "=r" (status);
*/
/* Match an individual register number and assign to \var */
#define _IFC_REG(n) \
".ifc \\r, $" #n "\n\t" \
"\\var = " #n "\n\t" \
".endif\n\t"
__asm__(".macro parse_r var r\n\t"
"\\var = -1\n\t"
_IFC_REG(0) _IFC_REG(1) _IFC_REG(2) _IFC_REG(3)
_IFC_REG(4) _IFC_REG(5) _IFC_REG(6) _IFC_REG(7)
_IFC_REG(8) _IFC_REG(9) _IFC_REG(10) _IFC_REG(11)
_IFC_REG(12) _IFC_REG(13) _IFC_REG(14) _IFC_REG(15)
_IFC_REG(16) _IFC_REG(17) _IFC_REG(18) _IFC_REG(19)
_IFC_REG(20) _IFC_REG(21) _IFC_REG(22) _IFC_REG(23)
_IFC_REG(24) _IFC_REG(25) _IFC_REG(26) _IFC_REG(27)
_IFC_REG(28) _IFC_REG(29) _IFC_REG(30) _IFC_REG(31)
".iflt \\var\n\t"
".error \"Unable to parse register name \\r\"\n\t"
".endif\n\t"
".endm");
#define HWCAP_LOONGSON_CPUCFG (1 << 14)
static int cpucfg_available(void)
{
return getauxval(AT_HWCAP) & HWCAP_LOONGSON_CPUCFG;
}
static int strstart(const char *str, const char *pfx, const char **ptr)
{
while (*pfx && *pfx == *str) {
pfx++;
str++;
}
if (!*pfx && ptr)
*ptr = str;
return !*pfx;
}
/* Most toolchains have no CPUCFG support yet */
static uint32_t read_cpucfg(uint32_t reg)
{
uint32_t __res;
__asm__ __volatile__(
"parse_r __res,%0\n\t"
"parse_r reg,%1\n\t"
".insn \n\t"
".word (0xc8080118 | (reg << 21) | (__res << 11))\n\t"
:"=r"(__res)
:"r"(reg)
:
);
return __res;
}
#define LOONGSON_CFG1 0x1
#define LOONGSON_CFG1_MMI (1 << 4)
static int cpu_flags_cpucfg(void)
{
int flags = 0;
uint32_t cfg1 = read_cpucfg(LOONGSON_CFG1);
if (cfg1 & LOONGSON_CFG1_MMI)
flags = 1;
return flags;
}
static int cpu_flags_cpuinfo(void)
{
FILE *f = fopen("/proc/cpuinfo", "r");
char buf[200];
int flags = 0;
if (!f)
return flags;
while (fgets(buf, sizeof(buf), f)) {
/* Legacy kernel may not export MMI in ASEs implemented */
if (strstart(buf, "cpu model", NULL)) {
if (strstr(buf, "Loongson-3 "))
flags = 1;
break;
}
if (strstart(buf, "ASEs implemented", NULL)) {
if (strstr(buf, " loongson-mmi"))
flags = 1;
break;
}
}
fclose(f);
return flags;
}
static int png_have_mmi()
{
if (cpucfg_available())
return cpu_flags_cpucfg();
else
return cpu_flags_cpuinfo();
return 0;
}

View file

@ -1,64 +1,54 @@
/* contrib/mips-msa/linux.c
*
* Copyright (c) 2020-2023 Cosmin Truta
* Copyright (c) 2016 Glenn Randers-Pehrson
* Written by Mandar Sahastrabuddhe, 2016.
* Last changed in libpng 1.6.25beta03 [August 29, 2016]
* Updated by Sui Jingfeng, 2021.
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
* SEE contrib/mips-msa/README before reporting bugs
* On Linux, png_have_msa is implemented by reading the pseudo-file
* "/proc/self/auxv".
*
* See contrib/mips-msa/README before reporting bugs.
*
* STATUS: SUPPORTED
* BUG REPORTS: png-mng-implement@sourceforge.net
*
* png_have_msa implemented for Linux by reading the widely available
* pseudo-file /proc/cpuinfo.
*
* This code is strict ANSI-C and is probably moderately portable; it does
* however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.
*/
#include <stdio.h>
#include <string.h>
#include <elf.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
static int
png_have_msa(png_structp png_ptr)
{
FILE *f = fopen("/proc/cpuinfo", "rb");
Elf64_auxv_t aux;
int fd;
int has_msa = 0;
char *string = "msa";
char word[10];
if (f != NULL)
fd = open("/proc/self/auxv", O_RDONLY);
if (fd >= 0)
{
while(!feof(f))
while (read(fd, &aux, sizeof(Elf64_auxv_t)) == sizeof(Elf64_auxv_t))
{
int ch = fgetc(f);
static int i = 0;
while(!(ch <= 32))
if (aux.a_type == AT_HWCAP)
{
word[i++] = ch;
ch = fgetc(f);
uint64_t hwcap = aux.a_un.a_val;
has_msa = (hwcap >> 1) & 1;
break;
}
int val = strcmp(string, word);
if (val == 0)
return 1;
i = 0;
memset(word, 0, 10);
}
fclose(f);
close(fd);
}
#ifdef PNG_WARNINGS_SUPPORTED
else
png_warning(png_ptr, "/proc/cpuinfo open failed");
png_warning(png_ptr, "/proc/self/auxv open failed");
#endif
return 0;
return has_msa;
}

View file

@ -1,4 +1,3 @@
Last changed in libpng 1.6.33 [September 28, 2017]
Copyright (c) 2017 Glenn Randers-Pehrson
This code is released under the libpng license.

View file

@ -1,4 +1,5 @@
#!/bin/bash -eu
# Copyright 2017-2018 Glenn Randers-Pehrson
# Copyright 2016 Google Inc.
#
@ -14,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Last changed in libpng 1.6.35 [July 15, 2018]
#
# Revisions by Glenn Randers-Pehrson, 2017:
# 1. Build only the library, not the tools (changed "make -j$(nproc) all" to
# "make -j$(nproc) libpng16.la").

View file

@ -1,12 +1,9 @@
// libpng_read_fuzzer.cc
// Copyright 2017-2018 Glenn Randers-Pehrson
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that may
// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE
// Last changed in libpng 1.6.35 [July 15, 2018]
// The modifications in 2017 by Glenn Randers-Pehrson include
// 1. addition of a PNG_CLEANUP macro,
// 2. setting the option to ignore ADLER32 checksums,
@ -17,14 +14,17 @@
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#define PNG_INTERNAL
#include "png.h"
#include "nalloc.h"
#define PNG_CLEANUP \
nalloc_end(); \
if(png_handler.png_ptr) \
{ \
if (png_handler.row_ptr) \
@ -60,7 +60,7 @@ struct PngObjectHandler {
png_free(png_ptr, row_ptr);
if (end_info_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr);
else if (info_ptr)
else if (info_ptr)
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
else
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
@ -78,6 +78,22 @@ void user_read_data(png_structp png_ptr, png_bytep data, size_t length) {
buf_state->data += length;
}
void* limited_malloc(png_structp, png_alloc_size_t size) {
// libpng may allocate large amounts of memory that the fuzzer reports as
// an error. In order to silence these errors, make libpng fail when trying
// to allocate a large amount. This allocator used to be in the Chromium
// version of this fuzzer.
// This number is chosen to match the default png_user_chunk_malloc_max.
if (size > 8000000)
return nullptr;
return malloc(size);
}
void default_free(png_structp, png_voidp ptr) {
return free(ptr);
}
static const int kPngHeaderSize = 8;
// Entry point for LibFuzzer.
@ -87,6 +103,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size < kPngHeaderSize) {
return 0;
}
nalloc_init(nullptr);
std::vector<unsigned char> v(data, data + size);
if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) {
@ -106,6 +123,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
return 0;
}
nalloc_start(data, size);
png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr);
if (!png_handler.info_ptr) {
PNG_CLEANUP
@ -118,6 +136,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
return 0;
}
// Use a custom allocator that fails for large allocations to avoid OOM.
png_set_mem_fn(png_handler.png_ptr, nullptr, limited_malloc, default_free);
png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
#ifdef PNG_IGNORE_ADLER32
png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON);
@ -186,5 +207,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
PNG_CLEANUP
#ifdef PNG_SIMPLIFIED_READ_SUPPORTED
// Simplified READ API
png_image image;
memset(&image, 0, (sizeof image));
image.version = PNG_IMAGE_VERSION;
if (!png_image_begin_read_from_memory(&image, data, size)) {
return 0;
}
image.format = PNG_FORMAT_RGBA;
std::vector<png_byte> buffer(PNG_IMAGE_SIZE(image));
png_image_finish_read(&image, NULL, buffer.data(), 0, NULL);
#endif
return 0;
}

View file

@ -0,0 +1,330 @@
/*
MIT License
Copyright (c) 2025 Catena cyber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef NALLOC_H_
#define NALLOC_H_
#if defined(__clang__) && defined(__has_feature)
#if __has_feature(address_sanitizer)
#define NALLOC_ASAN 1
#endif
#endif
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
static const uint32_t nalloc_crc32_table[] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
// Nallocfuzz data to take a decision
uint32_t nalloc_random_state = 0;
__thread unsigned int nalloc_running = 0;
bool nalloc_initialized = false;
uint32_t nalloc_runs = 0;
// Nalloc fuzz parameters
uint32_t nalloc_bitmask = 0xFF;
bool nalloc_random_bitmask = true;
uint32_t nalloc_magic = 0x294cee63;
bool nalloc_verbose = false;
#ifdef NALLOC_ASAN
extern void __sanitizer_print_stack_trace(void);
#endif
// Generic init, using env variables to get parameters
void nalloc_init(const char *prog) {
if (nalloc_initialized) {
return;
}
nalloc_initialized = true;
char *bitmask = getenv("NALLOC_FREQ");
if (bitmask) {
int shift = atoi(bitmask);
if (shift > 0 && shift < 31) {
nalloc_bitmask = 1 << shift;
nalloc_random_bitmask = false;
} else if (shift == 0) {
nalloc_random_bitmask = false;
nalloc_bitmask = 0;
}
} else if (prog == NULL || strstr(prog, "nalloc") == NULL) {
nalloc_random_bitmask = false;
nalloc_bitmask = 0;
return;
}
char *magic = getenv("NALLOC_MAGIC");
if (magic) {
nalloc_magic = (uint32_t)strtol(magic, NULL, 0);
}
char *verbose = getenv("NALLOC_VERBOSE");
if (verbose) {
nalloc_verbose = true;
}
}
// add one byte to the CRC
static inline void nalloc_random_update(uint8_t b) {
nalloc_random_state =
((uint32_t)((uint32_t)nalloc_random_state << 8)) ^
nalloc_crc32_table[((nalloc_random_state >> 24) ^ b) & 0xFF];
}
// Start the failure injections, using a buffer as seed
static int nalloc_start(const uint8_t *data, size_t size) {
if (nalloc_random_bitmask) {
if (nalloc_random_state & 0x10) {
nalloc_bitmask = 0xFFFFFFFF;
} else {
nalloc_bitmask = 1 << (5 + (nalloc_random_state & 0xF));
}
} else if (nalloc_bitmask == 0) {
// nalloc disabled
return 0;
}
nalloc_random_state = 0;
for (size_t i = 0; i < size; i++) {
nalloc_random_update(data[i]);
}
if (__sync_fetch_and_add(&nalloc_running, 1)) {
__sync_fetch_and_sub(&nalloc_running, 1);
return 0;
}
nalloc_runs++;
return 1;
}
// Stop the failure injections
static void nalloc_end() { __sync_fetch_and_sub(&nalloc_running, 1); }
static bool nalloc_backtrace_exclude(size_t size, const char *op) {
if (nalloc_verbose) {
fprintf(stderr, "failed %s(%zu) \n", op, size);
#ifdef NALLOC_ASAN
__sanitizer_print_stack_trace();
#endif
}
return false;
}
//
static bool nalloc_fail(size_t size, const char *op) {
// do not fail before thread init
if (nalloc_runs == 0) {
return false;
}
if (__sync_fetch_and_add(&nalloc_running, 1) != 1) {
// do not fail allocations outside of fuzzer input
// and do not fail inside of this function
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
nalloc_random_update((uint8_t)size);
if (size >= 0x100) {
nalloc_random_update((uint8_t)(size >> 8));
if (size >= 0x10000) {
nalloc_random_update((uint8_t)(size >> 16));
// bigger may already fail or oom
}
}
if (((nalloc_random_state ^ nalloc_magic) & nalloc_bitmask) == 0) {
if (nalloc_backtrace_exclude(size, op)) {
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
__sync_fetch_and_sub(&nalloc_running, 1);
return true;
}
__sync_fetch_and_sub(&nalloc_running, 1);
return false;
}
// ASAN interceptor for libc routines
#ifdef NALLOC_ASAN
extern void *__interceptor_malloc(size_t);
extern void *__interceptor_calloc(size_t, size_t);
extern void *__interceptor_realloc(void *, size_t);
extern void *__interceptor_reallocarray(void *, size_t, size_t);
extern ssize_t __interceptor_read(int, void *, size_t);
extern ssize_t __interceptor_write(int, const void *, size_t);
extern ssize_t __interceptor_recv(int, void *, size_t, int);
extern ssize_t __interceptor_send(int, const void *, size_t, int);
#define nalloc_malloc(s) __interceptor_malloc(s)
#define nalloc_calloc(s, n) __interceptor_calloc(s, n)
#define nalloc_realloc(p, s) __interceptor_realloc(p, s)
#define nalloc_reallocarray(p, s, n) __interceptor_reallocarray(p, s, n)
#define nalloc_read(f, b, s) __interceptor_read(f, b, s)
#define nalloc_write(f, b, s) __interceptor_write(f, b, s)
#define nalloc_recv(f, b, s, x) __interceptor_recv(f, b, s, x)
#define nalloc_send(f, b, s, x) __interceptor_send(f, b, s, x)
#else
extern void *__libc_malloc(size_t);
extern void *__libc_calloc(size_t, size_t);
extern void *__libc_realloc(void *, size_t);
extern void *__libc_reallocarray(void *, size_t, size_t);
extern ssize_t __read(int, void *, size_t);
extern ssize_t __write(int, const void *, size_t);
extern ssize_t __recv(int, void *, size_t, int);
extern ssize_t __send(int, const void *, size_t, int);
#define nalloc_malloc(s) __libc_malloc(s)
#define nalloc_calloc(s, n) __libc_calloc(s, n)
#define nalloc_realloc(p, s) __libc_realloc(p, s)
#define nalloc_reallocarray(p, s, n) __libc_reallocarray(p, s, n)
#define nalloc_read(f, b, s) __read(f, b, s)
#define nalloc_write(f, b, s) __write(f, b, s)
#define nalloc_recv(f, b, s, x) __recv(f, b, s, x)
#define nalloc_send(f, b, s, x) __send(f, b, s, x)
#endif
// nalloc standard function overwrites with pseudo-random failures
ssize_t read(int fd, void *buf, size_t count) {
if (nalloc_fail(count, "read")) {
errno = EIO;
return -1;
}
return nalloc_read(fd, buf, count);
}
ssize_t write(int fd, const void *buf, size_t count) {
if (nalloc_fail(count, "write")) {
errno = EIO;
return -1;
}
return nalloc_write(fd, buf, count);
}
ssize_t recv(int fd, void *buf, size_t count, int flags) {
if (nalloc_fail(count, "recv")) {
errno = EIO;
return -1;
}
return nalloc_recv(fd, buf, count, flags);
}
ssize_t send(int fd, const void *buf, size_t count, int flags) {
if (nalloc_fail(count, "send")) {
errno = EIO;
return -1;
}
return nalloc_send(fd, buf, count, flags);
}
void *calloc(size_t nmemb, size_t size) {
if (nalloc_fail(size, "calloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_calloc(nmemb, size);
}
void *malloc(size_t size) {
if (nalloc_fail(size, "malloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_malloc(size);
}
void *realloc(void *ptr, size_t size) {
if (nalloc_fail(size, "realloc")) {
errno = ENOMEM;
return NULL;
}
return nalloc_realloc(ptr, size);
}
void *reallocarray(void *ptr, size_t nmemb, size_t size) {
if (nalloc_fail(size, "reallocarray")) {
errno = ENOMEM;
return NULL;
}
return nalloc_reallocarray(ptr, nmemb, size);
}
#ifdef __cplusplus
} // extern "C" {
#endif
#endif // NALLOC_H_

View file

@ -0,0 +1,12 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
insert_final_newline = true
max_doc_length = 79
max_line_length = 79
trim_trailing_whitespace = true

View file

@ -0,0 +1,3 @@
__pycache__
*.py[co]
*$py.class

View file

@ -0,0 +1,8 @@
[COMPATIBILITY]
disable=consider-using-f-string
[COMPLEXITY]
disable=too-many-branches,too-many-instance-attributes
[STYLE]
disable=consider-using-in

View file

@ -0,0 +1,19 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,20 @@
pngexifinfo
===========
Show the EXIF information embedded in a PNG file.
Sample usage
------------
Show the EXIF info inside a PNG file:
pngexifinfo /path/to/file.png
Show the EXIF info inside a raw `.exif` file, using base 16 for the EXIF tags:
pngexifinfo --hex /path/to/file.exif
Show the help text:
pngexifinfo --help

View file

@ -0,0 +1,48 @@
#!/usr/bin/env python
"""
Byte packing and unpacking utilities.
Copyright (C) 2017-2020 Cosmin Truta.
Use, modification and distribution are subject to the MIT License.
Please see the accompanying file LICENSE_MIT.txt
"""
from __future__ import absolute_import, division, print_function
import struct
def unpack_uint32be(buffer, offset=0):
"""Unpack an unsigned int from its 32-bit big-endian representation."""
return struct.unpack(">I", buffer[offset:offset + 4])[0]
def unpack_uint32le(buffer, offset=0):
"""Unpack an unsigned int from its 32-bit little-endian representation."""
return struct.unpack("<I", buffer[offset:offset + 4])[0]
def unpack_uint16be(buffer, offset=0):
"""Unpack an unsigned int from its 16-bit big-endian representation."""
return struct.unpack(">H", buffer[offset:offset + 2])[0]
def unpack_uint16le(buffer, offset=0):
"""Unpack an unsigned int from its 16-bit little-endian representation."""
return struct.unpack("<H", buffer[offset:offset + 2])[0]
def unpack_uint8(buffer, offset=0):
"""Unpack an unsigned int from its 8-bit representation."""
return struct.unpack("B", buffer[offset:offset + 1])[0]
if __name__ == "__main__":
# For testing only.
assert unpack_uint32be(b"ABCDEF", 1) == 0x42434445
assert unpack_uint32le(b"ABCDEF", 1) == 0x45444342
assert unpack_uint16be(b"ABCDEF", 1) == 0x4243
assert unpack_uint16le(b"ABCDEF", 1) == 0x4342
assert unpack_uint8(b"ABCDEF", 1) == 0x42

View file

@ -0,0 +1,306 @@
#!/usr/bin/env python
"""
Show the EXIF information.
Copyright (C) 2017-2020 Cosmin Truta.
Use, modification and distribution are subject to the MIT License.
Please see the accompanying file LICENSE_MIT.txt
"""
from __future__ import absolute_import, division, print_function
import sys
from bytepack import (unpack_uint32be,
unpack_uint32le,
unpack_uint16be,
unpack_uint16le,
unpack_uint8)
# Generously allow the TIFF file to occupy up to a quarter-gigabyte.
# TODO: Reduce this limit to 64K and use file seeking for anything larger.
_READ_DATA_SIZE_MAX = 256 * 1024 * 1024
_TIFF_TAG_TYPES = {
1: "byte",
2: "ascii",
3: "short",
4: "long",
5: "rational",
6: "sbyte",
7: "undefined",
8: "sshort",
9: "slong",
10: "srational",
11: "float",
12: "double",
}
# See http://www.digitalpreservation.gov/formats/content/tiff_tags.shtml
_TIFF_TAGS = {
0x00fe: "Subfile Type",
0x0100: "Width",
0x0101: "Height",
0x0102: "Bits per Sample",
0x0103: "Compression",
0x0106: "Photometric",
0x010d: "Document Name",
0x010e: "Image Description",
0x010f: "Make",
0x0110: "Model",
0x0111: "Strip Offsets",
0x0112: "Orientation",
0x0115: "Samples per Pixel",
0x0116: "Rows per Strip",
0x0117: "Strip Byte Counts",
0x0118: "Min Sample Value",
0x0119: "Max Sample Value",
0x011a: "X Resolution",
0x011b: "Y Resolution",
0x011c: "Planar Configuration",
0x011d: "Page Name",
0x011e: "X Position",
0x011f: "Y Position",
0x0128: "Resolution Unit",
0x0129: "Page Number",
0x0131: "Software",
0x0132: "Date Time",
0x013b: "Artist",
0x013c: "Host Computer",
0x013d: "Predictor",
0x013e: "White Point",
0x013f: "Primary Chromaticities",
0x0140: "Color Map",
0x0141: "Half-Tone Hints",
0x0142: "Tile Width",
0x0143: "Tile Length",
0x0144: "Tile Offsets",
0x0145: "Tile Byte Counts",
0x0211: "YCbCr Coefficients",
0x0212: "YCbCr Subsampling",
0x0213: "YCbCr Positioning",
0x0214: "Reference Black White",
0x022f: "Strip Row Counts",
0x02bc: "XMP",
0x8298: "Copyright",
0x83bb: "IPTC",
0x8769: "EXIF IFD",
0x8773: "ICC Profile",
0x8825: "GPS IFD",
0xa005: "Interoperability IFD",
0xc4a5: "Print IM",
# EXIF IFD tags
0x829a: "Exposure Time",
0x829d: "F-Number",
0x8822: "Exposure Program",
0x8824: "Spectral Sensitivity",
0x8827: "ISO Speed Ratings",
0x8828: "OECF",
0x9000: "EXIF Version",
0x9003: "DateTime Original",
0x9004: "DateTime Digitized",
0x9101: "Components Configuration",
0x9102: "Compressed Bits Per Pixel",
0x9201: "Shutter Speed Value",
0x9202: "Aperture Value",
0x9203: "Brightness Value",
0x9204: "Exposure Bias Value",
0x9205: "Max Aperture Value",
0x9206: "Subject Distance",
0x9207: "Metering Mode",
0x9208: "Light Source",
0x9209: "Flash",
0x920a: "Focal Length",
0x9214: "Subject Area",
0x927c: "Maker Note",
0x9286: "User Comment",
# ... TODO
0xa000: "Flashpix Version",
0xa001: "Color Space",
0xa002: "Pixel X Dimension",
0xa003: "Pixel Y Dimension",
0xa004: "Related Sound File",
# ... TODO
# GPS IFD tags
# ... TODO
}
_TIFF_EXIF_IFD = 0x8769
_GPS_IFD = 0x8825
_INTEROPERABILITY_IFD = 0xa005
class ExifInfo:
"""EXIF reader and information lister."""
_endian = None
_buffer = None
_offset = 0
_global_ifd_offset = 0
_exif_ifd_offset = 0
_gps_ifd_offset = 0
_interoperability_ifd_offset = 0
_hex = False
def __init__(self, buffer, **kwargs):
"""Initialize the EXIF data reader."""
self._hex = kwargs.get("hex", False)
self._verbose = kwargs.get("verbose", False)
if not isinstance(buffer, bytes):
raise RuntimeError("invalid EXIF data type")
if buffer.startswith(b"MM\x00\x2a"):
self._endian = "MM"
elif buffer.startswith(b"II\x2a\x00"):
self._endian = "II"
else:
raise RuntimeError("invalid EXIF header")
self._buffer = buffer
self._offset = 4
self._global_ifd_offset = self._ui32()
def endian(self):
"""Return the endianness of the EXIF data."""
return self._endian
def _tags_for_ifd(self, ifd_offset):
"""Yield the tags found at the given TIFF IFD offset."""
if ifd_offset < 8:
raise RuntimeError("invalid TIFF IFD offset")
self._offset = ifd_offset
ifd_size = self._ui16()
for _ in range(0, ifd_size):
tag_id = self._ui16()
tag_type = self._ui16()
count = self._ui32()
value_or_offset = self._ui32()
if self._endian == "MM":
# FIXME:
# value_or_offset requires a fixup under big-endian encoding.
if tag_type == 2:
# 2 --> "ascii"
value_or_offset >>= 24
elif tag_type == 3:
# 3 --> "short"
value_or_offset >>= 16
else:
# ... FIXME
pass
if count == 0:
raise RuntimeError("unsupported count=0 in tag 0x%x" % tag_id)
if tag_id == _TIFF_EXIF_IFD:
if tag_type != 4:
raise RuntimeError("incorrect tag type for EXIF IFD")
self._exif_ifd_offset = value_or_offset
elif tag_id == _GPS_IFD:
if tag_type != 4:
raise RuntimeError("incorrect tag type for GPS IFD")
self._gps_ifd_offset = value_or_offset
elif tag_id == _INTEROPERABILITY_IFD:
if tag_type != 4:
raise RuntimeError("incorrect tag type for Interop IFD")
self._interoperability_ifd_offset = value_or_offset
yield (tag_id, tag_type, count, value_or_offset)
def tags(self):
"""Yield all TIFF/EXIF tags."""
if self._verbose:
print("TIFF IFD : 0x%08x" % self._global_ifd_offset)
for tag in self._tags_for_ifd(self._global_ifd_offset):
yield tag
if self._exif_ifd_offset > 0:
if self._verbose:
print("EXIF IFD : 0x%08x" % self._exif_ifd_offset)
for tag in self._tags_for_ifd(self._exif_ifd_offset):
yield tag
if self._gps_ifd_offset > 0:
if self._verbose:
print("GPS IFD : 0x%08x" % self._gps_ifd_offset)
for tag in self._tags_for_ifd(self._gps_ifd_offset):
yield tag
if self._interoperability_ifd_offset > 0:
if self._verbose:
print("Interoperability IFD : 0x%08x" %
self._interoperability_ifd_offset)
for tag in self._tags_for_ifd(self._interoperability_ifd_offset):
yield tag
def tagid2str(self, tag_id):
"""Return an informative string representation of a TIFF tag id."""
idstr = _TIFF_TAGS.get(tag_id, "[Unknown]")
if self._hex:
idnum = "0x%04x" % tag_id
else:
idnum = "%d" % tag_id
return "%s (%s)" % (idstr, idnum)
@staticmethod
def tagtype2str(tag_type):
"""Return an informative string representation of a TIFF tag type."""
typestr = _TIFF_TAG_TYPES.get(tag_type, "[unknown]")
return "%d:%s" % (tag_type, typestr)
def tag2str(self, tag_id, tag_type, count, value_or_offset):
"""Return an informative string representation of a TIFF tag tuple."""
return "%s (type=%s) (count=%d) : 0x%08x" \
% (self.tagid2str(tag_id), self.tagtype2str(tag_type), count,
value_or_offset)
def _ui32(self):
"""Decode a 32-bit unsigned int found at the current offset;
advance the offset by 4.
"""
if self._offset + 4 > len(self._buffer):
raise RuntimeError("out-of-bounds uint32 access in EXIF")
if self._endian == "MM":
result = unpack_uint32be(self._buffer, self._offset)
else:
result = unpack_uint32le(self._buffer, self._offset)
self._offset += 4
return result
def _ui16(self):
"""Decode a 16-bit unsigned int found at the current offset;
advance the offset by 2.
"""
if self._offset + 2 > len(self._buffer):
raise RuntimeError("out-of-bounds uint16 access in EXIF")
if self._endian == "MM":
result = unpack_uint16be(self._buffer, self._offset)
else:
result = unpack_uint16le(self._buffer, self._offset)
self._offset += 2
return result
def _ui8(self):
"""Decode an 8-bit unsigned int found at the current offset;
advance the offset by 1.
"""
if self._offset + 1 > len(self._buffer):
raise RuntimeError("out-of-bounds uint8 access in EXIF")
result = unpack_uint8(self._buffer, self._offset)
self._offset += 1
return result
def print_raw_exif_info(buffer, **kwargs):
"""Print the EXIF information found in a raw byte stream."""
lister = ExifInfo(buffer, **kwargs)
print("EXIF (endian=%s)" % lister.endian())
for (tag_id, tag_type, count, value_or_offset) in lister.tags():
print(lister.tag2str(tag_id=tag_id,
tag_type=tag_type,
count=count,
value_or_offset=value_or_offset))
if __name__ == "__main__":
# For testing only.
for arg in sys.argv[1:]:
with open(arg, "rb") as test_stream:
test_buffer = test_stream.read(_READ_DATA_SIZE_MAX)
print_raw_exif_info(test_buffer, hex=True, verbose=True)

View file

@ -0,0 +1,10 @@
#!/bin/sh
set -eu
my_python="$(command -v python3 || command -v python)" || {
echo >&2 "error: program not found: Python interpreter"
exit 127
}
my_python_flags="-BES"
exec "$my_python" "$my_python_flags" "$(dirname "$0")/pngexifinfo.py" "$@"

View file

@ -0,0 +1,4 @@
@echo off
@setlocal enableextensions
python.exe -BES %~dp0.\pngexifinfo.py %*

View file

@ -0,0 +1,178 @@
#!/usr/bin/env python
"""
Show the PNG EXIF information.
Copyright (C) 2017-2020 Cosmin Truta.
Use, modification and distribution are subject to the MIT License.
Please see the accompanying file LICENSE_MIT.txt
"""
from __future__ import absolute_import, division, print_function
import argparse
import io
import re
import sys
import zlib
from bytepack import unpack_uint32be, unpack_uint8
from exifinfo import print_raw_exif_info
_PNG_SIGNATURE = b"\x89PNG\x0d\x0a\x1a\x0a"
_PNG_CHUNK_SIZE_MAX = 0x7fffffff
_READ_DATA_SIZE_MAX = 0x3ffff
def print_error(msg):
"""Print an error message to stderr."""
sys.stderr.write("%s: error: %s\n" % (sys.argv[0], msg))
def print_debug(msg):
"""Print a debug message to stderr."""
sys.stderr.write("%s: debug: %s\n" % (sys.argv[0], msg))
def _check_png(condition, chunk_sig=None):
"""Check a PNG-specific assertion."""
if condition:
return
if chunk_sig is None:
raise RuntimeError("bad PNG data")
raise RuntimeError("bad PNG data in '%s'" % chunk_sig)
def _check_png_crc(data, checksum, chunk_sig):
"""Check a CRC32 value inside a PNG stream."""
if unpack_uint32be(data) == (checksum & 0xffffffff):
return
raise RuntimeError("bad PNG checksum in '%s'" % chunk_sig)
def _extract_png_exif(data, **kwargs):
"""Extract the EXIF header and data from a PNG chunk."""
debug = kwargs.get("debug", False)
if unpack_uint8(data, 0) == 0:
if debug:
print_debug("found compressed EXIF, compression method 0")
if (unpack_uint8(data, 1) & 0x0f) == 0x08:
data = zlib.decompress(data[1:])
elif unpack_uint8(data, 1) == 0 \
and (unpack_uint8(data, 5) & 0x0f) == 0x08:
if debug:
print_debug("found uncompressed-length EXIF field")
data_len = unpack_uint32be(data, 1)
data = zlib.decompress(data[5:])
if data_len != len(data):
raise RuntimeError(
"incorrect uncompressed-length field in PNG EXIF")
else:
raise RuntimeError("invalid compression method in PNG EXIF")
if data.startswith(b"MM\x00\x2a") or data.startswith(b"II\x2a\x00"):
return data
raise RuntimeError("invalid TIFF/EXIF header in PNG EXIF")
def print_png_exif_info(instream, **kwargs):
"""Print the EXIF information found in the given PNG datastream."""
debug = kwargs.get("debug", False)
has_exif = False
while True:
chunk_hdr = instream.read(8)
_check_png(len(chunk_hdr) == 8)
chunk_len = unpack_uint32be(chunk_hdr, offset=0)
chunk_sig = chunk_hdr[4:8].decode("latin_1", errors="ignore")
_check_png(re.search(r"^[A-Za-z]{4}$", chunk_sig), chunk_sig=chunk_sig)
_check_png(chunk_len < _PNG_CHUNK_SIZE_MAX, chunk_sig=chunk_sig)
if debug:
print_debug("processing chunk: %s" % chunk_sig)
if chunk_len <= _READ_DATA_SIZE_MAX:
# The chunk size does not exceed an arbitrary, reasonable limit.
chunk_data = instream.read(chunk_len)
chunk_crc = instream.read(4)
_check_png(len(chunk_data) == chunk_len and len(chunk_crc) == 4,
chunk_sig=chunk_sig)
checksum = zlib.crc32(chunk_hdr[4:8])
checksum = zlib.crc32(chunk_data, checksum)
_check_png_crc(chunk_crc, checksum, chunk_sig=chunk_sig)
else:
# The chunk is too big. Skip it.
instream.seek(chunk_len + 4, io.SEEK_CUR)
continue
if chunk_sig == "IEND":
_check_png(chunk_len == 0, chunk_sig=chunk_sig)
break
if chunk_sig.lower() in ["exif", "zxif"] and chunk_len > 8:
has_exif = True
exif_data = _extract_png_exif(chunk_data, **kwargs)
print_raw_exif_info(exif_data, **kwargs)
if not has_exif:
raise RuntimeError("no EXIF data in PNG stream")
def print_exif_info(file, **kwargs):
"""Print the EXIF information found in the given file."""
with open(file, "rb") as stream:
header = stream.read(4)
if header == _PNG_SIGNATURE[0:4]:
if stream.read(4) != _PNG_SIGNATURE[4:8]:
raise RuntimeError("corrupted PNG file")
print_png_exif_info(instream=stream, **kwargs)
elif header == b"II\x2a\x00" or header == b"MM\x00\x2a":
data = header + stream.read(_READ_DATA_SIZE_MAX)
print_raw_exif_info(data, **kwargs)
else:
raise RuntimeError("not a PNG file")
def main():
"""The main function."""
parser = argparse.ArgumentParser(
prog="pngexifinfo",
usage="%(prog)s [options] [--] files...",
description="Show the PNG EXIF information.")
parser.add_argument("files",
metavar="file",
nargs="*",
help="a PNG file or a raw EXIF blob")
parser.add_argument("-x",
"--hex",
dest="hex",
action="store_true",
help="show EXIF tags in base 16")
parser.add_argument("-v",
"--verbose",
dest="verbose",
action="store_true",
help="run in verbose mode")
parser.add_argument("--debug",
dest="debug",
action="store_true",
help="run in debug mode")
args = parser.parse_args()
if not args.files:
parser.error("missing file operand")
result = 0
for file in args.files:
try:
print_exif_info(file,
hex=args.hex,
debug=args.debug,
verbose=args.verbose)
except (IOError, OSError) as err:
print_error(str(err))
result = 66 # os.EX_NOINPUT
except RuntimeError as err:
print_error("%s: %s" % (file, str(err)))
result = 69 # os.EX_UNAVAILABLE
parser.exit(result)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
sys.stderr.write("INTERRUPTED\n")
sys.exit(130) # SIGINT

View file

@ -1,4 +1,3 @@
This demonstrates the use of PNG_USER_CONFIG, pngusr.h and pngusr.dfa
to build minimal decoder, encoder, and progressive reader applications.

View file

@ -54,7 +54,7 @@ ZOBJS = adler32$(O) crc32$(O) \
PNGSRCS=png$(C) pngerror$(C) pngget$(C) pngmem$(C) \
pngread$(C) pngrio$(C) pngrtran$(C) pngrutil$(C) \
pngset$(C) pngtrans$(C)
# Standard headers
PNGH =png.h pngconf.h pngdebug.h pnginfo.h pngpriv.h pngstruct.h

View file

@ -0,0 +1,29 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = unset
indent_size = unset
indent_style = space
insert_final_newline = true
max_doc_length = 79
max_line_length = 79
trim_trailing_whitespace = true
[*.[ch]]
indent_size = 2
indent_style = space
[CMakeLists.txt]
indent_size = 4
indent_style = space
max_doc_length = 79
max_line_length = 99
[{Makefile,makevms.com}]
indent_size = unset
indent_style = unset
max_doc_length = 79
max_line_length = 99

View file

@ -0,0 +1,11 @@
# Compiled executables
png2pnm
png2pnm.exe
png2pnm-static*
pnm2png
pnm2png.exe
pnm2png-static*
# Test artifacts
*.png
*.p[abgnp]m

View file

@ -1,9 +1,8 @@
pnm2png / png2pnm --- conversion from PBM/PGM/PPM-file to PNG-file
copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
version 1.0 - 1999.10.15 - First version.
1.1 - 2015.07.29 - Fixed leaks (Glenn Randers-Pehrson)
1.1 - 2015.07.29 - Fix memory leaks (Glenn Randers-Pehrson)
1.2 - 2017.04.22 - Add buffer-size check
1.3 - 2017.08.24 - Fix potential overflow in buffer-size check
(Glenn Randers-Pehrson)
@ -11,3 +10,5 @@ version 1.0 - 1999.10.15 - First version.
1.5 - 2018.08.05 - Fix buffer overflow in tokenizer (Cosmin Truta)
1.6 - 2018.08.05 - Improve portability and fix style (Cosmin Truta)
1.7 - 2019.01.22 - Change license to MIT (Willem van Schaik)
1.8 - 2024.01.09 - Fix, improve, modernize (Cosmin Truta)
1.9 - 2025.01.10 - Delete conditionally-compiled code (Cosmin Truta)

View file

@ -1,24 +1,41 @@
cmake_minimum_required(VERSION 3.1)
cmake_policy(VERSION 3.1)
# Copyright (c) 2018-2025 Cosmin Truta
#
# This software is released under the MIT license. For conditions of
# distribution and use, see the LICENSE file part of this package.
cmake_minimum_required(VERSION 3.14)
project(PNGMINUS C)
option(PNGMINUS_USE_STATIC_LIBRARIES "Use the static library builds" ON)
option(PNGMINUS_USE_SYSTEM_PNG
"Use the libpng build found in the system" OFF)
# libpng
add_subdirectory(../.. libpng)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../..)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/libpng)
if(PNGMINUS_USE_STATIC_LIBRARIES)
set(PNGMINUS_PNG_LIBRARY png_static)
else()
set(PNGMINUS_PNG_LIBRARY png)
endif()
# png2pnm
add_executable(png2pnm png2pnm.c)
target_link_libraries(png2pnm ${PNGMINUS_PNG_LIBRARY})
# pnm2png
add_executable(pnm2png pnm2png.c)
target_link_libraries(pnm2png ${PNGMINUS_PNG_LIBRARY})
if(PNGMINUS_USE_SYSTEM_PNG)
# Use the system libpng.
find_package(PNG REQUIRED)
target_link_libraries(png2pnm PRIVATE PNG::PNG)
target_link_libraries(pnm2png PRIVATE PNG::PNG)
else()
# Build and use the internal libpng.
# Configure libpng for static linking, to produce single-file executables.
set(PNG_STATIC ON
CACHE STRING "Build the internal libpng as a static library" FORCE)
set(PNG_SHARED OFF
CACHE STRING "Build the internal libpng as a shared library" FORCE)
set(PNG_FRAMEWORK OFF
CACHE STRING "Build the internal libpng as a framework bundle" FORCE)
add_subdirectory(../.. libpng)
target_include_directories(png2pnm PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/libpng>"
)
target_include_directories(pnm2png PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>"
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/libpng>"
)
target_link_libraries(png2pnm PRIVATE png_static)
target_link_libraries(pnm2png PRIVATE png_static)
endif()

View file

@ -1,4 +1,3 @@
pnm2png / png2pnm --- conversion from PBM/PGM/PPM-file to PNG-file
copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
@ -16,7 +15,7 @@ copies or substantial portions of the Software.
The software is provided "as is", without warranty of any kind, express or
implied, including but not limited to the warranties of merchantability,
fitness for a particular purpose and noninfringement. In no event shall the
authors or copyight holders be liable for any claim, damages or other
authors or copyright holders be liable for any claim, damages or other
liability, whether in an action of contract, tort or otherwise, arising from,
out of or in connection with the software or the use or other dealings in the
software.

View file

@ -14,15 +14,10 @@
#define BOOL unsigned char
#endif
#ifndef TRUE
#define TRUE (BOOL) 1
#define TRUE ((BOOL) 1)
#endif
#ifndef FALSE
#define FALSE (BOOL) 0
#endif
/* make png2pnm verbose so we can find problems (needs to be before png.h) */
#ifndef PNG_DEBUG
#define PNG_DEBUG 0
#define FALSE ((BOOL) 0)
#endif
#include "png.h"
@ -33,6 +28,9 @@ int main (int argc, char *argv[]);
void usage ();
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
BOOL raw, BOOL alpha);
BOOL do_png2pnm (png_struct *png_ptr, png_info *info_ptr,
FILE *pnm_file, FILE *alpha_file,
BOOL raw, BOOL alpha);
/*
* main
@ -43,9 +41,12 @@ int main (int argc, char *argv[])
FILE *fp_rd = stdin;
FILE *fp_wr = stdout;
FILE *fp_al = NULL;
const char *fname_wr = NULL;
const char *fname_al = NULL;
BOOL raw = TRUE;
BOOL alpha = FALSE;
int argi;
int ret;
for (argi = 1; argi < argc; argi++)
{
@ -64,7 +65,8 @@ int main (int argc, char *argv[])
argi++;
if ((fp_al = fopen (argv[argi], "wb")) == NULL)
{
fprintf (stderr, "PNM2PNG\n");
fname_al = argv[argi];
fprintf (stderr, "PNG2PNM\n");
fprintf (stderr, "Error: cannot create alpha-channel file %s\n",
argv[argi]);
exit (1);
@ -94,6 +96,7 @@ int main (int argc, char *argv[])
}
else if (fp_wr == stdout)
{
fname_wr = argv[argi];
if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
{
fprintf (stderr, "PNG2PNM\n");
@ -119,12 +122,7 @@ int main (int argc, char *argv[])
#endif
/* call the conversion program itself */
if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
{
fprintf (stderr, "PNG2PNM\n");
fprintf (stderr, "Error: unsuccessful conversion of PNG-image\n");
exit (1);
}
ret = png2pnm (fp_rd, fp_wr, fp_al, raw, alpha);
/* close input file */
fclose (fp_rd);
@ -134,6 +132,17 @@ int main (int argc, char *argv[])
if (alpha)
fclose (fp_al);
if (!ret)
{
fprintf (stderr, "PNG2PNM\n");
fprintf (stderr, "Error: unsuccessful conversion of PNG-image\n");
if (fname_wr)
remove (fname_wr); /* no broken output file shall remain behind */
if (fname_al)
remove (fname_al); /* ditto */
exit (1);
}
return 0;
}
@ -163,35 +172,11 @@ void usage ()
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
BOOL raw, BOOL alpha)
{
png_struct *png_ptr = NULL;
png_info *info_ptr = NULL;
png_byte buf[8];
png_byte *png_pixels = NULL;
png_byte **row_pointers = NULL;
png_byte *pix_ptr = NULL;
png_uint_32 row_bytes;
png_struct *png_ptr;
png_info *info_ptr;
BOOL ret;
png_uint_32 width;
png_uint_32 height;
int bit_depth;
int channels;
int color_type;
int alpha_present;
int row, col;
int ret;
int i;
long dep_16;
/* read and check signature in PNG file */
ret = fread (buf, 1, 8, png_file);
if (ret != 8)
return FALSE;
ret = png_sig_cmp (buf, 0, 8);
if (ret != 0)
return FALSE;
/* create png and info structures */
/* initialize the libpng context for reading from png_file */
png_ptr = png_create_read_struct (png_get_libpng_ver(NULL),
NULL, NULL, NULL);
@ -208,64 +193,56 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
if (setjmp (png_jmpbuf (png_ptr)))
{
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
return FALSE;
return FALSE; /* generic libpng error */
}
/* set up the input control for C streams */
png_init_io (png_ptr, png_file);
png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
/* read the file information */
png_read_info (png_ptr, info_ptr);
/* do the actual conversion */
ret = do_png2pnm (png_ptr, info_ptr, pnm_file, alpha_file, raw, alpha);
/* get size and bit-depth of the PNG-image */
/* clean up the libpng structures and their internally-managed data */
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
return ret;
}
/*
* do_png2pnm - does the conversion in a fully-initialized libpng context
*/
BOOL do_png2pnm (png_struct *png_ptr, png_info *info_ptr,
FILE *pnm_file, FILE *alpha_file,
BOOL raw, BOOL alpha)
{
png_byte **row_pointers;
png_byte *pix_ptr;
png_uint_32 width;
png_uint_32 height;
int bit_depth;
int channels;
int color_type;
int alpha_present;
png_uint_32 row, col, i;
long dep_16;
/* set up the image transformations that are necessary for the PNM format */
/* set up (if applicable) the expansion of paletted images to full-color rgb,
* and the expansion of transparency maps to full alpha-channel */
png_set_expand (png_ptr);
/* set up (if applicable) the expansion of grayscale images to bit-depth 8 */
png_set_expand_gray_1_2_4_to_8 (png_ptr);
/* read the image file, with all of the above image transforms applied */
png_read_png (png_ptr, info_ptr, 0, NULL);
/* get the image size, bit-depth and color-type */
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
NULL, NULL, NULL);
/* set-up the transformations */
/* transform paletted images into full-color rgb */
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand (png_ptr);
/* expand images to bit-depth 8 (only applicable for grayscale images) */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand (png_ptr);
/* transform transparency maps into full alpha-channel */
if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_expand (png_ptr);
#ifdef NJET
/* downgrade 16-bit images to 8-bit */
if (bit_depth == 16)
png_set_strip_16 (png_ptr);
/* transform grayscale images into full-color */
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb (png_ptr);
/* only if file has a file gamma, we do a correction */
if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
png_set_gamma (png_ptr, (double) 2.2, file_gamma);
#endif
/* all transformations have been registered; now update info_ptr data,
* get rowbytes and channels, and allocate image memory */
png_read_update_info (png_ptr, info_ptr);
/* get the new color-type and bit-depth (after expansion/stripping) */
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
NULL, NULL, NULL);
/* check for 16-bit files */
if (bit_depth == 16)
{
raw = FALSE;
#if defined(O_BINARY) && (O_BINARY != 0)
setmode (fileno (pnm_file), O_BINARY);
#endif
}
/* calculate new number of channels and store alpha-presence */
/* calculate the number of channels and store alpha-presence */
if (color_type == PNG_COLOR_TYPE_GRAY)
channels = 1;
else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
@ -282,47 +259,12 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
if (alpha && !alpha_present)
{
fprintf (stderr, "PNG2PNM\n");
fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n");
exit (1);
}
/* row_bytes is the width x number of channels x (bit-depth / 8) */
row_bytes = png_get_rowbytes (png_ptr, info_ptr);
if ((row_bytes == 0) ||
((size_t) height > (size_t) (-1) / (size_t) row_bytes))
{
/* too big */
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
return FALSE;
}
if ((png_pixels = (png_byte *)
malloc ((size_t) row_bytes * (size_t) height)) == NULL)
{
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
fprintf (stderr, "Warning: no alpha channel in PNG file\n");
return FALSE;
}
if ((row_pointers = (png_byte **)
malloc ((size_t) height * sizeof (png_byte *))) == NULL)
{
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
free (png_pixels);
return FALSE;
}
/* set the individual row_pointers to point at the correct offsets */
for (i = 0; i < ((int) height); i++)
row_pointers[i] = png_pixels + i * row_bytes;
/* now we can go ahead and just read the whole image */
png_read_image (png_ptr, row_pointers);
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end (png_ptr, info_ptr);
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
/* get address of internally-allocated image data */
row_pointers = png_get_rows (png_ptr, info_ptr);
/* write header of PNM file */
@ -353,24 +295,27 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
}
/* write data to PNM file */
pix_ptr = png_pixels;
for (row = 0; row < (int) height; row++)
for (row = 0; row < height; row++)
{
for (col = 0; col < (int) width; col++)
pix_ptr = row_pointers[row];
for (col = 0; col < width; col++)
{
for (i = 0; i < (channels - alpha_present); i++)
for (i = 0; i < (png_uint_32) (channels - alpha_present); i++)
{
if (raw)
{
fputc ((int) *pix_ptr++, pnm_file);
if (bit_depth == 16)
fputc ((int) *pix_ptr++, pnm_file);
}
else
{
if (bit_depth == 16)
{
dep_16 = (long) *pix_ptr++;
fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
dep_16 = ((long) *pix_ptr++) << 8;
dep_16 += ((long) *pix_ptr++);
fprintf (pnm_file, "%ld ", dep_16);
}
else
{
@ -382,22 +327,27 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
{
if (!alpha)
{
pix_ptr++; /* alpha */
/* skip the alpha-channel */
pix_ptr++;
if (bit_depth == 16)
pix_ptr++;
}
else /* output alpha-channel as pgm file */
else
{
/* output the alpha-channel as pgm file */
if (raw)
{
fputc ((int) *pix_ptr++, alpha_file);
if (bit_depth == 16)
fputc ((int) *pix_ptr++, alpha_file);
}
else
{
if (bit_depth == 16)
{
dep_16 = (long) *pix_ptr++;
fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
dep_16 = ((long) *pix_ptr++) << 8;
dep_16 += ((long) *pix_ptr++);
fprintf (alpha_file, "%ld ", dep_16);
}
else
{
@ -417,11 +367,5 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
fprintf (pnm_file, "\n");
} /* end for row */
if (row_pointers != NULL)
free (row_pointers);
if (png_pixels != NULL)
free (png_pixels);
return TRUE;
} /* end of source */

View file

@ -6,6 +6,7 @@
* distribution and use, see the LICENSE file part of this package.
*/
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
@ -14,15 +15,10 @@
#define BOOL unsigned char
#endif
#ifndef TRUE
#define TRUE (BOOL) 1
#define TRUE ((BOOL) 1)
#endif
#ifndef FALSE
#define FALSE (BOOL) 0
#endif
/* make pnm2png verbose so we can find problems (needs to be before png.h) */
#ifndef PNG_DEBUG
#define PNG_DEBUG 0
#define FALSE ((BOOL) 0)
#endif
#include "png.h"
@ -33,9 +29,14 @@ int main (int argc, char *argv[]);
void usage ();
BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
BOOL interlace, BOOL alpha);
void get_token (FILE *pnm_file, char *token_buf, size_t token_buf_size);
png_uint_32 get_data (FILE *pnm_file, int depth);
png_uint_32 get_value (FILE *pnm_file, int depth);
BOOL do_pnm2png (png_struct *png_ptr, png_info *info_ptr,
FILE *pnm_file, FILE *alpha_file,
BOOL interlace, BOOL alpha);
int fscan_pnm_magic (FILE *pnm_file, char *magic_buf, size_t magic_buf_size);
int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size);
int fscan_pnm_uint_32 (FILE *pnm_file, png_uint_32 *num_ptr);
png_uint_32 get_pnm_data (FILE *pnm_file, int depth);
png_uint_32 get_pnm_value (FILE *pnm_file, int depth);
/*
* main
@ -46,9 +47,11 @@ int main (int argc, char *argv[])
FILE *fp_rd = stdin;
FILE *fp_al = NULL;
FILE *fp_wr = stdout;
const char *fname_wr = NULL;
BOOL interlace = FALSE;
BOOL alpha = FALSE;
int argi;
int ret;
for (argi = 1; argi < argc; argi++)
{
@ -94,6 +97,7 @@ int main (int argc, char *argv[])
}
else if (fp_wr == stdout)
{
fname_wr = argv[argi];
if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
{
fprintf (stderr, "PNM2PNG\n");
@ -121,12 +125,7 @@ int main (int argc, char *argv[])
#endif
/* call the conversion program itself */
if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE)
{
fprintf (stderr, "PNM2PNG\n");
fprintf (stderr, "Error: unsuccessful converting to PNG-image\n");
exit (1);
}
ret = pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha);
/* close input file */
fclose (fp_rd);
@ -136,6 +135,15 @@ int main (int argc, char *argv[])
if (alpha)
fclose (fp_al);
if (!ret)
{
fprintf (stderr, "PNM2PNG\n");
fprintf (stderr, "Error: unsuccessful converting to PNG-image\n");
if (fname_wr)
remove (fname_wr); /* no broken output file shall remain behind */
exit (1);
}
return 0;
}
@ -163,77 +171,98 @@ void usage ()
BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
BOOL interlace, BOOL alpha)
{
png_struct *png_ptr = NULL;
png_info *info_ptr = NULL;
png_byte *png_pixels = NULL;
png_byte **row_pointers = NULL;
png_byte *pix_ptr = NULL;
volatile png_uint_32 row_bytes;
png_struct *png_ptr;
png_info *info_ptr;
BOOL ret;
char type_token[16];
char width_token[16];
char height_token[16];
char maxval_token[16];
volatile int color_type = 1;
unsigned long ul_width = 0, ul_alpha_width = 0;
unsigned long ul_height = 0, ul_alpha_height = 0;
unsigned long ul_maxval = 0;
volatile png_uint_32 width = 0, height = 0;
volatile png_uint_32 alpha_width = 0, alpha_height = 0;
png_uint_32 maxval;
volatile int bit_depth = 0;
int channels = 0;
int alpha_depth = 0;
int alpha_present = 0;
int row, col;
BOOL raw, alpha_raw = FALSE;
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
/* initialize the libpng context for writing to png_file */
png_ptr = png_create_write_struct (png_get_libpng_ver(NULL),
NULL, NULL, NULL);
if (!png_ptr)
return FALSE; /* out of memory */
info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
{
png_destroy_write_struct (&png_ptr, NULL);
return FALSE; /* out of memory */
}
if (setjmp (png_jmpbuf (png_ptr)))
{
png_destroy_write_struct (&png_ptr, &info_ptr);
return FALSE; /* generic libpng error */
}
png_init_io (png_ptr, png_file);
/* do the actual conversion */
ret = do_pnm2png (png_ptr, info_ptr, pnm_file, alpha_file, interlace, alpha);
/* clean up the libpng structures and their internally-managed data */
png_destroy_write_struct (&png_ptr, &info_ptr);
return ret;
}
/*
* do_pnm2png - does the conversion in a fully-initialized libpng context
*/
BOOL do_pnm2png (png_struct *png_ptr, png_info *info_ptr,
FILE *pnm_file, FILE *alpha_file,
BOOL interlace, BOOL alpha)
{
png_byte **row_pointers;
png_byte *pix_ptr;
int bit_depth;
int color_type;
int channels;
char magic_token[4];
BOOL raw;
png_uint_32 width, height, maxval;
png_uint_32 row_bytes;
png_uint_32 row, col;
png_uint_32 val16, i;
png_uint_32 alpha_width = 0, alpha_height = 0;
int alpha_depth = 0, alpha_present = 0;
BOOL alpha_raw = FALSE;
BOOL packed_bitmap = FALSE;
#endif
png_uint_32 tmp16;
int i;
/* read header of PNM file */
get_token (pnm_file, type_token, sizeof (type_token));
if (type_token[0] != 'P')
{
return FALSE;
}
else if ((type_token[1] == '1') || (type_token[1] == '4'))
{
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
raw = (type_token[1] == '4');
color_type = PNG_COLOR_TYPE_GRAY;
get_token (pnm_file, width_token, sizeof (width_token));
sscanf (width_token, "%lu", &ul_width);
width = (png_uint_32) ul_width;
get_token (pnm_file, height_token, sizeof (height_token));
sscanf (height_token, "%lu", &ul_height);
height = (png_uint_32) ul_height;
bit_depth = 1;
packed_bitmap = TRUE;
#else
fprintf (stderr, "PNM2PNG built without PNG_WRITE_INVERT_SUPPORTED and\n");
fprintf (stderr, "PNG_WRITE_PACK_SUPPORTED can't read PBM (P1,P4) files\n");
return FALSE;
#endif
}
else if ((type_token[1] == '2') || (type_token[1] == '5'))
{
raw = (type_token[1] == '5');
color_type = PNG_COLOR_TYPE_GRAY;
get_token (pnm_file, width_token, sizeof (width_token));
sscanf (width_token, "%lu", &ul_width);
width = (png_uint_32) ul_width;
get_token (pnm_file, height_token, sizeof (height_token));
sscanf (height_token, "%lu", &ul_height);
height = (png_uint_32) ul_height;
get_token (pnm_file, maxval_token, sizeof (maxval_token));
sscanf (maxval_token, "%lu", &ul_maxval);
maxval = (png_uint_32) ul_maxval;
if (fscan_pnm_magic (pnm_file, magic_token, sizeof (magic_token)) != 1)
return FALSE; /* not a PNM file */
if (maxval <= 1)
if ((magic_token[1] == '1') || (magic_token[1] == '4'))
{
if ((fscan_pnm_uint_32 (pnm_file, &width) != 1) ||
(fscan_pnm_uint_32 (pnm_file, &height) != 1))
return FALSE; /* bad PBM file header */
} else if ((magic_token[1] == '2') || (magic_token[1] == '5') ||
(magic_token[1] == '3') || (magic_token[1] == '6'))
{
if ((fscan_pnm_uint_32 (pnm_file, &width) != 1) ||
(fscan_pnm_uint_32 (pnm_file, &height) != 1) ||
(fscan_pnm_uint_32 (pnm_file, &maxval) != 1))
return FALSE; /* bad PGM/PPM file header */
}
if ((magic_token[1] == '1') || (magic_token[1] == '4'))
{
raw = (magic_token[1] == '4');
bit_depth = 1;
color_type = PNG_COLOR_TYPE_GRAY;
packed_bitmap = TRUE;
}
else if ((magic_token[1] == '2') || (magic_token[1] == '5'))
{
raw = (magic_token[1] == '5');
color_type = PNG_COLOR_TYPE_GRAY;
if (maxval == 0)
return FALSE;
else if (maxval == 1)
bit_depth = 1;
else if (maxval <= 3)
bit_depth = 2;
@ -246,20 +275,13 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
else /* maxval > 65535U */
return FALSE;
}
else if ((type_token[1] == '3') || (type_token[1] == '6'))
else if ((magic_token[1] == '3') || (magic_token[1] == '6'))
{
raw = (type_token[1] == '6');
raw = (magic_token[1] == '6');
color_type = PNG_COLOR_TYPE_RGB;
get_token (pnm_file, width_token, sizeof (width_token));
sscanf (width_token, "%lu", &ul_width);
width = (png_uint_32) ul_width;
get_token (pnm_file, height_token, sizeof (height_token));
sscanf (height_token, "%lu", &ul_height);
height = (png_uint_32) ul_height;
get_token (pnm_file, maxval_token, sizeof (maxval_token));
sscanf (maxval_token, "%lu", &ul_maxval);
maxval = (png_uint_32) ul_maxval;
if (maxval <= 1)
if (maxval == 0)
return FALSE;
else if (maxval == 1)
bit_depth = 1;
else if (maxval <= 3)
bit_depth = 2;
@ -272,6 +294,11 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
else /* maxval > 65535U */
return FALSE;
}
else if (magic_token[1] == '7')
{
fprintf (stderr, "PNM2PNG can't read PAM (P7) files\n");
return FALSE;
}
else
{
return FALSE;
@ -281,51 +308,36 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
if (alpha)
{
if (color_type == PNG_COLOR_TYPE_GRAY)
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
if (color_type == PNG_COLOR_TYPE_RGB)
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
if ((fscan_pnm_magic (alpha_file, magic_token, sizeof (magic_token)) != 1)
|| ((magic_token[1] != '2') && (magic_token[1] != '5')))
return FALSE; /* not a PGM file */
get_token (alpha_file, type_token, sizeof (type_token));
if (type_token[0] != 'P')
{
if ((fscan_pnm_uint_32 (alpha_file, &alpha_width) != 1) ||
(fscan_pnm_uint_32 (alpha_file, &alpha_height) != 1) ||
(fscan_pnm_uint_32 (alpha_file, &maxval) != 1))
return FALSE; /* bad PGM file header */
if ((alpha_width != width) || (alpha_height != height))
return FALSE; /* mismatched PGM dimensions */
alpha_raw = (magic_token[1] == '5');
color_type |= PNG_COLOR_MASK_ALPHA;
if (maxval == 0)
return FALSE;
}
else if ((type_token[1] == '2') || (type_token[1] == '5'))
{
alpha_raw = (type_token[1] == '5');
get_token (alpha_file, width_token, sizeof (width_token));
sscanf (width_token, "%lu", &ul_alpha_width);
alpha_width = (png_uint_32) ul_alpha_width;
if (alpha_width != width)
return FALSE;
get_token (alpha_file, height_token, sizeof (height_token));
sscanf (height_token, "%lu", &ul_alpha_height);
alpha_height = (png_uint_32) ul_alpha_height;
if (alpha_height != height)
return FALSE;
get_token (alpha_file, maxval_token, sizeof (maxval_token));
sscanf (maxval_token, "%lu", &ul_maxval);
maxval = (png_uint_32) ul_maxval;
if (maxval <= 1)
alpha_depth = 1;
else if (maxval <= 3)
alpha_depth = 2;
else if (maxval <= 15)
alpha_depth = 4;
else if (maxval <= 255)
alpha_depth = 8;
else if (maxval <= 65535U)
alpha_depth = 16;
else /* maxval > 65535U */
return FALSE;
if (alpha_depth != bit_depth)
return FALSE;
}
else
{
else if (maxval == 1)
alpha_depth = 1;
else if (maxval <= 3)
alpha_depth = 2;
else if (maxval <= 15)
alpha_depth = 4;
else if (maxval <= 255)
alpha_depth = 8;
else if (maxval <= 65535U)
alpha_depth = 16;
else /* maxval > 65535U */
return FALSE;
if (alpha_depth != bit_depth)
return FALSE;
}
} /* end if alpha */
/* calculate the number of channels and store alpha-presence */
@ -337,21 +349,17 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
channels = 3;
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
channels = 4;
#if 0
else
channels = 0; /* cannot happen */
#endif
return FALSE; /* NOTREACHED */
alpha_present = (channels - 1) % 2;
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
if (packed_bitmap)
{
/* row data is as many bytes as can fit width x channels x bit_depth */
row_bytes = (width * channels * bit_depth + 7) / 8;
}
else
#endif
{
/* row_bytes is the width x number of channels x (bit-depth / 8) */
row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
@ -363,50 +371,59 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
/* too big */
return FALSE;
}
if ((png_pixels = (png_byte *)
malloc ((size_t) row_bytes * (size_t) height)) == NULL)
/* allocate the rows using the same memory layout as libpng, and transfer
* their ownership to libpng, with the responsibility to clean everything up;
* please note the use of png_calloc instead of png_malloc */
row_pointers = (png_byte **)
png_calloc (png_ptr, height * sizeof (png_byte *));
png_set_rows (png_ptr, info_ptr, row_pointers);
png_data_freer (png_ptr, info_ptr, PNG_DESTROY_WILL_FREE_DATA, PNG_FREE_ALL);
for (row = 0; row < height; row++)
{
/* out of memory */
return FALSE;
/* the individual rows should only be allocated after all the previous
* steps completed successfully, because libpng must handle correctly
* any image allocation left incomplete after an out-of-memory error */
row_pointers[row] = (png_byte *) png_malloc (png_ptr, row_bytes);
}
/* read data from PNM file */
pix_ptr = png_pixels;
/* read the data from PNM file */
for (row = 0; row < (int) height; row++)
for (row = 0; row < height; row++)
{
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
pix_ptr = row_pointers[row];
if (packed_bitmap)
{
for (i = 0; i < (int) row_bytes; i++)
for (i = 0; i < row_bytes; i++)
{
/* png supports this format natively so no conversion is needed */
*pix_ptr++ = get_data (pnm_file, 8);
*pix_ptr++ = get_pnm_data (pnm_file, 8);
}
}
else
#endif
{
for (col = 0; col < (int) width; col++)
for (col = 0; col < width; col++)
{
for (i = 0; i < (channels - alpha_present); i++)
for (i = 0; i < (png_uint_32) (channels - alpha_present); i++)
{
if (raw)
{
*pix_ptr++ = get_data (pnm_file, bit_depth);
*pix_ptr++ = get_pnm_data (pnm_file, bit_depth);
if (bit_depth == 16)
*pix_ptr++ = get_pnm_data (pnm_file, bit_depth);
}
else
{
if (bit_depth <= 8)
{
*pix_ptr++ = get_value (pnm_file, bit_depth);
*pix_ptr++ = get_pnm_value (pnm_file, bit_depth);
}
else
{
tmp16 = get_value (pnm_file, bit_depth);
*pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
val16 = get_pnm_value (pnm_file, bit_depth);
*pix_ptr = (png_byte) ((val16 >> 8) & 0xFF);
pix_ptr++;
*pix_ptr = (png_byte) (tmp16 & 0xFF);
*pix_ptr = (png_byte) (val16 & 0xFF);
pix_ptr++;
}
}
@ -416,19 +433,21 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
{
if (alpha_raw)
{
*pix_ptr++ = get_data (alpha_file, alpha_depth);
*pix_ptr++ = get_pnm_data (alpha_file, alpha_depth);
if (alpha_depth == 16)
*pix_ptr++ = get_pnm_data (alpha_file, alpha_depth);
}
else
{
if (alpha_depth <= 8)
{
*pix_ptr++ = get_value (alpha_file, bit_depth);
*pix_ptr++ = get_pnm_value (alpha_file, bit_depth);
}
else
{
tmp16 = get_value (alpha_file, bit_depth);
*pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
*pix_ptr++ = (png_byte) (tmp16 & 0xFF);
val16 = get_pnm_value (alpha_file, bit_depth);
*pix_ptr++ = (png_byte) ((val16 >> 8) & 0xFF);
*pix_ptr++ = (png_byte) (val16 & 0xFF);
}
}
} /* end if alpha */
@ -436,63 +455,19 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
} /* end for col */
} /* end for row */
/* prepare the standard PNG structures */
png_ptr = png_create_write_struct (png_get_libpng_ver(NULL),
NULL, NULL, NULL);
if (!png_ptr)
{
free (png_pixels);
return FALSE;
}
info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr)
{
png_destroy_write_struct (&png_ptr, NULL);
free (png_pixels);
return FALSE;
}
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
if (packed_bitmap == TRUE)
{
png_set_packing (png_ptr);
png_set_invert_mono (png_ptr);
}
#endif
if (setjmp (png_jmpbuf (png_ptr)))
{
png_destroy_write_struct (&png_ptr, &info_ptr);
free (png_pixels);
return FALSE;
}
/* initialize the png structure */
png_init_io (png_ptr, png_file);
/* we're going to write more or less the same PNG as the input file */
png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
(!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
/* write the file header information */
png_write_info (png_ptr, info_ptr);
/* if needed we will allocate memory for an new array of row-pointers */
if (row_pointers == NULL)
if (packed_bitmap == TRUE)
{
if ((row_pointers = (png_byte **)
malloc (height * sizeof (png_byte *))) == NULL)
{
png_destroy_write_struct (&png_ptr, &info_ptr);
free (png_pixels);
return FALSE;
}
png_set_packing (png_ptr);
png_set_invert_mono (png_ptr);
}
/* set the individual row_pointers to point at the correct offsets */
for (i = 0; i < (int) height; i++)
row_pointers[i] = png_pixels + i * row_bytes;
/* write the file header information */
png_write_info (png_ptr, info_ptr);
/* write out the entire image data in one call */
png_write_image (png_ptr, row_pointers);
@ -500,22 +475,46 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
/* write the additional chunks to the PNG file (not really needed) */
png_write_end (png_ptr, info_ptr);
/* clean up after the write, and free any memory allocated */
png_destroy_write_struct (&png_ptr, &info_ptr);
if (row_pointers != NULL)
free (row_pointers);
if (png_pixels != NULL)
free (png_pixels);
return TRUE;
} /* end of pnm2png */
/*
* get_token - gets the first string after whitespace
* fscan_pnm_magic - like fscan_pnm_token below, but expects the magic string
* to start immediately, without any comment or whitespace,
* and to match the regex /^P[1-9]$/
*/
void get_token (FILE *pnm_file, char *token_buf, size_t token_buf_size)
int fscan_pnm_magic (FILE *pnm_file, char *magic_buf, size_t magic_buf_size)
{
int ret;
ret = fgetc (pnm_file);
if (ret == EOF) return 0;
ungetc (ret, pnm_file);
if (ret != 'P') return 0;
/* the string buffer must be at least four bytes long, i.e., the capacity
* required for strings of at least three characters long, i.e., the minimum
* required for ensuring that our magic string is exactly two characters long
*/
if (magic_buf_size < 4) return -1;
ret = fscan_pnm_token (pnm_file, magic_buf, magic_buf_size);
if (ret < 1) return ret;
if ((magic_buf[1] < '1') || (magic_buf[1] > '9')) return 0;
if (magic_buf[2] != '\0') return 0;
return 1;
}
/*
* fscan_pnm_token - extracts the first string token after whitespace,
* and (like fscanf) returns the number of successful
* extractions, which can be either 0 or 1
*/
int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size)
{
size_t i = 0;
int ret;
@ -543,29 +542,66 @@ void get_token (FILE *pnm_file, char *token_buf, size_t token_buf_size)
{
ret = fgetc (pnm_file);
if (ret == EOF) break;
if (ret == '0')
{
/* avoid storing more than one leading '0' in the token buffer,
* to ensure that all valid (in-range) numeric inputs can fit in. */
if ((i == 0) && (token_buf[i] == '0')) continue;
}
if (++i == token_buf_size - 1) break;
token_buf[i] = (char) ret;
}
while ((ret != '\n') && (ret != '\r') && (ret != ' '));
token_buf[i] = '\0';
return;
return (i > 0) ? 1 : 0;
}
/*
* get_data - takes first byte and converts into next pixel value,
* taking as much bits as defined by bit-depth and
* using the bit-depth to fill up a byte (0Ah -> AAh)
* fscan_pnm_uint_32 - like fscan_token above, but expects the extracted token
* to be numeric, and converts it to an unsigned 32-bit int
*/
png_uint_32 get_data (FILE *pnm_file, int depth)
int fscan_pnm_uint_32 (FILE *pnm_file, png_uint_32 *num_ptr)
{
char token[16];
unsigned long token_value;
int ret;
ret = fscan_pnm_token (pnm_file, token, sizeof (token));
if (ret < 1) return ret;
if ((token[0] < '0') && (token[0] > '9'))
return 0; /* the token starts with junk, or a +/- sign, which is invalid */
ret = sscanf (token, "%lu%*c", &token_value);
if (ret != 1)
return 0; /* the token ends with junk */
*num_ptr = (png_uint_32) token_value;
#if ULONG_MAX > 0xFFFFFFFFUL
/* saturate the converted number, following the fscanf convention */
if (token_value > 0xFFFFFFFFUL)
*num_ptr = 0xFFFFFFFFUL;
#endif
return 1;
}
/*
* get_pnm_data - takes first byte and converts into next pixel value,
* taking as many bits as defined by bit-depth and
* using the bit-depth to fill up a byte (0x0A -> 0xAA)
*/
png_uint_32 get_pnm_data (FILE *pnm_file, int depth)
{
static int bits_left = 0;
static int old_value = 0;
static int mask = 0;
int i;
png_uint_32 ret_value;
int i;
if (mask == 0)
for (i = 0; i < depth; i++)
@ -573,7 +609,11 @@ png_uint_32 get_data (FILE *pnm_file, int depth)
if (bits_left <= 0)
{
/* FIXME:
* signal the premature end of file, instead of pretending to read zeroes
*/
old_value = fgetc (pnm_file);
if (old_value == EOF) return 0;
bits_left = 8;
}
@ -588,25 +628,28 @@ png_uint_32 get_data (FILE *pnm_file, int depth)
}
/*
* get_value - takes first (numeric) string and converts into number,
* using the bit-depth to fill up a byte (0Ah -> AAh)
* get_pnm_value - takes first (numeric) string and converts into number,
* using the bit-depth to fill up a byte (0x0A -> 0xAA)
*/
png_uint_32 get_value (FILE *pnm_file, int depth)
png_uint_32 get_pnm_value (FILE *pnm_file, int depth)
{
static png_uint_32 mask = 0;
char token[16];
unsigned long ul_ret_value;
png_uint_32 ret_value;
int i = 0;
int i;
if (mask == 0)
for (i = 0; i < depth; i++)
mask = (mask << 1) | 0x01;
get_token (pnm_file, token, sizeof (token));
sscanf (token, "%lu", &ul_ret_value);
ret_value = (png_uint_32) ul_ret_value;
if (fscan_pnm_uint_32 (pnm_file, &ret_value) != 1)
{
/* FIXME:
* signal the invalid numeric tokens or the premature end of file,
* instead of pretending to read zeroes
*/
return 0;
}
ret_value &= mask;

View file

@ -1,4 +1,3 @@
pngsuite
--------
Copyright (c) Willem van Schaik, 1999, 2011, 2012

View file

@ -1,2 +1 @@
These images fail the "pngimage-quick" and "pngimage-full" tests.

View file

@ -2,7 +2,6 @@
*
* Copyright (c) 2017 Glenn Randers-Pehrson
* Written by Vadim Barkov, 2017.
* Last changed in libpng 1.6.29 [March 16, 2017]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -12,7 +11,7 @@
* BUG REPORTS: png-mng-implement@sourceforge.net
*
* png_have_vsx implemented for Linux by reading the widely available
* pseudo-file /proc/cpuinfo.
* pseudo-file /proc/cpuinfo.
*
* This code is strict ANSI-C and is probably moderately portable; it does
* however use <stdio.h> and it assumes that /proc/cpuinfo is never localized.

View file

@ -2,7 +2,6 @@
*
* Copyright (c) 2017 Glenn Randers-Pehrson
* Written by Vadim Barkov, 2017.
* Last changed in libpng 1.6.29 [March 16, 2017]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -1,12 +1,10 @@
#!/bin/sh
#
#!/usr/bin/env bash
# Make a set of test PNG files, MAKEPNG is the name of the makepng executable
# built from contrib/libtests/makepng.c
# Copyright (c) 2015 John Cunningham Bowler
# Last changed in libpng 1.6.20 [December 3, 2015]
# This code is released under the libpng license.
# For conditions of distribution and use, see the disclaimer
# and license in png.h

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 B

View file

@ -2,8 +2,6 @@
*
* Copyright (c) 2013 John Cunningham Bowler
*
* Last changed in libpng 1.6.0 [February 14, 2013]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@ -11,8 +9,8 @@
* Generate crc32 and adler32 checksums of the given input files, used to
* generate check-codes for use when matching ICC profiles within libpng.
*/
#include <stdio.h>
#include <stdio.h>
#include <zlib.h>
static int

View file

@ -1,144 +0,0 @@
#!/bin/sh
# chkfmt
#
# COPYRIGHT: Written by John Cunningham Bowler, 2010.
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
#
# Check the format of the source files in the current directory - checks for a
# line length of 80 characters max and no tab characters.
#
# Optionally arguments are files or directories to check.
#
# -v: output the long lines (makes fixing them easier)
# -e: spawn an editor for each file that needs a change ($EDITOR must be
# defined). When using -e the script MUST be run from an interactive
# command line.
verbose=
edit=
vers=
test "$1" = "-v" && {
shift
verbose=yes
}
test "$1" = "-e" && {
shift
if test -n "$EDITOR"
then
edit=yes
# Copy the standard streams for the editor
exec 3>&0 4>&1 5>&2
else
echo "chkfmt -e: EDITOR must be defined" >&2
exit 1
fi
}
# Function to edit a single file - if the file isn't changed ask the user
# whether or not to continue. This stuff only works if the script is run from
# the command line (otherwise, don't specify -e or you will be sorry).
doed(){
cp "$file" "$file".orig
"$EDITOR" "$file" 0>&3 1>&4 2>&5 3>&- 4>&- 5>&- || exit 1
if cmp -s "$file".orig "$file"
then
rm "$file".orig
echo -n "$file: file not changed, type anything to continue: " >&5
read ans 0>&3
test -n "$ans" || return 1
fi
return 0
}
# In beta versions the version string which appears in files can be a little
# long and cause spuriously overlong lines. To avoid this substitute the version
# string with a 'standard' version a.b.cc before checking for long lines.
if test -r png.h
then
vers="`sed -n -e \
's/^#define PNG_LIBPNG_VER_STRING .\([0-9]\.[0-9]\.[0-9][0-9a-z]*\).$/\1/p' \
png.h`"
echo "chkfmt: checking version $vers"
fi
if test -z "$vers"
then
echo "chkfmt: png.h not found, ignoring version number" >&2
fi
test -n "$1" || set -- .
find "$@" \( -type d \( -name '.git' -o -name '.libs' -o -name 'projects' \) \
-prune \) -o \( -type f \
! -name '*.[oa]' ! -name '*.l[oa]' ! -name '*.png' ! -name '*.out' \
! -name '*.jpg' ! -name '*.patch' ! -name '*.obj' ! -name '*.exe' \
! -name '*.com' ! -name '*.tar.*' ! -name '*.zip' ! -name '*.ico' \
! -name '*.res' ! -name '*.rc' ! -name '*.mms' ! -name '*.rej' \
! -name '*.dsp' ! -name '*.orig' ! -name '*.dfn' ! -name '*.swp' \
! -name '~*' ! -name '*.3' \
! -name 'missing' ! -name 'mkinstalldirs' ! -name 'depcomp' \
! -name 'aclocal.m4' ! -name 'install-sh' ! -name 'Makefile.in' \
! -name 'ltmain.sh' ! -name 'config*' -print \) | {
st=0
while read file
do
case "$file" in
*.mak|*[Mm]akefile.*|*[Mm]akefile)
# Makefiles require tabs, dependency lines can be this long.
check_tabs=
line_length=100;;
*.awk)
# Includes literal tabs
check_tabs=
# The following is arbitrary
line_length=132;;
*contrib/*/*.[ch])
check_tabs=yes
line_length=96;;
*)
check_tabs=yes
line_length=80;;
esac
# Note that vers can only contain 0-9, . and a-z
if test -n "$vers"
then
sed -e "s/$vers/a.b.cc/g" "$file" >"$file".$$
else
cp "$file" "$file".$$
fi
splt="`fold -$line_length "$file".$$ | diff -c "$file".$$ -`"
rm "$file".$$
if test -n "$splt"
then
echo "$file: lines too long"
st=1
if test -n "$EDITOR" -a -n "$edit"
then
doed "$file" || exit 1
elif test -n "$verbose"
then
echo "$splt"
fi
fi
if test -n "$check_tabs"
then
tab="`tr -c -d '\t' <"$file"`"
if test -n "$tab"
then
echo "$file: file contains tab characters"
st=1
if test -n "$EDITOR" -a -n "$edit"
then
doed "$file" || exit 1
elif test -n "$verbose"
then
echo "$splt"
fi
fi
fi
done
exit $st
}

View file

@ -1,7 +1,4 @@
/*-
* convert.c
*
* Last changed in libpng 1.6.0 [February 14, 2013]
/* convert.c
*
* COPYRIGHT: Written by John Cunningham Bowler, 2013.
* To the extent possible under law, the author has waived all copyright and
@ -10,6 +7,7 @@
*
* Convert 8-bit sRGB or 16-bit linear values to another format.
*/
#define _ISOC99_SOURCE 1
#include <stdlib.h>

View file

@ -1,4 +1,4 @@
/*- genpng
/* genpng
*
* COPYRIGHT: Written by John Cunningham Bowler, 2015.
* Revised by Glenn Randers-Pehrson, 2017, to add buffer-size check.
@ -69,6 +69,7 @@
* joins are mitres; the outside of the lines are continued to the point of
* intersection.
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@ -453,7 +454,7 @@ check_square(const struct arg *arg, double x, double y)
* { inside_circle_filled, check_circle_filled },
* { inside_circle, check_circle }
*
* The functions here are analoguous to the square ones; however, they check
* The functions here are analogous to the square ones; however, they check
* the corresponding ellipse as opposed to the rectangle.
*/
static int

View file

@ -1,13 +1,11 @@
#!/bin/sh
#
# intgamma.sh
#
# Last changed in libpng 1.6.0 [February 14, 2013]
#
# COPYRIGHT: Written by John Cunningham Bowler, 2013.
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
# related or neighboring rights to this work. The author published this work
# from the United States.
#
# Shell script to generate png.c 8-bit and 16-bit log tables (see the code in
# png.c for details).
@ -17,11 +15,11 @@
# (0..255) value and a similar table for the exponent calculation.
#
# "bc" must be on the path when the script is executed, and the math library
# (-lm) must be available
#
# function to print out a list of numbers as integers; the function truncates
# the integers which must be one-per-line
function print(){
# (-lm) must be available.
# Function to print out a list of numbers as integers; the function truncates
# the integers which must be one-per-line.
print(){
awk 'BEGIN{
str = ""
}

View file

@ -1,6 +1,4 @@
/* makesRGB.c -- build sRGB-to-linear and linear-to-sRGB conversion tables
*
* Last changed in libpng 1.6.0 [February 14, 2013]
*
* COPYRIGHT: Written by John Cunningham Bowler, 2013.
* To the extent possible under law, the author has waived all copyright and
@ -14,6 +12,7 @@
* approximation to the 8-bit sRGB encoded value. Calculate the error in these
* tables and display it.
*/
#define _C99_SOURCE 1
#include <stdio.h>
#include <math.h>

View file

@ -1,8 +1,6 @@
/* png-fix-itxt version 1.0.0
/* png-fix-itxt
*
* Copyright 2015 Glenn Randers-Pehrson
* Last changed in libpng 1.6.18 [July 23, 2015]
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -10,7 +8,7 @@
*
* Usage:
*
* png-fix-itxt.exe < bad.png > good.png
* png-fix-itxt < bad.png > good.png
*
* Fixes a PNG file written with libpng-1.6.0 or 1.6.1 that has one or more
* uncompressed iTXt chunks. Assumes that the actual length is greater

View file

@ -1,8 +1,6 @@
/* pngcp.c
*
* Copyright (c) 2016 John Cunningham Bowler
*
* Last changed in libpng 1.6.24 [August 4, 2016]
* Copyright (c) 2016,2022,2024 John Cunningham Bowler
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -14,7 +12,12 @@
*
* For a more extensive example that uses the transforms see
* contrib/libtests/pngimage.c in the libpng distribution.
*
* This code is not intended for installation in a release system; the command
* line options are not documented and most of the behavior is intended for
* testing libpng performance, both speed and compression.
*/
#include "pnglibconf.h" /* To find how libpng was configured. */
#ifdef PNG_PNGCP_TIMING_SUPPORTED
@ -85,16 +88,6 @@
# define voidcast(type, value) (value)
#endif /* __cplusplus */
#ifdef __GNUC__
/* Many versions of GCC erroneously report that local variables unmodified
* within the scope of a setjmp may be clobbered. This hacks round the
* problem (sometimes) without harming other compilers.
*/
# define gv volatile
#else
# define gv
#endif
/* 'CLOCK_PROCESS_CPUTIME_ID' is one of the clock timers for clock_gettime. It
* need not be supported even when clock_gettime is available. It returns the
* 'CPU' time the process has consumed. 'CPU' time is assumed to include time
@ -336,7 +329,7 @@ static const option options[] =
# define VLC(name) VLCIDAT(name) VLCiCCP(name) VLCzTXt(name)
# ifdef PNG_SW_COMPRESS_png_level
/* The libpng compression level isn't searched because it justs sets the
/* The libpng compression level isn't searched because it just sets the
* other things that are searched!
*/
VLO("compression", compression, 0)
@ -392,6 +385,7 @@ struct display
{
jmp_buf error_return; /* Where to go to on error */
unsigned int errset; /* error_return is set */
int errlevel; /* error level from longjmp */
const char *operation; /* What is happening */
const char *filename; /* The name of the original file */
@ -503,10 +497,10 @@ display_init(struct display *dp)
}
static void
display_clean_read(struct display *dp)
display_clean_read(struct display *dp, int freeinfo)
{
if (dp->read_pp != NULL)
png_destroy_read_struct(&dp->read_pp, NULL, NULL);
png_destroy_read_struct(&dp->read_pp, freeinfo ? &dp->ip : NULL, NULL);
if (dp->fp != NULL)
{
@ -517,7 +511,7 @@ display_clean_read(struct display *dp)
}
static void
display_clean_write(struct display *dp)
display_clean_write(struct display *dp, int freeinfo)
{
if (dp->fp != NULL)
{
@ -527,14 +521,14 @@ display_clean_write(struct display *dp)
}
if (dp->write_pp != NULL)
png_destroy_write_struct(&dp->write_pp, dp->tsp > 0 ? NULL : &dp->ip);
png_destroy_write_struct(&dp->write_pp, freeinfo ? &dp->ip : NULL);
}
static void
display_clean(struct display *dp)
{
display_clean_read(dp);
display_clean_write(dp);
display_clean_read(dp, 1/*freeinfo*/);
display_clean_write(dp, 1/*freeinfo*/);
dp->output_file = NULL;
# if PNG_LIBPNG_VER < 10700 && defined PNG_TEXT_SUPPORTED
@ -631,7 +625,10 @@ display_log(struct display *dp, error_level level, const char *fmt, ...)
if (level > APP_FAIL || (level > ERRORS && !(dp->options & CONTINUE)))
{
if (dp->errset)
{
dp->errlevel = level;
longjmp(dp->error_return, level);
}
else
exit(99);
@ -778,7 +775,7 @@ static void
set_opt_string(struct display *dp, unsigned int sp)
/* Add the appropriate option string to dp->curr. */
{
dp->stack[sp].opt_string_end = set_opt_string_(dp, sp, dp->stack[sp].opt,
dp->stack[sp].opt_string_end = set_opt_string_(dp, sp, dp->stack[sp].opt,
options[dp->stack[sp].opt].values[dp->stack[sp].entry].name);
}
@ -1745,7 +1742,17 @@ read_function(png_structp pp, png_bytep data, size_t size)
static void
read_png(struct display *dp, const char *filename)
{
display_clean_read(dp); /* safety */
/* This is an assumption of the code; it may happen if a previous write fails
* and there is a bug in the cleanup handling below (look for setjmp).
* Passing freeinfo==1 to display_clean_read below avoids a second error
* on dp->ip != NULL below.
*/
if (dp->read_pp != NULL)
{
display_log(dp, APP_FAIL, "unexpected png_read_struct");
display_clean_read(dp, 1/*freeinfo*/); /* recovery */
}
display_start_read(dp, filename);
dp->read_pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, dp,
@ -1769,6 +1776,13 @@ read_png(struct display *dp, const char *filename)
png_set_check_for_invalid_index(dp->read_pp, -1/*off completely*/);
# endif /* IGNORE_INDEX */
if (dp->ip != NULL)
{
/* UNEXPECTED: some problem in the display_clean function calls! */
display_log(dp, APP_FAIL, "read_png: freeing old info struct");
png_destroy_info_struct(dp->read_pp, &dp->ip);
}
/* The png_read_png API requires us to make the info struct, but it does the
* call to png_read_info.
*/
@ -1848,7 +1862,14 @@ read_png(struct display *dp, const char *filename)
}
#endif /* FIX_INDEX */
display_clean_read(dp);
/* NOTE: dp->ip is where all the information about the PNG that was just read
* is stored. It can be used to write and write again a single PNG file,
* however be aware that prior to libpng 1.7 text chunks could only be
* written once; this is a bug which would require a significant code rewrite
* to fix, it has been there in several versions of libpng (it was introduced
* to fix another bug involving duplicate writes of the text chunks.)
*/
display_clean_read(dp, 0/*freeiinfo*/);
dp->operation = "none";
}
@ -1975,7 +1996,21 @@ set_text_compression(struct display *dp)
static void
write_png(struct display *dp, const char *destname)
{
display_clean_write(dp); /* safety */
/* If this test fails png_write_png would fail *silently* below; this
* is not helpful, so catch the problem now and give up:
*/
if (dp->ip == NULL)
display_log(dp, INTERNAL_ERROR, "missing png_info");
/* This is an assumption of the code; it may happen if a previous
* write fails and there is a bug in the cleanup handling below.
*/
if (dp->write_pp != NULL)
{
display_log(dp, APP_FAIL, "unexpected png_write_struct");
display_clean_write(dp, 0/*!freeinfo*/);
}
display_start_write(dp, destname);
dp->write_pp = png_create_write_struct(PNG_LIBPNG_VER_STRING, dp,
@ -2073,10 +2108,6 @@ write_png(struct display *dp, const char *destname)
destname == NULL ? "stdout" : destname, strerror(errno));
}
/* Clean it on the way out - if control returns to the caller then the
* written_file contains the required data.
*/
display_clean_write(dp);
dp->operation = "none";
}
@ -2243,6 +2274,10 @@ cp_one_file(struct display *dp, const char *filename, const char *destname)
/* Loop to find the best option. */
do
{
/* Clean before each write_png; this just removes *dp->write_pp which
* cannot be reused.
*/
display_clean_write(dp, 0/*!freeinfo*/);
write_png(dp, tmpname);
/* And compare the sizes (the write function makes sure write_size
@ -2272,17 +2307,14 @@ cp_one_file(struct display *dp, const char *filename, const char *destname)
/* Do this for the 'sizes' option so that it reports the correct size. */
dp->write_size = dp->best_size;
}
display_clean_write(dp, 1/*freeinfo*/);
}
static int
cppng(struct display *dp, const char *file, const char *gv dest)
/* Exists solely to isolate the setjmp clobbers which some versions of GCC
* erroneously generate.
*/
cppng(struct display *dp, const char *file, const char *dest)
{
int ret = setjmp(dp->error_return);
if (ret == 0)
if (setjmp(dp->error_return) == 0)
{
dp->errset = 1;
cp_one_file(dp, file, dest);
@ -2294,10 +2326,11 @@ cppng(struct display *dp, const char *file, const char *gv dest)
{
dp->errset = 0;
if (ret < ERRORS) /* shouldn't longjmp on warnings */
display_log(dp, INTERNAL_ERROR, "unexpected return code %d", ret);
if (dp->errlevel < ERRORS) /* shouldn't longjmp on warnings */
display_log(dp, INTERNAL_ERROR, "unexpected return code %d",
dp->errlevel);
return ret;
return dp->errlevel;
}
}

View file

@ -1,7 +1,6 @@
/* pngfix.c
*
* Last changed in libpng 1.6.31 [July 27, 2017]
* Copyright (c) 2014-2017 John Cunningham Bowler
* Copyright (c) 2014-2017,2024 John Cunningham Bowler
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
@ -10,6 +9,7 @@
* Tool to check and fix the zlib inflate 'too far back' problem.
* See the usage message for more information.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -20,19 +20,6 @@
#define implies(x,y) assert(!(x) || (y))
#ifdef __GNUC__
/* This is used to fix the error:
*
* pngfix.c:
* In function 'zlib_advance':
* pngfix.c:181:13: error: assuming signed overflow does not
* occur when simplifying conditional to constant [-Werror=strict-overflow]
*/
# define FIX_GCC volatile
#else
# define FIX_GCC
#endif
#define PROGRAM_NAME "pngfix"
/* Define the following to use this program against your installed libpng,
@ -45,7 +32,7 @@
#endif
#if PNG_LIBPNG_VER < 10603 /* 1.6.3 */
# error "pngfix will not work with libpng prior to 1.6.3"
# error pngfix requires libpng version 1.6.3 or newer
#endif
#ifdef PNG_SETJMP_SUPPORTED
@ -81,7 +68,7 @@
#endif
#ifndef PNG_MAXIMUM_INFLATE_WINDOW
# error "pngfix not supported in this libpng version"
# error pngfix requires libpng with PNG_MAXIMUM_INFLATE_WINDOW supported
#endif
#if ZLIB_VERNUM >= 0x1240
@ -146,11 +133,6 @@
/* Is it safe to copy? */
#define SAFE_TO_COPY(chunk) (((chunk) & PNG_U32(0,0,0,32)) != 0)
/* Fix ups for builds with limited read support */
#ifndef PNG_ERROR_TEXT_SUPPORTED
# define png_error(a,b) png_err(a)
#endif
/********************************* UTILITIES **********************************/
/* UNREACHED is a value to cause an assert to fail. Because of the way the
* assert macro is written the string "UNREACHED" is produced in the error
@ -218,7 +200,7 @@ uarb_inc(uarb num, int in_digits, png_int_32 add)
* in_digits+1 if add is known to be in the range -65535..65535.
*/
{
FIX_GCC int out_digits = 0;
int out_digits = 0;
while (out_digits < in_digits)
{
@ -263,7 +245,7 @@ uarb_add32(uarb num, int in_digits, png_uint_32 add)
}
static int
uarb_mult_digit(uarb acc, int a_digits, uarb num, FIX_GCC int n_digits,
uarb_mult_digit(uarb acc, int a_digits, uarb num, int n_digits,
png_uint_16 val)
/* Primitive one-digit multiply - 'val' must be 0..65535. Note that this
* primitive is a multiply and accumulate - the result of *num * val is added
@ -336,7 +318,7 @@ uarb_shift(uarb inout, int ndigits, unsigned int right_shift)
* 1..15
*/
{
FIX_GCC int i = ndigits;
int i = ndigits;
png_uint_16 carry = 0;
assert(right_shift >= 1 && right_shift <= 15);
@ -351,7 +333,7 @@ uarb_shift(uarb inout, int ndigits, unsigned int right_shift)
inout[i] = temp;
/* The shift may reduce ndigits */
if (i == ndigits-1 && temp == 0)
if (i+1 == ndigits && temp == 0)
ndigits = i;
}
@ -867,7 +849,7 @@ struct file
* signature (in length,type).
*
* When a chunk control structure is instantiated these values are copied
* into the structure and can then be overritten with the data for the next
* into the structure and can then be overwritten with the data for the next
* chunk.
*/
fpos_t data_pos; /* Position of first byte of chunk data */
@ -1005,10 +987,18 @@ file_end(struct file *file)
if (file->out != NULL)
{
/* NOTE: this is bitwise |, all the following functions must execute and
* must succeed.
/* On some systems 'fclose' deletes the FILE struct (making it
* inaccessbile). There is no guarantee that fclose returns an error
* code from fflush or, indeed, from the FILE error indicator. There is
* also no explicit (or clear) guarantee in the standard that anything
* other than a read or write operation sets the error indicator; fflush
* is not a read or write operation, so both conditions must be checked
* to ensure the close succeeded and in ANSI-C conformant code they must
* be checked before the fclose call.
*/
if (ferror(file->out) | fflush(file->out) | fclose(file->out))
const int err = fflush(file->out) || ferror(file->out);
if (fclose(file->out) || err)
{
perror(file->out_name);
emit_error(file, READ_ERROR_CODE, "output write error");
@ -1598,7 +1588,7 @@ chunk_init(struct chunk * const chunk, struct file * const file)
chunk->chunk_length = file->length;
chunk->chunk_type = file->type;
/* Compresssed/uncompressed size information (from the zlib control structure
/* Compressed/uncompressed size information (from the zlib control structure
* that is used to check the compressed data in a chunk.)
*/
chunk->uncompressed_digits = 0;
@ -2929,7 +2919,7 @@ process_chunk(struct file *file, png_uint_32 file_crc, png_uint_32 next_length,
}
/* Control reaches this point if the chunk must be skipped. For chunks other
* than IDAT this means that the zlib compressed data is fatally damanged and
* than IDAT this means that the zlib compressed data is fatally damaged and
* the chunk will not be passed to libpng. For IDAT it means that the end of
* the IDAT stream has not yet been reached and we must handle the next
* (IDAT) chunk. If the LZ data in an IDAT stream cannot be read 'stop' must
@ -3961,6 +3951,14 @@ main(int argc, const char **argv)
{
size_t outlen = strlen(*argv);
if (outlen > FILENAME_MAX)
{
fprintf(stderr, "%s: output file name too long: %s%s%s\n",
prog, prefix, *argv, suffix ? suffix : "");
global.status_code |= WRITE_ERROR;
continue;
}
if (outfile == NULL) /* else this takes precedence */
{
/* Consider the prefix/suffix options */
@ -4046,4 +4044,4 @@ main(void)
return 77;
}
#endif /* PNG_SETJMP_SUPPORTED */
/* vi: set textwidth=80 shiftwidth=3 softtabstop=-1 expandtab: */

View file

@ -1,25 +0,0 @@
#!/bin/sh
# reindent a libpng C source
# COPYRIGHT: Written by Glenn Randers-Pehrson, 2016.
# To the extent possible under law, the author has waived all copyright and
# related or neighboring rights to this work. This work is published from:
# United States.
# Usage:
# reindent inputtabsize outputtabsize inputcontinuestring outputcontinuestring
#
# Assumes that continued lines begin with indentation plus one space, and
# that continued comments begin with indentation plus " *".
#
# eg, to change libpng coding style from 3-space indentation with 4-space
# continuations to 4-space indentation with 2-space continuations:
#
# reindent 3 4 "\t " " " < example.c > example.c_4_2
# and to restore the file back to libpng coding style
# reindent 4 3 " " " " < example.c_4_2 > example.c_3_4
unexpand --first-only --t $1 | \
sed -e "/^ *$3[^\*]/{s/$3/$4/}" | \
expand -t $2

View file

@ -1,7 +1,4 @@
/*-
* sRGB.h
*
* Last changed in libpng 1.6.0 [February 14, 2013]
/* sRGB.h
*
* COPYRIGHT: Written by John Cunningham Bowler, 2013.
* To the extent possible under law, the author has waived all copyright and
@ -16,6 +13,7 @@
* (in fact the source of the numbers is the wikipedia article at
* https://en.wikipedia.org/wiki/SRGB).
*/
static double
sRGB_from_linear(double l)
{

View file

@ -0,0 +1,23 @@
# https://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = unset
indent_size = 4
indent_style = space
insert_final_newline = true
max_doc_length = 80
max_line_length = 100
trim_trailing_whitespace = true
[*.rc]
end_of_line = crlf
trim_trailing_whitespace = unset
[*.ds[pw]]
end_of_line = crlf
max_doc_length = unset
max_line_length = unset
trim_trailing_whitespace = unset

View file

@ -103,7 +103,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
return 0;
}
/* if filename given on commandline, store it */
/* if filename given on command line, store it */
if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
if (szCmdLine[0] == '"')
strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);