]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/bmp/bmp_dec.c
270e3f23986f109c346ea470854657ec9c2ec0ab
[gdcm.git] / src / gdcmjasper / src / libjasper / bmp / bmp_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  * Windows Bitmap File Library
66  *
67  * $Id: bmp_dec.c,v 1.1 2005/05/22 18:33:00 malaterre Exp $
68  */
69
70 /******************************************************************************\
71 * Includes.
72 \******************************************************************************/
73
74 #include <assert.h>
75
76 #include "jasper/jas_types.h"
77 #include "jasper/jas_stream.h"
78 #include "jasper/jas_image.h"
79 #include "jasper/jas_malloc.h"
80
81 #include "bmp_cod.h"
82
83 /******************************************************************************\
84 * Local prototypes.
85 \******************************************************************************/
86
87 static int bmp_gethdr(jas_stream_t *in, bmp_hdr_t *hdr);
88 static bmp_info_t *bmp_getinfo(jas_stream_t *in);
89 static int bmp_getdata(jas_stream_t *in, bmp_info_t *info, jas_image_t *image);
90 static int bmp_getint16(jas_stream_t *in, int_fast16_t *val);
91 static int bmp_getint32(jas_stream_t *in, int_fast32_t *val);
92 static int bmp_gobble(jas_stream_t *in, long n);
93
94 /******************************************************************************\
95 * Interface functions.
96 \******************************************************************************/
97
98 jas_image_t *bmp_decode(jas_stream_t *in, char *optstr)
99 {
100   jas_image_t *image;
101   bmp_hdr_t hdr;
102   bmp_info_t *info;
103   uint_fast16_t cmptno;
104   jas_image_cmptparm_t cmptparms[3];
105   jas_image_cmptparm_t *cmptparm;
106   uint_fast16_t numcmpts;
107   long n;
108
109   if (optstr) {
110     fprintf(stderr, "warning: ignoring BMP decoder options\n");
111   }
112
113   fprintf(stderr,
114     "THE BMP FORMAT IS NOT FULLY SUPPORTED!\n"
115     "THAT IS, THE JASPER SOFTWARE CANNOT DECODE ALL TYPES OF BMP DATA.\n"
116     "IF YOU HAVE ANY PROBLEMS, PLEASE TRY CONVERTING YOUR IMAGE DATA\n"
117     "TO THE PNM FORMAT, AND USING THIS FORMAT INSTEAD.\n"
118     );
119
120   /* Read the bitmap header. */
121   if (bmp_gethdr(in, &hdr)) {
122     fprintf(stderr, "cannot get header\n");
123     return 0;
124   }
125
126   /* Read the bitmap information. */
127   if (!(info = bmp_getinfo(in))) {
128     fprintf(stderr, "cannot get info\n");
129     return 0;
130   }
131
132   /* Ensure that we support this type of BMP file. */
133   if (!bmp_issupported(&hdr, info)) {
134     fprintf(stderr, "error: unsupported BMP encoding\n");
135     bmp_info_destroy(info);
136     return 0;
137   }
138
139   /* Skip over any useless data between the end of the palette
140     and start of the bitmap data. */
141   if ((n = hdr.off - (BMP_HDRLEN + BMP_INFOLEN + BMP_PALLEN(info))) < 0) {
142     fprintf(stderr, "error: possibly bad bitmap offset?\n");
143     return 0;
144   }
145   if (n > 0) {
146     fprintf(stderr, "skipping unknown data in BMP file\n");
147     if (bmp_gobble(in, n)) {
148       bmp_info_destroy(info);
149       return 0;
150     }
151   }
152
153   /* Get the number of components. */
154   numcmpts = bmp_numcmpts(info);
155
156   for (cmptno = 0, cmptparm = cmptparms; cmptno < numcmpts; ++cmptno,
157     ++cmptparm) {
158     cmptparm->tlx = 0;
159     cmptparm->tly = 0;
160     cmptparm->hstep = 1;
161     cmptparm->vstep = 1;
162     cmptparm->width = info->width;
163     cmptparm->height = info->height;
164     cmptparm->prec = 8;
165     cmptparm->sgnd = false;
166   }
167
168   /* Create image object. */
169   if (!(image = jas_image_create(numcmpts, cmptparms,
170     JAS_CLRSPC_UNKNOWN))) {
171     bmp_info_destroy(info);
172     return 0;
173   }
174
175   if (numcmpts == 3) {
176     jas_image_setclrspc(image, JAS_CLRSPC_SRGB);
177     jas_image_setcmpttype(image, 0,
178       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R));
179     jas_image_setcmpttype(image, 1,
180       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G));
181     jas_image_setcmpttype(image, 2,
182       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B));
183   } else {
184     jas_image_setclrspc(image, JAS_CLRSPC_SGRAY);
185     jas_image_setcmpttype(image, 0,
186       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y));
187   }
188
189   /* Read the bitmap data. */
190   if (bmp_getdata(in, info, image)) {
191     bmp_info_destroy(info);
192     jas_image_destroy(image);
193     return 0;
194   }
195
196   bmp_info_destroy(info);
197
198   return image;
199 }
200
201 int bmp_validate(jas_stream_t *in)
202 {
203   int n;
204   int i;
205   uchar buf[2];
206
207   assert(JAS_STREAM_MAXPUTBACK >= 2);
208
209   /* Read the first two characters that constitute the signature. */
210   if ((n = jas_stream_read(in, (char *) buf, 2)) < 0) {
211     return -1;
212   }
213   /* Put the characters read back onto the stream. */
214   for (i = n - 1; i >= 0; --i) {
215     if (jas_stream_ungetc(in, buf[i]) == EOF) {
216       return -1;
217     }
218   }
219   /* Did we read enough characters? */
220   if (n < 2) {
221     return -1;
222   }
223   /* Is the signature correct for the BMP format? */
224   if (buf[0] == (BMP_MAGIC & 0xff) && buf[1] == (BMP_MAGIC >> 8)) {
225     return 0;
226   }
227   return -1;
228 }
229
230 /******************************************************************************\
231 * Code for aggregate types.
232 \******************************************************************************/
233
234 static int bmp_gethdr(jas_stream_t *in, bmp_hdr_t *hdr)
235 {
236   if (bmp_getint16(in, &hdr->magic) || hdr->magic != BMP_MAGIC ||
237     bmp_getint32(in, &hdr->siz) || bmp_getint16(in, &hdr->reserved1) ||
238     bmp_getint16(in, &hdr->reserved2) || bmp_getint32(in, &hdr->off)) {
239     return -1;
240   }
241   return 0;
242 }
243
244 static bmp_info_t *bmp_getinfo(jas_stream_t *in)
245 {
246   bmp_info_t *info;
247   int i;
248   bmp_palent_t *palent;
249
250   if (!(info = bmp_info_create())) {
251     return 0;
252   }
253
254   if (bmp_getint32(in, &info->len) || info->len != 40 ||
255     bmp_getint32(in, &info->width) || bmp_getint32(in, &info->height) ||
256     bmp_getint16(in, &info->numplanes) ||
257     bmp_getint16(in, &info->depth) || bmp_getint32(in, &info->enctype) ||
258     bmp_getint32(in, &info->siz) ||
259     bmp_getint32(in, &info->hres) || bmp_getint32(in, &info->vres) ||
260     bmp_getint32(in, &info->numcolors) ||
261     bmp_getint32(in, &info->mincolors)) {
262     bmp_info_destroy(info);
263     return 0;
264   }
265
266   if (info->height < 0) {
267     info->topdown = 1;
268     info->height = -info->height;
269   } else {
270     info->topdown = 0;
271   }
272
273   if (info->width <= 0 || info->height <= 0 || info->numplanes <= 0 ||
274     info->depth <= 0  || info->numcolors < 0 || info->mincolors < 0) {
275     bmp_info_destroy(info);
276     return 0;
277   }
278
279   if (info->enctype != BMP_ENC_RGB) {
280     fprintf(stderr, "unsupported BMP encoding\n");
281     bmp_info_destroy(info);
282     return 0;
283   }
284
285   if (info->numcolors > 0) {
286     if (!(info->palents = jas_malloc(info->numcolors *
287       sizeof(bmp_palent_t)))) {
288       bmp_info_destroy(info);
289       return 0;
290     }
291   } else {
292     info->palents = 0;
293   }
294
295   for (i = 0; i < info->numcolors; ++i) {
296     palent = &info->palents[i];
297     if ((palent->blu = jas_stream_getc(in)) == EOF ||
298       (palent->grn = jas_stream_getc(in)) == EOF ||
299       (palent->red = jas_stream_getc(in)) == EOF ||
300       (palent->res = jas_stream_getc(in)) == EOF) {
301       bmp_info_destroy(info);
302       return 0;
303     }
304   }
305
306   return info;
307 }
308
309 static int bmp_getdata(jas_stream_t *in, bmp_info_t *info, jas_image_t *image)
310 {
311   int i;
312   int j;
313   int y;
314   jas_matrix_t *cmpts[3];
315   int numpad;
316   int red;
317   int grn;
318   int blu;
319   int ret;
320   int numcmpts;
321   int cmptno;
322   int ind;
323   bmp_palent_t *palent;
324   int mxind;
325   int haspal;
326
327   assert(info->depth == 8 || info->depth == 24);
328   assert(info->enctype == BMP_ENC_RGB);
329
330   numcmpts = bmp_numcmpts(info);
331   haspal = bmp_haspal(info);
332
333   ret = 0;
334   for (i = 0; i < numcmpts; ++i) {
335     cmpts[i] = 0;
336   }
337
338   /* Create temporary matrices to hold component data. */
339   for (i = 0; i < numcmpts; ++i) {
340     if (!(cmpts[i] = jas_matrix_create(1, info->width))) {
341       ret = -1;
342       goto bmp_getdata_done;
343     }
344   }
345
346   /* Calculate number of padding bytes per row of image data. */
347   numpad = (numcmpts * info->width) % 4;
348   if (numpad) {
349     numpad = 4 - numpad;
350   }
351
352   mxind = (1 << info->depth) - 1;
353   for (i = 0; i < info->height; ++i) {
354     for (j = 0; j < info->width; ++j) {
355       if (haspal) {
356         if ((ind = jas_stream_getc(in)) == EOF) {
357           ret = -1;
358           goto bmp_getdata_done;
359         }
360         if (ind > mxind) {
361           ret = -1;
362           goto bmp_getdata_done;
363         }
364         if (ind < info->numcolors) {
365           palent = &info->palents[ind];
366           red = palent->red;
367           grn = palent->grn;
368           blu = palent->blu;
369         } else {
370           red = ind;
371           grn = ind;
372           blu = ind;
373         }
374       } else {
375         if ((blu = jas_stream_getc(in)) == EOF ||
376           (grn = jas_stream_getc(in)) == EOF ||
377           (red = jas_stream_getc(in)) == EOF) {
378           ret = -1;
379           goto bmp_getdata_done;
380         }
381       }
382       if (numcmpts == 3) {
383         jas_matrix_setv(cmpts[0], j, red);
384         jas_matrix_setv(cmpts[1], j, grn);
385         jas_matrix_setv(cmpts[2], j, blu);
386       } else {
387         jas_matrix_setv(cmpts[0], j, red);
388       }
389     }
390     for (j = numpad; j > 0; --j) {
391         if (jas_stream_getc(in) == EOF) {
392           ret = -1;
393           goto bmp_getdata_done;
394         }
395     }
396     for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
397       y = info->topdown ? i : (info->height - 1 - i);
398       if (jas_image_writecmpt(image, cmptno, 0, y, info->width,
399         1, cmpts[cmptno])) {
400         ret = -1;
401         goto bmp_getdata_done;
402       }
403     }
404   }
405
406 bmp_getdata_done:
407   /* Destroy the temporary matrices. */
408   for (i = 0; i < numcmpts; ++i) {
409     if (cmpts[i]) {
410       jas_matrix_destroy(cmpts[i]);
411     }
412   }
413
414   return ret;
415 }
416
417 /******************************************************************************\
418 * Code for primitive types.
419 \******************************************************************************/
420
421 static int bmp_getint16(jas_stream_t *in, int_fast16_t *val)
422 {
423   int lo;
424   int hi;
425   if ((lo = jas_stream_getc(in)) == EOF || (hi = jas_stream_getc(in)) == EOF) {
426     return -1;
427   }
428   if (val) {
429     *val = (hi << 8) | lo;
430   }
431   return 0;
432 }
433
434 static int bmp_getint32(jas_stream_t *in, int_fast32_t *val)
435 {
436   int n;
437   uint_fast32_t v;
438   int c;
439   for (n = 4, v = 0;;) {
440     if ((c = jas_stream_getc(in)) == EOF) {
441       return -1;
442     }
443     v |= (c << 24);
444     if (--n <= 0) {
445       break;
446     }
447     v >>= 8;
448   }
449   if (val) {
450     *val = v;
451   }
452   return 0;
453 }
454
455 static int bmp_gobble(jas_stream_t *in, long n)
456 {
457   while (--n >= 0) {
458     if (jas_stream_getc(in) == EOF) {
459       return -1;
460     }
461   }
462   return 0;
463 }