1 namespace gfx::bitmaps;
14 struct jpeg_error_mgr jpeg;
18 static void JPEG_ExitHandler(j_common_ptr cinfo)
20 longjmp(((ErrorHandler *) cinfo->err)->setjmpBuffer, 1);
26 struct jpeg_source_mgr pub;
33 #define INPUT_BUF_SIZE 4096
35 static void JPEG_InitSource (j_decompress_ptr cinfo)
37 SourceManager * src = (SourceManager *) cinfo->src;
38 src->startOfFile = TRUE;
41 static boolean JPEG_FillInputBuffer (j_decompress_ptr cinfo)
43 SourceManager * src = (SourceManager *) cinfo->src;
44 uint nbytes = src->infile.Read(src->buffer, sizeof(byte), INPUT_BUF_SIZE);
48 ERREXIT(cinfo, JERR_INPUT_EMPTY);
49 WARNMS(cinfo, JWRN_JPEG_EOF);
51 src->buffer[0] = (byte) 0xFF;
52 src->buffer[1] = (byte) JPEG_EOI;
56 src->pub.next_input_byte = src->buffer;
57 src->pub.bytes_in_buffer = nbytes;
58 src->startOfFile = FALSE;
63 static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes)
65 SourceManager * src = (SourceManager *) cinfo->src;
69 while (num_bytes > (long) src->pub.bytes_in_buffer)
71 num_bytes -= (long) src->pub.bytes_in_buffer;
72 JPEG_FillInputBuffer(cinfo);
74 src->pub.next_input_byte += (uint) num_bytes;
75 src->pub.bytes_in_buffer -= (uint) num_bytes;
79 static void JPEG_TermSource(j_decompress_ptr cinfo)
84 static void JPEG_SetSource(j_decompress_ptr cinfo, File infile)
90 cinfo->src = (struct jpeg_source_mgr *)
91 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
92 sizeof(SourceManager));
93 src = (SourceManager *) cinfo->src;
94 src->buffer = (byte *)
95 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
96 INPUT_BUF_SIZE * sizeof(byte));
99 src = (SourceManager *) cinfo->src;
100 src->pub.init_source = JPEG_InitSource;
101 src->pub.fill_input_buffer = JPEG_FillInputBuffer;
102 src->pub.skip_input_data = JPEG_SkipInputData;
103 src->pub.term_source = JPEG_TermSource;
104 src->pub.resync_to_restart = jpeg_resync_to_restart;
105 src->infile = infile;
106 src->pub.bytes_in_buffer = 0;
107 src->pub.next_input_byte = null;
113 struct jpeg_destination_mgr pub;
117 } DestinationManager;
119 #define OUTPUT_BUF_SIZE 4096
121 static void JPEG_InitDestination(j_compress_ptr cinfo)
123 DestinationManager * dest = (DestinationManager * ) cinfo->dest;
125 dest->buffer = (byte *)
126 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
127 OUTPUT_BUF_SIZE * sizeof(byte));
129 dest->pub.next_output_byte = dest->buffer;
130 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
133 static boolean JPEG_EmptyOutputBuffer(j_compress_ptr cinfo)
135 DestinationManager * dest = (DestinationManager *) cinfo->dest;
137 if (dest->outfile.Write(dest->buffer, sizeof(byte), OUTPUT_BUF_SIZE) !=
138 (uint) OUTPUT_BUF_SIZE)
139 ERREXIT(cinfo, JERR_FILE_WRITE);
141 dest->pub.next_output_byte = dest->buffer;
142 dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
147 static void JPEG_TermDestination(j_compress_ptr cinfo)
149 DestinationManager * dest = (DestinationManager *) cinfo->dest;
150 uint datacount = (uint)(OUTPUT_BUF_SIZE - dest->pub.free_in_buffer);
154 if (dest->outfile.Write(dest->buffer, sizeof(byte), datacount) != datacount)
155 ERREXIT(cinfo, JERR_FILE_WRITE);
158 fflush(dest->outfile);
159 if (ferror(dest->outfile)) ERREXIT(cinfo, JERR_FILE_WRITE);
163 static void JPEG_SetDestination(j_compress_ptr cinfo, File outfile)
165 DestinationManager * dest;
169 cinfo->dest = (struct jpeg_destination_mgr *)
170 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
171 sizeof(DestinationManager));
174 dest = (DestinationManager *) cinfo->dest;
175 dest->pub.init_destination = JPEG_InitDestination;
176 dest->pub.empty_output_buffer = JPEG_EmptyOutputBuffer;
177 dest->pub.term_destination = JPEG_TermDestination;
178 dest->outfile = outfile;
182 static const char * extensions[] = { "jpg", "jpeg", null };
184 class JPGFormat : BitmapFormat
186 class_property(extensions) = extensions;
188 bool Load(Bitmap bitmap, File f)
191 struct jpeg_decompress_struct cinfo;
193 ErrorHandler handler;
194 cinfo.err = jpeg_std_error(&handler.jpeg);
195 handler.jpeg.error_exit = JPEG_ExitHandler;
196 if(!setjmp(handler.setjmpBuffer))
198 jpeg_create_decompress(&cinfo);
200 JPEG_SetSource(&cinfo, f);
202 jpeg_read_header(&cinfo, TRUE);
204 if(bitmap.Allocate(null, cinfo.image_width, cinfo.image_height, 0, pixelFormat888, false))
207 ColorAlpha * picture;
209 jpeg_start_decompress(&cinfo);
210 buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
212 for(picture = (ColorAlpha *)bitmap.picture; cinfo.output_scanline < cinfo.output_height; picture += bitmap.stride)
215 jpeg_read_scanlines(&cinfo, buffer, 1);
216 for(c = 0; c<cinfo.image_width; c++)
218 if(cinfo.out_color_space == JCS_CMYK && cinfo.output_components == 4)
220 int cyan = 255-buffer[0][c*4+0];
221 int m = 255-buffer[0][c*4+1];
222 int y = 255-buffer[0][c*4+2];
223 int k = 255-buffer[0][c*4+3];
224 //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))] } };
225 picture[c] = ColorCMYK { cyan * 100.0f / 255, m * 100.0f / 255, y * 100.0f / 255, k * 100.0f / 255 };
227 else if(cinfo.output_components == 1)
228 picture[c] = ColorAlpha { 255, { buffer[0][c], buffer[0][c], buffer[0][c] } };
230 picture[c] = ColorAlpha { 255, { buffer[0][c*3], buffer[0][c*3+1], buffer[0][c*3+2] } };
235 jpeg_finish_decompress(&cinfo);
238 jpeg_destroy_decompress(&cinfo);
245 bool Save(Bitmap bitmap, const char *filename, void * options)
248 if(bitmap.pixelFormat == pixelFormat888)
250 File f = FileOpen(filename, write);
253 struct jpeg_compress_struct cinfo;
254 struct jpeg_error_mgr jerr;
256 ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
259 cinfo.err = jpeg_std_error(&jerr);
261 jpeg_create_compress(&cinfo);
262 JPEG_SetDestination(&cinfo, f);
264 cinfo.image_width = bitmap.width;
265 cinfo.image_height = bitmap.height;
266 cinfo.input_components = 3;
267 cinfo.in_color_space = JCS_RGB;
269 jpeg_set_defaults(&cinfo);
271 jpeg_set_quality(&cinfo, 100, TRUE);
273 jpeg_start_compress(&cinfo, TRUE);
275 buffer = new byte[bitmap.width * 3];
277 for(;cinfo.next_scanline < cinfo.image_height;)
280 for(c = 0; c<bitmap.width; c++)
282 if(cinfo.input_components == 1)
283 buffer[c] = (picture[c].color.r + picture[c].color.g + picture[c].color.b) / 3;
286 buffer[c*3] = picture[c].color.r;
287 buffer[c*3+1] = picture[c].color.g;
288 buffer[c*3+2] = picture[c].color.b;
292 jpeg_write_scanlines(&cinfo, &row, 1);
294 picture += bitmap.stride;
299 jpeg_finish_compress(&cinfo);
300 jpeg_destroy_compress(&cinfo);
309 ColorAlpha * LoadPalette(const char * fileName, const char * type)
311 ColorAlpha * result = null;