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