]> Creatis software - gdcm.git/blob - src/gdcmjasper/src/libjasper/bmp/bmp_enc.c
4dce928443a78cf2deb524172c7f36be665bc444
[gdcm.git] / src / gdcmjasper / src / libjasper / bmp / bmp_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  * Windows Bitmap File Library
66  *
67  * $Id: bmp_enc.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_debug.h"
80
81 #include "bmp_enc.h"
82 #include "bmp_cod.h"
83
84 /******************************************************************************\
85 * Local prototypes.
86 \******************************************************************************/
87
88 static int bmp_puthdr(jas_stream_t *out, bmp_hdr_t *hdr);
89 static int bmp_putinfo(jas_stream_t *out, bmp_info_t *info);
90 static int bmp_putdata(jas_stream_t *out, bmp_info_t *info, jas_image_t *image, int *cmpts);
91 static int bmp_putint16(jas_stream_t *in, int_fast16_t val);
92 static int bmp_putint32(jas_stream_t *out, int_fast32_t val);
93
94 /******************************************************************************\
95 * Interface functions.
96 \******************************************************************************/
97
98 int bmp_encode(jas_image_t *image, jas_stream_t *out, char *optstr)
99 {
100   jas_image_coord_t width;
101   jas_image_coord_t height;
102   int depth;
103   int cmptno;
104   bmp_hdr_t hdr;
105   bmp_info_t *info;
106   int_fast32_t datalen;
107   int numpad;
108   bmp_enc_t encbuf;
109   bmp_enc_t *enc = &encbuf;
110   jas_clrspc_t clrspc;
111
112   if (optstr) {
113     fprintf(stderr, "warning: ignoring BMP encoder options\n");
114   }
115
116   clrspc = jas_image_clrspc(image);
117   switch (jas_clrspc_fam(clrspc)) {
118   case JAS_CLRSPC_FAM_RGB:
119     if (clrspc != JAS_CLRSPC_SRGB)
120       jas_eprintf("warning: inaccurate color\n");
121     break;
122   case JAS_CLRSPC_FAM_GRAY:
123     if (clrspc != JAS_CLRSPC_SGRAY)
124       jas_eprintf("warning: inaccurate color\n");
125     break;
126   default:
127     jas_eprintf("error: BMP format does not support color space\n");
128     return -1;
129     break;
130   }
131
132   switch (jas_clrspc_fam(clrspc)) {
133   case JAS_CLRSPC_FAM_RGB:
134     enc->numcmpts = 3;
135     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
136       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
137       (enc->cmpts[1] = jas_image_getcmptbytype(image,
138       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
139       (enc->cmpts[2] = jas_image_getcmptbytype(image,
140       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
141       jas_eprintf("error: missing color component\n");
142       return -1;
143     }
144     break;
145   case JAS_CLRSPC_FAM_GRAY:
146     enc->numcmpts = 1;
147     if ((enc->cmpts[0] = jas_image_getcmptbytype(image,
148       JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_GRAY_Y))) < 0) {
149       jas_eprintf("error: missing color component\n");
150       return -1;
151     }
152     break;
153   default:
154     abort();
155     break;
156   }
157
158   width = jas_image_cmptwidth(image, enc->cmpts[0]);
159   height = jas_image_cmptheight(image, enc->cmpts[0]);
160   depth = jas_image_cmptprec(image, enc->cmpts[0]);
161
162   /* Check to ensure that the image to be saved can actually be represented
163     using the BMP format. */
164   for (cmptno = 0; cmptno < enc->numcmpts; ++cmptno) {
165     if (jas_image_cmptwidth(image, enc->cmpts[cmptno]) != width ||
166       jas_image_cmptheight(image, enc->cmpts[cmptno]) != height ||
167       jas_image_cmptprec(image, enc->cmpts[cmptno]) != depth ||
168       jas_image_cmptsgnd(image, enc->cmpts[cmptno]) != false ||
169       jas_image_cmpttlx(image, enc->cmpts[cmptno]) != 0 ||
170       jas_image_cmpttly(image, enc->cmpts[cmptno]) != 0) {
171       fprintf(stderr, "The BMP format cannot be used to represent an image with this geometry.\n");
172       return -1;
173     }
174   }
175
176   /* The component depths must be 1, 4, or 8. */
177   if (depth != 1 && depth != 4 && depth != 8) {
178     return -1;
179   }
180
181   numpad = (width * enc->numcmpts) % 4;
182   if (numpad) {
183     numpad = 4 - numpad;
184   }
185   datalen = (enc->numcmpts * width + numpad) * height;
186
187   if (!(info = bmp_info_create())) {
188     return -1;
189   }
190   info->len = BMP_INFOLEN;
191   info->width = width;
192   info->height = height;
193   info->numplanes = 1;
194   info->depth = enc->numcmpts * depth;
195   info->enctype = BMP_ENC_RGB;
196   info->siz = datalen;
197   info->hres = 0;
198   info->vres = 0;
199   info->numcolors = (enc->numcmpts == 1) ? 256 : 0;
200   info->mincolors = 0;
201
202   hdr.magic = BMP_MAGIC;
203   hdr.siz = BMP_HDRLEN + BMP_INFOLEN + 0 + datalen;
204   hdr.off = BMP_HDRLEN + BMP_INFOLEN + BMP_PALLEN(info);
205
206   /* Write the bitmap header. */
207   if (bmp_puthdr(out, &hdr)) {
208     return -1;
209   }
210
211   /* Write the bitmap information. */
212   if (bmp_putinfo(out, info)) {
213     return -1;
214   }
215
216   /* Write the bitmap data. */
217   if (bmp_putdata(out, info, image, enc->cmpts)) {
218     return -1;
219   }
220
221   bmp_info_destroy(info);
222
223   return 0;
224 }
225
226 /******************************************************************************\
227 * Code for aggregate types.
228 \******************************************************************************/
229
230 static int bmp_puthdr(jas_stream_t *out, bmp_hdr_t *hdr)
231 {
232   assert(hdr->magic == BMP_MAGIC);
233   if (bmp_putint16(out, hdr->magic) || bmp_putint32(out, hdr->siz) ||
234     bmp_putint32(out, 0) || bmp_putint32(out, hdr->off)) {
235     return -1;
236   }
237   return 0;
238 }
239
240 static int bmp_putinfo(jas_stream_t *out, bmp_info_t *info)
241 {
242   int i;
243
244   info->len = 40;
245   if (bmp_putint32(out, info->len) ||
246     bmp_putint32(out, info->width) ||
247     bmp_putint32(out, info->height) ||
248     bmp_putint16(out, info->numplanes) ||
249     bmp_putint16(out, info->depth) ||
250     bmp_putint32(out, info->enctype) ||
251     bmp_putint32(out, info->siz) ||
252     bmp_putint32(out, info->hres) ||
253     bmp_putint32(out, info->vres) ||
254     bmp_putint32(out, info->numcolors) ||
255     bmp_putint32(out, info->mincolors)) {
256     return -1;
257   }
258
259   for (i = 0; i < info->numcolors; ++i)
260   {
261     if (jas_stream_putc(out, i) == EOF ||
262       jas_stream_putc(out, i) == EOF ||
263       jas_stream_putc(out, i) == EOF ||
264       jas_stream_putc(out, 0) == EOF)
265     {
266       return -1;
267     }
268   }
269
270   return 0;
271 }
272
273 static int bmp_putdata(jas_stream_t *out, bmp_info_t *info, jas_image_t *image,
274   int *cmpts)
275 {
276   int i;
277   int j;
278   jas_matrix_t *bufs[3];
279   int numpad;
280   unsigned char red;
281   unsigned char grn;
282   unsigned char blu;
283   int ret;
284   int numcmpts;
285   int v;
286   int cmptno;
287
288   numcmpts = (info->depth == 24) ? 3:1;
289
290   /* We do not support palettized images. */
291   if (BMP_HASPAL(info) && numcmpts == 3) {
292     fprintf(stderr, "no palettized image support for BMP format\n");
293     return -1;
294   }
295
296   ret = 0;
297   for (i = 0; i < numcmpts; ++i) {
298     bufs[i] = 0;
299   }
300
301   /* Create temporary matrices to hold component data. */
302   for (i = 0; i < numcmpts; ++i) {
303     if (!(bufs[i] = jas_matrix_create(1, info->width))) {
304       ret = -1;
305       goto bmp_putdata_done;
306     }
307   }
308
309   /* Calculate number of padding bytes per row of image data. */
310   numpad = (numcmpts * info->width) % 4;
311   if (numpad) {
312     numpad = 4 - numpad;
313   }
314
315   /* Put the image data. */
316   for (i = info->height - 1; i >= 0; --i) {
317     for (cmptno = 0; cmptno < numcmpts; ++cmptno) {
318       if (jas_image_readcmpt(image, cmptno, 0, i, info->width,
319         1, bufs[cmpts[cmptno]])) {
320         ret = -1;
321         goto bmp_putdata_done;
322       }
323     }
324     for (j = 0; j < info->width; ++j) {
325       if (numcmpts == 3) {
326         red = (jas_matrix_getv(bufs[0], j));
327         grn = (jas_matrix_getv(bufs[1], j));
328         blu = (jas_matrix_getv(bufs[2], j));
329         if (jas_stream_putc(out, blu) == EOF ||
330           jas_stream_putc(out, grn) == EOF ||
331           jas_stream_putc(out, red) == EOF) {
332           ret = -1;
333           goto bmp_putdata_done;
334         }
335       } else if (numcmpts == 1) {
336         v = (jas_matrix_getv(bufs[cmpts[0]], j));
337         if (jas_stream_putc(out, v) == EOF) {
338           ret = -1;
339           goto bmp_putdata_done;
340         }
341       } else {
342         abort();
343       }
344     }
345     for (j = numpad; j > 0; --j) {
346       if (jas_stream_putc(out, 0) == EOF) {
347         ret = -1;
348         goto bmp_putdata_done;
349       }
350     }
351   }
352
353 bmp_putdata_done:
354   /* Destroy the temporary matrices. */
355   for (i = 0; i < numcmpts; ++i) {
356     if (bufs[i]) {
357       jas_matrix_destroy(bufs[i]);
358     }
359   }
360
361   return ret;
362 }
363
364 /******************************************************************************\
365 * Code for primitive types.
366 \******************************************************************************/
367
368 static int bmp_putint16(jas_stream_t *in, int_fast16_t val)
369 {
370   if (jas_stream_putc(in, val & 0xff) == EOF || jas_stream_putc(in, (val >> 8) &
371     0xff) == EOF) {
372     return -1;
373   }
374   return 0;
375 }
376
377 static int bmp_putint32(jas_stream_t *out, int_fast32_t val)
378 {
379   int n;
380   int_fast32_t v;
381
382   /* This code needs to be changed if we want to handle negative values. */
383   assert(val >= 0);
384   v = val;
385   for (n = 4;;) {
386     if (jas_stream_putc(out, v & 0xff) == EOF) {
387       return -1;
388     }
389     if (--n <= 0) {
390       break;
391     }
392     v >>= 8;
393   }
394   return 0;
395 }