1 /* 2 * Copyright (C)2011 D. R. Commander. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of the libjpeg-turbo Project nor the names of its 13 * contributors may be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <setjmp.h> 32 #include <errno.h> 33 #include "cdjpeg.h" 34 #include <jpeglib.h> 35 #include <jpegint.h> 36 #include "tjutil.h" 37 #include "bmp.h" 38 39 40 /* This duplicates the functionality of the VirtualGL bitmap library using 41 the components from cjpeg and djpeg */ 42 43 44 /* Error handling (based on example in example.c) */ 45 46 static char errStr[JMSG_LENGTH_MAX]="No error"; 47 48 struct my_error_mgr 49 { 50 struct jpeg_error_mgr pub; 51 jmp_buf setjmp_buffer; 52 }; 53 typedef struct my_error_mgr *my_error_ptr; 54 55 static void my_error_exit(j_common_ptr cinfo) 56 { 57 my_error_ptr myerr=(my_error_ptr)cinfo->err; 58 (*cinfo->err->output_message)(cinfo); 59 longjmp(myerr->setjmp_buffer, 1); 60 } 61 62 /* Based on output_message() in jerror.c */ 63 64 static void my_output_message(j_common_ptr cinfo) 65 { 66 (*cinfo->err->format_message)(cinfo, errStr); 67 } 68 69 #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ 70 retval=-1; goto bailout;} 71 #define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \ 72 strerror(errno)); retval=-1; goto bailout;} 73 74 75 static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup, 76 unsigned char *dstbuf, int dstpf, int dstbottomup, int w, int h) 77 { 78 unsigned char *srcptr=srcbuf, *srcptr2; 79 int srcps=tjPixelSize[srcpf]; 80 int srcstride=srcbottomup? -w*srcps:w*srcps; 81 unsigned char *dstptr=dstbuf, *dstptr2; 82 int dstps=tjPixelSize[dstpf]; 83 int dststride=dstbottomup? -w*dstps:w*dstps; 84 int row, col; 85 86 if(srcbottomup) srcptr=&srcbuf[w*srcps*(h-1)]; 87 if(dstbottomup) dstptr=&dstbuf[w*dstps*(h-1)]; 88 for(row=0; row<h; row++, srcptr+=srcstride, dstptr+=dststride) 89 { 90 for(col=0, srcptr2=srcptr, dstptr2=dstptr; col<w; col++, srcptr2+=srcps, 91 dstptr2+=dstps) 92 { 93 dstptr2[tjRedOffset[dstpf]]=srcptr2[tjRedOffset[srcpf]]; 94 dstptr2[tjGreenOffset[dstpf]]=srcptr2[tjGreenOffset[srcpf]]; 95 dstptr2[tjBlueOffset[dstpf]]=srcptr2[tjBlueOffset[srcpf]]; 96 } 97 } 98 } 99 100 101 int loadbmp(char *filename, unsigned char **buf, int *w, int *h, 102 int dstpf, int bottomup) 103 { 104 int retval=0, dstps, srcpf, tempc; 105 struct jpeg_compress_struct cinfo; 106 struct my_error_mgr jerr; 107 cjpeg_source_ptr src; 108 FILE *file=NULL; 109 110 memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); 111 112 if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=TJ_NUMPF) 113 _throw("loadbmp(): Invalid argument"); 114 115 if((file=fopen(filename, "rb"))==NULL) 116 _throwunix("loadbmp(): Cannot open input file"); 117 118 cinfo.err=jpeg_std_error(&jerr.pub); 119 jerr.pub.error_exit=my_error_exit; 120 jerr.pub.output_message=my_output_message; 121 122 if(setjmp(jerr.setjmp_buffer)) 123 { 124 /* If we get here, the JPEG code has signaled an error. */ 125 retval=-1; goto bailout; 126 } 127 128 jpeg_create_compress(&cinfo); 129 if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF) 130 _throwunix("loadbmp(): Could not read input file") 131 else if(tempc==EOF) _throw("loadbmp(): Input file contains no data"); 132 133 if(tempc=='B') 134 { 135 if((src=jinit_read_bmp(&cinfo))==NULL) 136 _throw("loadbmp(): Could not initialize bitmap loader"); 137 } 138 else if(tempc=='P') 139 { 140 if((src=jinit_read_ppm(&cinfo))==NULL) 141 _throw("loadbmp(): Could not initialize bitmap loader"); 142 } 143 else _throw("loadbmp(): Unsupported file type"); 144 145 src->input_file=file; 146 (*src->start_input)(&cinfo, src); 147 (*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo); 148 149 *w=cinfo.image_width; *h=cinfo.image_height; 150 151 if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB) 152 srcpf=TJPF_GRAY; 153 else srcpf=TJPF_RGB; 154 155 dstps=tjPixelSize[dstpf]; 156 if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL) 157 _throw("loadbmp(): Memory allocation failure"); 158 159 while(cinfo.next_scanline<cinfo.image_height) 160 { 161 int i, nlines=(*src->get_pixel_rows)(&cinfo, src); 162 for(i=0; i<nlines; i++) 163 { 164 unsigned char *outbuf; int row; 165 row=cinfo.next_scanline+i; 166 if(bottomup) outbuf=&(*buf)[((*h)-row-1)*(*w)*dstps]; 167 else outbuf=&(*buf)[row*(*w)*dstps]; 168 pixelconvert(src->buffer[i], srcpf, 0, outbuf, dstpf, bottomup, *w, 169 nlines); 170 } 171 cinfo.next_scanline+=nlines; 172 } 173 174 (*src->finish_input)(&cinfo, src); 175 176 bailout: 177 jpeg_destroy_compress(&cinfo); 178 if(file) fclose(file); 179 if(retval<0 && buf && *buf) {free(*buf); *buf=NULL;} 180 return retval; 181 } 182 183 184 int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf, 185 int bottomup) 186 { 187 int retval=0, srcps, dstpf; 188 struct jpeg_decompress_struct dinfo; 189 struct my_error_mgr jerr; 190 djpeg_dest_ptr dst; 191 FILE *file=NULL; 192 char *ptr=NULL; 193 194 memset(&dinfo, 0, sizeof(struct jpeg_decompress_struct)); 195 196 if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF) 197 _throw("savebmp(): Invalid argument"); 198 199 if((file=fopen(filename, "wb"))==NULL) 200 _throwunix("savebmp(): Cannot open output file"); 201 202 dinfo.err=jpeg_std_error(&jerr.pub); 203 jerr.pub.error_exit=my_error_exit; 204 jerr.pub.output_message=my_output_message; 205 206 if(setjmp(jerr.setjmp_buffer)) 207 { 208 /* If we get here, the JPEG code has signaled an error. */ 209 retval=-1; goto bailout; 210 } 211 212 jpeg_create_decompress(&dinfo); 213 if(srcpf==TJPF_GRAY) 214 { 215 dinfo.out_color_components=dinfo.output_components=1; 216 dinfo.out_color_space=JCS_GRAYSCALE; 217 } 218 else 219 { 220 dinfo.out_color_components=dinfo.output_components=3; 221 dinfo.out_color_space=JCS_RGB; 222 } 223 dinfo.image_width=w; dinfo.image_height=h; 224 dinfo.global_state=DSTATE_READY; 225 dinfo.scale_num=dinfo.scale_denom=1; 226 227 ptr=strrchr(filename, '.'); 228 if(ptr && !strcasecmp(ptr, ".bmp")) 229 { 230 if((dst=jinit_write_bmp(&dinfo, 0))==NULL) 231 _throw("savebmp(): Could not initialize bitmap writer"); 232 } 233 else 234 { 235 if((dst=jinit_write_ppm(&dinfo))==NULL) 236 _throw("savebmp(): Could not initialize PPM writer"); 237 } 238 239 dst->output_file=file; 240 (*dst->start_output)(&dinfo, dst); 241 (*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo); 242 243 if(srcpf==TJPF_GRAY) dstpf=srcpf; 244 else dstpf=TJPF_RGB; 245 srcps=tjPixelSize[srcpf]; 246 247 while(dinfo.output_scanline<dinfo.output_height) 248 { 249 int i, nlines=dst->buffer_height; 250 for(i=0; i<nlines; i++) 251 { 252 unsigned char *inbuf; int row; 253 row=dinfo.output_scanline+i; 254 if(bottomup) inbuf=&buf[(h-row-1)*w*srcps]; 255 else inbuf=&buf[row*w*srcps]; 256 pixelconvert(inbuf, srcpf, bottomup, dst->buffer[i], dstpf, 0, w, 257 nlines); 258 } 259 (*dst->put_pixel_rows)(&dinfo, dst, nlines); 260 dinfo.output_scanline+=nlines; 261 } 262 263 (*dst->finish_output)(&dinfo, dst); 264 265 bailout: 266 jpeg_destroy_decompress(&dinfo); 267 if(file) fclose(file); 268 return retval; 269 } 270 271 const char *bmpgeterr(void) 272 { 273 return errStr; 274 } 275