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