1 namespace gfx::bitmaps;
7 typedef uintptr size_t; // For now, until we add uintsize
15 struct jpeg_error_mgr jpeg;
19 static void JPEG_ExitHandler(j_common_ptr cinfo)
21 longjmp(((ErrorHandler *) cinfo->err)->setjmpBuffer, 1);
27 struct jpeg_source_mgr pub;
34 #define INPUT_BUF_SIZE 4096
36 static void JPEG_InitSource (j_decompress_ptr cinfo)
38 SourceManager * src = (SourceManager *) cinfo->src;
39 src->startOfFile = TRUE;
42 static boolean JPEG_FillInputBuffer (j_decompress_ptr cinfo)
44 SourceManager * src = (SourceManager *) cinfo->src;
45 uint nbytes = src->infile.Read(src->buffer, sizeof(byte), INPUT_BUF_SIZE);
49 ERREXIT(cinfo, JERR_INPUT_EMPTY);
50 WARNMS(cinfo, JWRN_JPEG_EOF);
52 src->buffer[0] = (byte) 0xFF;
53 src->buffer[1] = (byte) JPEG_EOI;
57 src->pub.next_input_byte = src->buffer;
58 src->pub.bytes_in_buffer = (size_t)nbytes;
59 src->startOfFile = FALSE;
64 static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes)
66 SourceManager * src = (SourceManager *) cinfo->src;
70 while (num_bytes > (long) src->pub.bytes_in_buffer)
72 num_bytes -= (long) src->pub.bytes_in_buffer;
73 JPEG_FillInputBuffer(cinfo);
75 src->pub.next_input_byte += (uint) num_bytes;
76 src->pub.bytes_in_buffer -= (uint) num_bytes;
80 static void JPEG_TermSource(j_decompress_ptr cinfo)
85 static void JPEG_SetSource(j_decompress_ptr cinfo, File infile)
91 cinfo->src = (struct jpeg_source_mgr *)
92 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
93 sizeof(SourceManager));
94 src = (SourceManager *) cinfo->src;
95 src->buffer = (byte *)
96 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
97 INPUT_BUF_SIZE * sizeof(byte));
100 src = (SourceManager *) cinfo->src;
101 src->pub.init_source = JPEG_InitSource;
102 src->pub.fill_input_buffer = JPEG_FillInputBuffer;
103 src->pub.skip_input_data = JPEG_SkipInputData;
104 src->pub.term_source = JPEG_TermSource;
105 src->pub.resync_to_restart = jpeg_resync_to_restart;
106 src->infile = infile;
107 src->pub.bytes_in_buffer = 0;
108 src->pub.next_input_byte = null;
114 struct jpeg_destination_mgr pub;
118 } DestinationManager;
120 #define OUTPUT_BUF_SIZE 4096
122 static void JPEG_InitDestination(j_compress_ptr cinfo)
124 DestinationManager * dest = (DestinationManager * ) cinfo->dest;
126 dest->buffer = (byte *)
127 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
128 OUTPUT_BUF_SIZE * sizeof(byte));
130 dest->pub.next_output_byte = dest->buffer;
131 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
134 static boolean JPEG_EmptyOutputBuffer(j_compress_ptr cinfo)
136 DestinationManager * dest = (DestinationManager *) cinfo->dest;
138 if (dest->outfile.Write(dest->buffer, sizeof(byte), OUTPUT_BUF_SIZE) !=
139 (uint) OUTPUT_BUF_SIZE)
140 ERREXIT(cinfo, JERR_FILE_WRITE);
142 dest->pub.next_output_byte = dest->buffer;
143 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
148 static void JPEG_TermDestination(j_compress_ptr cinfo)
150 DestinationManager * dest = (DestinationManager *) cinfo->dest;
151 uint datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
155 if (dest->outfile.Write(dest->buffer, sizeof(byte), datacount) != datacount)
156 ERREXIT(cinfo, JERR_FILE_WRITE);
159 fflush(dest->outfile);
160 if (ferror(dest->outfile)) ERREXIT(cinfo, JERR_FILE_WRITE);
164 static void JPEG_SetDestination(j_compress_ptr cinfo, File outfile)
166 DestinationManager * dest;
170 cinfo->dest = (struct jpeg_destination_mgr *)
171 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
172 sizeof(DestinationManager));
175 dest = (DestinationManager *) cinfo->dest;
176 dest->pub.init_destination = JPEG_InitDestination;
177 dest->pub.empty_output_buffer = JPEG_EmptyOutputBuffer;
178 dest->pub.term_destination = JPEG_TermDestination;
179 dest->outfile = outfile;
183 static char * extensions[] = { "jpg", "jpeg", null };
185 class JPGFormat : BitmapFormat
187 class_property(extensions) = extensions;
189 bool Load(Bitmap bitmap, File f)
192 struct jpeg_decompress_struct cinfo;
194 ErrorHandler handler;
195 cinfo.err = jpeg_std_error(&handler.jpeg);
196 handler.jpeg.error_exit = JPEG_ExitHandler;
197 if(!setjmp(handler.setjmpBuffer))
199 jpeg_create_decompress(&cinfo);
201 JPEG_SetSource(&cinfo, f);
203 jpeg_read_header(&cinfo, TRUE);
205 if(bitmap.Allocate(null, cinfo.image_width, cinfo.image_height, 0, pixelFormat888, false))
208 ColorAlpha * picture;
210 jpeg_start_decompress(&cinfo);
211 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
213 for(picture = (ColorAlpha *)bitmap.picture; cinfo.output_scanline < cinfo.output_height; picture += bitmap.stride)
216 jpeg_read_scanlines(&cinfo, buffer, 1);
217 for(c = 0; c<cinfo.image_width; c++)
219 if(cinfo.output_components == 1)
220 picture[c] = ColorAlpha { 255, { buffer[0][c], buffer[0][c], buffer[0][c] } };
222 picture[c] = ColorAlpha { 255, { buffer[0][c*3], buffer[0][c*3+1], buffer[0][c*3+2] } };
227 jpeg_finish_decompress(&cinfo);
230 jpeg_destroy_decompress(&cinfo);
237 bool Save(Bitmap bitmap, char *filename, void * options)
240 if(bitmap.pixelFormat == pixelFormat888)
242 File f = FileOpen(filename, write);
245 struct jpeg_compress_struct cinfo;
246 struct jpeg_error_mgr jerr;
248 ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
251 cinfo.err = jpeg_std_error(&jerr);
253 jpeg_create_compress(&cinfo);
254 JPEG_SetDestination(&cinfo, f);
256 cinfo.image_width = bitmap.width;
257 cinfo.image_height = bitmap.height;
258 cinfo.input_components = 3;
259 cinfo.in_color_space = JCS_RGB;
261 jpeg_set_defaults(&cinfo);
263 jpeg_set_quality(&cinfo, 100, TRUE);
265 jpeg_start_compress(&cinfo, TRUE);
267 buffer = new byte[bitmap.width * 3];
269 for(;cinfo.next_scanline < cinfo.image_height;)
272 for(c = 0; c<bitmap.width; c++)
274 if(cinfo.input_components == 1)
275 buffer[c] = (picture[c].color.r + picture[c].color.g + picture[c].color.b) / 3;
278 buffer[c*3] = picture[c].color.r;
279 buffer[c*3+1] = picture[c].color.g;
280 buffer[c*3+2] = picture[c].color.b;
284 jpeg_write_scanlines(&cinfo, &row, 1);
286 picture += bitmap.stride;
291 jpeg_finish_compress(&cinfo);
292 jpeg_destroy_compress(&cinfo);
301 ColorAlpha * LoadPalette(char * fileName, char * type)
303 ColorAlpha * result = null;