2 * Copyright (c) 1999-2000 Image Power, Inc. and the University of
4 * Copyright (c) 2001-2003 Michael David Adams.
8 /* __START_OF_JASPER_LICENSE__
10 * JasPer License Version 2.0
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
16 * All rights reserved.
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:
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.
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
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.
61 * __END_OF_JASPER_LICENSE__
65 * Portable Pixmap/Graymap Format Support
67 * $Id: pnm_dec.c,v 1.1 2005/05/22 18:33:09 malaterre Exp $
70 /******************************************************************************\
72 \******************************************************************************/
79 #include "jasper/jas_types.h"
80 #include "jasper/jas_stream.h"
81 #include "jasper/jas_image.h"
85 /******************************************************************************\
86 * Local function prototypes.
87 \******************************************************************************/
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);
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);
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)
102 /******************************************************************************\
104 \******************************************************************************/
106 static int pnm_allowtrunc = 1;
108 /******************************************************************************\
110 \******************************************************************************/
112 jas_image_t *pnm_decode(jas_stream_t *in, char *opts)
116 jas_image_cmptparm_t cmptparms[3];
117 jas_image_cmptparm_t *cmptparm;
121 fprintf(stderr, "warning: ignoring options\n");
124 /* Read the file header. */
125 if (pnm_gethdr(in, &hdr)) {
129 /* Create an image of the correct size. */
130 for (i = 0, cmptparm = cmptparms; i < hdr.numcmpts; ++i, ++cmptparm) {
135 cmptparm->width = hdr.width;
136 cmptparm->height = hdr.height;
137 cmptparm->prec = pnm_maxvaltodepth(hdr.maxval);
138 cmptparm->sgnd = hdr.sgnd;
140 if (!(image = jas_image_create(hdr.numcmpts, cmptparms, JAS_CLRSPC_UNKNOWN))) {
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));
153 jas_image_setclrspc(image, JAS_CLRSPC_SGRAY);
154 jas_image_setcmpttype(image, 0,
155 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
158 /* Read image data from stream into image. */
159 if (pnm_getdata(in, &hdr, image)) {
160 jas_image_destroy(image);
167 /******************************************************************************\
168 * Validation function.
169 \******************************************************************************/
171 int pnm_validate(jas_stream_t *in)
177 assert(JAS_STREAM_MAXPUTBACK >= 2);
179 /* Read the first two characters that constitute the signature. */
180 if ((n = jas_stream_read(in, buf, 2)) < 0) {
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) {
189 /* Did we read enough data? */
193 /* Is this the correct signature for a PNM file? */
194 if (buf[0] == 'P' && isdigit(buf[1])) {
200 /******************************************************************************\
201 * Functions for reading the header.
202 \******************************************************************************/
204 static int pnm_gethdr(jas_stream_t *in, pnm_hdr_t *hdr)
207 if (pnm_getint16(in, &hdr->magic) || pnm_getsintstr(in, &hdr->width) ||
208 pnm_getsintstr(in, &hdr->height)) {
211 if (pnm_type(hdr->magic) != PNM_TYPE_PBM) {
212 if (pnm_getsintstr(in, &maxval)) {
219 hdr->maxval = -maxval;
222 hdr->maxval = maxval;
226 switch (pnm_type(hdr->magic)) {
242 /******************************************************************************\
243 * Functions for processing the sample data.
244 \******************************************************************************/
246 static int pnm_getdata(jas_stream_t *in, pnm_hdr_t *hdr, jas_image_t *image)
254 jas_matrix_t *data[3];
266 numcmpts = jas_image_numcmpts(image);
268 fmt = pnm_fmt(hdr->magic);
269 type = pnm_type(hdr->magic);
270 depth = pnm_maxvaltodepth(hdr->maxval);
275 for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
276 if (!(data[cmptno] = jas_matrix_create(1, hdr->width))) {
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) {
289 while (n > 0 && x < hdr->width) {
290 jas_matrix_set(data[0], 0, x, 1 - ((c >> 7) & 1));
297 for (x = 0; x < hdr->width; ++x) {
299 if (pnm_getbitstr(in, &uv)) {
302 jas_matrix_set(data[0], 0, x, 1 - uv);
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. */
311 /* The sample data is signed. */
313 if (pnm_getsint(in, depth, &sv)) {
314 if (!pnm_allowtrunc) {
321 /* The sample data is unsigned. */
323 if (pnm_getuint(in, depth, &uv)) {
324 if (!pnm_allowtrunc) {
332 /* The sample data is in text format. */
334 /* The sample data is signed. */
336 if (pnm_getsintstr(in, &sv)) {
337 if (!pnm_allowtrunc) {
344 /* The sample data is unsigned. */
346 if (pnm_getuintstr(in, &uv)) {
347 if (!pnm_allowtrunc) {
355 jas_matrix_set(data[cmptno], 0, x, v);
359 for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
360 if (jas_image_writecmpt(image, cmptno, 0, y, hdr->width, 1,
371 for (cmptno = 0; cmptno < hdr->numcmpts; ++cmptno) {
373 jas_matrix_destroy(data[cmptno]);
380 /******************************************************************************\
381 * Miscellaneous functions.
382 \******************************************************************************/
384 static int pnm_getsint(jas_stream_t *in, int wordsize, int_fast32_t *val)
386 uint_fast32_t tmpval;
388 if (pnm_getuint(in, wordsize, &tmpval)) {
392 assert((tmpval & (1 << (wordsize - 1))) == 0);
399 static int pnm_getuint(jas_stream_t *in, int wordsize, uint_fast32_t *val)
401 uint_fast32_t tmpval;
406 n = (wordsize + 7) / 8;
408 if ((c = jas_stream_getc(in)) == EOF) {
411 tmpval = (tmpval << 8) | c;
413 tmpval &= (((uint_fast64_t) 1) << wordsize) - 1;
421 static int pnm_getbitstr(jas_stream_t *in, int *val)
426 if ((c = pnm_getc(in)) == EOF) {
431 if ((c = pnm_getc(in)) == EOF) {
438 } else if (c == '0' || c == '1') {
449 static int pnm_getuintstr(jas_stream_t *in, uint_fast32_t *val)
454 /* Discard any leading whitespace. */
456 if ((c = pnm_getc(in)) == EOF) {
459 } while (isspace(c));
461 /* Parse the number. */
464 v = 10 * v + c - '0';
465 if ((c = pnm_getc(in)) < 0) {
470 /* The number must be followed by whitespace. */
481 static int pnm_getsintstr(jas_stream_t *in, int_fast32_t *val)
487 /* Discard any leading whitespace. */
489 if ((c = pnm_getc(in)) == EOF) {
492 } while (isspace(c));
494 /* Get the number, allowing for a negative sign. */
498 if ((c = pnm_getc(in)) == EOF) {
501 } else if (c == '+') {
502 if ((c = pnm_getc(in)) == EOF) {
508 v = 10 * v + c - '0';
509 if ((c = pnm_getc(in)) < 0) {
514 /* The number must be followed by whitespace. */
520 *val = (s >= 0) ? v : (-v);
526 static int pnm_getc(jas_stream_t *in)
530 if ((c = jas_stream_getc(in)) == EOF) {
537 if ((c = jas_stream_getc(in)) == EOF) {
540 } while (c != '\n' && c != '\r');
544 static int pnm_getint16(jas_stream_t *in, int *val)
549 if ((c = jas_stream_getc(in)) == EOF) {
553 if ((c = jas_stream_getc(in)) == EOF) {
556 v = (v << 8) | (c & 0xff);