| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- /*
- * Copyright (C)2011, 2015 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 *srcrowptr=srcbuf, *srccolptr;
- int srcps=tjPixelSize[srcpf];
- int srcstride=srcbottomup? -w*srcps:w*srcps;
- unsigned char *dstrowptr=dstbuf, *dstcolptr;
- int dstps=tjPixelSize[dstpf];
- int dststride=dstbottomup? -w*dstps:w*dstps;
- int row, col;
- if(srcbottomup) srcrowptr=&srcbuf[w*srcps*(h-1)];
- if(dstbottomup) dstrowptr=&dstbuf[w*dstps*(h-1)];
- /* NOTE: These quick & dirty CMYK<->RGB conversion routines are for testing
- purposes only. Properly converting between CMYK and RGB requires a color
- management system. */
- if(dstpf==TJPF_CMYK)
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, srccolptr+=srcps)
- {
- double c=1.0-((double)(srccolptr[tjRedOffset[srcpf]])/255.);
- double m=1.0-((double)(srccolptr[tjGreenOffset[srcpf]])/255.);
- double y=1.0-((double)(srccolptr[tjBlueOffset[srcpf]])/255.);
- double k=min(min(c,m),min(y,1.0));
- if(k==1.0) c=m=y=0.0;
- else
- {
- c=(c-k)/(1.0-k);
- m=(m-k)/(1.0-k);
- y=(y-k)/(1.0-k);
- }
- if(c>1.0) c=1.0;
- if(c<0.) c=0.;
- if(m>1.0) m=1.0;
- if(m<0.) m=0.;
- if(y>1.0) y=1.0;
- if(y<0.) y=0.;
- if(k>1.0) k=1.0;
- if(k<0.) k=0.;
- *dstcolptr++=(unsigned char)(255.0-c*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-m*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-y*255.0+0.5);
- *dstcolptr++=(unsigned char)(255.0-k*255.0+0.5);
- }
- }
- }
- else if(srcpf==TJPF_CMYK)
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, dstcolptr+=dstps)
- {
- double c=(double)(*srccolptr++);
- double m=(double)(*srccolptr++);
- double y=(double)(*srccolptr++);
- double k=(double)(*srccolptr++);
- double r=c*k/255.;
- double g=m*k/255.;
- double b=y*k/255.;
- if(r>255.0) r=255.0;
- if(r<0.) r=0.;
- if(g>255.0) g=255.0;
- if(g<0.) g=0.;
- if(b>255.0) b=255.0;
- if(b<0.) b=0.;
- dstcolptr[tjRedOffset[dstpf]]=(unsigned char)(r+0.5);
- dstcolptr[tjGreenOffset[dstpf]]=(unsigned char)(g+0.5);
- dstcolptr[tjBlueOffset[dstpf]]=(unsigned char)(b+0.5);
- }
- }
- }
- else
- {
- for(row=0; row<h; row++, srcrowptr+=srcstride, dstrowptr+=dststride)
- {
- for(col=0, srccolptr=srcrowptr, dstcolptr=dstrowptr;
- col<w; col++, srccolptr+=srcps, dstcolptr+=dstps)
- {
- dstcolptr[tjRedOffset[dstpf]]=srccolptr[tjRedOffset[srcpf]];
- dstcolptr[tjGreenOffset[dstpf]]=srccolptr[tjGreenOffset[srcpf]];
- dstcolptr[tjBlueOffset[dstpf]]=srccolptr[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;
- }
|