Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 967 lines (814 sloc) 22.439 kb
92bda63 - start of external Imager API access:
Tony Cook authored
1 #include "imager.h"
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
2 #include "log.h"
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
3 #include "iolayer.h"
92bda63 - start of external Imager API access:
Tony Cook authored
4 #include "imageri.h"
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
5
6 #include <stdlib.h>
f0e7b64 I'm suprised the errno.h is needed, but here it is
Tony Cook authored
7 #include <errno.h>
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
8
9
10 /*
11 =head1 NAME
12
13 pnm.c - implements reading and writing ppm/pnm/pbm files, uses io layer.
14
15 =head1 SYNOPSIS
16
17 io_glue *ig = io_new_fd( fd );
9c10632 Various changes:
Tony Cook authored
18 i_img *im = i_readpnm_wiol(ig, 0); // no limit on how much is read
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
19 // or
20 io_glue *ig = io_new_fd( fd );
21 return_code = i_writepnm_wiol(im, ig);
22
23 =head1 DESCRIPTION
24
25 pnm.c implements the basic functions to read and write portable
26 anymap files. It uses the iolayer and needs either a seekable source
27 or an entire memory mapped buffer.
28
29 =head1 FUNCTION REFERENCE
30
31 Some of these functions are internal.
32
b8c2033 Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod…
Arnar Mar Hrafnkelsson authored
33 =over
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
34
35 =cut
36 */
37
38
39 #define BSIZ 1024
40 #define misspace(x) (x==' ' || x=='\n' || x=='\r' || x=='\t' || x=='\f' || x=='\v')
41 #define misnumber(x) (x <= '9' && x>='0')
42
43 static char *typenames[]={"ascii pbm", "ascii pgm", "ascii ppm", "binary pbm", "binary pgm", "binary ppm"};
44
45 /*
46 * Type to encapsulate the local buffer
47 * management skipping over in a file
48 */
49
50 typedef struct {
51 io_glue *ig;
52 int len;
53 int cp;
54 char buf[BSIZ];
55 } mbuf;
56
57
58 static
59 void init_buf(mbuf *mb, io_glue *ig) {
60 mb->len = 0;
61 mb->cp = 0;
62 mb->ig = ig;
63 }
64
65
66
67 /*
68 =item gnext(mbuf *mb)
69
70 Fetches a character and advances in stream by one character.
71 Returns a pointer to the byte or NULL on failure (internal).
72
73 mb - buffer object
74
75 =cut
76 */
77
9c10632 Various changes:
Tony Cook authored
78 #define gnext(mb) (((mb)->cp == (mb)->len) ? gnextf(mb) : (mb)->buf + (mb)->cp++)
79
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
80 static
81 char *
9c10632 Various changes:
Tony Cook authored
82 gnextf(mbuf *mb) {
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
83 io_glue *ig = mb->ig;
84 if (mb->cp == mb->len) {
85 mb->cp = 0;
86 mb->len = ig->readcb(ig, mb->buf, BSIZ);
87 if (mb->len == -1) {
fac8664 added error reporting code
Tony Cook authored
88 i_push_error(errno, "file read error");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
89 mm_log((1, "i_readpnm: read error\n"));
90 return NULL;
91 }
92 if (mb->len == 0) {
93 mm_log((1, "i_readpnm: end of file\n"));
94 return NULL;
95 }
96 }
97 return &mb->buf[mb->cp++];
98 }
99
100
101 /*
fdd00d5 fix some function headers, removed some junk code
Tony Cook authored
102 =item gpeek(mbuf *mb)
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
103
104 Fetches a character but does NOT advance. Returns a pointer to
105 the byte or NULL on failure (internal).
106
107 mb - buffer object
108
109 =cut
110 */
111
9c10632 Various changes:
Tony Cook authored
112 #define gpeek(mb) ((mb)->cp == (mb)->len ? gpeekf(mb) : (mb)->buf + (mb)->cp)
113
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
114 static
115 char *
9c10632 Various changes:
Tony Cook authored
116 gpeekf(mbuf *mb) {
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
117 io_glue *ig = mb->ig;
118 if (mb->cp == mb->len) {
119 mb->cp = 0;
120 mb->len = ig->readcb(ig, mb->buf, BSIZ);
121 if (mb->len == -1) {
fac8664 added error reporting code
Tony Cook authored
122 i_push_error(errno, "read error");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
123 mm_log((1, "i_readpnm: read error\n"));
124 return NULL;
125 }
126 if (mb->len == 0) {
127 mm_log((1, "i_readpnm: end of file\n"));
128 return NULL;
129 }
130 }
131 return &mb->buf[mb->cp];
132 }
133
9c10632 Various changes:
Tony Cook authored
134 int
135 gread(mbuf *mb, unsigned char *buf, size_t read_size) {
136 int total_read = 0;
137 if (mb->cp != mb->len) {
138 int avail_size = mb->len - mb->cp;
139 int use_size = read_size > avail_size ? avail_size : read_size;
140 memcpy(buf, mb->buf+mb->cp, use_size);
141 mb->cp += use_size;
142 total_read += use_size;
143 read_size -= use_size;
144 buf += use_size;
145 }
146 if (read_size) {
147 io_glue *ig = mb->ig;
148 int read_res = i_io_read(ig, buf, read_size);
149 if (read_res >= 0) {
150 total_read += read_res;
151 }
152 }
153 return total_read;
154 }
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
155
156
157 /*
158 =item skip_spaces(mb)
159
160 Advances in stream until it is positioned at a
161 non white space character. (internal)
162
163 mb - buffer object
164
165 =cut
166 */
167
168 static
169 int
170 skip_spaces(mbuf *mb) {
171 char *cp;
172 while( (cp = gpeek(mb)) && misspace(*cp) ) if ( !gnext(mb) ) break;
173 if (!cp) return 0;
174 return 1;
175 }
176
177
178 /*
fdd00d5 fix some function headers, removed some junk code
Tony Cook authored
179 =item skip_comment(mb)
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
180
181 Advances in stream over whitespace and a comment if one is found. (internal)
182
183 mb - buffer object
184
185 =cut
186 */
187
188 static
189 int
190 skip_comment(mbuf *mb) {
191 char *cp;
192
193 if (!skip_spaces(mb)) return 0;
194
195 if (!(cp = gpeek(mb))) return 0;
196 if (*cp == '#') {
197 while( (cp = gpeek(mb)) && (*cp != '\n' && *cp != '\r') ) {
198 if ( !gnext(mb) ) break;
199 }
200 }
201 if (!cp) return 0;
202
203 return 1;
204 }
205
206
207 /*
208 =item gnum(mb, i)
209
210 Fetches the next number from stream and stores in i, returns true
211 on success else false.
212
213 mb - buffer object
214 i - integer to store result in
215
216 =cut
217 */
218
219 static
220 int
221 gnum(mbuf *mb, int *i) {
222 char *cp;
223 *i = 0;
224
225 if (!skip_spaces(mb)) return 0;
226
9c10632 Various changes:
Tony Cook authored
227 if (!(cp = gpeek(mb)))
228 return 0;
229 if (!misnumber(*cp))
230 return 0;
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
231 while( (cp = gpeek(mb)) && misnumber(*cp) ) {
232 *i = *i*10+(*cp-'0');
233 cp = gnext(mb);
234 }
235 return 1;
236 }
237
9c10632 Various changes:
Tony Cook authored
238 static
239 i_img *
240 read_pgm_ppm_bin8(mbuf *mb, i_img *im, int width, int height,
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
241 int channels, int maxval, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
242 i_color *line, *linep;
243 int read_size;
244 unsigned char *read_buf, *readp;
245 int x, y, ch;
246 int rounder = maxval / 2;
247
248 line = mymalloc(width * sizeof(i_color));
249 read_size = channels * width;
250 read_buf = mymalloc(read_size);
251 for(y=0;y<height;y++) {
252 linep = line;
253 readp = read_buf;
254 if (gread(mb, read_buf, read_size) != read_size) {
255 myfree(line);
256 myfree(read_buf);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
257 if (allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
258 i_tags_setn(&im->tags, "i_incomplete", 1);
259 i_tags_setn(&im->tags, "i_lines_read", y);
260 return im;
261 }
262 else {
263 i_push_error(0, "short read - file truncated?");
264 i_img_destroy(im);
265 return NULL;
266 }
267 }
268 if (maxval == 255) {
269 for(x=0; x<width; x++) {
270 for(ch=0; ch<channels; ch++) {
271 linep->channel[ch] = *readp++;
272 }
273 ++linep;
274 }
275 }
276 else {
277 for(x=0; x<width; x++) {
278 for(ch=0; ch<channels; ch++) {
279 /* we just clamp samples to the correct range */
280 unsigned sample = *readp++;
281 if (sample > maxval)
282 sample = maxval;
283 linep->channel[ch] = (sample * 255 + rounder) / maxval;
284 }
285 ++linep;
286 }
287 }
288 i_plin(im, 0, width, y, line);
289 }
290 myfree(read_buf);
291 myfree(line);
292
293 return im;
294 }
295
296 static
297 i_img *
298 read_pgm_ppm_bin16(mbuf *mb, i_img *im, int width, int height,
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
299 int channels, int maxval, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
300 i_fcolor *line, *linep;
301 int read_size;
302 unsigned char *read_buf, *readp;
303 int x, y, ch;
304 double maxvalf = maxval;
305
306 line = mymalloc(width * sizeof(i_fcolor));
307 read_size = channels * width * 2;
308 read_buf = mymalloc(read_size);
309 for(y=0;y<height;y++) {
310 linep = line;
311 readp = read_buf;
312 if (gread(mb, read_buf, read_size) != read_size) {
313 myfree(line);
314 myfree(read_buf);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
315 if (allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
316 i_tags_setn(&im->tags, "i_incomplete", 1);
317 i_tags_setn(&im->tags, "i_lines_read", y);
318 return im;
319 }
320 else {
321 i_push_error(0, "short read - file truncated?");
322 i_img_destroy(im);
323 return NULL;
324 }
325 }
326 for(x=0; x<width; x++) {
327 for(ch=0; ch<channels; ch++) {
328 unsigned sample = (readp[0] << 8) + readp[1];
329 if (sample > maxval)
330 sample = maxval;
331 readp += 2;
332 linep->channel[ch] = sample / maxvalf;
333 }
334 ++linep;
335 }
336 i_plinf(im, 0, width, y, line);
337 }
338 myfree(read_buf);
339 myfree(line);
340
341 return im;
342 }
343
344 static
345 i_img *
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
346 read_pbm_bin(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
347 i_palidx *line, *linep;
348 int read_size;
349 unsigned char *read_buf, *readp;
350 int x, y;
351 unsigned mask;
352
353 line = mymalloc(width * sizeof(i_palidx));
354 read_size = (width + 7) / 8;
355 read_buf = mymalloc(read_size);
356 for(y = 0; y < height; y++) {
357 if (gread(mb, read_buf, read_size) != read_size) {
358 myfree(line);
359 myfree(read_buf);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
360 if (allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
361 i_tags_setn(&im->tags, "i_incomplete", 1);
362 i_tags_setn(&im->tags, "i_lines_read", y);
363 return im;
364 }
365 else {
366 i_push_error(0, "short read - file truncated?");
367 i_img_destroy(im);
368 return NULL;
369 }
370 }
371 linep = line;
372 readp = read_buf;
373 mask = 0x80;
374 for(x = 0; x < width; ++x) {
375 *linep++ = *readp & mask ? 1 : 0;
376 mask >>= 1;
377 if (mask == 0) {
378 ++readp;
379 mask = 0x80;
380 }
381 }
382 i_ppal(im, 0, width, y, line);
383 }
384 myfree(read_buf);
385 myfree(line);
386
387 return im;
388 }
389
390 /* unlike pgm/ppm pbm:
391 - doesn't require spaces between samples (bits)
392 - 1 (maxval) is black instead of white
393 */
394 static
395 i_img *
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
396 read_pbm_ascii(mbuf *mb, i_img *im, int width, int height, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
397 i_palidx *line, *linep;
398 int x, y;
399
400 line = mymalloc(width * sizeof(i_palidx));
401 for(y = 0; y < height; y++) {
402 linep = line;
403 for(x = 0; x < width; ++x) {
404 char *cp;
405 skip_spaces(mb);
406 if (!(cp = gnext(mb)) || (*cp != '0' && *cp != '1')) {
407 myfree(line);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
408 if (allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
409 i_tags_setn(&im->tags, "i_incomplete", 1);
410 i_tags_setn(&im->tags, "i_lines_read", y);
411 return im;
412 }
413 else {
414 if (cp)
415 i_push_error(0, "invalid data for ascii pnm");
416 else
417 i_push_error(0, "short read - file truncated?");
418 i_img_destroy(im);
419 return NULL;
420 }
421 }
422 *linep++ = *cp == '0' ? 0 : 1;
423 }
424 i_ppal(im, 0, width, y, line);
425 }
426 myfree(line);
427
428 return im;
429 }
430
431 static
432 i_img *
433 read_pgm_ppm_ascii(mbuf *mb, i_img *im, int width, int height, int channels,
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
434 int maxval, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
435 i_color *line, *linep;
436 int x, y, ch;
437 int rounder = maxval / 2;
438
439 line = mymalloc(width * sizeof(i_color));
440 for(y=0;y<height;y++) {
441 linep = line;
442 for(x=0; x<width; x++) {
443 for(ch=0; ch<channels; ch++) {
444 int sample;
445
446 if (!gnum(mb, &sample)) {
447 myfree(line);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
448 if (allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
449 i_tags_setn(&im->tags, "i_incomplete", 1);
450 i_tags_setn(&im->tags, "i_lines_read", 1);
451 return im;
452 }
453 else {
454 if (gpeek(mb))
455 i_push_error(0, "invalid data for ascii pnm");
456 else
457 i_push_error(0, "short read - file truncated?");
458 i_img_destroy(im);
459 return NULL;
460 }
461 }
462 if (sample > maxval)
463 sample = maxval;
464 linep->channel[ch] = (sample * 255 + rounder) / maxval;
465 }
466 ++linep;
467 }
468 i_plin(im, 0, width, y, line);
469 }
470 myfree(line);
471
472 return im;
473 }
474
475 static
476 i_img *
477 read_pgm_ppm_ascii_16(mbuf *mb, i_img *im, int width, int height,
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
478 int channels, int maxval, int allow_incomplete) {
9c10632 Various changes:
Tony Cook authored
479 i_fcolor *line, *linep;
480 int x, y, ch;
481 double maxvalf = maxval;
482
483 line = mymalloc(width * sizeof(i_fcolor));
484 for(y=0;y<height;y++) {
485 linep = line;
486 for(x=0; x<width; x++) {
487 for(ch=0; ch<channels; ch++) {
488 int sample;
489
490 if (!gnum(mb, &sample)) {
491 myfree(line);
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
492 if (allow_incomplete) {
493 i_tags_setn(&im->tags, "i_incomplete", 1);
494 i_tags_setn(&im->tags, "i_lines_read", y);
495 return im;
9c10632 Various changes:
Tony Cook authored
496 }
497 else {
498 if (gpeek(mb))
499 i_push_error(0, "invalid data for ascii pnm");
500 else
501 i_push_error(0, "short read - file truncated?");
502 i_img_destroy(im);
503 return NULL;
504 }
505 }
506 if (sample > maxval)
507 sample = maxval;
508 linep->channel[ch] = sample / maxvalf;
509 }
510 ++linep;
511 }
512 i_plinf(im, 0, width, y, line);
513 }
514 myfree(line);
515
516 return im;
517 }
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
518
519 /*
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
520 =item i_readpnm_wiol(ig, allow_incomplete)
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
521
522 Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
523
524 ig - io_glue object
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
525 allow_incomplete - allows a partial file to be read successfully
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
526
527 =cut
528 */
2086be6 reading multi-image PNM files
Tony Cook authored
529 static i_img *i_readpnm_wiol_low( mbuf*, int);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
530
531 i_img *
d87dc9a change C<allow_partial> to C<allow_incomplete> to match the tag name
Tony Cook authored
532 i_readpnm_wiol(io_glue *ig, int allow_incomplete) {
2086be6 reading multi-image PNM files
Tony Cook authored
533 mbuf buf;
534 io_glue_commit_types(ig);
535 init_buf(&buf, ig);
536
537 return i_readpnm_wiol_low( &buf, allow_incomplete );
538 }
539
540 static i_img *
541 i_readpnm_wiol_low( mbuf *buf, int allow_incomplete) {
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
542 i_img* im;
543 int type;
544 int width, height, maxval, channels, pcount;
8b69555 - the pnm reader read maxval for ppm/pgm files and then ignor…
Tony Cook authored
545 int rounder;
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
546 char *cp;
547
fac8664 added error reporting code
Tony Cook authored
548 i_clear_error();
2086be6 reading multi-image PNM files
Tony Cook authored
549 mm_log((1,"i_readpnm(ig %p, allow_incomplete %d)\n", buf->ig, allow_incomplete));
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
550
2086be6 reading multi-image PNM files
Tony Cook authored
551 cp = gnext(buf);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
552
553 if (!cp || *cp != 'P') {
fac8664 added error reporting code
Tony Cook authored
554 i_push_error(0, "bad header magic, not a PNM file");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
555 mm_log((1, "i_readpnm: Could not read header of file\n"));
556 return NULL;
557 }
558
2086be6 reading multi-image PNM files
Tony Cook authored
559 if ( !(cp = gnext(buf)) ) {
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
560 mm_log((1, "i_readpnm: Could not read header of file\n"));
561 return NULL;
562 }
563
564 type = *cp-'0';
565
566 if (type < 1 || type > 6) {
fac8664 added error reporting code
Tony Cook authored
567 i_push_error(0, "unknown PNM file type, not a PNM file");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
568 mm_log((1, "i_readpnm: Not a pnm file\n"));
569 return NULL;
570 }
571
2086be6 reading multi-image PNM files
Tony Cook authored
572 if ( !(cp = gnext(buf)) ) {
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
573 mm_log((1, "i_readpnm: Could not read header of file\n"));
574 return NULL;
575 }
576
577 if ( !misspace(*cp) ) {
fac8664 added error reporting code
Tony Cook authored
578 i_push_error(0, "unexpected character, not a PNM file");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
579 mm_log((1, "i_readpnm: Not a pnm file\n"));
580 return NULL;
581 }
582
583 mm_log((1, "i_readpnm: image is a %s\n", typenames[type-1] ));
584
585
586 /* Read sizes and such */
587
2086be6 reading multi-image PNM files
Tony Cook authored
588 if (!skip_comment(buf)) {
fac8664 added error reporting code
Tony Cook authored
589 i_push_error(0, "while skipping to width");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
590 mm_log((1, "i_readpnm: error reading before width\n"));
591 return NULL;
592 }
593
2086be6 reading multi-image PNM files
Tony Cook authored
594 if (!gnum(buf, &width)) {
fac8664 added error reporting code
Tony Cook authored
595 i_push_error(0, "could not read image width");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
596 mm_log((1, "i_readpnm: error reading width\n"));
597 return NULL;
598 }
599
2086be6 reading multi-image PNM files
Tony Cook authored
600 if (!skip_comment(buf)) {
fac8664 added error reporting code
Tony Cook authored
601 i_push_error(0, "while skipping to height");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
602 mm_log((1, "i_readpnm: error reading before height\n"));
603 return NULL;
604 }
605
2086be6 reading multi-image PNM files
Tony Cook authored
606 if (!gnum(buf, &height)) {
fac8664 added error reporting code
Tony Cook authored
607 i_push_error(0, "could not read image height");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
608 mm_log((1, "i_readpnm: error reading height\n"));
609 return NULL;
610 }
611
612 if (!(type == 1 || type == 4)) {
2086be6 reading multi-image PNM files
Tony Cook authored
613 if (!skip_comment(buf)) {
fac8664 added error reporting code
Tony Cook authored
614 i_push_error(0, "while skipping to maxval");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
615 mm_log((1, "i_readpnm: error reading before maxval\n"));
616 return NULL;
617 }
618
2086be6 reading multi-image PNM files
Tony Cook authored
619 if (!gnum(buf, &maxval)) {
fac8664 added error reporting code
Tony Cook authored
620 i_push_error(0, "could not read maxval");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
621 mm_log((1, "i_readpnm: error reading maxval\n"));
622 return NULL;
623 }
8b69555 - the pnm reader read maxval for ppm/pgm files and then ignor…
Tony Cook authored
624
625 if (maxval == 0) {
626 i_push_error(0, "maxval is zero - invalid pnm file");
627 mm_log((1, "i_readpnm: maxval is zero, invalid pnm file\n"));
628 return NULL;
629 }
630 else if (maxval > 65535) {
631 i_push_errorf(0, "maxval of %d is over 65535 - invalid pnm file",
632 maxval);
633 mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n"));
634 return NULL;
635 }
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
636 } else maxval=1;
8b69555 - the pnm reader read maxval for ppm/pgm files and then ignor…
Tony Cook authored
637 rounder = maxval / 2;
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
638
2086be6 reading multi-image PNM files
Tony Cook authored
639 if (!(cp = gnext(buf)) || !misspace(*cp)) {
fac8664 added error reporting code
Tony Cook authored
640 i_push_error(0, "garbage in header, invalid PNM file");
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
641 mm_log((1, "i_readpnm: garbage in header\n"));
642 return NULL;
643 }
644
645 channels = (type == 3 || type == 6) ? 3:1;
646 pcount = width*height*channels;
647
7715772 - convert t/t107bmp.t to Test::More
Tony Cook authored
648 if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
649 mm_log((1, "i_readpnm: image size exceeds limits\n"));
650 return NULL;
651 }
652
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
653 mm_log((1, "i_readpnm: (%d x %d), channels = %d, maxval = %d\n", width, height, channels, maxval));
654
9c10632 Various changes:
Tony Cook authored
655 if (type == 1 || type == 4) {
656 i_color pbm_pal[2];
657 pbm_pal[0].channel[0] = 255;
658 pbm_pal[1].channel[0] = 0;
659
660 im = i_img_pal_new(width, height, 1, 256);
661 i_addcolors(im, pbm_pal, 2);
662 }
663 else {
664 if (maxval > 255)
665 im = i_img_16_new(width, height, channels);
666 else
667 im = i_img_8_new(width, height, channels);
668 }
642a675 - set i_format to pnm when reading pnm files and test for it
Tony Cook authored
669
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
670 switch (type) {
671 case 1: /* Ascii types */
2086be6 reading multi-image PNM files
Tony Cook authored
672 im = read_pbm_ascii(buf, im, width, height, allow_incomplete);
9c10632 Various changes:
Tony Cook authored
673 break;
674
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
675 case 2:
676 case 3:
9c10632 Various changes:
Tony Cook authored
677 if (maxval > 255)
2086be6 reading multi-image PNM files
Tony Cook authored
678 im = read_pgm_ppm_ascii_16(buf, im, width, height, channels, maxval, allow_incomplete);
9c10632 Various changes:
Tony Cook authored
679 else
2086be6 reading multi-image PNM files
Tony Cook authored
680 im = read_pgm_ppm_ascii(buf, im, width, height, channels, maxval, allow_incomplete);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
681 break;
682
683 case 4: /* binary pbm */
2086be6 reading multi-image PNM files
Tony Cook authored
684 im = read_pbm_bin(buf, im, width, height, allow_incomplete);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
685 break;
686
687 case 5: /* binary pgm */
688 case 6: /* binary ppm */
9c10632 Various changes:
Tony Cook authored
689 if (maxval > 255)
2086be6 reading multi-image PNM files
Tony Cook authored
690 im = read_pgm_ppm_bin16(buf, im, width, height, channels, maxval, allow_incomplete);
9c10632 Various changes:
Tony Cook authored
691 else
2086be6 reading multi-image PNM files
Tony Cook authored
692 im = read_pgm_ppm_bin8(buf, im, width, height, channels, maxval, allow_incomplete);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
693 break;
9c10632 Various changes:
Tony Cook authored
694
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
695 default:
696 mm_log((1, "type %s [P%d] unsupported\n", typenames[type-1], type));
697 return NULL;
698 }
9c10632 Various changes:
Tony Cook authored
699
700 if (!im)
701 return NULL;
702
703 i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0);
704 i_tags_setn(&im->tags, "pnm_maxval", maxval);
705 i_tags_setn(&im->tags, "pnm_type", type);
706
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
707 return im;
708 }
709
2086be6 reading multi-image PNM files
Tony Cook authored
710 static void free_images(i_img **imgs, int count) {
711 int i;
712
713 if (count) {
714 for (i = 0; i < count; ++i)
715 i_img_destroy(imgs[i]);
716 myfree(imgs);
717 }
718 }
719
720 i_img **i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete) {
721 i_img **results = NULL;
722 i_img *img = NULL;
723 char *cp = NULL;
724 mbuf buf;
725 int result_alloc = 0,
726 value = 0,
727 eof = 0;
728 *count=0;
729 io_glue_commit_types(ig);
730 init_buf(&buf, ig);
731 do {
732 mm_log((1, "read image %i\n", 1+*count));
733 img = i_readpnm_wiol_low( &buf, allow_incomplete );
734 if( !img ) {
735 free_images( results, *count );
736 return NULL;
737 }
738 ++*count;
739 if (*count > result_alloc) {
740 if (result_alloc == 0) {
741 result_alloc = 5;
742 results = mymalloc(result_alloc * sizeof(i_img *));
743 }
744 else {
745 /* myrealloc never fails (it just dies if it can't allocate) */
746 result_alloc *= 2;
747 results = myrealloc(results, result_alloc * sizeof(i_img *));
748 }
749 }
750 results[*count-1] = img;
751
752
753 if( i_tags_get_int(&img->tags, "i_incomplete", 0, &value ) && value) {
754 eof = 1;
755 }
756 else if( skip_spaces( &buf ) && ( cp=gpeek( &buf ) ) && *cp == 'P' ) {
757 eof = 0;
758 }
759 else {
760 eof = 1;
761 }
762 } while(!eof);
763 return results;
764 }
765
766
767
9c10632 Various changes:
Tony Cook authored
768 static
769 int
770 write_pbm(i_img *im, io_glue *ig, int zero_is_white) {
771 int x, y;
772 i_palidx *line;
773 int write_size;
774 unsigned char *write_buf;
775 unsigned char *writep;
776 char header[255];
777 unsigned mask;
778
779 sprintf(header, "P4\012# CREATOR: Imager\012%d %d\012",
780 im->xsize, im->ysize);
781 if (i_io_write(ig, header, strlen(header)) < 0) {
782 i_push_error(0, "could not write pbm header");
783 return 0;
784 }
785 write_size = (im->xsize + 7) / 8;
786 line = mymalloc(sizeof(i_palidx) * im->xsize);
787 write_buf = mymalloc(write_size);
788 for (y = 0; y < im->ysize; ++y) {
789 i_gpal(im, 0, im->xsize, y, line);
790 mask = 0x80;
791 writep = write_buf;
792 memset(write_buf, 0, write_size);
793 for (x = 0; x < im->xsize; ++x) {
794 if (zero_is_white ? line[x] : !line[x])
795 *writep |= mask;
796 mask >>= 1;
797 if (!mask) {
798 ++writep;
799 mask = 0x80;
800 }
801 }
802 if (i_io_write(ig, write_buf, write_size) != write_size) {
803 i_push_error(0, "write failure");
804 myfree(write_buf);
805 myfree(line);
806 return 0;
807 }
808 }
809 myfree(write_buf);
810 myfree(line);
811
812 return 1;
813 }
814
815 static
816 int
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
817 write_ppm_data_8(i_img *im, io_glue *ig, int want_channels) {
818 int write_size = im->xsize * want_channels;
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
819 int buf_size = im->xsize * im->channels;
820 unsigned char *data = mymalloc(buf_size);
9c10632 Various changes:
Tony Cook authored
821 int y = 0;
822 int rc = 1;
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
823 i_color bg;
9c10632 Various changes:
Tony Cook authored
824
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
825 i_get_file_background(im, &bg);
9c10632 Various changes:
Tony Cook authored
826 while (y < im->ysize && rc >= 0) {
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
827 i_gsamp_bg(im, 0, im->xsize, y, data, want_channels, &bg);
9c10632 Various changes:
Tony Cook authored
828 if (i_io_write(ig, data, write_size) != write_size) {
829 i_push_error(errno, "could not write ppm data");
830 rc = 0;
831 break;
832 }
833 ++y;
834 }
835 myfree(data);
836
837 return rc;
838 }
839
840 static
841 int
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
842 write_ppm_data_16(i_img *im, io_glue *ig, int want_channels) {
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
843 int line_size = im->channels * im->xsize * sizeof(i_fsample_t);
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
844 int sample_count = want_channels * im->xsize;
9c10632 Various changes:
Tony Cook authored
845 int write_size = sample_count * 2;
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
846 i_fsample_t *line_buf = mymalloc(line_size);
847 i_fsample_t *samplep;
9c10632 Various changes:
Tony Cook authored
848 unsigned char *write_buf = mymalloc(write_size);
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
849 unsigned char *writep;
850 int sample_num;
9c10632 Various changes:
Tony Cook authored
851 int y = 0;
852 int rc = 1;
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
853 i_fcolor bg;
854
855 i_get_file_backgroundf(im, &bg);
9c10632 Various changes:
Tony Cook authored
856
857 while (y < im->ysize) {
2a31a4b add i_gsamp_bg/i_gsampf_bg functions, sample based versions of
Tony Cook authored
858 i_gsampf_bg(im, 0, im->xsize, y, line_buf, want_channels, &bg);
859 samplep = line_buf;
860 writep = write_buf;
861 for (sample_num = 0; sample_num < sample_count; ++sample_num) {
862 unsigned sample16 = SampleFTo16(*samplep++);
863 *writep++ = sample16 >> 8;
864 *writep++ = sample16 & 0xFF;
9c10632 Various changes:
Tony Cook authored
865 }
866 if (i_io_write(ig, write_buf, write_size) != write_size) {
867 i_push_error(errno, "could not write ppm data");
868 rc = 0;
869 break;
870 }
871 ++y;
872 }
873 myfree(line_buf);
874 myfree(write_buf);
875
876 return rc;
877 }
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
878
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
879 undef_int
880 i_writeppm_wiol(i_img *im, io_glue *ig) {
881 char header[255];
9c10632 Various changes:
Tony Cook authored
882 int zero_is_white;
883 int wide_data;
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
884
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
885 mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig));
886 i_clear_error();
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
887
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
888 /* Add code to get the filename info from the iolayer */
889 /* Also add code to check for mmapped code */
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
890
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
891 io_glue_commit_types(ig);
02d1d62 Initial revision
Arnar Mar Hrafnkelsson authored
892
9c10632 Various changes:
Tony Cook authored
893 if (i_img_is_monochrome(im, &zero_is_white)) {
894 return write_pbm(im, ig, zero_is_white);
895 }
896 else {
897 int type;
898 int maxval;
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
899 int want_channels = im->channels;
900
901 if (want_channels == 2 || want_channels == 4)
902 --want_channels;
faa9b3e Egads
Tony Cook authored
903
9c10632 Various changes:
Tony Cook authored
904 if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data))
905 wide_data = 0;
906
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
907 if (want_channels == 3) {
9c10632 Various changes:
Tony Cook authored
908 type = 6;
faa9b3e Egads
Tony Cook authored
909 }
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
910 else if (want_channels == 1) {
9c10632 Various changes:
Tony Cook authored
911 type = 5;
faa9b3e Egads
Tony Cook authored
912 }
9c10632 Various changes:
Tony Cook authored
913 else {
914 i_push_error(0, "can only save 1 or 3 channel images to pnm");
915 mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
916 return(0);
917 }
9c10632 Various changes:
Tony Cook authored
918 if (im->bits <= 8 || !wide_data)
919 maxval = 255;
920 else
921 maxval = 65535;
922
923 sprintf(header,"P%d\n#CREATOR: Imager\n%d %d\n%d\n",
924 type, im->xsize, im->ysize, maxval);
925
926 if (ig->writecb(ig,header,strlen(header)) != strlen(header)) {
927 i_push_error(errno, "could not write ppm header");
928 mm_log((1,"i_writeppm: unable to write ppm header.\n"));
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
929 return(0);
930 }
faa9b3e Egads
Tony Cook authored
931
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
932 if (!im->virtual && im->bits == i_8_bits && im->type == i_direct_type
933 && im->channels == want_channels) {
9c10632 Various changes:
Tony Cook authored
934 if (ig->writecb(ig,im->idata,im->bytes) != im->bytes) {
935 i_push_error(errno, "could not write ppm data");
faa9b3e Egads
Tony Cook authored
936 return 0;
937 }
938 }
9c10632 Various changes:
Tony Cook authored
939 else if (maxval == 255) {
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
940 if (!write_ppm_data_8(im, ig, want_channels))
9c10632 Various changes:
Tony Cook authored
941 return 0;
942 }
943 else {
fa90de9 - writing a 2 or 4 channel image to a PGM/PPM will now write that
Tony Cook authored
944 if (!write_ppm_data_16(im, ig, want_channels))
9c10632 Various changes:
Tony Cook authored
945 return 0;
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
946 }
947 }
10461f9 enhanced iolayer
Tony Cook authored
948 ig->closecb(ig);
faa9b3e Egads
Tony Cook authored
949
067d6bd Removed i_writeppm and put in i_writeppm_wiol instead.
Arnar Mar Hrafnkelsson authored
950 return(1);
951 }
b8c2033 Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod…
Arnar Mar Hrafnkelsson authored
952
953 /*
954 =back
955
956 =head1 AUTHOR
957
5b480b1 @tonycoz replace (imager|tony)@imager.perl.org with tonyc@cpan.org
authored
958 Arnar M. Hrafnkelsson <addi@umich.edu>, Tony Cook <tonyc@cpan.org>,
2086be6 reading multi-image PNM files
Tony Cook authored
959 Philip Gwyn <gwyn@cpan.org>.
b8c2033 Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod…
Arnar Mar Hrafnkelsson authored
960
961 =head1 SEE ALSO
962
963 Imager(3)
964
965 =cut
966 */
Something went wrong with that request. Please try again.