bmp_enc.c (11565B)
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 1918 2005-07-24 14:12:08Z baford $ 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 }