mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
pngminus: Fix and improve the PNM processing
Improve png2pnm.c: * Add support for writing 16-bit raw PNM image files. Fix and improve pnm2png.c: * Add support for reading 16-bit raw PNM image files. * Fix the parsing of arbitrarily long numeric strings. In the parsing of PNM tokens, we can and we should avoid storing more than one leading '0' in the token buffer. All valid (in-range) numeric strings must fit in this limited-size buffer, regardless of their actual length in the input file. * Refactor the PNM parsing in order to make it more capable to handle various kinds of input file errors. * Remove the volatile qualifiers from all variable declarations. Their original purpose was to appease old (and incorrect) warnings issued by ancient optimizing compilers. * Print a note about the program's lack of support for the PAM ("P7") file format when the input is in this format. * Add FIXME notes about the need to signal incorrect or incomplete input files. (For png2pnm, this is done inside libpng.)
This commit is contained in:
parent
c993ae4c67
commit
abb8d4a71f
@ -14,10 +14,10 @@
|
|||||||
#define BOOL unsigned char
|
#define BOOL unsigned char
|
||||||
#endif
|
#endif
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (BOOL) 1
|
#define TRUE ((BOOL) 1)
|
||||||
#endif
|
#endif
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (BOOL) 0
|
#define FALSE ((BOOL) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* make png2pnm verbose so we can find problems (needs to be before png.h) */
|
/* make png2pnm verbose so we can find problems (needs to be before png.h) */
|
||||||
@ -256,15 +256,6 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
|
|||||||
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
|
||||||
NULL, NULL, NULL);
|
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 new number of channels and store alpha-presence */
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY)
|
if (color_type == PNG_COLOR_TYPE_GRAY)
|
||||||
channels = 1;
|
channels = 1;
|
||||||
@ -364,13 +355,16 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
|
|||||||
if (raw)
|
if (raw)
|
||||||
{
|
{
|
||||||
fputc ((int) *pix_ptr++, pnm_file);
|
fputc ((int) *pix_ptr++, pnm_file);
|
||||||
|
if (bit_depth == 16)
|
||||||
|
fputc ((int) *pix_ptr++, pnm_file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
{
|
{
|
||||||
dep_16 = (long) *pix_ptr++;
|
dep_16 = ((long) *pix_ptr++) << 8;
|
||||||
fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
|
dep_16 += ((long) *pix_ptr++);
|
||||||
|
fprintf (pnm_file, "%ld ", dep_16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -382,22 +376,27 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
|
|||||||
{
|
{
|
||||||
if (!alpha)
|
if (!alpha)
|
||||||
{
|
{
|
||||||
pix_ptr++; /* alpha */
|
/* skip the alpha-channel */
|
||||||
|
pix_ptr++;
|
||||||
if (bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
pix_ptr++;
|
pix_ptr++;
|
||||||
}
|
}
|
||||||
else /* output alpha-channel as pgm file */
|
else
|
||||||
{
|
{
|
||||||
|
/* output the alpha-channel as pgm file */
|
||||||
if (raw)
|
if (raw)
|
||||||
{
|
{
|
||||||
fputc ((int) *pix_ptr++, alpha_file);
|
fputc ((int) *pix_ptr++, alpha_file);
|
||||||
|
if (bit_depth == 16)
|
||||||
|
fputc ((int) *pix_ptr++, alpha_file);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
{
|
{
|
||||||
dep_16 = (long) *pix_ptr++;
|
dep_16 = ((long) *pix_ptr++) << 8;
|
||||||
fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
|
dep_16 += ((long) *pix_ptr++);
|
||||||
|
fprintf (alpha_file, "%ld ", dep_16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -423,5 +422,4 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
|
|||||||
free (png_pixels);
|
free (png_pixels);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
} /* end of source */
|
} /* end of source */
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
* distribution and use, see the LICENSE file part of this package.
|
* distribution and use, see the LICENSE file part of this package.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -14,10 +15,10 @@
|
|||||||
#define BOOL unsigned char
|
#define BOOL unsigned char
|
||||||
#endif
|
#endif
|
||||||
#ifndef TRUE
|
#ifndef TRUE
|
||||||
#define TRUE (BOOL) 1
|
#define TRUE ((BOOL) 1)
|
||||||
#endif
|
#endif
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE (BOOL) 0
|
#define FALSE ((BOOL) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* make pnm2png verbose so we can find problems (needs to be before png.h) */
|
/* make pnm2png verbose so we can find problems (needs to be before png.h) */
|
||||||
@ -33,9 +34,11 @@ int main (int argc, char *argv[]);
|
|||||||
void usage ();
|
void usage ();
|
||||||
BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
||||||
BOOL interlace, BOOL alpha);
|
BOOL interlace, BOOL alpha);
|
||||||
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);
|
||||||
png_uint_32 get_data (FILE *pnm_file, int depth);
|
int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size);
|
||||||
png_uint_32 get_value (FILE *pnm_file, int depth);
|
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
|
* main
|
||||||
@ -168,50 +171,47 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
png_byte *png_pixels = NULL;
|
png_byte *png_pixels = NULL;
|
||||||
png_byte **row_pointers = NULL;
|
png_byte **row_pointers = NULL;
|
||||||
png_byte *pix_ptr = NULL;
|
png_byte *pix_ptr = NULL;
|
||||||
volatile png_uint_32 row_bytes;
|
int bit_depth;
|
||||||
|
int color_type;
|
||||||
char type_token[16];
|
int channels;
|
||||||
char width_token[16];
|
char magic_token[4];
|
||||||
char height_token[16];
|
BOOL raw;
|
||||||
char maxval_token[16];
|
png_uint_32 width, height, maxval;
|
||||||
volatile int color_type = 1;
|
png_uint_32 row_bytes;
|
||||||
unsigned long ul_width = 0, ul_alpha_width = 0;
|
png_uint_32 row, col;
|
||||||
unsigned long ul_height = 0, ul_alpha_height = 0;
|
png_uint_32 val16, i;
|
||||||
unsigned long ul_maxval = 0;
|
png_uint_32 alpha_width = 0, alpha_height = 0;
|
||||||
volatile png_uint_32 width = 0, height = 0;
|
int alpha_depth = 0, alpha_present = 0;
|
||||||
volatile png_uint_32 alpha_width = 0, alpha_height = 0;
|
BOOL alpha_raw = FALSE;
|
||||||
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)
|
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
|
||||||
BOOL packed_bitmap = FALSE;
|
BOOL packed_bitmap = FALSE;
|
||||||
#endif
|
#endif
|
||||||
png_uint_32 tmp16;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* read header of PNM file */
|
/* read header of PNM file */
|
||||||
|
|
||||||
get_token (pnm_file, type_token, sizeof (type_token));
|
if (fscan_pnm_magic (pnm_file, magic_token, sizeof (magic_token)) != 1)
|
||||||
if (type_token[0] != 'P')
|
return FALSE; /* not a PNM file */
|
||||||
|
|
||||||
|
if ((magic_token[1] == '1') || (magic_token[1] == '4'))
|
||||||
{
|
{
|
||||||
return FALSE;
|
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 */
|
||||||
}
|
}
|
||||||
else if ((type_token[1] == '1') || (type_token[1] == '4'))
|
|
||||||
|
if ((magic_token[1] == '1') || (magic_token[1] == '4'))
|
||||||
{
|
{
|
||||||
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
|
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
|
||||||
raw = (type_token[1] == '4');
|
raw = (magic_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;
|
bit_depth = 1;
|
||||||
|
color_type = PNG_COLOR_TYPE_GRAY;
|
||||||
packed_bitmap = TRUE;
|
packed_bitmap = TRUE;
|
||||||
#else
|
#else
|
||||||
fprintf (stderr, "PNM2PNG built without PNG_WRITE_INVERT_SUPPORTED and\n");
|
fprintf (stderr, "PNM2PNG built without PNG_WRITE_INVERT_SUPPORTED and\n");
|
||||||
@ -219,21 +219,13 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if ((type_token[1] == '2') || (type_token[1] == '5'))
|
else if ((magic_token[1] == '2') || (magic_token[1] == '5'))
|
||||||
{
|
{
|
||||||
raw = (type_token[1] == '5');
|
raw = (magic_token[1] == '5');
|
||||||
color_type = PNG_COLOR_TYPE_GRAY;
|
color_type = PNG_COLOR_TYPE_GRAY;
|
||||||
get_token (pnm_file, width_token, sizeof (width_token));
|
if (maxval == 0)
|
||||||
sscanf (width_token, "%lu", &ul_width);
|
return FALSE;
|
||||||
width = (png_uint_32) ul_width;
|
else if (maxval == 1)
|
||||||
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)
|
|
||||||
bit_depth = 1;
|
bit_depth = 1;
|
||||||
else if (maxval <= 3)
|
else if (maxval <= 3)
|
||||||
bit_depth = 2;
|
bit_depth = 2;
|
||||||
@ -246,20 +238,13 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
else /* maxval > 65535U */
|
else /* maxval > 65535U */
|
||||||
return FALSE;
|
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;
|
color_type = PNG_COLOR_TYPE_RGB;
|
||||||
get_token (pnm_file, width_token, sizeof (width_token));
|
if (maxval == 0)
|
||||||
sscanf (width_token, "%lu", &ul_width);
|
return FALSE;
|
||||||
width = (png_uint_32) ul_width;
|
else if (maxval == 1)
|
||||||
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)
|
|
||||||
bit_depth = 1;
|
bit_depth = 1;
|
||||||
else if (maxval <= 3)
|
else if (maxval <= 3)
|
||||||
bit_depth = 2;
|
bit_depth = 2;
|
||||||
@ -272,6 +257,11 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
else /* maxval > 65535U */
|
else /* maxval > 65535U */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
else if (magic_token[1] == '7')
|
||||||
|
{
|
||||||
|
fprintf (stderr, "PNM2PNG can't read PAM (P7) files\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -281,51 +271,36 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
|
|
||||||
if (alpha)
|
if (alpha)
|
||||||
{
|
{
|
||||||
if (color_type == PNG_COLOR_TYPE_GRAY)
|
if ((fscan_pnm_magic (alpha_file, magic_token, sizeof (magic_token)) != 1)
|
||||||
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
|| ((magic_token[1] != '2') && (magic_token[1] != '5')))
|
||||||
if (color_type == PNG_COLOR_TYPE_RGB)
|
return FALSE; /* not a PGM file */
|
||||||
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
|
||||||
|
|
||||||
get_token (alpha_file, type_token, sizeof (type_token));
|
if ((fscan_pnm_uint_32 (alpha_file, &alpha_width) != 1) ||
|
||||||
if (type_token[0] != 'P')
|
(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;
|
return FALSE;
|
||||||
}
|
else if (maxval == 1)
|
||||||
else if ((type_token[1] == '2') || (type_token[1] == '5'))
|
alpha_depth = 1;
|
||||||
{
|
else if (maxval <= 3)
|
||||||
alpha_raw = (type_token[1] == '5');
|
alpha_depth = 2;
|
||||||
get_token (alpha_file, width_token, sizeof (width_token));
|
else if (maxval <= 15)
|
||||||
sscanf (width_token, "%lu", &ul_alpha_width);
|
alpha_depth = 4;
|
||||||
alpha_width = (png_uint_32) ul_alpha_width;
|
else if (maxval <= 255)
|
||||||
if (alpha_width != width)
|
alpha_depth = 8;
|
||||||
return FALSE;
|
else if (maxval <= 65535U)
|
||||||
get_token (alpha_file, height_token, sizeof (height_token));
|
alpha_depth = 16;
|
||||||
sscanf (height_token, "%lu", &ul_alpha_height);
|
else /* maxval > 65535U */
|
||||||
alpha_height = (png_uint_32) ul_alpha_height;
|
return FALSE;
|
||||||
if (alpha_height != height)
|
if (alpha_depth != bit_depth)
|
||||||
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
|
|
||||||
{
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
|
||||||
} /* end if alpha */
|
} /* end if alpha */
|
||||||
|
|
||||||
/* calculate the number of channels and store alpha-presence */
|
/* calculate the number of channels and store alpha-presence */
|
||||||
@ -337,10 +312,8 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
channels = 3;
|
channels = 3;
|
||||||
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
|
||||||
channels = 4;
|
channels = 4;
|
||||||
#if 0
|
|
||||||
else
|
else
|
||||||
channels = 0; /* cannot happen */
|
return FALSE; /* NOTREACHED */
|
||||||
#endif
|
|
||||||
|
|
||||||
alpha_present = (channels - 1) % 2;
|
alpha_present = (channels - 1) % 2;
|
||||||
|
|
||||||
@ -373,40 +346,42 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
/* read data from PNM file */
|
/* read data from PNM file */
|
||||||
pix_ptr = png_pixels;
|
pix_ptr = png_pixels;
|
||||||
|
|
||||||
for (row = 0; row < (int) height; row++)
|
for (row = 0; row < height; row++)
|
||||||
{
|
{
|
||||||
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
|
#if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
|
||||||
if (packed_bitmap)
|
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 */
|
/* 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
|
else
|
||||||
#endif
|
#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)
|
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
|
else
|
||||||
{
|
{
|
||||||
if (bit_depth <= 8)
|
if (bit_depth <= 8)
|
||||||
{
|
{
|
||||||
*pix_ptr++ = get_value (pnm_file, bit_depth);
|
*pix_ptr++ = get_pnm_value (pnm_file, bit_depth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmp16 = get_value (pnm_file, bit_depth);
|
val16 = get_pnm_value (pnm_file, bit_depth);
|
||||||
*pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
|
*pix_ptr = (png_byte) ((val16 >> 8) & 0xFF);
|
||||||
pix_ptr++;
|
pix_ptr++;
|
||||||
*pix_ptr = (png_byte) (tmp16 & 0xFF);
|
*pix_ptr = (png_byte) (val16 & 0xFF);
|
||||||
pix_ptr++;
|
pix_ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,19 +391,21 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
{
|
{
|
||||||
if (alpha_raw)
|
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
|
else
|
||||||
{
|
{
|
||||||
if (alpha_depth <= 8)
|
if (alpha_depth <= 8)
|
||||||
{
|
{
|
||||||
*pix_ptr++ = get_value (alpha_file, bit_depth);
|
*pix_ptr++ = get_pnm_value (alpha_file, bit_depth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tmp16 = get_value (alpha_file, bit_depth);
|
val16 = get_pnm_value (alpha_file, bit_depth);
|
||||||
*pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
|
*pix_ptr++ = (png_byte) ((val16 >> 8) & 0xFF);
|
||||||
*pix_ptr++ = (png_byte) (tmp16 & 0xFF);
|
*pix_ptr++ = (png_byte) (val16 & 0xFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* end if alpha */
|
} /* end if alpha */
|
||||||
@ -491,7 +468,7 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* set the individual row_pointers to point at the correct offsets */
|
/* set the individual row_pointers to point at the correct offsets */
|
||||||
for (i = 0; i < (int) height; i++)
|
for (i = 0; i < height; i++)
|
||||||
row_pointers[i] = png_pixels + i * row_bytes;
|
row_pointers[i] = png_pixels + i * row_bytes;
|
||||||
|
|
||||||
/* write out the entire image data in one call */
|
/* write out the entire image data in one call */
|
||||||
@ -512,10 +489,42 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file,
|
|||||||
} /* end of pnm2png */
|
} /* 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;
|
size_t i = 0;
|
||||||
int ret;
|
int ret;
|
||||||
@ -543,29 +552,66 @@ void get_token (FILE *pnm_file, char *token_buf, size_t token_buf_size)
|
|||||||
{
|
{
|
||||||
ret = fgetc (pnm_file);
|
ret = fgetc (pnm_file);
|
||||||
if (ret == EOF) break;
|
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;
|
if (++i == token_buf_size - 1) break;
|
||||||
token_buf[i] = (char) ret;
|
token_buf[i] = (char) ret;
|
||||||
}
|
}
|
||||||
while ((ret != '\n') && (ret != '\r') && (ret != ' '));
|
while ((ret != '\n') && (ret != '\r') && (ret != ' '));
|
||||||
|
|
||||||
token_buf[i] = '\0';
|
token_buf[i] = '\0';
|
||||||
|
return (i > 0) ? 1 : 0;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_data - takes first byte and converts into next pixel value,
|
* fscan_pnm_uint_32 - like fscan_token above, but expects the extracted token
|
||||||
* taking as much bits as defined by bit-depth and
|
* to be numeric, and converts it to an unsigned 32-bit int
|
||||||
* using the bit-depth to fill up a byte (0Ah -> AAh)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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 bits_left = 0;
|
||||||
static int old_value = 0;
|
static int old_value = 0;
|
||||||
static int mask = 0;
|
static int mask = 0;
|
||||||
int i;
|
|
||||||
png_uint_32 ret_value;
|
png_uint_32 ret_value;
|
||||||
|
int i;
|
||||||
|
|
||||||
if (mask == 0)
|
if (mask == 0)
|
||||||
for (i = 0; i < depth; i++)
|
for (i = 0; i < depth; i++)
|
||||||
@ -573,7 +619,11 @@ png_uint_32 get_data (FILE *pnm_file, int depth)
|
|||||||
|
|
||||||
if (bits_left <= 0)
|
if (bits_left <= 0)
|
||||||
{
|
{
|
||||||
|
/* FIXME:
|
||||||
|
* signal the premature end of file, instead of pretending to read zeroes
|
||||||
|
*/
|
||||||
old_value = fgetc (pnm_file);
|
old_value = fgetc (pnm_file);
|
||||||
|
if (old_value == EOF) return 0;
|
||||||
bits_left = 8;
|
bits_left = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,25 +638,28 @@ png_uint_32 get_data (FILE *pnm_file, int depth)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_value - takes first (numeric) string and converts into number,
|
* get_pnm_value - takes first (numeric) string and converts into number,
|
||||||
* using the bit-depth to fill up a byte (0Ah -> AAh)
|
* 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;
|
static png_uint_32 mask = 0;
|
||||||
char token[16];
|
|
||||||
unsigned long ul_ret_value;
|
|
||||||
png_uint_32 ret_value;
|
png_uint_32 ret_value;
|
||||||
int i = 0;
|
int i;
|
||||||
|
|
||||||
if (mask == 0)
|
if (mask == 0)
|
||||||
for (i = 0; i < depth; i++)
|
for (i = 0; i < depth; i++)
|
||||||
mask = (mask << 1) | 0x01;
|
mask = (mask << 1) | 0x01;
|
||||||
|
|
||||||
get_token (pnm_file, token, sizeof (token));
|
if (fscan_pnm_uint_32 (pnm_file, &ret_value) != 1)
|
||||||
sscanf (token, "%lu", &ul_ret_value);
|
{
|
||||||
ret_value = (png_uint_32) ul_ret_value;
|
/* FIXME:
|
||||||
|
* signal the invalid numeric tokens or the premature end of file,
|
||||||
|
* instead of pretending to read zeroes
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ret_value &= mask;
|
ret_value &= mask;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user