1 namespace gfx::bitmaps;
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 = 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 = (uint)(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 const 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.out_color_space == JCS_CMYK && cinfo.output_components == 4)
221 int cyan = 255-buffer[0][c*4+0];
222 int m = 255-buffer[0][c*4+1];
223 int y = 255-buffer[0][c*4+2];
224 int k = 255-buffer[0][c*4+3];
225 //picture[c] = ColorAlpha { 255, { cinfo.sample_range_limit[(255 - (cyan + k))], cinfo.sample_range_limit[(255 - (m + k))], cinfo.sample_range_limit[(255 - (y + k))] } };
226 picture[c] = ColorCMYK { cyan * 100.0f / 255, m * 100.0f / 255, y * 100.0f / 255, k * 100.0f / 255 };
228 else if(cinfo.output_components == 1)
229 picture[c] = ColorAlpha { 255, { buffer[0][c], buffer[0][c], buffer[0][c] } };
231 picture[c] = ColorAlpha { 255, { buffer[0][c*3], buffer[0][c*3+1], buffer[0][c*3+2] } };
236 jpeg_finish_decompress(&cinfo);
239 jpeg_destroy_decompress(&cinfo);
246 bool Save(Bitmap bitmap, const char *filename, void * options)
249 if(bitmap.pixelFormat == pixelFormat888)
251 File f = FileOpen(filename, write);
254 struct jpeg_compress_struct cinfo;
255 struct jpeg_error_mgr jerr;
257 ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
260 cinfo.err = jpeg_std_error(&jerr);
262 jpeg_create_compress(&cinfo);
263 JPEG_SetDestination(&cinfo, f);
265 cinfo.image_width = bitmap.width;
266 cinfo.image_height = bitmap.height;
267 cinfo.input_components = 3;
268 cinfo.in_color_space = JCS_RGB;
270 jpeg_set_defaults(&cinfo);
272 jpeg_set_quality(&cinfo, 100, TRUE);
274 jpeg_start_compress(&cinfo, TRUE);
276 buffer = new byte[bitmap.width * 3];
278 for(;cinfo.next_scanline < cinfo.image_height;)
281 for(c = 0; c<bitmap.width; c++)
283 if(cinfo.input_components == 1)
284 buffer[c] = (picture[c].color.r + picture[c].color.g + picture[c].color.b) / 3;
287 buffer[c*3] = picture[c].color.r;
288 buffer[c*3+1] = picture[c].color.g;
289 buffer[c*3+2] = picture[c].color.b;
293 jpeg_write_scanlines(&cinfo, &row, 1);
295 picture += bitmap.stride;
300 jpeg_finish_compress(&cinfo);
301 jpeg_destroy_compress(&cinfo);
310 ColorAlpha * LoadPalette(const char * fileName, const char * type)
312 ColorAlpha * result = null;