blob: fa4479dad7b3bf173a750ee6fdadac1fe0f7ecea [file] [log] [blame]
hbono@chromium.org98626972011-08-03 03:13:08 +00001/*
2 * Copyright (C)2011 D. R. Commander. All Rights Reserved.
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00003 *
hbono@chromium.org98626972011-08-03 03:13:08 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +00006 *
hbono@chromium.org98626972011-08-03 03:13:08 +00007 * - 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 */
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000028
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000029#include <stdio.h>
30#include <string.h>
hbono@chromium.org98626972011-08-03 03:13:08 +000031#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"
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000038
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000039
hbono@chromium.org98626972011-08-03 03:13:08 +000040/* 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
46static char errStr[JMSG_LENGTH_MAX]="No error";
47
48struct my_error_mgr
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000049{
hbono@chromium.org98626972011-08-03 03:13:08 +000050 struct jpeg_error_mgr pub;
51 jmp_buf setjmp_buffer;
52};
53typedef struct my_error_mgr *my_error_ptr;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000054
hbono@chromium.org98626972011-08-03 03:13:08 +000055static void my_error_exit(j_common_ptr cinfo)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000056{
hbono@chromium.org98626972011-08-03 03:13:08 +000057 my_error_ptr myerr=(my_error_ptr)cinfo->err;
58 (*cinfo->err->output_message)(cinfo);
59 longjmp(myerr->setjmp_buffer, 1);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000060}
61
hbono@chromium.org98626972011-08-03 03:13:08 +000062/* Based on output_message() in jerror.c */
63
64static void my_output_message(j_common_ptr cinfo)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000065{
hbono@chromium.org98626972011-08-03 03:13:08 +000066 (*cinfo->err->format_message)(cinfo, errStr);
67}
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000068
hbono@chromium.org98626972011-08-03 03:13:08 +000069#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;}
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000073
hbono@chromium.org98626972011-08-03 03:13:08 +000074
75static 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)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000089 {
hbono@chromium.org98626972011-08-03 03:13:08 +000090 for(col=0, srcptr2=srcptr, dstptr2=dstptr; col<w; col++, srcptr2+=srcps,
91 dstptr2+=dstps)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000092 {
hbono@chromium.org98626972011-08-03 03:13:08 +000093 dstptr2[tjRedOffset[dstpf]]=srcptr2[tjRedOffset[srcpf]];
94 dstptr2[tjGreenOffset[dstpf]]=srcptr2[tjGreenOffset[srcpf]];
95 dstptr2[tjBlueOffset[dstpf]]=srcptr2[tjBlueOffset[srcpf]];
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000096 }
97 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +000098}
99
100
101int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
hbono@chromium.org98626972011-08-03 03:13:08 +0000102 int dstpf, int bottomup)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000103{
hbono@chromium.org98626972011-08-03 03:13:08 +0000104 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000109
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000110 memset(&cinfo, 0, sizeof(struct jpeg_compress_struct));
111
hbono@chromium.org98626972011-08-03 03:13:08 +0000112 if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=TJ_NUMPF)
113 _throw("loadbmp(): Invalid argument");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000114
hbono@chromium.org98626972011-08-03 03:13:08 +0000115 if((file=fopen(filename, "rb"))==NULL)
116 _throwunix("loadbmp(): Cannot open input file");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000117
hbono@chromium.org98626972011-08-03 03:13:08 +0000118 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))
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000123 {
hbono@chromium.org98626972011-08-03 03:13:08 +0000124 /* If we get here, the JPEG code has signaled an error. */
125 retval=-1; goto bailout;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000126 }
127
hbono@chromium.org98626972011-08-03 03:13:08 +0000128 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");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000132
hbono@chromium.org98626972011-08-03 03:13:08 +0000133 if(tempc=='B')
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000134 {
hbono@chromium.org98626972011-08-03 03:13:08 +0000135 if((src=jinit_read_bmp(&cinfo))==NULL)
136 _throw("loadbmp(): Could not initialize bitmap loader");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000137 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000138 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");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000144
hbono@chromium.org98626972011-08-03 03:13:08 +0000145 src->input_file=file;
146 (*src->start_input)(&cinfo, src);
147 (*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000148
hbono@chromium.org98626972011-08-03 03:13:08 +0000149 *w=cinfo.image_width; *h=cinfo.image_height;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000150
hbono@chromium.org98626972011-08-03 03:13:08 +0000151 if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB)
152 srcpf=TJPF_GRAY;
153 else srcpf=TJPF_RGB;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000154
hbono@chromium.org98626972011-08-03 03:13:08 +0000155 dstps=tjPixelSize[dstpf];
156 if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL)
157 _throw("loadbmp(): Memory allocation failure");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000158
hbono@chromium.org98626972011-08-03 03:13:08 +0000159 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;
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000172 }
hbono@chromium.org98626972011-08-03 03:13:08 +0000173
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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000181}
182
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000183
hbono@chromium.org98626972011-08-03 03:13:08 +0000184int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf,
185 int bottomup)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000186{
hbono@chromium.org98626972011-08-03 03:13:08 +0000187 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;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000193
hbono@chromium.orgc6beb742011-11-29 05:16:26 +0000194 memset(&dinfo, 0, sizeof(struct jpeg_decompress_struct));
195
hbono@chromium.org98626972011-08-03 03:13:08 +0000196 if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF)
197 _throw("savebmp(): Invalid argument");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000198
hbono@chromium.org98626972011-08-03 03:13:08 +0000199 if((file=fopen(filename, "wb"))==NULL)
200 _throwunix("savebmp(): Cannot open output file");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000201
hbono@chromium.org98626972011-08-03 03:13:08 +0000202 dinfo.err=jpeg_std_error(&jerr.pub);
203 jerr.pub.error_exit=my_error_exit;
204 jerr.pub.output_message=my_output_message;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000205
hbono@chromium.org98626972011-08-03 03:13:08 +0000206 if(setjmp(jerr.setjmp_buffer))
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000207 {
hbono@chromium.org98626972011-08-03 03:13:08 +0000208 /* If we get here, the JPEG code has signaled an error. */
209 retval=-1; goto bailout;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000210 }
211
hbono@chromium.org98626972011-08-03 03:13:08 +0000212 jpeg_create_decompress(&dinfo);
213 if(srcpf==TJPF_GRAY)
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000214 {
hbono@chromium.org98626972011-08-03 03:13:08 +0000215 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");
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000237 }
238
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000239 dst->output_file=file;
hbono@chromium.org98626972011-08-03 03:13:08 +0000240 (*dst->start_output)(&dinfo, dst);
241 (*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000242
hbono@chromium.org98626972011-08-03 03:13:08 +0000243 if(srcpf==TJPF_GRAY) dstpf=srcpf;
244 else dstpf=TJPF_RGB;
245 srcps=tjPixelSize[srcpf];
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000246
hbono@chromium.org98626972011-08-03 03:13:08 +0000247 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;
noel@chromium.org3395bcc2014-04-14 06:56:00 +0000261 }
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000262
hbono@chromium.org98626972011-08-03 03:13:08 +0000263 (*dst->finish_output)(&dinfo, dst);
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000264
hbono@chromium.org98626972011-08-03 03:13:08 +0000265 bailout:
266 jpeg_destroy_decompress(&dinfo);
267 if(file) fclose(file);
268 return retval;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000269}
270
271const char *bmpgeterr(void)
272{
hbono@chromium.org98626972011-08-03 03:13:08 +0000273 return errStr;
hbono@chromium.orgf0c4f332010-11-01 05:14:55 +0000274}