blob: 01353c72ff670901194e89ef59b6af80baa76260 [file] [log] [blame]
DRC0fc884a2011-05-24 09:13:17 +00001/*
2 * Copyright (C)2011 D. R. Commander. All Rights Reserved.
DRC2e7b76b2009-04-03 12:04:24 +00003 *
DRC0fc884a2011-05-24 09:13:17 +00004 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
DRC2e7b76b2009-04-03 12:04:24 +00006 *
DRC0fc884a2011-05-24 09:13:17 +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 */
DRC2e7b76b2009-04-03 12:04:24 +000028
DRC2e7b76b2009-04-03 12:04:24 +000029#include <stdio.h>
30#include <string.h>
DRC0fc884a2011-05-24 09:13:17 +000031#include <setjmp.h>
32#include <errno.h>
33#include <jpeglib.h>
34#include <jpegint.h>
35#include "cdjpeg.h"
36#include "bmp.h"
DRC2e7b76b2009-04-03 12:04:24 +000037
DRC2e7b76b2009-04-03 12:04:24 +000038
DRC0fc884a2011-05-24 09:13:17 +000039/* This duplicates the functionality of the VirtualGL bitmap library using
40 the components from cjpeg and djpeg */
41
42
43/* Error handling (based on example in example.c) */
44
45static char errStr[JMSG_LENGTH_MAX]="No error";
46
47struct my_error_mgr
DRC2e7b76b2009-04-03 12:04:24 +000048{
DRC0fc884a2011-05-24 09:13:17 +000049 struct jpeg_error_mgr pub;
50 jmp_buf setjmp_buffer;
51};
52typedef struct my_error_mgr *my_error_ptr;
DRC2e7b76b2009-04-03 12:04:24 +000053
DRC0fc884a2011-05-24 09:13:17 +000054static void my_error_exit(j_common_ptr cinfo)
DRC2e7b76b2009-04-03 12:04:24 +000055{
DRC0fc884a2011-05-24 09:13:17 +000056 my_error_ptr myerr=(my_error_ptr)cinfo->err;
57 (*cinfo->err->output_message)(cinfo);
58 longjmp(myerr->setjmp_buffer, 1);
DRC2e7b76b2009-04-03 12:04:24 +000059}
60
DRC0fc884a2011-05-24 09:13:17 +000061/* Based on output_message() in jerror.c */
62
63static void my_output_message(j_common_ptr cinfo)
DRC2e7b76b2009-04-03 12:04:24 +000064{
DRC0fc884a2011-05-24 09:13:17 +000065 (*cinfo->err->format_message)(cinfo, errStr);
66}
DRC2e7b76b2009-04-03 12:04:24 +000067
DRC0fc884a2011-05-24 09:13:17 +000068#define _throw(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s", m); \
69 retval=-1; goto bailout;}
70#define _throwunix(m) {snprintf(errStr, JMSG_LENGTH_MAX, "%s\n%s", m, \
71 strerror(errno)); retval=-1; goto bailout;}
DRC2e7b76b2009-04-03 12:04:24 +000072
DRC0fc884a2011-05-24 09:13:17 +000073
74static void pixelconvert(unsigned char *srcbuf, int srcpf, int srcbottomup,
75 unsigned char *dstbuf, int dstpf, int dstbottomup, int w, int h)
76{
77 unsigned char *srcptr=srcbuf, *srcptr2;
78 int srcps=tjPixelSize[srcpf];
79 int srcstride=srcbottomup? -w*srcps:w*srcps;
80 unsigned char *dstptr=dstbuf, *dstptr2;
81 int dstps=tjPixelSize[dstpf];
82 int dststride=dstbottomup? -w*dstps:w*dstps;
83 int row, col;
84
85 if(srcbottomup) srcptr=&srcbuf[w*srcps*(h-1)];
86 if(dstbottomup) dstptr=&dstbuf[w*dstps*(h-1)];
87 for(row=0; row<h; row++, srcptr+=srcstride, dstptr+=dststride)
DRC2e7b76b2009-04-03 12:04:24 +000088 {
DRC0fc884a2011-05-24 09:13:17 +000089 for(col=0, srcptr2=srcptr, dstptr2=dstptr; col<w; col++, srcptr2+=srcps,
90 dstptr2+=dstps)
DRC2e7b76b2009-04-03 12:04:24 +000091 {
DRC0fc884a2011-05-24 09:13:17 +000092 dstptr2[tjRedOffset[dstpf]]=srcptr2[tjRedOffset[srcpf]];
93 dstptr2[tjGreenOffset[dstpf]]=srcptr2[tjGreenOffset[srcpf]];
94 dstptr2[tjBlueOffset[dstpf]]=srcptr2[tjBlueOffset[srcpf]];
DRC2e7b76b2009-04-03 12:04:24 +000095 }
96 }
DRC2e7b76b2009-04-03 12:04:24 +000097}
98
99
100int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
DRC0fc884a2011-05-24 09:13:17 +0000101 int dstpf, int bottomup)
DRC2e7b76b2009-04-03 12:04:24 +0000102{
DRC0fc884a2011-05-24 09:13:17 +0000103 int retval=0, dstps, srcpf, tempc;
104 struct jpeg_compress_struct cinfo;
105 struct my_error_mgr jerr;
106 cjpeg_source_ptr src;
107 FILE *file=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000108
DRC0fc884a2011-05-24 09:13:17 +0000109 if(!filename || !buf || !w || !h || dstpf<0 || dstpf>=TJ_NUMPF)
110 _throw("loadbmp(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000111
DRC0fc884a2011-05-24 09:13:17 +0000112 if((file=fopen(filename, "rb"))==NULL)
113 _throwunix("loadbmp(): Cannot open input file");
DRC2e7b76b2009-04-03 12:04:24 +0000114
DRC0fc884a2011-05-24 09:13:17 +0000115 cinfo.err=jpeg_std_error(&jerr.pub);
116 jerr.pub.error_exit=my_error_exit;
117 jerr.pub.output_message=my_output_message;
118
119 if(setjmp(jerr.setjmp_buffer))
DRC2e7b76b2009-04-03 12:04:24 +0000120 {
DRC0fc884a2011-05-24 09:13:17 +0000121 /* If we get here, the JPEG code has signaled an error. */
122 retval=-1; goto bailout;
DRC2e7b76b2009-04-03 12:04:24 +0000123 }
124
DRC0fc884a2011-05-24 09:13:17 +0000125 jpeg_create_compress(&cinfo);
126 if((tempc=getc(file))<0 || ungetc(tempc, file)==EOF)
127 _throwunix("loadbmp(): Could not read input file")
128 else if(tempc==EOF) _throw("loadbmp(): Input file contains no data");
DRC2e7b76b2009-04-03 12:04:24 +0000129
DRC0fc884a2011-05-24 09:13:17 +0000130 if(tempc=='B')
DRC2e7b76b2009-04-03 12:04:24 +0000131 {
DRC0fc884a2011-05-24 09:13:17 +0000132 if((src=jinit_read_bmp(&cinfo))==NULL)
133 _throw("loadbmp(): Could not initialize bitmap loader");
DRC2e7b76b2009-04-03 12:04:24 +0000134 }
DRC0fc884a2011-05-24 09:13:17 +0000135 else if(tempc=='P')
136 {
137 if((src=jinit_read_ppm(&cinfo))==NULL)
138 _throw("loadbmp(): Could not initialize bitmap loader");
139 }
140 else _throw("loadbmp(): Unsupported file type");
DRC2e7b76b2009-04-03 12:04:24 +0000141
DRC0fc884a2011-05-24 09:13:17 +0000142 src->input_file=file;
143 (*src->start_input)(&cinfo, src);
144 (*cinfo.mem->realize_virt_arrays)((j_common_ptr)&cinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000145
DRC0fc884a2011-05-24 09:13:17 +0000146 *w=cinfo.image_width; *h=cinfo.image_height;
DRC2e7b76b2009-04-03 12:04:24 +0000147
DRC0fc884a2011-05-24 09:13:17 +0000148 if(cinfo.input_components==1 && cinfo.in_color_space==JCS_RGB)
149 srcpf=TJPF_GRAY;
150 else srcpf=TJPF_RGB;
DRC2e7b76b2009-04-03 12:04:24 +0000151
DRC0fc884a2011-05-24 09:13:17 +0000152 dstps=tjPixelSize[dstpf];
153 if((*buf=(unsigned char *)malloc((*w)*(*h)*dstps))==NULL)
154 _throw("loadbmp(): Memory allocation failure");
DRC2e7b76b2009-04-03 12:04:24 +0000155
DRC0fc884a2011-05-24 09:13:17 +0000156 while(cinfo.next_scanline<cinfo.image_height)
157 {
158 int i, nlines=(*src->get_pixel_rows)(&cinfo, src);
159 for(i=0; i<nlines; i++)
160 {
161 unsigned char *outbuf; int row;
162 row=cinfo.next_scanline+i;
163 if(bottomup) outbuf=&(*buf)[((*h)-row-1)*(*w)*dstps];
164 else outbuf=&(*buf)[row*(*w)*dstps];
165 pixelconvert(src->buffer[i], srcpf, 0, outbuf, dstpf, bottomup, *w,
166 nlines);
167 }
168 cinfo.next_scanline+=nlines;
169 }
170
171 (*src->finish_input)(&cinfo, src);
172
173 bailout:
174 jpeg_destroy_compress(&cinfo);
175 if(file) fclose(file);
176 if(retval<0 && buf && *buf) {free(*buf); *buf=NULL;}
177 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000178}
179
DRC2e7b76b2009-04-03 12:04:24 +0000180
DRC0fc884a2011-05-24 09:13:17 +0000181int savebmp(char *filename, unsigned char *buf, int w, int h, int srcpf,
182 int bottomup)
DRC2e7b76b2009-04-03 12:04:24 +0000183{
DRC0fc884a2011-05-24 09:13:17 +0000184 int retval=0, srcps, dstpf;
185 struct jpeg_decompress_struct dinfo;
186 struct my_error_mgr jerr;
187 djpeg_dest_ptr dst;
188 FILE *file=NULL;
189 char *ptr=NULL;
DRC2e7b76b2009-04-03 12:04:24 +0000190
DRC0fc884a2011-05-24 09:13:17 +0000191 if(!filename || !buf || w<1 || h<1 || srcpf<0 || srcpf>=TJ_NUMPF)
192 _throw("savebmp(): Invalid argument");
DRC2e7b76b2009-04-03 12:04:24 +0000193
DRC0fc884a2011-05-24 09:13:17 +0000194 if((file=fopen(filename, "wb"))==NULL)
195 _throwunix("savebmp(): Cannot open output file");
DRC2e7b76b2009-04-03 12:04:24 +0000196
DRC0fc884a2011-05-24 09:13:17 +0000197 dinfo.err=jpeg_std_error(&jerr.pub);
198 jerr.pub.error_exit=my_error_exit;
199 jerr.pub.output_message=my_output_message;
DRC2e7b76b2009-04-03 12:04:24 +0000200
DRC0fc884a2011-05-24 09:13:17 +0000201 if(setjmp(jerr.setjmp_buffer))
DRC2e7b76b2009-04-03 12:04:24 +0000202 {
DRC0fc884a2011-05-24 09:13:17 +0000203 /* If we get here, the JPEG code has signaled an error. */
204 retval=-1; goto bailout;
DRC2e7b76b2009-04-03 12:04:24 +0000205 }
206
DRC0fc884a2011-05-24 09:13:17 +0000207 jpeg_create_decompress(&dinfo);
208 if(srcpf==TJPF_GRAY)
DRC2e7b76b2009-04-03 12:04:24 +0000209 {
DRC0fc884a2011-05-24 09:13:17 +0000210 dinfo.out_color_components=dinfo.output_components=1;
211 dinfo.out_color_space=JCS_GRAYSCALE;
212 }
213 else
214 {
215 dinfo.out_color_components=dinfo.output_components=3;
216 dinfo.out_color_space=JCS_RGB;
217 }
218 dinfo.image_width=w; dinfo.image_height=h;
219 dinfo.global_state=DSTATE_READY;
220 dinfo.scale_num=dinfo.scale_denom=1;
221
222 ptr=strrchr(filename, '.');
223 if(ptr && !strcasecmp(ptr, ".bmp"))
224 {
225 if((dst=jinit_write_bmp(&dinfo, 0))==NULL)
226 _throw("savebmp(): Could not initialize bitmap writer");
227 }
228 else
229 {
230 if((dst=jinit_write_ppm(&dinfo))==NULL)
231 _throw("savebmp(): Could not initialize PPM writer");
DRC2e7b76b2009-04-03 12:04:24 +0000232 }
233
DRC0fc884a2011-05-24 09:13:17 +0000234 dst->output_file=file;
235 (*dst->start_output)(&dinfo, dst);
236 (*dinfo.mem->realize_virt_arrays)((j_common_ptr)&dinfo);
DRC2e7b76b2009-04-03 12:04:24 +0000237
DRC0fc884a2011-05-24 09:13:17 +0000238 if(srcpf==TJPF_GRAY) dstpf=srcpf;
239 else dstpf=TJPF_RGB;
240 srcps=tjPixelSize[srcpf];
DRC2e7b76b2009-04-03 12:04:24 +0000241
DRC0fc884a2011-05-24 09:13:17 +0000242 while(dinfo.output_scanline<dinfo.output_height)
243 {
244 int i, nlines=dst->buffer_height;
245 for(i=0; i<nlines; i++)
246 {
247 unsigned char *inbuf; int row;
248 row=dinfo.output_scanline+i;
249 if(bottomup) inbuf=&buf[(h-row-1)*w*srcps];
250 else inbuf=&buf[row*w*srcps];
251 pixelconvert(inbuf, srcpf, bottomup, dst->buffer[i], dstpf, 0, w,
252 nlines);
253 }
254 (*dst->put_pixel_rows)(&dinfo, dst, nlines);
255 dinfo.output_scanline+=nlines;
256 }
DRC2e7b76b2009-04-03 12:04:24 +0000257
DRC0fc884a2011-05-24 09:13:17 +0000258 (*dst->finish_output)(&dinfo, dst);
DRC2e7b76b2009-04-03 12:04:24 +0000259
DRC0fc884a2011-05-24 09:13:17 +0000260 bailout:
261 jpeg_destroy_decompress(&dinfo);
262 if(file) fclose(file);
263 return retval;
DRC2e7b76b2009-04-03 12:04:24 +0000264}
265
266const char *bmpgeterr(void)
267{
DRC0fc884a2011-05-24 09:13:17 +0000268 return errStr;
DRC2e7b76b2009-04-03 12:04:24 +0000269}