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