]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/pnm/pnm_dec.c
47716a7b9c26221e2d143cdcbb2979e2995bd631
[gdcm.git] / src / gdcmjasper / src / libjasper / pnm / pnm_dec.c
1 /*
2  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
3  *   British Columbia.
4  * Copyright (c) 2001-2003 Michael David Adams.
5  * All rights reserved.
6  */
7
8 /* __START_OF_JASPER_LICENSE__
9  * 
10  * JasPer License Version 2.0
11  * 
12  * Copyright (c) 1999-2000 Image Power, Inc.
13  * Copyright (c) 1999-2000 The University of British Columbia
14  * Copyright (c) 2001-2003 Michael David Adams
15  * 
16  * All rights reserved.
17  * 
18  * Permission is hereby granted, free of charge, to any person (the
19  * "User") obtaining a copy of this software and associated documentation
20  * files (the "Software"), to deal in the Software without restriction,
21  * including without limitation the rights to use, copy, modify, merge,
22  * publish, distribute, and/or sell copies of the Software, and to permit
23  * persons to whom the Software is furnished to do so, subject to the
24  * following conditions:
25  * 
26  * 1.  The above copyright notices and this permission notice (which
27  * includes the disclaimer below) shall be included in all copies or
28  * substantial portions of the Software.
29  * 
30  * 2.  The name of a copyright holder shall not be used to endorse or
31  * promote products derived from the Software without specific prior
32  * written permission.
33  * 
34  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
35  * LICENSE.  NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
36  * THIS DISCLAIMER.  THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
37  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
39  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  IN NO
40  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
41  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
42  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
43  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
44  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  NO ASSURANCES ARE
45  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
46  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
47  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
48  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
49  * PROPERTY RIGHTS OR OTHERWISE.  AS A CONDITION TO EXERCISING THE RIGHTS
50  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
51  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY.  THE SOFTWARE
52  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
53  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
54  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
55  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
56  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
57  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
58  * RISK ACTIVITIES").  THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
59  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
60  * 
61  * __END_OF_JASPER_LICENSE__
62  */
63
64 /*
65  * Portable Pixmap/Graymap Format Support
66  *
67  * $Id: pnm_dec.c,v 1.2 2005/06/11 02:05:38 malaterre Exp $
68  */
69
70 /******************************************************************************\
71 * Includes.
72 \******************************************************************************/
73
74 #include <ctype.h>
75 #include <math.h>
76 #include <stdlib.h>
77 #include <assert.h>
78
79 #include "jasper/jas_types.h"
80 #include "jasper/jas_stream.h"
81 #include "jasper/jas_image.h"
82
83 #include "pnm_cod.h"
84
85 /******************************************************************************\
86 * Local function prototypes.
87 \******************************************************************************/
88
89 static int pnm_gethdr(jas_stream_t *in, pnm_hdr_t *hdr);
90 static int pnm_getdata(jas_stream_t *in, pnm_hdr_t *hdr, jas_image_t *image);
91
92 static int pnm_getsintstr(jas_stream_t *in, int_fast32_t *val);
93 static int pnm_getuintstr(jas_stream_t *in, uint_fast32_t *val);
94 static int pnm_getbitstr(jas_stream_t *in, int *val);
95 static int pnm_getc(jas_stream_t *in);
96
97 static int pnm_getsint(jas_stream_t *in, int wordsize, int_fast32_t *val);
98 static int pnm_getuint(jas_stream_t *in, int wordsize, uint_fast32_t *val);
99 static int pnm_getint16(jas_stream_t *in, int *val);
100 #define  pnm_getuint32(in, val)  pnm_getuint(in, 32, val)
101
102 /******************************************************************************\
103 * Local data.
104 \******************************************************************************/
105
106 static int pnm_allowtrunc = 1;
107
108 /******************************************************************************\
109 * Load function.
110 \******************************************************************************/
111
112 jas_image_t *pnm_decode(jas_stream_t *in, char *opts)
113 {
114   pnm_hdr_t hdr;
115   jas_image_t *image;
116   jas_image_cmptparm_t cmptparms[3];
117   jas_image_cmptparm_t *cmptparm;
118   int i;
119
120   if (opts) {
121     fprintf(stderr, "warning: ignoring options\n");
122   }
123
124   /* Read the file header. */
125   if (pnm_gethdr(in, &hdr)) {
126     return 0;
127   }
128
129   /* Create an image of the correct size. */
130   for (i = 0, cmptparm = cmptparms; i < hdr.numcmpts; ++i, ++cmptparm) {
131     cmptparm->tlx = 0;
132     cmptparm->tly = 0;
133     cmptparm->hstep = 1;
134     cmptparm->vstep = 1;
135     cmptparm->width = hdr.width;
136     cmptparm->height = hdr.height;
137     cmptparm->prec = pnm_maxvaltodepth(hdr.maxval);
138     cmptparm->sgnd = hdr.sgnd;
139   }
140   if (!(image = jas_image_create(hdr.numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN))) {
141     return 0;
142   }
143
144   if (hdr.numcmpts == 3) {
145     jas_image_setclrspc(image, JAS_CLRSPC_SRGB);
146     jas_image_setcmpttype(image, 0,
147       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
148     jas_image_setcmpttype(image, 1,
149       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
150     jas_image_setcmpttype(image, 2,
151       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
152   } else {
153     jas_image_setclrspc(image, JAS_CLRSPC_SGRAY);
154     jas_image_setcmpttype(image, 0,
155       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
156   }
157
158   /* Read image data from stream into image. */
159   if (pnm_getdata(in, &hdr, image)) {
160     jas_image_destroy(image);
161     return 0;
162   }
163
164   return image;
165 }
166
167 /******************************************************************************\
168 * Validation function.
169 \******************************************************************************/
170
171 int pnm_validate(jas_stream_t *in)
172 {
173   uchar buf[2];
174   int i;
175   int n;
176
177   assert(JAS_STREAM_MAXPUTBACK >= 2);
178
179   /* Read the first two characters that constitute the signature. */
180   if ((n = jas_stream_read(in, buf, 2)) < 0) {
181     return -1;
182   }
183   /* Put these characters back to the stream. */
184   for (i = n - 1; i >= 0; --i) {
185     if (jas_stream_ungetc(in, buf[i]) == EOF) {
186       return -1;
187     }
188   }
189   /* Did we read enough data? */
190   if (n < 2) {
191     return -1;
192   }
193   /* Is this the correct signature for a PNM file? */
194   if (buf[0] == 'P' && isdigit(buf[1])) {
195     return 0;
196   }
197   return -1;
198 }
199
200 /******************************************************************************\
201 * Functions for reading the header.
202 \******************************************************************************/
203
204 static int pnm_gethdr(jas_stream_t *in, pnm_hdr_t *hdr)
205 {
206   int_fast32_t maxval;
207   if (pnm_getint16(in, &hdr->magic) || pnm_getsintstr(in, &hdr->width) ||
208     pnm_getsintstr(in, &hdr->height)) {
209     return -1;
210   }
211   if (pnm_type(hdr->magic) != PNM_TYPE_PBM) {
212     if (pnm_getsintstr(in, &maxval)) {
213       return -1;
214     }
215   } else {
216     maxval = 1;
217   }
218   if (maxval < 0) {
219     hdr->maxval = -maxval;
220     hdr->sgnd = true;
221   } else {
222     hdr->maxval = maxval;
223     hdr->sgnd = false;
224   }
225
226   switch (pnm_type(hdr->magic)) {
227   case PNM_TYPE_PBM:
228   case PNM_TYPE_PGM:
229     hdr->numcmpts = 1;
230     break;
231   case PNM_TYPE_PPM:
232     hdr->numcmpts = 3;
233     break;
234   default:
235     abort();
236     break;
237   }
238
239   return 0;
240 }
241
242 /******************************************************************************\
243 * Functions for processing the sample data.
244 \******************************************************************************/
245
246 static int pnm_getdata(jas_stream_t *in, pnm_hdr_t *hdr, jas_image_t *image)
247 {
248   int ret;
249 #if 0
250   int numcmpts;
251 #endif
252   int cmptno;
253   int fmt;
254   jas_matrix_t *data[3];
255   int x;
256   int y;
257   int_fast64_t v;
258   int depth;
259   int type;
260   int c;
261   int n;
262
263   ret = -1;
264
265 #if 0
266   numcmpts = jas_image_numcmpts(image);
267 #endif
268   fmt = pnm_fmt(hdr->magic);
269   type = pnm_type(hdr->magic);
270   depth = pnm_maxvaltodepth(hdr->maxval);
271
272   data[0] = 0;
273   data[1] = 0;
274   data[2] = 0;
275   for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
276     if (!(data[cmptno] = jas_matrix_create(1, hdr->width))) {
277       goto done;
278     }
279   }
280
281   for (y = 0; y < hdr->height; ++y) {
282     if (type == PNM_TYPE_PBM) {
283       if (fmt == PNM_FMT_BIN) {
284         for (x = 0; x < hdr->width;) {
285           if ((c = jas_stream_getc(in)) == EOF) {
286             goto done;
287           }
288           n = 8;
289           while (n > 0 && x < hdr->width) {
290             jas_matrix_set(data[0], 0, x, 1 - ((c >> 7) & 1));
291             c <<= 1;
292             --n;
293             ++x;
294           }
295         }
296       } else {
297         for (x = 0; x < hdr->width; ++x) {
298           int uv;
299           if (pnm_getbitstr(in, &uv)) {
300             goto done;
301           }
302           jas_matrix_set(data[0], 0, x, 1 - uv);
303         }
304       }
305     } else {
306       for (x = 0; x < hdr->width; ++x) {
307         for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
308           if (fmt == PNM_FMT_BIN) {
309             /* The sample data is in binary format. */
310             if (hdr->sgnd) {
311               /* The sample data is signed. */
312               int_fast32_t sv;
313               if (pnm_getsint(in, depth, &sv)) {
314                 if (!pnm_allowtrunc) {
315                   goto done;
316                 }
317                 sv = 0;
318               }
319               v = sv;
320             } else {
321               /* The sample data is unsigned. */
322               uint_fast32_t uv;
323               if (pnm_getuint(in, depth, &uv)) {
324                 if (!pnm_allowtrunc) {
325                   goto done;
326                 }
327                 uv = 0;
328               }
329               v = uv;
330             }
331           } else {
332             /* The sample data is in text format. */
333             if (hdr->sgnd) {
334               /* The sample data is signed. */
335               int_fast32_t sv;
336               if (pnm_getsintstr(in, &sv)) {
337                 if (!pnm_allowtrunc) {
338                   goto done;
339                 }
340                 sv = 0;
341               }
342               v = sv;
343             } else {
344               /* The sample data is unsigned. */
345               uint_fast32_t uv;
346               if (pnm_getuintstr(in, &uv)) {
347                 if (!pnm_allowtrunc) {
348                   goto done;
349                 }
350                 uv = 0;
351               }
352               v = uv;
353             }
354           }
355           jas_matrix_set(data[cmptno], 0, x, (jas_seqent_t)v);
356         }
357       }
358     }
359     for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
360       if (jas_image_writecmpt(image, cmptno, 0, y, hdr->width, 1,
361         data[cmptno])) {
362         goto done;
363       }
364     }
365   }
366
367   ret = 0;
368
369 done:
370
371   for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
372     if (data[cmptno]) {
373       jas_matrix_destroy(data[cmptno]);
374     }
375   }
376
377   return ret;
378 }
379
380 /******************************************************************************\
381 * Miscellaneous functions.
382 \******************************************************************************/
383
384 static int pnm_getsint(jas_stream_t *in, int wordsize, int_fast32_t *val)
385 {
386   uint_fast32_t tmpval;
387
388   if (pnm_getuint(in, wordsize, &tmpval)) {
389     return -1;
390   }
391   if (val) {
392     assert((tmpval & (1 << (wordsize - 1))) == 0);
393     *val = tmpval;
394   }
395
396   return 0;
397 }
398
399 static int pnm_getuint(jas_stream_t *in, int wordsize, uint_fast32_t *val)
400 {
401   uint_fast32_t tmpval;
402   int c;
403   int n;
404
405   tmpval = 0;
406   n = (wordsize + 7) / 8;
407   while (--n >= 0) {
408     if ((c = jas_stream_getc(in)) == EOF) {
409       return -1;
410     }
411     tmpval = (tmpval << 8) | c;
412   }
413   tmpval &= (((uint_fast64_t) 1) << wordsize) - 1;
414   if (val) {
415     *val = tmpval;
416   }
417
418   return 0;
419 }
420
421 static int pnm_getbitstr(jas_stream_t *in, int *val)
422 {
423   int c;
424   int_fast32_t v;
425   for (;;) {
426     if ((c = pnm_getc(in)) == EOF) {
427       return -1;
428     }
429     if (c == '#') {
430       for (;;) {
431         if ((c = pnm_getc(in)) == EOF) {
432           return -1;
433         }
434         if (c == '\n') {
435           break;
436         }
437       }
438     } else if (c == '0' || c == '1') {
439       v = c - '0';
440       break;
441     }
442   }
443   if (val) {
444     *val = v;
445   }
446   return 0;
447 }
448
449 static int pnm_getuintstr(jas_stream_t *in, uint_fast32_t *val)
450 {
451   uint_fast32_t v;
452   int c;
453
454   /* Discard any leading whitespace. */
455   do {
456     if ((c = pnm_getc(in)) == EOF) {
457       return -1;
458     }
459   } while (isspace(c));
460
461   /* Parse the number. */
462   v = 0;
463   while (isdigit(c)) {
464     v = 10 * v + c - '0';
465     if ((c = pnm_getc(in)) < 0) {
466       return -1;
467     }
468   }
469
470   /* The number must be followed by whitespace. */
471   if (!isspace(c)) {
472     return -1;
473   }
474
475   if (val) {
476     *val = v;
477   }
478   return 0;
479 }
480
481 static int pnm_getsintstr(jas_stream_t *in, int_fast32_t *val)
482 {
483   int c;
484   int s;
485   int_fast32_t v;
486
487   /* Discard any leading whitespace. */
488   do {
489     if ((c = pnm_getc(in)) == EOF) {
490       return -1;
491     }
492   } while (isspace(c));
493
494   /* Get the number, allowing for a negative sign. */
495   s = 1;
496   if (c == '-') {
497     s = -1;
498     if ((c = pnm_getc(in)) == EOF) {
499       return -1;
500     }
501   } else if (c == '+') {
502     if ((c = pnm_getc(in)) == EOF) {
503       return -1;
504     }
505   }
506   v = 0;
507   while (isdigit(c)) {
508     v = 10 * v + c - '0';
509     if ((c = pnm_getc(in)) < 0) {
510       return -1;
511     }
512   }
513
514   /* The number must be followed by whitespace. */
515   if (!isspace(c)) {
516     return -1;
517   }
518
519   if (val) {
520     *val = (s >= 0) ? v : (-v);
521   }
522
523   return 0;
524 }
525
526 static int pnm_getc(jas_stream_t *in)
527 {
528   int c;
529   for (;;) {
530     if ((c = jas_stream_getc(in)) == EOF) {
531       return -1;
532     }
533     if (c != '#') {
534       return c;
535     }
536     do {
537       if ((c = jas_stream_getc(in)) == EOF) {
538         return -1;
539       }
540     } while (c != '\n' && c != '\r');
541   }
542 }
543
544 static int pnm_getint16(jas_stream_t *in, int *val)
545 {
546   int v;
547   int c;
548
549   if ((c = jas_stream_getc(in)) == EOF) {
550     return -1;
551   }
552   v = c & 0xff;
553   if ((c = jas_stream_getc(in)) == EOF) {
554     return -1;
555   }
556   v = (v << 8) | (c & 0xff);
557   *val = v;
558
559   return 0;
560 }