1 // jpeg
2
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <ctype.h>
7
8 #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
9
10 unsigned char *pixels;
11 int xsize, ysize, ncomps;
12
13 /*
14 * Since BMP stores scanlines bottom-to-top, we have to invert the image
15 * from JPEG's top-to-bottom order. To do this, we save the outgoing data
16 * in a virtual array during put_pixel_row calls, then actually emit the
17 * BMP file during finish_output. The virtual array contains one JSAMPLE per
18 * pixel if the output is grayscale or colormapped, three if it is full color.
19 */
20
21 /* Private version of data destination object */
22
23 typedef struct {
24 struct djpeg_dest_struct pub; /* public fields */
25
26 jvirt_sarray_ptr whole_image; /* needed to reverse row order */
27 JDIMENSION data_width; /* JSAMPLEs per row */
28 JDIMENSION row_width; /* physical width of one row in the BMP file */
29 JDIMENSION cur_output_row; /* next row# to write to virtual array */
30 } bmp_dest_struct;
31
32 typedef bmp_dest_struct * bmp_dest_ptr;
33
34
35 /*
36 * Write some pixel data.
37 * In this module rows_supplied will always be 1.
38 */
39
40 METHODDEF(void)
put_pixel_rows(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo,JDIMENSION rows_supplied)41 put_pixel_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
42 JDIMENSION rows_supplied)
43 /* This version is for writing 24-bit pixels */
44 {
45 bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
46 JSAMPARRAY image_ptr;
47 register JSAMPROW inptr, outptr;
48 register JDIMENSION col;
49 /* int pad; */
50
51 /* Access next row in virtual array */
52 image_ptr = (*cinfo->mem->access_virt_sarray)
53 ((j_common_ptr) cinfo, dest->whole_image,
54 dest->cur_output_row, (JDIMENSION) 1, TRUE);
55 dest->cur_output_row++;
56
57 /* Transfer data.
58 */
59 inptr = dest->pub.buffer[0];
60 outptr = image_ptr[0];
61 for (col = cinfo->output_width; col > 0; col--) {
62 outptr[0] = *inptr++; /* can omit GETJSAMPLE() safely */
63 outptr[1] = *inptr++;
64 outptr[2] = *inptr++;
65 outptr += 3;
66 }
67 }
68
69 METHODDEF(void)
put_gray_rows(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo,JDIMENSION rows_supplied)70 put_gray_rows (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo,
71 JDIMENSION rows_supplied)
72 /* This version is for grayscale OR quantized color output */
73 {
74 //printf("put gray rows\n");
75 bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
76 JSAMPARRAY image_ptr;
77 register JSAMPROW inptr, outptr;
78 register JDIMENSION col;
79 /* int pad; */
80
81 /* Access next row in virtual array */
82 image_ptr = (*cinfo->mem->access_virt_sarray)
83 ((j_common_ptr) cinfo, dest->whole_image,
84 dest->cur_output_row, (JDIMENSION) 1, TRUE);
85 dest->cur_output_row++;
86
87 /* Transfer data. */
88 inptr = dest->pub.buffer[0];
89 outptr = image_ptr[0];
90 for (col = cinfo->output_width; col > 0; col--) {
91 *outptr++ = *inptr++; /* can omit GETJSAMPLE() safely */
92 }
93
94 }
95
96
97 /*
98 * Startup: normally writes the file header.
99 * In this module we may as well postpone everything until finish_output.
100 */
101
102 METHODDEF(void)
start_output_pixels(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)103 start_output_pixels (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
104 {
105 //printf("start output\n");
106 /* no work here */
107 }
108
109
110
111 METHODDEF(void)
finish_output_pixels(j_decompress_ptr cinfo,djpeg_dest_ptr dinfo)112 finish_output_pixels (j_decompress_ptr cinfo, djpeg_dest_ptr dinfo)
113 {
114 unsigned char *p;
115
116 bmp_dest_ptr dest = (bmp_dest_ptr) dinfo;
117
118 JSAMPARRAY image_ptr;
119 register JSAMPROW data_ptr;
120 JDIMENSION row;
121 register JDIMENSION col;
122 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
123
124 p = pixels; // final output
125 //printf("finish output_pixels row_width=%d\n",dest->row_width);
126 /* Write the file body from our virtual array */
127 for (row = cinfo->output_height; row > 0; row--) {
128 if (progress != NULL) {
129 progress->pub.pass_counter = (long) (cinfo->output_height - row);
130 progress->pub.pass_limit = (long) cinfo->output_height;
131 (*progress->pub.progress_monitor) ((j_common_ptr) cinfo);
132 }
133 image_ptr = (*cinfo->mem->access_virt_sarray)
134 ((j_common_ptr) cinfo, dest->whole_image, row-1, (JDIMENSION) 1, FALSE);
135 data_ptr = image_ptr[0];
136 for (col = dest->row_width; col > 0; col--)
137 {
138 // putc(GETJSAMPLE(*data_ptr), outfile);
139 *p++ = *data_ptr;
140 data_ptr++;
141 }
142 }
143 if (progress != NULL)
144 progress->completed_extra_passes++;
145
146 }
147
148
149 /*
150 * The module selection routine for BMP format output.
151 */
152
153 GLOBAL(djpeg_dest_ptr)
jinit_write_pixels(j_decompress_ptr cinfo)154 jinit_write_pixels (j_decompress_ptr cinfo)
155 {
156 bmp_dest_ptr dest;
157 JDIMENSION row_width;
158
159 /* Create module interface object, fill in method pointers */
160 dest = (bmp_dest_ptr)
161 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
162 SIZEOF(bmp_dest_struct));
163 dest->pub.start_output = start_output_pixels;
164 dest->pub.finish_output = finish_output_pixels;
165
166 if (cinfo->out_color_space == JCS_GRAYSCALE) {
167 dest->pub.put_pixel_rows = put_gray_rows;
168 } else if (cinfo->out_color_space == JCS_RGB) {
169 if (cinfo->quantize_colors)
170 dest->pub.put_pixel_rows = put_gray_rows;
171 else
172 dest->pub.put_pixel_rows = put_pixel_rows;
173 } else {
174 ERREXIT(cinfo, JERR_BMP_COLORSPACE);
175 }
176
177 /* Calculate output image dimensions so we can allocate space */
178 jpeg_calc_output_dimensions(cinfo);
179
180 /* Determine width of rows in the BMP file (padded to 4-byte boundary). */
181 row_width = cinfo->output_width * cinfo->output_components;
182 dest->data_width = row_width;
183 dest->row_width = row_width;
184
185 xsize = cinfo->output_width;
186 ysize = cinfo->output_height;
187 ncomps = cinfo->output_components;
188
189 //allocate space for final pixels
190 pixels = new unsigned char[xsize*ysize*ncomps];
191
192 /* Allocate space for inversion array, prepare for write pass */
193 dest->whole_image = (*cinfo->mem->request_virt_sarray)
194 ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE,
195 row_width, cinfo->output_height, (JDIMENSION) 1);
196 dest->cur_output_row = 0;
197 if (cinfo->progress != NULL) {
198 cd_progress_ptr progress = (cd_progress_ptr) cinfo->progress;
199 progress->total_extra_passes++; /* count file input as separate pass */
200 }
201
202 /* Create decompressor output buffer. */
203 dest->pub.buffer = (*cinfo->mem->alloc_sarray)
204 ((j_common_ptr) cinfo, JPOOL_IMAGE, row_width, (JDIMENSION) 1);
205 dest->pub.buffer_height = 1;
206
207 return (djpeg_dest_ptr) dest;
208 }
209
210 #define DBG 0
211
212 unsigned char
read_jpeg(char * fname,int * width,int * height,int * num_components)213 *read_jpeg(char *fname, int *width, int *height, int *num_components)
214 {
215 FILE *fd;
216
217 struct jpeg_decompress_struct cinfo;
218 struct jpeg_error_mgr jerr;
219 djpeg_dest_ptr dest_mgr = NULL;
220
221 pixels = NULL;
222
223 int num_scanlines;
224
225 if( (fd = fopen(fname,"rb")) == NULL)
226 {
227 fprintf(stderr,"read_jpeg: could not open file %s\n",fname);
228 return NULL;
229 }
230
231 #if DBG
232 fprintf(stderr,"read_jpeg: reading file %s\n",fname);
233 #endif
234
235 cinfo.err = jpeg_std_error(&jerr);
236 jpeg_create_decompress(&cinfo);
237
238 /* Specify data source for decompression */
239 jpeg_stdio_src(&cinfo, fd);
240
241 /* Read file header, set default decompression parameters */
242 (void) jpeg_read_header(&cinfo, TRUE);
243
244 dest_mgr = jinit_write_pixels(&cinfo);
245
246 // print header information
247
248
249 /* Start decompressor */
250 (void) jpeg_start_decompress(&cinfo);
251 #if DBG
252 fprintf(stderr,"read_jpeg: started decompressor for file %s\n",fname);
253 #endif
254
255 /* Write output file header */
256 (*dest_mgr->start_output) (&cinfo, dest_mgr);
257
258
259 #if 1
260 // (*dest_mgr->start_output) (&cinfo, dest_mgr);
261
262 /* Process data */
263 while (cinfo.output_scanline < cinfo.output_height) {
264 num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height);
265 (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines);
266 }
267 #endif
268
269 (*dest_mgr->finish_output) (&cinfo, dest_mgr);
270 (void) jpeg_finish_decompress(&cinfo);
271 jpeg_destroy_decompress(&cinfo);
272
273
274 *width = xsize;
275 *height = ysize;
276 *num_components=ncomps;
277 return pixels;
278 }
279
280
281