*/
-#define BSIZ 1024
#define misspace(x) (x==' ' || x=='\n' || x=='\r' || x=='\t' || x=='\f' || x=='\v')
#define misnumber(x) (x <= '9' && x>='0')
static char *typenames[]={"ascii pbm", "ascii pgm", "ascii ppm", "binary pbm", "binary pgm", "binary ppm"};
/*
- * Type to encapsulate the local buffer
- * management skipping over in a file
- */
-
-typedef struct {
- io_glue *ig;
- int len;
- int cp;
- char buf[BSIZ];
-} mbuf;
-
-
-static
-void init_buf(mbuf *mb, io_glue *ig) {
- mb->len = 0;
- mb->cp = 0;
- mb->ig = ig;
-}
-
-
-
-/*
-=item gnext(mbuf *mb)
-
-Fetches a character and advances in stream by one character.
-Returns a pointer to the byte or NULL on failure (internal).
-
- mb - buffer object
-
-=cut
-*/
-
-#define gnext(mb) (((mb)->cp == (mb)->len) ? gnextf(mb) : (mb)->buf + (mb)->cp++)
-
-static
-char *
-gnextf(mbuf *mb) {
- io_glue *ig = mb->ig;
- if (mb->cp == mb->len) {
- mb->cp = 0;
- mb->len = ig->readcb(ig, mb->buf, BSIZ);
- if (mb->len == -1) {
- i_push_error(errno, "file read error");
- mm_log((1, "i_readpnm: read error\n"));
- return NULL;
- }
- if (mb->len == 0) {
- mm_log((1, "i_readpnm: end of file\n"));
- return NULL;
- }
- }
- return &mb->buf[mb->cp++];
-}
-
-
-/*
-=item gpeek(mbuf *mb)
-
-Fetches a character but does NOT advance. Returns a pointer to
-the byte or NULL on failure (internal).
-
- mb - buffer object
-
-=cut
-*/
-
-#define gpeek(mb) ((mb)->cp == (mb)->len ? gpeekf(mb) : (mb)->buf + (mb)->cp)
-
-static
-char *
-gpeekf(mbuf *mb) {
- io_glue *ig = mb->ig;
- if (mb->cp == mb->len) {
- mb->cp = 0;
- mb->len = ig->readcb(ig, mb->buf, BSIZ);
- if (mb->len == -1) {
- i_push_error(errno, "read error");
- mm_log((1, "i_readpnm: read error\n"));
- return NULL;
- }
- if (mb->len == 0) {
- mm_log((1, "i_readpnm: end of file\n"));
- return NULL;
- }
- }
- return &mb->buf[mb->cp];
-}
-
-int
-gread(mbuf *mb, unsigned char *buf, size_t read_size) {
- int total_read = 0;
- if (mb->cp != mb->len) {
- int avail_size = mb->len - mb->cp;
- int use_size = read_size > avail_size ? avail_size : read_size;
- memcpy(buf, mb->buf+mb->cp, use_size);
- mb->cp += use_size;
- total_read += use_size;
- read_size -= use_size;
- buf += use_size;
- }
- if (read_size) {
- io_glue *ig = mb->ig;
- int read_res = i_io_read(ig, buf, read_size);
- if (read_res >= 0) {
- total_read += read_res;
- }
- }
- return total_read;
-}
-
-
-/*
-=item skip_spaces(mb)
+=item skip_spaces(ig)
Advances in stream until it is positioned at a
non white space character. (internal)
- mb - buffer object
+ ig - io_glue
=cut
*/
static
int
-skip_spaces(mbuf *mb) {
- char *cp;
- while( (cp = gpeek(mb)) && misspace(*cp) ) if ( !gnext(mb) ) break;
- if (!cp) return 0;
+skip_spaces(io_glue *ig) {
+ int c;
+ while( (c = i_io_peekc(ig)) != EOF && misspace(c) ) {
+ if ( i_io_getc(ig) == EOF )
+ break;
+ }
+ if (c == EOF)
+ return 0;
+
return 1;
}
/*
-=item skip_comment(mb)
+=item skip_comment(ig)
Advances in stream over whitespace and a comment if one is found. (internal)
- mb - buffer object
+ ig - io_glue object
=cut
*/
static
int
-skip_comment(mbuf *mb) {
- char *cp;
+skip_comment(io_glue *ig) {
+ int c;
+
+ if (!skip_spaces(ig))
+ return 0;
- if (!skip_spaces(mb)) return 0;
+ if ((c = i_io_peekc(ig)) == EOF)
+ return 0;
- if (!(cp = gpeek(mb))) return 0;
- if (*cp == '#') {
- while( (cp = gpeek(mb)) && (*cp != '\n' && *cp != '\r') ) {
- if ( !gnext(mb) ) break;
+ if (c == '#') {
+ while( (c = i_io_peekc(ig)) != EOF && (c != '\n' && c != '\r') ) {
+ if ( i_io_getc(ig) == EOF )
+ break;
}
}
- if (!cp) return 0;
+ if (c == EOF)
+ return 0;
return 1;
}
static
int
-gnum(mbuf *mb, int *i) {
- char *cp;
+gnum(io_glue *ig, int *i) {
+ int c;
*i = 0;
- if (!skip_spaces(mb)) return 0;
+ if (!skip_spaces(ig)) return 0;
- if (!(cp = gpeek(mb)))
+ if ((c = i_io_peekc(ig)) == EOF)
return 0;
- if (!misnumber(*cp))
+ if (!misnumber(c))
return 0;
- while( (cp = gpeek(mb)) && misnumber(*cp) ) {
- *i = *i*10+(*cp-'0');
- cp = gnext(mb);
+ while( (c = i_io_peekc(ig)) != EOF && misnumber(c) ) {
+ int work = *i * 10 + (c - '0');
+ if (work < *i) {
+ /* overflow */
+ i_push_error(0, "integer overflow");
+ return 0;
+ }
+ *i = work;
+ i_io_getc(ig);
}
+
return 1;
}
static
i_img *
-read_pgm_ppm_bin8(mbuf *mb, i_img *im, int width, int height,
+read_pgm_ppm_bin8(io_glue *ig, i_img *im, int width, int height,
int channels, int maxval, int allow_incomplete) {
i_color *line, *linep;
int read_size;
for(y=0;y<height;y++) {
linep = line;
readp = read_buf;
- if (gread(mb, read_buf, read_size) != read_size) {
+ if (i_io_read(ig, read_buf, read_size) != read_size) {
myfree(line);
myfree(read_buf);
if (allow_incomplete) {
static
i_img *
-read_pgm_ppm_bin16(mbuf *mb, i_img *im, int width, int height,
+read_pgm_ppm_bin16(io_glue *ig, i_img *im, int width, int height,
int channels, int maxval, int allow_incomplete) {
i_fcolor *line, *linep;
int read_size;
for(y=0;y<height;y++) {
linep = line;
readp = read_buf;
- if (gread(mb, read_buf, read_size) != read_size) {
+ if (i_io_read(ig, read_buf, read_size) != read_size) {
myfree(line);
myfree(read_buf);
if (allow_incomplete) {
static
i_img *
-read_pbm_bin(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
+read_pbm_bin(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) {
i_palidx *line, *linep;
int read_size;
unsigned char *read_buf, *readp;
read_size = (width + 7) / 8;
read_buf = mymalloc(read_size);
for(y = 0; y < height; y++) {
- if (gread(mb, read_buf, read_size) != read_size) {
+ if (i_io_read(ig, read_buf, read_size) != read_size) {
myfree(line);
myfree(read_buf);
if (allow_incomplete) {
*/
static
i_img *
-read_pbm_ascii(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
+read_pbm_ascii(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) {
i_palidx *line, *linep;
int x, y;
for(y = 0; y < height; y++) {
linep = line;
for(x = 0; x < width; ++x) {
- char *cp;
- skip_spaces(mb);
- if (!(cp = gnext(mb)) || (*cp != '0' && *cp != '1')) {
+ int c;
+ skip_spaces(ig);
+ if ((c = i_io_getc(ig)) == EOF || (c != '0' && c != '1')) {
myfree(line);
if (allow_incomplete) {
i_tags_setn(&im->tags, "i_incomplete", 1);
return im;
}
else {
- if (cp)
+ if (c != EOF)
i_push_error(0, "invalid data for ascii pnm");
else
i_push_error(0, "short read - file truncated?");
return NULL;
}
}
- *linep++ = *cp == '0' ? 0 : 1;
+ *linep++ = c == '0' ? 0 : 1;
}
i_ppal(im, 0, width, y, line);
}
static
i_img *
-read_pgm_ppm_ascii(mbuf *mb, i_img *im, int width, int height, int channels,
+read_pgm_ppm_ascii(io_glue *ig, i_img *im, int width, int height, int channels,
int maxval, int allow_incomplete) {
i_color *line, *linep;
int x, y, ch;
for(ch=0; ch<channels; ch++) {
int sample;
- if (!gnum(mb, &sample)) {
+ if (!gnum(ig, &sample)) {
myfree(line);
if (allow_incomplete) {
i_tags_setn(&im->tags, "i_incomplete", 1);
return im;
}
else {
- if (gpeek(mb))
+ if (i_io_peekc(ig) != EOF)
i_push_error(0, "invalid data for ascii pnm");
else
i_push_error(0, "short read - file truncated?");
static
i_img *
-read_pgm_ppm_ascii_16(mbuf *mb, i_img *im, int width, int height,
+read_pgm_ppm_ascii_16(io_glue *ig, i_img *im, int width, int height,
int channels, int maxval, int allow_incomplete) {
i_fcolor *line, *linep;
int x, y, ch;
for(ch=0; ch<channels; ch++) {
int sample;
- if (!gnum(mb, &sample)) {
+ if (!gnum(ig, &sample)) {
myfree(line);
if (allow_incomplete) {
i_tags_setn(&im->tags, "i_incomplete", 1);
return im;
}
else {
- if (gpeek(mb))
+ if (i_io_peekc(ig) != EOF)
i_push_error(0, "invalid data for ascii pnm");
else
i_push_error(0, "short read - file truncated?");
=cut
*/
-
i_img *
-i_readpnm_wiol(io_glue *ig, int allow_incomplete) {
+i_readpnm_wiol( io_glue *ig, int allow_incomplete) {
i_img* im;
int type;
- int width, height, maxval, channels, pcount;
+ int width, height, maxval, channels;
int rounder;
- char *cp;
- mbuf buf;
+ int c;
i_clear_error();
mm_log((1,"i_readpnm(ig %p, allow_incomplete %d)\n", ig, allow_incomplete));
- io_glue_commit_types(ig);
- init_buf(&buf, ig);
+ c = i_io_getc(ig);
- cp = gnext(&buf);
-
- if (!cp || *cp != 'P') {
+ if (c != 'P') {
i_push_error(0, "bad header magic, not a PNM file");
mm_log((1, "i_readpnm: Could not read header of file\n"));
return NULL;
}
- if ( !(cp = gnext(&buf)) ) {
+ if ((c = i_io_getc(ig)) == EOF ) {
mm_log((1, "i_readpnm: Could not read header of file\n"));
return NULL;
}
- type = *cp-'0';
+ type = c - '0';
if (type < 1 || type > 6) {
i_push_error(0, "unknown PNM file type, not a PNM file");
return NULL;
}
- if ( !(cp = gnext(&buf)) ) {
+ if ( (c = i_io_getc(ig)) == EOF ) {
mm_log((1, "i_readpnm: Could not read header of file\n"));
return NULL;
}
- if ( !misspace(*cp) ) {
+ if ( !misspace(c) ) {
i_push_error(0, "unexpected character, not a PNM file");
mm_log((1, "i_readpnm: Not a pnm file\n"));
return NULL;
/* Read sizes and such */
- if (!skip_comment(&buf)) {
+ if (!skip_comment(ig)) {
i_push_error(0, "while skipping to width");
mm_log((1, "i_readpnm: error reading before width\n"));
return NULL;
}
- if (!gnum(&buf, &width)) {
+ if (!gnum(ig, &width)) {
i_push_error(0, "could not read image width");
mm_log((1, "i_readpnm: error reading width\n"));
return NULL;
}
- if (!skip_comment(&buf)) {
+ if (!skip_comment(ig)) {
i_push_error(0, "while skipping to height");
mm_log((1, "i_readpnm: error reading before height\n"));
return NULL;
}
- if (!gnum(&buf, &height)) {
+ if (!gnum(ig, &height)) {
i_push_error(0, "could not read image height");
mm_log((1, "i_readpnm: error reading height\n"));
return NULL;
}
if (!(type == 1 || type == 4)) {
- if (!skip_comment(&buf)) {
+ if (!skip_comment(ig)) {
i_push_error(0, "while skipping to maxval");
mm_log((1, "i_readpnm: error reading before maxval\n"));
return NULL;
}
- if (!gnum(&buf, &maxval)) {
+ if (!gnum(ig, &maxval)) {
i_push_error(0, "could not read maxval");
mm_log((1, "i_readpnm: error reading maxval\n"));
return NULL;
else if (maxval > 65535) {
i_push_errorf(0, "maxval of %d is over 65535 - invalid pnm file",
maxval);
- mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n"));
+ mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n", maxval));
return NULL;
}
} else maxval=1;
rounder = maxval / 2;
- if (!(cp = gnext(&buf)) || !misspace(*cp)) {
+ if ((c = i_io_getc(ig)) == EOF || !misspace(c)) {
i_push_error(0, "garbage in header, invalid PNM file");
mm_log((1, "i_readpnm: garbage in header\n"));
return NULL;
}
channels = (type == 3 || type == 6) ? 3:1;
- pcount = width*height*channels;
if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
mm_log((1, "i_readpnm: image size exceeds limits\n"));
switch (type) {
case 1: /* Ascii types */
- im = read_pbm_ascii(&buf, im, width, height, allow_incomplete);
+ im = read_pbm_ascii(ig, im, width, height, allow_incomplete);
break;
case 2:
case 3:
if (maxval > 255)
- im = read_pgm_ppm_ascii_16(&buf, im, width, height, channels, maxval, allow_incomplete);
+ im = read_pgm_ppm_ascii_16(ig, im, width, height, channels, maxval, allow_incomplete);
else
- im = read_pgm_ppm_ascii(&buf, im, width, height, channels, maxval, allow_incomplete);
+ im = read_pgm_ppm_ascii(ig, im, width, height, channels, maxval, allow_incomplete);
break;
case 4: /* binary pbm */
- im = read_pbm_bin(&buf, im, width, height, allow_incomplete);
+ im = read_pbm_bin(ig, im, width, height, allow_incomplete);
break;
case 5: /* binary pgm */
case 6: /* binary ppm */
if (maxval > 255)
- im = read_pgm_ppm_bin16(&buf, im, width, height, channels, maxval, allow_incomplete);
+ im = read_pgm_ppm_bin16(ig, im, width, height, channels, maxval, allow_incomplete);
else
- im = read_pgm_ppm_bin8(&buf, im, width, height, channels, maxval, allow_incomplete);
+ im = read_pgm_ppm_bin8(ig, im, width, height, channels, maxval, allow_incomplete);
break;
default:
return im;
}
+static void free_images(i_img **imgs, int count) {
+ int i;
+
+ if (count) {
+ for (i = 0; i < count; ++i)
+ i_img_destroy(imgs[i]);
+ myfree(imgs);
+ }
+}
+
+i_img **i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete) {
+ i_img **results = NULL;
+ i_img *img = NULL;
+ char c = EOF;
+ int result_alloc = 0,
+ value = 0,
+ eof = 0;
+ *count=0;
+
+ do {
+ mm_log((1, "read image %i\n", 1+*count));
+ img = i_readpnm_wiol( ig, allow_incomplete );
+ if( !img ) {
+ free_images( results, *count );
+ return NULL;
+ }
+ ++*count;
+ if (*count > result_alloc) {
+ if (result_alloc == 0) {
+ result_alloc = 5;
+ results = mymalloc(result_alloc * sizeof(i_img *));
+ }
+ else {
+ /* myrealloc never fails (it just dies if it can't allocate) */
+ result_alloc *= 2;
+ results = myrealloc(results, result_alloc * sizeof(i_img *));
+ }
+ }
+ results[*count-1] = img;
+
+
+ if( i_tags_get_int(&img->tags, "i_incomplete", 0, &value ) && value) {
+ eof = 1;
+ }
+ else if( skip_spaces( ig ) && ( c=i_io_peekc( ig ) ) != EOF && c == 'P' ) {
+ eof = 0;
+ }
+ else {
+ eof = 1;
+ }
+ } while(!eof);
+ return results;
+}
+
+
+
static
int
write_pbm(i_img *im, io_glue *ig, int zero_is_white) {
int x, y;
i_palidx *line;
- int write_size;
+ i_img_dim write_size;
unsigned char *write_buf;
unsigned char *writep;
char header[255];
unsigned mask;
- sprintf(header, "P4\012# CREATOR: Imager\012%d %d\012",
- im->xsize, im->ysize);
+ sprintf(header, "P4\012# CREATOR: Imager\012%" i_DF " %" i_DF "\012",
+ i_DFc(im->xsize), i_DFc(im->ysize));
if (i_io_write(ig, header, strlen(header)) < 0) {
i_push_error(0, "could not write pbm header");
return 0;
static
int
-write_ppm_data_8(i_img *im, io_glue *ig) {
- int write_size = im->xsize * im->channels;
- unsigned char *data = mymalloc(write_size);
- int y = 0;
+write_ppm_data_8(i_img *im, io_glue *ig, int want_channels) {
+ size_t write_size = im->xsize * want_channels;
+ size_t buf_size = im->xsize * im->channels;
+ unsigned char *data = mymalloc(buf_size);
+ i_img_dim y = 0;
int rc = 1;
+ i_color bg;
+ i_get_file_background(im, &bg);
while (y < im->ysize && rc >= 0) {
- i_gsamp(im, 0, im->xsize, y, data, NULL, im->channels);
+ i_gsamp_bg(im, 0, im->xsize, y, data, want_channels, &bg);
if (i_io_write(ig, data, write_size) != write_size) {
i_push_error(errno, "could not write ppm data");
rc = 0;
static
int
-write_ppm_data_16(i_img *im, io_glue *ig) {
- int sample_count = im->channels * im->xsize;
- int write_size = sample_count * 2;
- int line_size = sample_count * sizeof(i_fsample_t);
+write_ppm_data_16(i_img *im, io_glue *ig, int want_channels) {
+ size_t line_size = im->channels * im->xsize * sizeof(i_fsample_t);
+ size_t sample_count = want_channels * im->xsize;
+ size_t write_size = sample_count * 2;
i_fsample_t *line_buf = mymalloc(line_size);
i_fsample_t *samplep;
unsigned char *write_buf = mymalloc(write_size);
unsigned char *writep;
- int sample_num;
- int y = 0;
+ size_t sample_num;
+ i_img_dim y = 0;
int rc = 1;
+ i_fcolor bg;
+
+ i_get_file_backgroundf(im, &bg);
while (y < im->ysize) {
- i_gsampf(im, 0, im->xsize, y, line_buf, NULL, im->channels);
+ i_gsampf_bg(im, 0, im->xsize, y, line_buf, want_channels, &bg);
samplep = line_buf;
writep = write_buf;
for (sample_num = 0; sample_num < sample_count; ++sample_num) {
/* Add code to get the filename info from the iolayer */
/* Also add code to check for mmapped code */
- io_glue_commit_types(ig);
-
if (i_img_is_monochrome(im, &zero_is_white)) {
- return write_pbm(im, ig, zero_is_white);
+ if (!write_pbm(im, ig, zero_is_white))
+ return 0;
}
else {
int type;
int maxval;
+ int want_channels = im->channels;
+
+ if (want_channels == 2 || want_channels == 4)
+ --want_channels;
if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data))
wide_data = 0;
- if (im->channels == 3) {
+ if (want_channels == 3) {
type = 6;
}
- else if (im->channels == 1) {
+ else if (want_channels == 1) {
type = 5;
}
else {
else
maxval = 65535;
- sprintf(header,"P%d\n#CREATOR: Imager\n%d %d\n%d\n",
- type, im->xsize, im->ysize, maxval);
+ sprintf(header,"P%d\n#CREATOR: Imager\n%" i_DF " %" i_DF"\n%d\n",
+ type, i_DFc(im->xsize), i_DFc(im->ysize), maxval);
- if (ig->writecb(ig,header,strlen(header)) != strlen(header)) {
+ if (i_io_write(ig,header,strlen(header)) != strlen(header)) {
i_push_error(errno, "could not write ppm header");
mm_log((1,"i_writeppm: unable to write ppm header.\n"));
return(0);
}
- if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type) {
- if (ig->writecb(ig,im->idata,im->bytes) != im->bytes) {
+ if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type
+ && im->channels == want_channels) {
+ if (i_io_write(ig,im->idata,im->bytes) != im->bytes) {
i_push_error(errno, "could not write ppm data");
return 0;
}
}
else if (maxval == 255) {
- if (!write_ppm_data_8(im, ig))
+ if (!write_ppm_data_8(im, ig, want_channels))
return 0;
}
else {
- if (!write_ppm_data_16(im, ig))
+ if (!write_ppm_data_16(im, ig, want_channels))
return 0;
}
}
- ig->closecb(ig);
+ if (i_io_close(ig)) {
+ i_push_errorf(i_io_error(ig), "Error closing stream: %d", i_io_error(ig));
+ return 0;
+ }
return(1);
}
=head1 AUTHOR
-Arnar M. Hrafnkelsson <addi@umich.edu>, Tony Cook<tony@imager.perl.org>
+Arnar M. Hrafnkelsson <addi@umich.edu>, Tony Cook <tonyc@cpan.org>,
+Philip Gwyn <gwyn@cpan.org>.
=head1 SEE ALSO