Home | History | Annotate | Download | only in libjpeg_turbo
      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