/* * Copyright (C)2011 D. R. Commander. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the libjpeg-turbo Project nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "cdjpeg.h" #include #include #include "tjutil.h" #include "bmp.h" /* This duplicates the functionality of the VirtualGL bitmap library using the components from cjpeg and djpeg */ /* Error handling (based on example in example.c) */ static char errStr[JMSG_LENGTH_MAX]="No error"; struct my_error_mgr { struct jpeg_error_mgr pub; jmp_buf setjmp_buffer; }; typedef struct my_error_mgr *my_error_ptr; static void my_error_exit(j_common_ptr cinfo) { my_error_ptr myerr=(my_error_ptr)cinfo->err; (*cinfo->err->output_message)(cinfo); longjmp(myerr->setjmp_buffer, 1); } /* Based on output_message() in jerror.c */ static void my_output_message(j_common_ptr cinfo) { (*cinfo->err->format_message)(cinfo, errStr); } #define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \ retval=-1; goto bailout;} #define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \ strerror(errno)); retval=-1; goto bailout;} static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup, unsigned char *dstbuf, int dstpf, int dstbottomup, int w, int h) { unsigned char *srcptr=srcbuf, *srcptr2; int srcps=tjPixelSize[srcpf]; int srcstride=srcbottomup? -w*srcps:w*srcps; unsigned char *dstptr=dstbuf, *dstptr2; int dstps=tjPixelSize[dstpf]; int dststride=dstbottomup? -w*dstps:w*dstps; int row, col; if(srcbottomup) srcptr=&srcbuf[w*srcps*(h-1)]; if(dstbottomup) dstptr=&dstbuf[w*dstps*(h-1)]; for(row=0; row=TJ_NUMPF) _throw("loadbmp(): Invalid argument"); if((file=fopen(filename, "rb"))==NULL) _throwunix("loadbmp(): Cannot open input file"); cinfo.err=jpeg_std_error(&jerr.pub); jerr.pub.error_exit=my_error_exit; jerr.pub.output_message=my_output_message; if(setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ retval=-1; goto bailout; } jpeg_create_compress(&cinfo); if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF) _throwunix("loadbmp(): Could not read input file") else if(tempc==EOF) _throw("loadbmp(): Input file contains no data"); if(tempc=='B') { if((src=jinit_read_bmp(&cinfo))==NULL) _throw("loadbmp(): Could not initialize bitmap loader"); } else if(tempc=='P') { if((src=jinit_read_ppm(&cinfo))==NULL) _throw("loadbmp(): Could not initialize bitmap loader"); } else _throw("loadbmp(): Unsupported file type"); src->input_file=file; (*src->start_input)(&cinfo, src); (*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo); *w=cinfo.image_width; *h=cinfo.image_height; if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB) srcpf=TJPF_GRAY; else srcpf=TJPF_RGB; dstps=tjPixelSize[dstpf]; if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL) _throw("loadbmp(): Memory allocation failure"); while(cinfo.next_scanlineget_pixel_rows)(&cinfo, src); for(i=0; ibuffer[i], srcpf, 0, outbuf, dstpf, bottomup, *w, nlines); } cinfo.next_scanline+=nlines; } (*src->finish_input)(&cinfo, src); bailout: jpeg_destroy_compress(&cinfo); if(file) fclose(file); if(retval<0 && buf && *buf) {free(*buf); *buf=NULL;} return retval; } int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf, int bottomup) { int retval=0, srcps, dstpf; struct jpeg_decompress_struct dinfo; struct my_error_mgr jerr; djpeg_dest_ptr dst; FILE *file=NULL; char *ptr=NULL; memset(&dinfo, 0, sizeof(struct jpeg_decompress_struct)); if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF) _throw("savebmp(): Invalid argument"); if((file=fopen(filename, "wb"))==NULL) _throwunix("savebmp(): Cannot open output file"); dinfo.err=jpeg_std_error(&jerr.pub); jerr.pub.error_exit=my_error_exit; jerr.pub.output_message=my_output_message; if(setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ retval=-1; goto bailout; } jpeg_create_decompress(&dinfo); if(srcpf==TJPF_GRAY) { dinfo.out_color_components=dinfo.output_components=1; dinfo.out_color_space=JCS_GRAYSCALE; } else { dinfo.out_color_components=dinfo.output_components=3; dinfo.out_color_space=JCS_RGB; } dinfo.image_width=w; dinfo.image_height=h; dinfo.global_state=DSTATE_READY; dinfo.scale_num=dinfo.scale_denom=1; ptr=strrchr(filename, '.'); if(ptr && !strcasecmp(ptr, ".bmp")) { if((dst=jinit_write_bmp(&dinfo, 0))==NULL) _throw("savebmp(): Could not initialize bitmap writer"); } else { if((dst=jinit_write_ppm(&dinfo))==NULL) _throw("savebmp(): Could not initialize PPM writer"); } dst->output_file=file; (*dst->start_output)(&dinfo, dst); (*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo); if(srcpf==TJPF_GRAY) dstpf=srcpf; else dstpf=TJPF_RGB; srcps=tjPixelSize[srcpf]; while(dinfo.output_scanlinebuffer_height; for(i=0; ibuffer[i], dstpf, 0, w, nlines); } (*dst->put_pixel_rows)(&dinfo, dst, nlines); dinfo.output_scanline+=nlines; } (*dst->finish_output)(&dinfo, dst); bailout: jpeg_destroy_decompress(&dinfo); if(file) fclose(file); return retval; } const char *bmpgeterr(void) { return errStr; }