File Coverage

pnm.c
Criterion Covered Total %
statement 361 438 82.4
branch 246 340 72.3
condition n/a
subroutine n/a
pod n/a
total 607 778 78.0


line stmt bran cond sub pod time code
1             #include "imager.h"
2             #include "log.h"
3             #include "iolayer.h"
4             #include "imageri.h"
5              
6             #include
7             #include
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 );
18             i_img *im = i_readpnm_wiol(ig, 0); // no limit on how much is read
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              
33             =over
34              
35             =cut
36             */
37              
38              
39             #define misspace(x) (x==' ' || x=='\n' || x=='\r' || x=='\t' || x=='\f' || x=='\v')
40             #define misnumber(x) (x <= '9' && x>='0')
41              
42             static char *typenames[]={"ascii pbm", "ascii pgm", "ascii ppm", "binary pbm", "binary pgm", "binary ppm"};
43              
44             /*
45             =item skip_spaces(ig)
46              
47             Advances in stream until it is positioned at a
48             non white space character. (internal)
49              
50             ig - io_glue
51              
52             =cut
53             */
54              
55             static
56             int
57 608           skip_spaces(io_glue *ig) {
58             int c;
59 915 100         while( (c = i_io_peekc(ig)) != EOF && misspace(c) ) {
    100          
    100          
    100          
    50          
    50          
    50          
    50          
60 307 50         if ( i_io_getc(ig) == EOF )
    50          
61 0           break;
62             }
63 608 100         if (c == EOF)
64 8           return 0;
65              
66 600           return 1;
67             }
68              
69              
70             /*
71             =item skip_comment(ig)
72              
73             Advances in stream over whitespace and a comment if one is found. (internal)
74              
75             ig - io_glue object
76              
77             =cut
78             */
79              
80             static
81             int
82 253           skip_comment(io_glue *ig) {
83             int c;
84              
85 253 100         if (!skip_spaces(ig))
86 1           return 0;
87              
88 252 50         if ((c = i_io_peekc(ig)) == EOF)
    50          
89 0           return 0;
90              
91 252 100         if (c == '#') {
92 2286 50         while( (c = i_io_peekc(ig)) != EOF && (c != '\n' && c != '\r') ) {
    50          
    100          
    50          
93 2220 50         if ( i_io_getc(ig) == EOF )
    50          
94 0           break;
95             }
96             }
97 252 50         if (c == EOF)
98 0           return 0;
99            
100 252           return 1;
101             }
102              
103              
104             /*
105             =item gnum(mb, i)
106              
107             Fetches the next number from stream and stores in i, returns true
108             on success else false.
109              
110             mb - buffer object
111             i - integer to store result in
112              
113             =cut
114             */
115              
116             static
117             int
118 328           gnum(io_glue *ig, int *i) {
119             int c;
120 328           *i = 0;
121              
122 328 100         if (!skip_spaces(ig)) return 0;
123              
124 324 50         if ((c = i_io_peekc(ig)) == EOF)
    50          
125 0           return 0;
126 324 100         if (!misnumber(c))
    50          
127 4           return 0;
128 1129 100         while( (c = i_io_peekc(ig)) != EOF && misnumber(c) ) {
    100          
    50          
    100          
129 811           int work = *i * 10 + (c - '0');
130 811 100         if (work < *i) {
131             /* overflow */
132 2           i_push_error(0, "integer overflow");
133 2           return 0;
134             }
135 809           *i = work;
136 809 50         i_io_nextc(ig);
137             }
138              
139 318           return 1;
140             }
141              
142             static
143             i_img *
144 52           read_pgm_ppm_bin8(io_glue *ig, i_img *im, int width, int height,
145             int channels, int maxval, int allow_incomplete) {
146             i_color *line, *linep;
147             int read_size;
148             unsigned char *read_buf, *readp;
149             int x, y, ch;
150 52           int rounder = maxval / 2;
151              
152 52           line = mymalloc(width * sizeof(i_color));
153 52           read_size = channels * width;
154 52           read_buf = mymalloc(read_size);
155 5666 100         for(y=0;y
156 5618           linep = line;
157 5618           readp = read_buf;
158 5618 100         if (i_io_read(ig, read_buf, read_size) != read_size) {
159 4           myfree(line);
160 4           myfree(read_buf);
161 4 100         if (allow_incomplete) {
162 2           i_tags_setn(&im->tags, "i_incomplete", 1);
163 2           i_tags_setn(&im->tags, "i_lines_read", y);
164 2           return im;
165             }
166             else {
167 2           i_push_error(0, "short read - file truncated?");
168 2           i_img_destroy(im);
169 2           return NULL;
170             }
171             }
172 5614 100         if (maxval == 255) {
173 854844 100         for(x=0; x
174 3351904 100         for(ch=0; ch
175 2502672           linep->channel[ch] = *readp++;
176             }
177 849232           ++linep;
178             }
179             }
180             else {
181 8 100         for(x=0; x
182 24 100         for(ch=0; ch
183             /* we just clamp samples to the correct range */
184 18           unsigned sample = *readp++;
185 18 50         if (sample > maxval)
186 0           sample = maxval;
187 18           linep->channel[ch] = (sample * 255 + rounder) / maxval;
188             }
189 6           ++linep;
190             }
191             }
192 5614           i_plin(im, 0, width, y, line);
193             }
194 48           myfree(read_buf);
195 48           myfree(line);
196              
197 48           return im;
198             }
199              
200             static
201             i_img *
202 8           read_pgm_ppm_bin16(io_glue *ig, i_img *im, int width, int height,
203             int channels, int maxval, int allow_incomplete) {
204             i_fcolor *line, *linep;
205             int read_size;
206             unsigned char *read_buf, *readp;
207             int x, y, ch;
208 8           double maxvalf = maxval;
209              
210 8           line = mymalloc(width * sizeof(i_fcolor));
211 8           read_size = channels * width * 2;
212 8           read_buf = mymalloc(read_size);
213 196 100         for(y=0;y
214 192           linep = line;
215 192           readp = read_buf;
216 192 100         if (i_io_read(ig, read_buf, read_size) != read_size) {
217 4           myfree(line);
218 4           myfree(read_buf);
219 4 100         if (allow_incomplete) {
220 2           i_tags_setn(&im->tags, "i_incomplete", 1);
221 2           i_tags_setn(&im->tags, "i_lines_read", y);
222 2           return im;
223             }
224             else {
225 2           i_push_error(0, "short read - file truncated?");
226 2           i_img_destroy(im);
227 2           return NULL;
228             }
229             }
230 23210 100         for(x=0; x
231 92080 100         for(ch=0; ch
232 69058           unsigned sample = (readp[0] << 8) + readp[1];
233 69058 50         if (sample > maxval)
234 0           sample = maxval;
235 69058           readp += 2;
236 69058           linep->channel[ch] = sample / maxvalf;
237             }
238 23022           ++linep;
239             }
240 188           i_plinf(im, 0, width, y, line);
241             }
242 4           myfree(read_buf);
243 4           myfree(line);
244              
245 4           return im;
246             }
247              
248             static
249             i_img *
250 4           read_pbm_bin(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) {
251             i_palidx *line, *linep;
252             int read_size;
253             unsigned char *read_buf, *readp;
254             int x, y;
255             unsigned mask;
256              
257 4           line = mymalloc(width * sizeof(i_palidx));
258 4           read_size = (width + 7) / 8;
259 4           read_buf = mymalloc(read_size);
260 26 100         for(y = 0; y < height; y++) {
261 24 100         if (i_io_read(ig, read_buf, read_size) != read_size) {
262 2           myfree(line);
263 2           myfree(read_buf);
264 2 100         if (allow_incomplete) {
265 1           i_tags_setn(&im->tags, "i_incomplete", 1);
266 1           i_tags_setn(&im->tags, "i_lines_read", y);
267 1           return im;
268             }
269             else {
270 1           i_push_error(0, "short read - file truncated?");
271 1           i_img_destroy(im);
272 1           return NULL;
273             }
274             }
275 22           linep = line;
276 22           readp = read_buf;
277 22           mask = 0x80;
278 254 100         for(x = 0; x < width; ++x) {
279 232           *linep++ = *readp & mask ? 1 : 0;
280 232           mask >>= 1;
281 232 100         if (mask == 0) {
282 24           ++readp;
283 24           mask = 0x80;
284             }
285             }
286 22 50         i_ppal(im, 0, width, y, line);
287             }
288 2           myfree(read_buf);
289 2           myfree(line);
290              
291 2           return im;
292             }
293              
294             /* unlike pgm/ppm pbm:
295             - doesn't require spaces between samples (bits)
296             - 1 (maxval) is black instead of white
297             */
298             static
299             i_img *
300 6           read_pbm_ascii(io_glue *ig, i_img *im, int width, int height, int allow_incomplete) {
301             i_palidx *line, *linep;
302             int x, y;
303              
304 6           line = mymalloc(width * sizeof(i_palidx));
305 14 100         for(y = 0; y < height; y++) {
306 12           linep = line;
307 32 100         for(x = 0; x < width; ++x) {
308             int c;
309 24           skip_spaces(ig);
310 24 100         if ((c = i_io_getc(ig)) == EOF || (c != '0' && c != '1')) {
    100          
    100          
    100          
311 4           myfree(line);
312 4 100         if (allow_incomplete) {
313 2           i_tags_setn(&im->tags, "i_incomplete", 1);
314 2           i_tags_setn(&im->tags, "i_lines_read", y);
315 2           return im;
316             }
317             else {
318 2 100         if (c != EOF)
319 1           i_push_error(0, "invalid data for ascii pnm");
320             else
321 1           i_push_error(0, "short read - file truncated?");
322 2           i_img_destroy(im);
323 2           return NULL;
324             }
325             }
326 20           *linep++ = c == '0' ? 0 : 1;
327             }
328 8 50         i_ppal(im, 0, width, y, line);
329             }
330 2           myfree(line);
331              
332 2           return im;
333             }
334              
335             static
336             i_img *
337 10           read_pgm_ppm_ascii(io_glue *ig, i_img *im, int width, int height, int channels,
338             int maxval, int allow_incomplete) {
339             i_color *line, *linep;
340             int x, y, ch;
341 10           int rounder = maxval / 2;
342              
343 10           line = mymalloc(width * sizeof(i_color));
344 21 100         for(y=0;y
345 19           linep = line;
346 48 100         for(x=0; x
347 96 100         for(ch=0; ch
348             int sample;
349            
350 67 100         if (!gnum(ig, &sample)) {
351 8           myfree(line);
352 8 100         if (allow_incomplete) {
353 4           i_tags_setn(&im->tags, "i_incomplete", 1);
354 4           i_tags_setn(&im->tags, "i_lines_read", 1);
355 8           return im;
356             }
357             else {
358 4 100         if (i_io_peekc(ig) != EOF)
    100          
359 2           i_push_error(0, "invalid data for ascii pnm");
360             else
361 2           i_push_error(0, "short read - file truncated?");
362 4           i_img_destroy(im);
363 4           return NULL;
364             }
365             }
366 59 50         if (sample > maxval)
367 0           sample = maxval;
368 59           linep->channel[ch] = (sample * 255 + rounder) / maxval;
369             }
370 29           ++linep;
371             }
372 11           i_plin(im, 0, width, y, line);
373             }
374 2           myfree(line);
375              
376 2           return im;
377             }
378              
379             static
380             i_img *
381 1           read_pgm_ppm_ascii_16(io_glue *ig, i_img *im, int width, int height,
382             int channels, int maxval, int allow_incomplete) {
383             i_fcolor *line, *linep;
384             int x, y, ch;
385 1           double maxvalf = maxval;
386              
387 1           line = mymalloc(width * sizeof(i_fcolor));
388 2 100         for(y=0;y
389 1           linep = line;
390 4 100         for(x=0; x
391 12 100         for(ch=0; ch
392             int sample;
393            
394 9 50         if (!gnum(ig, &sample)) {
395 0           myfree(line);
396 0 0         if (allow_incomplete) {
397 0           i_tags_setn(&im->tags, "i_incomplete", 1);
398 0           i_tags_setn(&im->tags, "i_lines_read", y);
399 0           return im;
400             }
401             else {
402 0 0         if (i_io_peekc(ig) != EOF)
    0          
403 0           i_push_error(0, "invalid data for ascii pnm");
404             else
405 0           i_push_error(0, "short read - file truncated?");
406 0           i_img_destroy(im);
407 0           return NULL;
408             }
409             }
410 9 50         if (sample > maxval)
411 0           sample = maxval;
412 9           linep->channel[ch] = sample / maxvalf;
413             }
414 3           ++linep;
415             }
416 1           i_plinf(im, 0, width, y, line);
417             }
418 1           myfree(line);
419              
420 1           return im;
421             }
422              
423             /*
424             =item i_readpnm_wiol(ig, allow_incomplete)
425              
426             Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
427              
428             ig - io_glue object
429             allow_incomplete - allows a partial file to be read successfully
430              
431             =cut
432             */
433              
434             i_img *
435 91           i_readpnm_wiol( io_glue *ig, int allow_incomplete) {
436             i_img* im;
437             int type;
438             int width, height, maxval, channels;
439             int c;
440              
441 91           i_clear_error();
442 91           mm_log((1,"i_readpnm(ig %p, allow_incomplete %d)\n", ig, allow_incomplete));
443              
444 91 100         c = i_io_getc(ig);
445              
446 91 100         if (c != 'P') {
447 2           i_push_error(0, "bad header magic, not a PNM file");
448 2           mm_log((1, "i_readpnm: Could not read header of file\n"));
449 2           return NULL;
450             }
451              
452 89 50         if ((c = i_io_getc(ig)) == EOF ) {
    50          
453 0           mm_log((1, "i_readpnm: Could not read header of file\n"));
454 0           return NULL;
455             }
456            
457 89           type = c - '0';
458              
459 89 50         if (type < 1 || type > 6) {
    50          
460 0           i_push_error(0, "unknown PNM file type, not a PNM file");
461 0           mm_log((1, "i_readpnm: Not a pnm file\n"));
462 0           return NULL;
463             }
464              
465 89 50         if ( (c = i_io_getc(ig)) == EOF ) {
    50          
466 0           mm_log((1, "i_readpnm: Could not read header of file\n"));
467 0           return NULL;
468             }
469            
470 89 50         if ( !misspace(c) ) {
    50          
    0          
    0          
    0          
    0          
471 0           i_push_error(0, "unexpected character, not a PNM file");
472 0           mm_log((1, "i_readpnm: Not a pnm file\n"));
473 0           return NULL;
474             }
475            
476 89           mm_log((1, "i_readpnm: image is a %s\n", typenames[type-1] ));
477              
478            
479             /* Read sizes and such */
480              
481 89 50         if (!skip_comment(ig)) {
482 0           i_push_error(0, "while skipping to width");
483 0           mm_log((1, "i_readpnm: error reading before width\n"));
484 0           return NULL;
485             }
486            
487 89 100         if (!gnum(ig, &width)) {
488 1           i_push_error(0, "could not read image width");
489 1           mm_log((1, "i_readpnm: error reading width\n"));
490 1           return NULL;
491             }
492              
493 88 100         if (!skip_comment(ig)) {
494 1           i_push_error(0, "while skipping to height");
495 1           mm_log((1, "i_readpnm: error reading before height\n"));
496 1           return NULL;
497             }
498              
499 87 100         if (!gnum(ig, &height)) {
500 1           i_push_error(0, "could not read image height");
501 1           mm_log((1, "i_readpnm: error reading height\n"));
502 1           return NULL;
503             }
504            
505 86 100         if (!(type == 1 || type == 4)) {
    100          
506 76 50         if (!skip_comment(ig)) {
507 0           i_push_error(0, "while skipping to maxval");
508 0           mm_log((1, "i_readpnm: error reading before maxval\n"));
509 0           return NULL;
510             }
511              
512 76 50         if (!gnum(ig, &maxval)) {
513 0           i_push_error(0, "could not read maxval");
514 0           mm_log((1, "i_readpnm: error reading maxval\n"));
515 0           return NULL;
516             }
517              
518 150 100         if (maxval == 0) {
519 1           i_push_error(0, "maxval is zero - invalid pnm file");
520 1           mm_log((1, "i_readpnm: maxval is zero, invalid pnm file\n"));
521 1           return NULL;
522             }
523 75 100         else if (maxval > 65535) {
524 1           i_push_errorf(0, "maxval of %d is over 65535 - invalid pnm file",
525             maxval);
526 1           mm_log((1, "i_readpnm: maxval of %d is over 65535 - invalid pnm file\n", maxval));
527 1           return NULL;
528             }
529 10           } else maxval=1;
530              
531 84 50         if ((c = i_io_getc(ig)) == EOF || !misspace(c)) {
    50          
    50          
    50          
    0          
    0          
    0          
    0          
532 0           i_push_error(0, "garbage in header, invalid PNM file");
533 0           mm_log((1, "i_readpnm: garbage in header\n"));
534 0           return NULL;
535             }
536              
537 84 100         channels = (type == 3 || type == 6) ? 3:1;
    100          
538              
539 84 100         if (!i_int_check_image_file_limits(width, height, channels, sizeof(i_sample_t))) {
540 3           mm_log((1, "i_readpnm: image size exceeds limits\n"));
541 3           return NULL;
542             }
543              
544 81           mm_log((1, "i_readpnm: (%d x %d), channels = %d, maxval = %d\n", width, height, channels, maxval));
545              
546 91 100         if (type == 1 || type == 4) {
    100          
547             i_color pbm_pal[2];
548 10           pbm_pal[0].channel[0] = 255;
549 10           pbm_pal[1].channel[0] = 0;
550            
551 10           im = i_img_pal_new(width, height, 1, 256);
552 10 50         i_addcolors(im, pbm_pal, 2);
553             }
554             else {
555 71 100         if (maxval > 255)
556 9           im = i_img_16_new(width, height, channels);
557             else
558 62           im = i_img_8_new(width, height, channels);
559             }
560              
561 81           switch (type) {
562             case 1: /* Ascii types */
563 6           im = read_pbm_ascii(ig, im, width, height, allow_incomplete);
564 6           break;
565              
566             case 2:
567             case 3:
568 11 100         if (maxval > 255)
569 1           im = read_pgm_ppm_ascii_16(ig, im, width, height, channels, maxval, allow_incomplete);
570             else
571 10           im = read_pgm_ppm_ascii(ig, im, width, height, channels, maxval, allow_incomplete);
572 11           break;
573            
574             case 4: /* binary pbm */
575 4           im = read_pbm_bin(ig, im, width, height, allow_incomplete);
576 4           break;
577              
578             case 5: /* binary pgm */
579             case 6: /* binary ppm */
580 60 100         if (maxval > 255)
581 8           im = read_pgm_ppm_bin16(ig, im, width, height, channels, maxval, allow_incomplete);
582             else
583 52           im = read_pgm_ppm_bin8(ig, im, width, height, channels, maxval, allow_incomplete);
584 60           break;
585              
586             default:
587 0           mm_log((1, "type %s [P%d] unsupported\n", typenames[type-1], type));
588 0           return NULL;
589             }
590              
591 81 100         if (!im)
592 11           return NULL;
593              
594 70           i_tags_add(&im->tags, "i_format", 0, "pnm", -1, 0);
595 70           i_tags_setn(&im->tags, "pnm_maxval", maxval);
596 70           i_tags_setn(&im->tags, "pnm_type", type);
597              
598 91           return im;
599             }
600              
601 0           static void free_images(i_img **imgs, int count) {
602             int i;
603              
604 0 0         if (count) {
605 0 0         for (i = 0; i < count; ++i)
606 0           i_img_destroy(imgs[i]);
607 0           myfree(imgs);
608             }
609 0           }
610              
611 1           i_img **i_readpnm_multi_wiol(io_glue *ig, int *count, int allow_incomplete) {
612 1           i_img **results = NULL;
613 1           i_img *img = NULL;
614 1           char c = EOF;
615 1           int result_alloc = 0,
616 1           value = 0,
617 1           eof = 0;
618 1           *count=0;
619              
620             do {
621 3           mm_log((1, "read image %i\n", 1+*count));
622 3           img = i_readpnm_wiol( ig, allow_incomplete );
623 3 50         if( !img ) {
624 0           free_images( results, *count );
625 0           return NULL;
626             }
627 3           ++*count;
628 3 100         if (*count > result_alloc) {
629 1 50         if (result_alloc == 0) {
630 1           result_alloc = 5;
631 1           results = mymalloc(result_alloc * sizeof(i_img *));
632             }
633             else {
634             /* myrealloc never fails (it just dies if it can't allocate) */
635 0           result_alloc *= 2;
636 0           results = myrealloc(results, result_alloc * sizeof(i_img *));
637             }
638             }
639 3           results[*count-1] = img;
640              
641              
642 3 50         if( i_tags_get_int(&img->tags, "i_incomplete", 0, &value ) && value) {
    0          
643 0           eof = 1;
644             }
645 3 100         else if( skip_spaces( ig ) && ( c=i_io_peekc( ig ) ) != EOF && c == 'P' ) {
    50          
    50          
    50          
646 2           eof = 0;
647             }
648             else {
649 1           eof = 1;
650             }
651 3 100         } while(!eof);
652 1           return results;
653             }
654              
655              
656              
657             static
658             int
659 5           write_pbm(i_img *im, io_glue *ig, int zero_is_white) {
660             int x, y;
661             i_palidx *line;
662             i_img_dim write_size;
663             unsigned char *write_buf;
664             unsigned char *writep;
665             char header[255];
666             unsigned mask;
667              
668 5           sprintf(header, "P4\012# CREATOR: Imager\012%" i_DF " %" i_DF "\012",
669 5           i_DFc(im->xsize), i_DFc(im->ysize));
670 5 50         if (i_io_write(ig, header, strlen(header)) < 0) {
671 0           i_push_error(0, "could not write pbm header");
672 0           return 0;
673             }
674 5           write_size = (im->xsize + 7) / 8;
675 5           line = mymalloc(sizeof(i_palidx) * im->xsize);
676 5           write_buf = mymalloc(write_size);
677 475 100         for (y = 0; y < im->ysize; ++y) {
678 470 50         i_gpal(im, 0, im->xsize, y, line);
679 470           mask = 0x80;
680 470           writep = write_buf;
681 470           memset(write_buf, 0, write_size);
682 68170 100         for (x = 0; x < im->xsize; ++x) {
683 67700 100         if (zero_is_white ? line[x] : !line[x])
    100          
684 48649           *writep |= mask;
685 67700           mask >>= 1;
686 67700 100         if (!mask) {
687 8120           ++writep;
688 8120           mask = 0x80;
689             }
690             }
691 470 50         if (i_io_write(ig, write_buf, write_size) != write_size) {
692 0           i_push_error(0, "write failure");
693 0           myfree(write_buf);
694 0           myfree(line);
695 0           return 0;
696             }
697             }
698 5           myfree(write_buf);
699 5           myfree(line);
700              
701 5           return 1;
702             }
703              
704             static
705             int
706 22           write_ppm_data_8(i_img *im, io_glue *ig, int want_channels) {
707 22           size_t write_size = im->xsize * want_channels;
708 22           size_t buf_size = im->xsize * im->channels;
709 22           unsigned char *data = mymalloc(buf_size);
710 22           i_img_dim y = 0;
711 22           int rc = 1;
712             i_color bg;
713              
714 22           i_get_file_background(im, &bg);
715 2279 100         while (y < im->ysize && rc >= 0) {
    50          
716 2257           i_gsamp_bg(im, 0, im->xsize, y, data, want_channels, &bg);
717 2257 50         if (i_io_write(ig, data, write_size) != write_size) {
718 0           i_push_error(errno, "could not write ppm data");
719 0           rc = 0;
720 0           break;
721             }
722 2257           ++y;
723             }
724 22           myfree(data);
725              
726 22           return rc;
727             }
728              
729             static
730             int
731 12           write_ppm_data_16(i_img *im, io_glue *ig, int want_channels) {
732 12           size_t line_size = im->channels * im->xsize * sizeof(i_fsample_t);
733 12           size_t sample_count = want_channels * im->xsize;
734 12           size_t write_size = sample_count * 2;
735 12           i_fsample_t *line_buf = mymalloc(line_size);
736             i_fsample_t *samplep;
737 12           unsigned char *write_buf = mymalloc(write_size);
738             unsigned char *writep;
739             size_t sample_num;
740 12           i_img_dim y = 0;
741 12           int rc = 1;
742             i_fcolor bg;
743              
744 12           i_get_file_backgroundf(im, &bg);
745              
746 1004 100         while (y < im->ysize) {
747 992           i_gsampf_bg(im, 0, im->xsize, y, line_buf, want_channels, &bg);
748 992           samplep = line_buf;
749 992           writep = write_buf;
750 345158 100         for (sample_num = 0; sample_num < sample_count; ++sample_num) {
751 344166           unsigned sample16 = SampleFTo16(*samplep++);
752 344166           *writep++ = sample16 >> 8;
753 344166           *writep++ = sample16 & 0xFF;
754             }
755 992 50         if (i_io_write(ig, write_buf, write_size) != write_size) {
756 0           i_push_error(errno, "could not write ppm data");
757 0           rc = 0;
758 0           break;
759             }
760 992           ++y;
761             }
762 12           myfree(line_buf);
763 12           myfree(write_buf);
764              
765 12           return rc;
766             }
767              
768             undef_int
769 136           i_writeppm_wiol(i_img *im, io_glue *ig) {
770             char header[255];
771             int zero_is_white;
772             int wide_data;
773              
774 136           mm_log((1,"i_writeppm(im %p, ig %p)\n", im, ig));
775 136           i_clear_error();
776              
777             /* Add code to get the filename info from the iolayer */
778             /* Also add code to check for mmapped code */
779              
780 136 100         if (i_img_is_monochrome(im, &zero_is_white)) {
781 5 50         if (!write_pbm(im, ig, zero_is_white))
782 0           return 0;
783             }
784             else {
785             int type;
786             int maxval;
787 131           int want_channels = im->channels;
788              
789 131 50         if (want_channels == 2 || want_channels == 4)
    100          
790 6           --want_channels;
791              
792 131 100         if (!i_tags_get_int(&im->tags, "pnm_write_wide_data", 0, &wide_data))
793 114           wide_data = 0;
794              
795 131 100         if (want_channels == 3) {
796 121           type = 6;
797             }
798 10 50         else if (want_channels == 1) {
799 10           type = 5;
800             }
801             else {
802 0           i_push_error(0, "can only save 1 or 3 channel images to pnm");
803 0           mm_log((1,"i_writeppm: ppm/pgm is 1 or 3 channel only (current image is %d)\n",im->channels));
804 0           return(0);
805             }
806 131 100         if (im->bits <= 8 || !wide_data)
    100          
807 119           maxval = 255;
808             else
809 12           maxval = 65535;
810              
811 131           sprintf(header,"P%d\n#CREATOR: Imager\n%" i_DF " %" i_DF"\n%d\n",
812 131           type, i_DFc(im->xsize), i_DFc(im->ysize), maxval);
813              
814 131 50         if (i_io_write(ig,header,strlen(header)) != strlen(header)) {
815 0           i_push_error(errno, "could not write ppm header");
816 0           mm_log((1,"i_writeppm: unable to write ppm header.\n"));
817 0           return(0);
818             }
819              
820 131 50         if (!i_img_virtual(im) && im->bits == i_8_bits && im->type == i_direct_type
    100          
    100          
821 100 100         && im->channels == want_channels) {
822 97 50         if (i_io_write(ig,im->idata,im->bytes) != im->bytes) {
823 0           i_push_error(errno, "could not write ppm data");
824 0           return 0;
825             }
826             }
827 34 100         else if (maxval == 255) {
828 22 50         if (!write_ppm_data_8(im, ig, want_channels))
829 0           return 0;
830             }
831             else {
832 12 50         if (!write_ppm_data_16(im, ig, want_channels))
833 0           return 0;
834             }
835             }
836 136 100         if (i_io_close(ig)) {
837 5 50         i_push_errorf(i_io_error(ig), "Error closing stream: %d", i_io_error(ig));
    50          
    50          
    50          
838 5           return 0;
839             }
840              
841 136           return(1);
842             }
843              
844             /*
845             =back
846              
847             =head1 AUTHOR
848              
849             Arnar M. Hrafnkelsson , Tony Cook ,
850             Philip Gwyn .
851              
852             =head1 SEE ALSO
853              
854             Imager(3)
855              
856             =cut
857             */