diff options
Diffstat (limited to 'bmp.c')
-rw-r--r-- | bmp.c | 274 |
1 files changed, 274 insertions, 0 deletions
@@ -0,0 +1,274 @@ +/* + * 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 <stdio.h> +#include <string.h> +#include <setjmp.h> +#include <errno.h> +#include "cdjpeg.h" +#include <jpeglib.h> +#include <jpegint.h> +#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<h; row++, srcptr+=srcstride, dstptr+=dststride) + { + for(col=0, srcptr2=srcptr, dstptr2=dstptr; col<w; col++, srcptr2+=srcps, + dstptr2+=dstps) + { + dstptr2[tjRedOffset[dstpf]]=srcptr2[tjRedOffset[srcpf]]; + dstptr2[tjGreenOffset[dstpf]]=srcptr2[tjGreenOffset[srcpf]]; + dstptr2[tjBlueOffset[dstpf]]=srcptr2[tjBlueOffset[srcpf]]; + } + } +} + + +int loadbmp(char *filename, unsigned char **buf, int *w, int *h, + int dstpf, int bottomup) +{ + int retval=0, dstps, srcpf, tempc; + struct jpeg_compress_struct cinfo; + struct my_error_mgr jerr; + cjpeg_source_ptr src; + FILE *file=NULL; + + memset(&cinfo, 0, sizeof(struct jpeg_compress_struct)); + + if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=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_scanline<cinfo.image_height) + { + int i, nlines=(*src->get_pixel_rows)(&cinfo, src); + for(i=0; i<nlines; i++) + { + unsigned char *outbuf; int row; + row=cinfo.next_scanline+i; + if(bottomup) outbuf=&(*buf)[((*h)-row-1)*(*w)*dstps]; + else outbuf=&(*buf)[row*(*w)*dstps]; + pixelconvert(src->buffer[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_scanline<dinfo.output_height) + { + int i, nlines=dst->buffer_height; + for(i=0; i<nlines; i++) + { + unsigned char *inbuf; int row; + row=dinfo.output_scanline+i; + if(bottomup) inbuf=&buf[(h-row-1)*w*srcps]; + else inbuf=&buf[row*w*srcps]; + pixelconvert(inbuf, srcpf, bottomup, dst->buffer[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; +} |