1 namespace gfx::bitmaps;
13 struct jpeg_error_mgr jpeg;
17 static void JPEG_ExitHandler(j_common_ptr cinfo)
19 longjmp(((ErrorHandler *) cinfo->err)->setjmpBuffer, 1);
25 struct jpeg_source_mgr pub;
32 #define INPUT_BUF_SIZE 4096
34 static void JPEG_InitSource (j_decompress_ptr cinfo)
36 SourceManager * src = (SourceManager *) cinfo->src;
37 src->startOfFile = TRUE;
40 static boolean JPEG_FillInputBuffer (j_decompress_ptr cinfo)
42 SourceManager * src = (SourceManager *) cinfo->src;
43 uint nbytes = src->infile.Read(src->buffer, sizeof(byte), INPUT_BUF_SIZE);
47 ERREXIT(cinfo, JERR_INPUT_EMPTY);
48 WARNMS(cinfo, JWRN_JPEG_EOF);
50 src->buffer[0] = (byte) 0xFF;
51 src->buffer[1] = (byte) JPEG_EOI;
55 src->pub.next_input_byte = src->buffer;
56 src->pub.bytes_in_buffer = nbytes;
57 src->startOfFile = FALSE;
62 static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes)
64 SourceManager * src = (SourceManager *) cinfo->src;
68 while (num_bytes > (long) src->pub.bytes_in_buffer)
70 num_bytes -= (long) src->pub.bytes_in_buffer;
71 JPEG_FillInputBuffer(cinfo);
73 src->pub.next_input_byte += (uint) num_bytes;
74 src->pub.bytes_in_buffer -= (uint) num_bytes;
78 static void JPEG_TermSource(j_decompress_ptr cinfo)
83 static void JPEG_SetSource(j_decompress_ptr cinfo, File infile)
89 cinfo->src = (struct jpeg_source_mgr *)
90 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
91 sizeof(SourceManager));
92 src = (SourceManager *) cinfo->src;
93 src->buffer = (byte *)
94 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
95 INPUT_BUF_SIZE * sizeof(byte));
98 src = (SourceManager *) cinfo->src;
99 src->pub.init_source = JPEG_InitSource;
100 src->pub.fill_input_buffer = JPEG_FillInputBuffer;
101 src->pub.skip_input_data = JPEG_SkipInputData;
102 src->pub.term_source = JPEG_TermSource;
103 src->pub.resync_to_restart = jpeg_resync_to_restart;
104 src->infile = infile;
105 src->pub.bytes_in_buffer = 0;
106 src->pub.next_input_byte = null;
112 struct jpeg_destination_mgr pub;
116 } DestinationManager;
118 #define OUTPUT_BUF_SIZE 4096
120 static void JPEG_InitDestination(j_compress_ptr cinfo)
122 DestinationManager * dest = (DestinationManager * ) cinfo->dest;
124 dest->buffer = (byte *)
125 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
126 OUTPUT_BUF_SIZE * sizeof(byte));
128 dest->pub.next_output_byte = dest->buffer;
129 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
132 static boolean JPEG_EmptyOutputBuffer(j_compress_ptr cinfo)
134 DestinationManager * dest = (DestinationManager *) cinfo->dest;
136 if (dest->outfile.Write(dest->buffer, sizeof(byte), OUTPUT_BUF_SIZE) !=
137 (uint) OUTPUT_BUF_SIZE)
138 ERREXIT(cinfo, JERR_FILE_WRITE);
140 dest->pub.next_output_byte = dest->buffer;
141 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
146 static void JPEG_TermDestination(j_compress_ptr cinfo)
148 DestinationManager * dest = (DestinationManager *) cinfo->dest;
149 uint datacount = (uint)(OUTPUT_BUF_SIZE - dest->pub.free_in_buffer);
153 if (dest->outfile.Write(dest->buffer, sizeof(byte), datacount) != datacount)
154 ERREXIT(cinfo, JERR_FILE_WRITE);
157 fflush(dest->outfile);
158 if (ferror(dest->outfile)) ERREXIT(cinfo, JERR_FILE_WRITE);
162 static void JPEG_SetDestination(j_compress_ptr cinfo, File outfile)
164 DestinationManager * dest;
168 cinfo->dest = (struct jpeg_destination_mgr *)
169 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
170 sizeof(DestinationManager));
173 dest = (DestinationManager *) cinfo->dest;
174 dest->pub.init_destination = JPEG_InitDestination;
175 dest->pub.empty_output_buffer = JPEG_EmptyOutputBuffer;
176 dest->pub.term_destination = JPEG_TermDestination;
177 dest->outfile = outfile;
181 static char * extensions[] = { "jpg", "jpeg", null };
183 class JPGFormat : BitmapFormat
185 class_property(extensions) = extensions;
187 bool Load(Bitmap bitmap, File f)
190 struct jpeg_decompress_struct cinfo;
192 ErrorHandler handler;
193 cinfo.err = jpeg_std_error(&handler.jpeg);
194 handler.jpeg.error_exit = JPEG_ExitHandler;
195 if(!setjmp(handler.setjmpBuffer))
197 jpeg_create_decompress(&cinfo);
199 JPEG_SetSource(&cinfo, f);
201 jpeg_read_header(&cinfo, TRUE);
203 if(bitmap.Allocate(null, cinfo.image_width, cinfo.image_height, 0, pixelFormat888, false))
206 ColorAlpha * picture;
208 jpeg_start_decompress(&cinfo);
209 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
211 for(picture = (ColorAlpha *)bitmap.picture; cinfo.output_scanline < cinfo.output_height; picture += bitmap.stride)
214 jpeg_read_scanlines(&cinfo, buffer, 1);
215 for(c = 0; c<cinfo.image_width; c++)
217 if(cinfo.output_components == 1)
218 picture[c] = ColorAlpha { 255, { buffer[0][c], buffer[0][c], buffer[0][c] } };
220 picture[c] = ColorAlpha { 255, { buffer[0][c*3], buffer[0][c*3+1], buffer[0][c*3+2] } };
225 jpeg_finish_decompress(&cinfo);
228 jpeg_destroy_decompress(&cinfo);
235 bool Save(Bitmap bitmap, char *filename, void * options)
238 if(bitmap.pixelFormat == pixelFormat888)
240 File f = FileOpen(filename, write);
243 struct jpeg_compress_struct cinfo;
244 struct jpeg_error_mgr jerr;
246 ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
249 cinfo.err = jpeg_std_error(&jerr);
251 jpeg_create_compress(&cinfo);
252 JPEG_SetDestination(&cinfo, f);
254 cinfo.image_width = bitmap.width;
255 cinfo.image_height = bitmap.height;
256 cinfo.input_components = 3;
257 cinfo.in_color_space = JCS_RGB;
259 jpeg_set_defaults(&cinfo);
261 jpeg_set_quality(&cinfo, 100, TRUE);
263 jpeg_start_compress(&cinfo, TRUE);
265 buffer = new byte[bitmap.width * 3];
267 for(;cinfo.next_scanline < cinfo.image_height;)
270 for(c = 0; c<bitmap.width; c++)
272 if(cinfo.input_components == 1)
273 buffer[c] = (picture[c].color.r + picture[c].color.g + picture[c].color.b) / 3;
276 buffer[c*3] = picture[c].color.r;
277 buffer[c*3+1] = picture[c].color.g;
278 buffer[c*3+2] = picture[c].color.b;
282 jpeg_write_scanlines(&cinfo, &row, 1);
284 picture += bitmap.stride;
289 jpeg_finish_compress(&cinfo);
290 jpeg_destroy_compress(&cinfo);
299 ColorAlpha * LoadPalette(char * fileName, char * type)
301 ColorAlpha * result = null;