1 /*
2 * jpeg.c:
3 * JPEG file support. Based on example.c in the IJG jpeg-6b distribution.
4 *
5 * Copyright (c) 2001 Chris Lightfoot.
6 * Email: chris@ex-parrot.com; WWW: http://www.ex-parrot.com/~chris/
7 *
8 */
9
10 #ifdef HAVE_CONFIG_H
11 #include <config.h>
12 #endif
13
14 #include "compat/compat.h"
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <setjmp.h>
20
21 #include <jpeglib.h>
22
23 #include "common/util.h"
24 #include "img.h"
25
26 /* struct my_error_mgr:
27 * Error handling struct for JPEG library interaction. */
28 struct my_error_mgr {
29 struct jpeg_error_mgr pub;
30 jmp_buf jb;
31 };
32
33 /* my_error_exit:
34 * Error handler method for JPEG library. */
my_error_exit(j_common_ptr cinfo)35 static void my_error_exit(j_common_ptr cinfo) {
36 struct my_error_mgr *e = (struct my_error_mgr*)cinfo->err;
37 (*cinfo->err->output_message)(cinfo);
38 longjmp(e->jb, 1);
39 }
40
41 /* jpeg_load_hdr:
42 * Load the header of a JPEG file. */
jpeg_load_hdr(img I)43 int jpeg_load_hdr(img I) {
44 struct jpeg_decompress_struct *cinfo;
45 struct my_error_mgr *jerr;
46 alloc_struct(jpeg_decompress_struct, cinfo);
47 I->us = cinfo;
48 alloc_struct(my_error_mgr, jerr);
49 cinfo->err = jpeg_std_error(&jerr->pub);
50 jerr->pub.error_exit = my_error_exit;
51 if (setjmp(jerr->jb)) {
52 /* Oops, something went wrong. */
53 I->err = IE_HDRFORMAT;
54 jpeg_destroy_decompress(cinfo);
55 return 0;
56 }
57
58 jpeg_create_decompress(cinfo);
59 jpeg_stdio_src(cinfo, I->fp);
60
61 /* Read the header of the image. */
62 jpeg_read_header(cinfo, TRUE);
63
64 jpeg_start_decompress(cinfo);
65
66 I->width = cinfo->output_width;
67 I->height = cinfo->output_height;
68
69 return 1;
70 }
71
72 /* jpeg_abort_load:
73 * Abort loading a JPEG after the header is done. */
jpeg_abort_load(img I)74 int jpeg_abort_load(img I) {
75 jpeg_finish_decompress((struct jpeg_decompress_struct*)I->us);
76 jpeg_destroy_decompress((struct jpeg_decompress_struct*)I->us);
77 return 1;
78 }
79
80 /* jpeg_load_img:
81 * Read a JPEG file into an image. */
jpeg_load_img(img I)82 int jpeg_load_img(img I) {
83 struct jpeg_decompress_struct *cinfo = I->us;
84 struct my_error_mgr *jerr;
85 JSAMPARRAY buffer;
86 img_alloc(I);
87 jerr = (struct my_error_mgr*)cinfo->err;
88 if (setjmp(jerr->jb)) {
89 /* Oops, something went wrong. */
90 I->err = IE_IMGFORMAT;
91 jpeg_destroy_decompress(cinfo);
92 return 0;
93 }
94
95 cinfo->out_color_space = JCS_RGB;
96 cinfo->out_color_components = cinfo->output_components = 3;
97
98 /* Start decompression. */
99 buffer = cinfo->mem->alloc_sarray((j_common_ptr)cinfo, JPOOL_IMAGE, cinfo->output_width * cinfo->output_components, 1);
100
101 while (cinfo->output_scanline < cinfo->output_height) {
102 pel *p, *end;
103 unsigned char *q;
104 jpeg_read_scanlines(cinfo, buffer, 1);
105
106 /* Now we have a buffer in RGB format. */
107 for (p = I->data[cinfo->output_scanline - 1], end = p + I->width, q = (unsigned char*)buffer[0]; p < end; ++p, q += 3)
108 *p = PEL(*q, *(q + 1), *(q + 2));
109 }
110
111 jpeg_finish_decompress(cinfo);
112 jpeg_destroy_decompress(cinfo);
113
114 return 1;
115 }
116
117 /* jpeg_save_img:
118 * Write an image out into a JPEG file. */
jpeg_save_img(const img I,FILE * fp)119 int jpeg_save_img(const img I, FILE *fp) {
120 struct jpeg_compress_struct cinfo;
121 struct my_error_mgr jerr;
122 JSAMPROW *buffer;
123
124 cinfo.err = jpeg_std_error(&jerr.pub);
125 jerr.pub.error_exit = my_error_exit;
126 if (setjmp(jerr.jb)) {
127 /* Oops, something went wrong. */
128 I->err = IE_SYSERROR;
129 jpeg_destroy_compress(&cinfo);
130 return 0;
131 }
132
133 jpeg_create_compress(&cinfo);
134
135 /* Compressor will write to fp. */
136 jpeg_stdio_dest(&cinfo, fp);
137
138 /* Image parameters. */
139 cinfo.image_width = I->width;
140 cinfo.image_height = I->height;
141 cinfo.input_components = 3;
142 cinfo.in_color_space = JCS_RGB;
143
144 /* Default parameters. */
145 jpeg_set_defaults(&cinfo);
146
147 /* XXX compression quality? */
148
149 jpeg_start_compress(&cinfo, TRUE);
150
151 buffer = cinfo.mem->alloc_sarray((j_common_ptr)&cinfo, JPOOL_IMAGE, I->width * 3, 1);
152
153 while (cinfo.next_scanline < cinfo.image_height) {
154 pel *p, *end;
155 unsigned char *q;
156 /* Copy image data into correct format. */
157 for (p = I->data[cinfo.next_scanline], end = p + I->width, q = (unsigned char*)buffer[0]; p < end; ++p) {
158 *q++ = (unsigned char)GETR(*p);
159 *q++ = (unsigned char)GETG(*p);
160 *q++ = (unsigned char)GETB(*p);
161 }
162
163 /* Write scanline. */
164 jpeg_write_scanlines(&cinfo, buffer, 1);
165 }
166
167 jpeg_finish_compress(&cinfo);
168 jpeg_destroy_compress(&cinfo);
169
170 return 1;
171 }
172