compiler/libec: (#307, #70) Warning on undeclared class; Overriding namespaces
[sdk] / ecere / src / gfx / bitmaps / JPEGFormat.ec
1 namespace gfx::bitmaps;
2
3 import "Display"
4
5 #include <setjmp.h>
6 #include <stdio.h>
7
8 #include "jpeglib.h"
9 #include "jerror.h"
10
11 // ERROR HANDLER
12 typedef struct
13 {
14    struct jpeg_error_mgr jpeg;
15    jmp_buf setjmpBuffer;
16 } ErrorHandler;
17
18 static void JPEG_ExitHandler(j_common_ptr cinfo)
19 {
20    longjmp(((ErrorHandler *) cinfo->err)->setjmpBuffer, 1);
21 }
22
23 // DATA SOURCE
24 typedef struct
25 {
26    struct jpeg_source_mgr pub;
27
28    File infile;
29    byte * buffer;
30    boolean startOfFile;
31 } SourceManager;
32
33 #define INPUT_BUF_SIZE  4096
34
35 static void JPEG_InitSource (j_decompress_ptr cinfo)
36 {
37    SourceManager * src = (SourceManager *) cinfo->src;
38    src->startOfFile = TRUE;
39 }
40
41 static boolean JPEG_FillInputBuffer (j_decompress_ptr cinfo)
42 {
43    SourceManager * src = (SourceManager *) cinfo->src;
44    uint nbytes = src->infile.Read(src->buffer, sizeof(byte), INPUT_BUF_SIZE);
45    if(nbytes <= 0)
46    {
47       if(src->startOfFile)
48          ERREXIT(cinfo, JERR_INPUT_EMPTY);
49       WARNMS(cinfo, JWRN_JPEG_EOF);
50
51       src->buffer[0] = (byte) 0xFF;
52       src->buffer[1] = (byte) JPEG_EOI;
53       nbytes = 2;
54    }
55
56    src->pub.next_input_byte = src->buffer;
57    src->pub.bytes_in_buffer = nbytes;
58    src->startOfFile = FALSE;
59
60    return TRUE;
61 }
62
63 static void JPEG_SkipInputData (j_decompress_ptr cinfo, long num_bytes)
64 {
65    SourceManager * src = (SourceManager *) cinfo->src;
66
67    if (num_bytes > 0)
68    {
69       while (num_bytes > (long) src->pub.bytes_in_buffer)
70       {
71          num_bytes -= (long) src->pub.bytes_in_buffer;
72          JPEG_FillInputBuffer(cinfo);
73       }
74       src->pub.next_input_byte += (uint) num_bytes;
75       src->pub.bytes_in_buffer -= (uint) num_bytes;
76    }
77 }
78
79 static void JPEG_TermSource(j_decompress_ptr cinfo)
80 {
81
82 }
83
84 static void JPEG_SetSource(j_decompress_ptr cinfo, File infile)
85 {
86    SourceManager * src;
87
88    if (!cinfo->src)
89    {
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));
97    }
98
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;
108 }
109
110 // DATA DESTINATION
111 typedef struct
112 {
113    struct jpeg_destination_mgr pub;
114
115    File outfile;
116    byte * buffer;
117 } DestinationManager;
118
119 #define OUTPUT_BUF_SIZE  4096
120
121 static void JPEG_InitDestination(j_compress_ptr cinfo)
122 {
123    DestinationManager * dest = (DestinationManager * ) cinfo->dest;
124
125    dest->buffer = (byte *)
126       (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
127                                   OUTPUT_BUF_SIZE * sizeof(byte));
128
129    dest->pub.next_output_byte = dest->buffer;
130    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
131 }
132
133 static boolean JPEG_EmptyOutputBuffer(j_compress_ptr cinfo)
134 {
135    DestinationManager * dest = (DestinationManager *) cinfo->dest;
136
137    if (dest->outfile.Write(dest->buffer, sizeof(byte), OUTPUT_BUF_SIZE) !=
138       (uint) OUTPUT_BUF_SIZE)
139       ERREXIT(cinfo, JERR_FILE_WRITE);
140
141    dest->pub.next_output_byte = dest->buffer;
142    dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
143
144    return TRUE;
145 }
146
147 static void JPEG_TermDestination(j_compress_ptr cinfo)
148 {
149    DestinationManager * dest = (DestinationManager *) cinfo->dest;
150    uint datacount = (uint)(OUTPUT_BUF_SIZE - dest->pub.free_in_buffer);
151
152    if (datacount > 0)
153    {
154       if (dest->outfile.Write(dest->buffer, sizeof(byte), datacount) != datacount)
155          ERREXIT(cinfo, JERR_FILE_WRITE);
156    }
157 /*
158    fflush(dest->outfile);
159    if (ferror(dest->outfile)) ERREXIT(cinfo, JERR_FILE_WRITE);
160 */
161 }
162
163 static void JPEG_SetDestination(j_compress_ptr cinfo, File outfile)
164 {
165    DestinationManager * dest;
166
167    if(!cinfo->dest)
168    {
169       cinfo->dest = (struct jpeg_destination_mgr *)
170          (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
171          sizeof(DestinationManager));
172    }
173
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;
179 }
180
181 // BITMAP DRIVER
182 static const char * extensions[] = { "jpg", "jpeg", null };
183
184 class JPGFormat : BitmapFormat
185 {
186    class_property(extensions) = extensions;
187
188    bool Load(Bitmap bitmap, File f)
189    {
190       bool result = false;
191       struct jpeg_decompress_struct cinfo;
192
193       ErrorHandler handler;
194       cinfo.err = jpeg_std_error(&handler.jpeg);
195       handler.jpeg.error_exit = JPEG_ExitHandler;
196       if(!setjmp(handler.setjmpBuffer))
197       {
198          jpeg_create_decompress(&cinfo);
199
200          JPEG_SetSource(&cinfo, f);
201
202          jpeg_read_header(&cinfo, TRUE);
203
204          if(bitmap.Allocate(null, cinfo.image_width, cinfo.image_height, 0, pixelFormat888, false))
205          {
206             JSAMPARRAY buffer;
207             ColorAlpha * picture;
208
209             jpeg_start_decompress(&cinfo);
210             buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);
211
212             for(picture = (ColorAlpha *)bitmap.picture; cinfo.output_scanline < cinfo.output_height; picture += bitmap.stride)
213             {
214                int c;
215                jpeg_read_scanlines(&cinfo, buffer, 1);
216                for(c = 0; c<cinfo.image_width; c++)
217                {
218                   if(cinfo.out_color_space == JCS_CMYK && cinfo.output_components == 4)
219                   {
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 };
226                   }
227                   else if(cinfo.output_components == 1)
228                      picture[c] = ColorAlpha { 255, { buffer[0][c], buffer[0][c], buffer[0][c] } };
229                   else
230                      picture[c] = ColorAlpha { 255, { buffer[0][c*3], buffer[0][c*3+1], buffer[0][c*3+2] } };
231                }
232             }
233             result = true;
234          }
235          jpeg_finish_decompress(&cinfo);
236       }
237
238       jpeg_destroy_decompress(&cinfo);
239
240       if(!result)
241          bitmap.Free();
242       return result;
243    }
244
245    bool Save(Bitmap bitmap, const char *filename, void * options)
246    {
247       bool result = false;
248       if(bitmap.pixelFormat == pixelFormat888)
249       {
250          File f = FileOpen(filename, write);
251          if(f)
252          {
253             struct jpeg_compress_struct cinfo;
254             struct jpeg_error_mgr jerr;
255             JSAMPROW row;
256             ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
257             byte * buffer;
258
259             cinfo.err = jpeg_std_error(&jerr);
260
261             jpeg_create_compress(&cinfo);
262             JPEG_SetDestination(&cinfo, f);
263
264             cinfo.image_width = bitmap.width;
265             cinfo.image_height = bitmap.height;
266             cinfo.input_components = 3;
267             cinfo.in_color_space = JCS_RGB;
268
269             jpeg_set_defaults(&cinfo);
270
271             jpeg_set_quality(&cinfo, 100, TRUE);
272
273             jpeg_start_compress(&cinfo, TRUE);
274
275             buffer = new byte[bitmap.width * 3];
276
277             for(;cinfo.next_scanline < cinfo.image_height;)
278             {
279                int c;
280                for(c = 0; c<bitmap.width; c++)
281                {
282                   if(cinfo.input_components == 1)
283                      buffer[c] = (picture[c].color.r + picture[c].color.g + picture[c].color.b) / 3;
284                   else
285                   {
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;
289                   }
290                }
291                row = buffer;
292                jpeg_write_scanlines(&cinfo, &row, 1);
293
294                picture += bitmap.stride;
295             }
296
297             delete buffer;
298
299             jpeg_finish_compress(&cinfo);
300             jpeg_destroy_compress(&cinfo);
301
302             delete f;
303             result = true;
304          }
305       }
306       return result;
307    }
308
309    ColorAlpha * LoadPalette(const char * fileName, const char * type)
310    {
311       ColorAlpha * result = null;
312       return result;
313    }
314 }