]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/pnm/pnm_enc.c
ENH: Ok since OJ warnings are not going to be fixed anytime soon remove them
[gdcm.git] / src / gdcmjasper / src / libjasper / pnm / pnm_enc.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_enc.c,v 1.1 2005/05/22 18:33:09 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_tvp.h"
81 #include "jasper/jas_image.h"
82 #include "jasper/jas_stream.h"
83 #include "jasper/jas_debug.h"
84
85 #include "pnm_cod.h"
86 #include "pnm_enc.h"
87
88 /******************************************************************************\
89 * Local types.
90 \******************************************************************************/
91
92 typedef struct {
93   bool bin;
94 } pnm_encopts_t;
95
96 typedef enum {
97   OPT_TEXT
98 } pnm_optid_t;
99
100 jas_taginfo_t pnm_opttab[] = {
101   {OPT_TEXT, "text"},
102   {-1, 0}
103 };
104
105 /******************************************************************************\
106 * Local function prototypes.
107 \******************************************************************************/
108
109 static int pnm_parseencopts(char *optstr, pnm_encopts_t *encopts);
110 static int pnm_puthdr(jas_stream_t *out, pnm_hdr_t *hdr);
111 static int pnm_putdata(jas_stream_t *out, pnm_hdr_t *hdr, jas_image_t *image, int numcmpts, int *cmpts);
112
113 static int pnm_putsint(jas_stream_t *out, int wordsize, int_fast32_t *val);
114 static int pnm_putuint(jas_stream_t *out, int wordsize, uint_fast32_t *val);
115 static int pnm_putuint16(jas_stream_t *out, uint_fast16_t val);
116
117 /******************************************************************************\
118 * Save function.
119 \******************************************************************************/
120
121 int pnm_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
122 {
123   int width;
124   int height;
125   int cmptno;
126   pnm_hdr_t hdr;
127   pnm_encopts_t encopts;
128   int prec;
129   int sgnd;
130   pnm_enc_t encbuf;
131   pnm_enc_t *enc = &encbuf;
132
133   /* Parse the encoder option string. */
134   if (pnm_parseencopts(optstr, &encopts)) {
135     fprintf(stderr, "invalid PNM encoder options specified\n");
136     return -1;
137   }
138
139   switch (jas_clrspc_fam(jas_image_clrspc(image))) {
140   case JAS_CLRSPC_FAM_RGB:
141     if (jas_image_clrspc(image) != JAS_CLRSPC_SRGB)
142       jas_eprintf("warning: inaccurate color\n");
143     enc->numcmpts = 3;
144     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
145       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
146       (enc->cmpts[1] = jas_image_getcmptbytype(image,
147       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
148       (enc->cmpts[2] = jas_image_getcmptbytype(image,
149       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
150       jas_eprintf("error: missing color component\n");
151       return -1;
152     }
153     break;
154   case JAS_CLRSPC_FAM_GRAY:
155     if (jas_image_clrspc(image) != JAS_CLRSPC_SGRAY)
156       jas_eprintf("warning: inaccurate color\n");
157     enc->numcmpts = 1;
158     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
159       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0) {
160       jas_eprintf("error: missing color component\n");
161       return -1;
162     }
163     break;
164   default:
165     jas_eprintf("error: unsupported color space\n");
166     return -1;
167     break;
168   }
169
170
171   width = jas_image_cmptwidth(image, enc->cmpts[0]);
172   height = jas_image_cmptheight(image, enc->cmpts[0]);
173   prec = jas_image_cmptprec(image, enc->cmpts[0]);
174   sgnd = jas_image_cmptsgnd(image, enc->cmpts[0]);
175
176   /* The PNM format is quite limited in the set of image geometries
177     that it can handle.  Here, we check to ensure that the image to
178     be saved can actually be represented reasonably accurately using the
179     PNM format. */
180   /* All of the components must have the same width and height. */
181   /* All of the components must have unsigned samples with the same
182     precision.*/
183   /* All of the components must have their top-left corner located at
184     the origin. */
185   for (cmptno = 0; cmptno < enc->numcmpts; ++cmptno) {
186     if (jas_image_cmptwidth(image, enc->cmpts[cmptno]) != width ||
187       jas_image_cmptheight(image, enc->cmpts[cmptno]) != height ||
188       jas_image_cmptprec(image, enc->cmpts[cmptno]) != prec ||
189       jas_image_cmptsgnd(image, enc->cmpts[cmptno]) != sgnd ||
190       jas_image_cmpthstep(image, enc->cmpts[cmptno]) != jas_image_cmpthstep(image, 0) ||
191       jas_image_cmptvstep(image, enc->cmpts[cmptno]) != jas_image_cmptvstep(image, 0) ||
192       jas_image_cmpttlx(image, enc->cmpts[cmptno]) != jas_image_cmpttlx(image, 0) ||
193       jas_image_cmpttly(image, enc->cmpts[cmptno]) != jas_image_cmpttly(image, 0)) {
194       fprintf(stderr, "The PNM format cannot be used to represent an image with this geometry.\n");
195       return -1;
196     }
197   }
198
199   if (sgnd) {
200     fprintf(stderr, "warning: support for signed sample data requires use of nonstandard extension to PNM format\n");
201     fprintf(stderr, "You may not be able to read or correctly display the resulting PNM data with other software.\n");
202   }
203
204   /* Initialize the header. */
205   if (enc->numcmpts == 1) {
206     hdr.magic = encopts.bin ? PNM_MAGIC_BINPGM : PNM_MAGIC_TXTPGM;
207   } else if (enc->numcmpts == 3) {
208     hdr.magic = encopts.bin ? PNM_MAGIC_BINPPM : PNM_MAGIC_TXTPPM;
209   } else {
210     return -1;
211   }
212   hdr.width = width;
213   hdr.height = height;
214   hdr.maxval = (1 << prec) - 1;
215   hdr.sgnd = sgnd;
216
217   /* Write the header. */
218   if (pnm_puthdr(out, &hdr)) {
219     return -1;
220   }
221
222   /* Write the image data. */
223   if (pnm_putdata(out, &hdr, image, enc->numcmpts, enc->cmpts)) {
224     return -1;
225   }
226
227   /* Flush the output stream. */
228   if (jas_stream_flush(out)) {
229     return -1;
230   }
231
232   return 0;
233 }
234
235 /******************************************************************************\
236 * Code for parsing options.
237 \******************************************************************************/
238
239 /* Parse the encoder options string. */
240 static int pnm_parseencopts(char *optstr, pnm_encopts_t *encopts)
241 {
242   jas_tvparser_t *tvp;
243   int ret;
244
245   tvp = 0;
246
247   /* Initialize default values for encoder options. */
248   encopts->bin = true;
249
250   /* Create the tag-value parser. */
251   if (!(tvp = jas_tvparser_create(optstr ? optstr : ""))) {
252     goto error;
253   }
254
255   /* Get tag-value pairs, and process as necessary. */
256   while (!(ret = jas_tvparser_next(tvp))) {
257     switch (jas_taginfo_nonull(jas_taginfos_lookup(pnm_opttab,
258       jas_tvparser_gettag(tvp)))->id) {
259     case OPT_TEXT:
260       encopts->bin = false;
261       break;
262     default:
263       fprintf(stderr, "warning: ignoring invalid option %s\n",
264         jas_tvparser_gettag(tvp));
265       break;
266     }  
267   }
268   if (ret < 0) {
269     goto error;
270   }
271
272   /* Destroy the tag-value parser. */
273   jas_tvparser_destroy(tvp);
274
275   return 0;
276
277 error:
278   if (tvp) {
279     jas_tvparser_destroy(tvp);
280   }
281   return -1;
282 }
283
284 /******************************************************************************\
285 * Function for writing header.
286 \******************************************************************************/
287
288 /* Write the header. */
289 static int pnm_puthdr(jas_stream_t *out, pnm_hdr_t *hdr)
290 {
291   int_fast32_t maxval;
292
293   if (pnm_putuint16(out, hdr->magic)) {
294     return -1;
295   }
296   if (hdr->sgnd) {
297     maxval = -hdr->maxval;
298   } else {
299     maxval = hdr->maxval;
300   }
301   jas_stream_printf(out, "\n%lu %lu\n%ld\n", (unsigned long) hdr->width,
302     (unsigned long) hdr->height, (long) maxval);
303   if (jas_stream_error(out)) {
304     return -1;
305   }
306   return 0;
307 }
308
309 /******************************************************************************\
310 * Functions for processing the sample data.
311 \******************************************************************************/
312
313 /* Write the image sample data. */
314 static int pnm_putdata(jas_stream_t *out, pnm_hdr_t *hdr, jas_image_t *image, int numcmpts, int *cmpts)
315 {
316   int ret;
317   int cmptno;
318   int x;
319   int y;
320   jas_matrix_t *data[3];
321   int fmt;
322   jas_seqent_t *d[3];
323   jas_seqent_t v;
324   int minval;
325   int linelen;
326   int n;
327   char buf[256];
328   int depth;
329
330   ret = -1;
331   fmt = pnm_fmt(hdr->magic);
332   minval = -((int) hdr->maxval + 1);
333   depth = pnm_maxvaltodepth(hdr->maxval);
334
335   data[0] = 0;
336   data[1] = 0;
337   data[2] = 0;
338   for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
339     if (!(data[cmptno] = jas_matrix_create(1, hdr->width))) {
340       goto done;
341     }
342   }
343
344   for (y = 0; y < hdr->height; ++y) {
345     for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
346       if (jas_image_readcmpt(image, cmpts[cmptno], 0, y, hdr->width, 1,
347         data[cmptno])) {
348         goto done;
349       }
350       d[cmptno] = jas_matrix_getref(data[cmptno], 0, 0);
351     }
352     linelen = 0;
353     for (x = 0; x < hdr->width; ++x) {
354       for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
355         v = *d[cmptno];
356         if (v < minval) {
357           v = minval;
358         }
359         if (v > ((int) hdr->maxval)) {
360           v = hdr->maxval;
361         }
362         if (fmt == PNM_FMT_BIN) {
363           if (hdr->sgnd) {
364             int_fast32_t sv;
365             sv = v;
366             if (pnm_putsint(out, depth, &sv)) {
367               goto done;
368             }
369           } else {
370             uint_fast32_t uv;
371             uv = v;
372             if (pnm_putuint(out, depth, &uv)) {
373               goto done;
374             }
375           }
376         } else {
377           n = sprintf(buf, "%s%ld", ((!(!x && !cmptno)) ? " " : ""),
378             (long) v);
379           if (linelen > 0 && linelen + n > PNM_MAXLINELEN) {
380             jas_stream_printf(out, "\n");
381             linelen = 0;
382           }
383           jas_stream_printf(out, "%s", buf);
384           linelen += n;
385         }
386         ++d[cmptno];
387       }
388     }
389     if (fmt != PNM_FMT_BIN) {
390       jas_stream_printf(out, "\n");
391       linelen = 0;
392     }
393     if (jas_stream_error(out)) {
394       goto done;
395     }
396   }
397
398   ret = 0;
399
400 done:
401
402   for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
403     if (data[cmptno]) {
404       jas_matrix_destroy(data[cmptno]);
405     }
406   }
407
408   return ret;
409 }
410
411 /******************************************************************************\
412 * Miscellaneous functions.
413 \******************************************************************************/
414
415 static int pnm_putsint(jas_stream_t *out, int wordsize, int_fast32_t *val)
416 {
417   uint_fast32_t tmpval;
418   tmpval = (*val < 0) ?
419     ((~(JAS_CAST(uint_fast32_t, -(*val)) + 1)) & PNM_ONES(wordsize)) :
420     JAS_CAST(uint_fast32_t, (*val));
421   return pnm_putuint(out, wordsize, &tmpval);
422 }
423
424 static int pnm_putuint(jas_stream_t *out, int wordsize, uint_fast32_t *val)
425 {
426   int n;
427   uint_fast32_t tmpval;
428   int c;
429
430   n = (wordsize + 7) / 8;
431   tmpval &= PNM_ONES(8 * n);
432   tmpval = (*val) << (8 * (4 - n));
433   while (--n >= 0) {
434     c = (tmpval >> 24) & 0xff;
435     if (jas_stream_putc(out, c) == EOF) {
436       return -1;
437     }
438     tmpval = (tmpval << 8) & 0xffffffff;
439   }
440   return 0;
441 }
442
443 /* Write a 16-bit unsigned integer to a stream. */
444 static int pnm_putuint16(jas_stream_t *out, uint_fast16_t val)
445 {
446   if (jas_stream_putc(out, (unsigned char)(val >> 8)) == EOF ||
447     jas_stream_putc(out, (unsigned char)(val & 0xff)) == EOF) {
448     return -1;
449   }
450   return 0;
451 }