1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* $Id$ */
21
22 #include <stdlib.h>
23
24 #include "jpeg.h"
25 #include "character.h"
26 #include "input.h"
27 #include "error.h"
28 #include "method.h"
29 #include "libming.h"
30
31
32 struct SWFJpegBitmap_s
33 {
34 struct SWFCharacter_s character;
35
36 SWFInput input;
37 int length;
38
39 #if TRACK_ALLOCS
40 /* memory node for garbage collection */
41 mem_node *gcnode;
42 #endif
43 };
44
45 struct SWFJpegWithAlpha_s
46 {
47 struct SWFCharacter_s character;
48
49 SWFInput input; /* leave these here so that we */
50 int length; /* can cast this to swfJpegBitmap */
51
52 #if TRACK_ALLOCS
53 /* memory node for garbage collection */
54 mem_node *gcnode;
55 #endif
56 /* ---insert additions here (for casting to swfJpegBitmap) --- */
57 SWFInput alpha;
58 int jpegLength;
59 };
60
61 /* JPEG stream markers: */
62 #define JPEG_MARKER 0xFF
63
64 /* Start of Image, End of Image */
65 #define JPEG_SOI 0xD8
66 #define JPEG_EOI 0xD9
67
68 #define JPEG_JFIF 0xE0
69
70 /* encoding markers, quantization tables and Huffman tables */
71 #define JPEG_QUANT 0xDB
72 #define JPEG_HUFF 0xC4
73
74 /* image markers, start of frame and start of scan */
75 #define JPEG_SOF0 0xC0
76 #define JPEG_SOF1 0xC1
77 #define JPEG_SOF2 0xC2
78 #define JPEG_SOS 0xDA
79
80 #define JPEG_ED 0xED /* app13 */
81 #define JPEG_EE 0xEE /* app14 */
82 #define JPEG_DD 0xDD /* ??? */
83
84
85 static int
completeSWFJpegBitmap(SWFBlock block)86 completeSWFJpegBitmap(SWFBlock block)
87 {
88 return ((SWFJpegBitmap)block)->length;
89 }
90
91
92
93 /* clumsy utility function.. */
94 void
dumpJpegBlock(byte type,SWFInput input,SWFByteOutputMethod method,void * data)95 dumpJpegBlock(byte type,
96 SWFInput input, SWFByteOutputMethod method, void *data)
97 {
98 int i, l0, l1, length;
99
100 method(JPEG_MARKER, data);
101 method(type, data);
102
103 method((unsigned char)(l0 = SWFInput_getChar(input)), data);
104 method((unsigned char)(l1 = SWFInput_getChar(input)), data);
105
106 length = (l0<<8) + l1 - 2;
107
108 for ( i=0; i<length; ++i )
109 method((unsigned char)SWFInput_getChar(input), data);
110 }
111
112
113 int
skipJpegBlock(SWFInput input)114 skipJpegBlock(SWFInput input)
115 {
116 int length = (SWFInput_getChar(input)<<8) + SWFInput_getChar(input);
117
118 SWFInput_seek(input, length-2, SEEK_CUR);
119
120 return length;
121 }
122
123
124 void
methodWriteJpegFile(SWFInput input,SWFByteOutputMethod method,void * data)125 methodWriteJpegFile(SWFInput input, SWFByteOutputMethod method, void *data)
126 {
127 int c;
128
129 SWFInput_rewind(input);
130
131 if ( (c = SWFInput_getChar(input)) != JPEG_MARKER )
132 SWF_error("Initial Jpeg marker not found!");
133
134 if ( (c = SWFInput_getChar(input)) != JPEG_SOI )
135 SWF_error("Jpeg SOI not found!");
136
137 /*
138 method(JPEG_MARKER, data);
139 method(JPEG_SOI, data);
140 method(JPEG_MARKER, data);
141 method(JPEG_EOI, data);
142 */
143
144 method(JPEG_MARKER, data);
145 method(JPEG_SOI, data);
146
147 for ( ;; )
148 {
149 if ( SWFInput_getChar(input) != JPEG_MARKER )
150 SWF_error("Jpeg marker not found where expected!");
151
152 switch ( c = SWFInput_getChar(input) )
153 {
154 case JPEG_EOI:
155 SWF_error("Unexpected end of Jpeg file (EOI found)!");
156
157 /* case JPEG_JFIF: */
158 case JPEG_QUANT:
159 case JPEG_HUFF:
160 case JPEG_DD:
161 /* if(!finishedEncoding) */
162 dumpJpegBlock((unsigned char)c, input, method, data);
163 /* else
164 SWF_error("Encoding tables found in Jpeg image section!"); */
165 break;
166
167 case JPEG_SOF0:
168 case JPEG_SOF1:
169 case JPEG_SOF2:
170 /*
171 if(!finishedEncoding)
172 {
173 finishedEncoding = TRUE;
174 method(JPEG_MARKER, data);
175 method(JPEG_EOI, data);
176 method(JPEG_MARKER, data);
177 method(JPEG_SOI, data);
178 method(JPEG_MARKER, data);
179 method(c, data);
180 }
181 */
182 dumpJpegBlock((unsigned char)c, input, method, data);
183 break;
184
185 case JPEG_SOS:
186 /*
187 if(!finishedEncoding)
188 SWF_error("Found SOS before SOF in Jpeg file!");
189 */
190 break;
191
192 default:
193 /* dumpJpegBlock(c, input, method, data); */
194 skipJpegBlock(input);
195 }
196
197 if ( c == JPEG_SOS )
198 break;
199
200 if ( SWFInput_eof(input) )
201 SWF_error("Unexpected end of Jpeg file (EOF found)!");
202 }
203
204 if ( c != JPEG_SOS )
205 SWF_error("SOS block not found in Jpeg file!");
206
207 /* rest is SOS, dump to end of file */
208 method(JPEG_MARKER, data);
209 method((unsigned char)c, data);
210
211 while ( (c = SWFInput_getChar(input)) != EOF )
212 method((unsigned char)c, data);
213 }
214
215
216 void
writeSWFJpegBitmapToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)217 writeSWFJpegBitmapToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
218 {
219 SWFJpegBitmap jpeg = (SWFJpegBitmap)block;
220
221 methodWriteUInt16(CHARACTERID(jpeg), method, data);
222 methodWriteJpegFile(jpeg->input, method, data);
223 }
224
225
226 void
writeSWFJpegWithAlphaToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)227 writeSWFJpegWithAlphaToMethod(SWFBlock block, SWFByteOutputMethod method, void *data)
228 {
229 SWFJpegWithAlpha jpeg = (SWFJpegWithAlpha)block;
230 int c;
231
232 methodWriteUInt16(CHARACTERID(jpeg), method, data);
233 methodWriteUInt32(jpeg->jpegLength, method, data);
234 methodWriteJpegFile(jpeg->input, method, data);
235
236 /* now write alpha file.. */
237
238 SWFInput_rewind(jpeg->alpha);
239
240 while ( (c = SWFInput_getChar(jpeg->alpha)) != EOF )
241 method((unsigned char)c, data);
242 }
243
244
245 void
destroySWFJpegBitmap(SWFJpegBitmap jpegBitmap)246 destroySWFJpegBitmap(SWFJpegBitmap jpegBitmap)
247 {
248 free(CHARACTER(jpegBitmap)->bounds);
249 #if TRACK_ALLOCS
250 ming_gc_remove_node(jpegBitmap->gcnode);
251 #endif
252 free(jpegBitmap);
253 }
254
255
256 struct jpegInfo
257 {
258 int width;
259 int height;
260 int length;
261 };
262
263 static struct jpegInfo*
scanJpegFile(SWFInput input)264 scanJpegFile(SWFInput input)
265 {
266 int length = 0, l, c;
267 long pos, end;
268
269 struct jpegInfo* info = (struct jpegInfo*)malloc(sizeof(struct jpegInfo));
270
271 /* If malloc failed, return NULL to signify this */
272 if (NULL == info)
273 return NULL;
274
275 /* scan file, get height and width, make sure it looks valid,
276 also figure length of block.. */
277
278 if ( SWFInput_getChar(input) != JPEG_MARKER )
279 SWF_error("Initial Jpeg marker not found!");
280
281 if ( SWFInput_getChar(input) != JPEG_SOI )
282 SWF_error("Jpeg SOI not found!");
283
284 for ( ;; )
285 {
286 if ( SWFInput_getChar(input) != JPEG_MARKER )
287 SWF_error("Jpeg marker not found where expected!");
288
289 switch ( c = SWFInput_getChar(input) )
290 {
291 case JPEG_EOI:
292 SWF_error("Unexpected end of Jpeg file (EOI found)!");
293
294 /* case JPEG_JFIF: */
295 case JPEG_QUANT:
296 case JPEG_HUFF:
297 case JPEG_DD:
298 /*
299 if(finishedEncoding)
300 SWF_error("Encoding tables found in Jpeg image section!");
301 */
302 length += skipJpegBlock(input) + 2;
303 break;
304
305 case JPEG_SOF2:
306 SWF_error("Only baseline (frame 0) jpegs are supported!");
307
308 case JPEG_SOF0:
309 case JPEG_SOF1:
310 /*
311 if ( finishedEncoding )
312 SWF_error("Found second SOF in Jpeg file!");
313 else
314 {
315 finishedEncoding = TRUE;
316 length += 4; // end image, start image
317 }
318 */
319
320 l = SWFInput_getUInt16_BE(input);
321 SWFInput_getChar(input); /* precision */
322 info->height = SWFInput_getUInt16_BE(input);
323 info->width = SWFInput_getUInt16_BE(input);
324
325 length += l + 2;
326 l -= 7;
327
328 SWFInput_seek(input, l, SEEK_CUR);
329
330 break;
331
332 case JPEG_SOS:
333 /*
334 if(!finishedEncoding)
335 SWF_error("Found SOS before SOF in Jpeg file!");
336 */
337 break;
338
339 default:
340 /* length += */
341 skipJpegBlock(input); /* + 2 */
342 }
343
344 if ( c == JPEG_SOS )
345 break;
346
347 if ( SWFInput_eof(input) )
348 SWF_error("Unexpected end of Jpeg file (EOF found)!");
349 }
350
351 if ( c != JPEG_SOS )
352 SWF_error("SOS block not found in Jpeg file!");
353
354 /* rest is SOS, dump to end of file */
355
356 length += 2; /* SOS tag */
357
358 /* figure out how long the rest of the file is */
359 pos = SWFInput_tell(input);
360 SWFInput_seek(input, 0, SEEK_END);
361 end = SWFInput_tell(input);
362
363 length += end - pos;
364
365 info->length = length;
366
367 return info;
368 }
369
370
371 SWFJpegBitmap
newSWFJpegBitmap_fromInput(SWFInput input)372 newSWFJpegBitmap_fromInput(SWFInput input)
373 {
374 SWFJpegBitmap jpeg;
375 struct jpegInfo *info;
376 SWFRect temp_rect;
377
378 jpeg = (SWFJpegBitmap) malloc(sizeof(struct SWFJpegBitmap_s));
379
380 /* If malloc failed, return NULL to signify this */
381 if (NULL == jpeg)
382 return NULL;
383
384 SWFCharacterInit((SWFCharacter)jpeg);
385
386 CHARACTERID(jpeg) = ++SWF_gNumCharacters;
387
388 BLOCK(jpeg)->writeBlock = writeSWFJpegBitmapToMethod;
389 BLOCK(jpeg)->complete = completeSWFJpegBitmap;
390 BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap;
391 BLOCK(jpeg)->type = SWF_DEFINEBITSJPEG2;
392
393 jpeg->input = input;
394
395 info = scanJpegFile(input);
396
397 /* If scanJpegFile() failed, return NULL to signify this */
398 if (NULL == info)
399 {
400 free (jpeg);
401 return NULL;
402 }
403
404 temp_rect = newSWFRect(0, info->width, 0, info->height);
405
406 /* If newSWFRect() failed, return NULL to signify this */
407 if (NULL == temp_rect)
408 {
409 free(info);
410 free(jpeg);
411 return NULL;
412 }
413
414 CHARACTER(jpeg)->bounds = temp_rect;
415 jpeg->length = info->length + 4;
416
417 free(info);
418
419 #if TRACK_ALLOCS
420 jpeg->gcnode = ming_gc_add_node(jpeg, (dtorfunctype) destroySWFBitmap);
421 #endif
422
423 return jpeg;
424 }
425
426
427 static void
destroySWFJpegBitmap_andInputs(SWFJpegBitmap jpegBitmap)428 destroySWFJpegBitmap_andInputs(SWFJpegBitmap jpegBitmap)
429 {
430 destroySWFInput(jpegBitmap->input);
431 destroySWFJpegBitmap(jpegBitmap);
432 }
433
434
435 SWFJpegBitmap
newSWFJpegBitmap(FILE * f)436 newSWFJpegBitmap(FILE *f)
437 {
438 SWFJpegBitmap jpeg = newSWFJpegBitmap_fromInput(newSWFInput_file(f));
439
440 /* If newSWFJpegBitmap_fromInput() failed, return NULL to signify this */
441 if (NULL == jpeg)
442 return NULL;
443
444 BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap_andInputs;
445 return jpeg;
446 }
447
448
449 /* f is a jpeg file, alpha is zlib-compressed data */
450
451 SWFJpegWithAlpha
newSWFJpegWithAlpha_fromInput(SWFInput input,SWFInput alpha)452 newSWFJpegWithAlpha_fromInput(SWFInput input, SWFInput alpha)
453 {
454 SWFRect temp_rect;
455 SWFJpegWithAlpha jpeg;
456 struct jpegInfo *info;
457 int alen;
458
459 jpeg = (SWFJpegWithAlpha) malloc(sizeof(struct SWFJpegWithAlpha_s));
460
461 /* If malloc failed, return NULL to signify this */
462 if (NULL == jpeg)
463 return NULL;
464
465 SWFCharacterInit((SWFCharacter)jpeg);
466
467 CHARACTERID(jpeg) = ++SWF_gNumCharacters;
468
469 BLOCK(jpeg)->writeBlock = writeSWFJpegWithAlphaToMethod;
470 BLOCK(jpeg)->complete = completeSWFJpegBitmap; // can use same complete
471 BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegBitmap; // ditto here
472 BLOCK(jpeg)->type = SWF_DEFINEBITSJPEG3;
473
474 jpeg->input = input;
475 jpeg->alpha = alpha;
476
477 info = scanJpegFile(input);
478
479 /* If scanJpegFile() failed, return NULL to signify this */
480 if (NULL == info)
481 {
482 free (jpeg);
483 return NULL;
484 }
485
486 temp_rect = newSWFRect(0, info->width, 0, info->height);
487
488 /* If newSWFRect() failed, return NULL to signify this */
489 if (NULL == temp_rect)
490 {
491 free(info);
492 free(jpeg);
493 return NULL;
494 }
495
496 CHARACTER(jpeg)->bounds = temp_rect;
497 jpeg->jpegLength = info->length + 2; /* ?? */
498
499 free(info);
500
501 if ( (alen = SWFInput_length(alpha)) == -1 )
502 SWF_error("couldn't get alpha file length!");
503
504 jpeg->length = jpeg->jpegLength + alen + 6;
505 #if TRACK_ALLOCS
506 jpeg->gcnode = ming_gc_add_node(jpeg, (dtorfunctype) destroySWFBitmap);
507 #endif
508
509 return jpeg;
510 }
511
512
513 void
destroySWFJpegAlpha_andInputs(SWFJpegWithAlpha jpegWithAlpha)514 destroySWFJpegAlpha_andInputs(SWFJpegWithAlpha jpegWithAlpha)
515 {
516 destroySWFInput(jpegWithAlpha->input);
517 destroySWFInput(jpegWithAlpha->alpha);
518 destroySWFJpegBitmap((SWFJpegBitmap) jpegWithAlpha);
519 }
520
521
522 SWFJpegWithAlpha
newSWFJpegWithAlpha(FILE * f,FILE * alpha)523 newSWFJpegWithAlpha(FILE *f, FILE *alpha)
524 {
525 SWFJpegWithAlpha jpeg =
526 newSWFJpegWithAlpha_fromInput(newSWFInput_file(f), newSWFInput_file(alpha));
527
528 /* If newSWFJpegBitmap_fromInput() failed, return NULL to signify this */
529 if (NULL == jpeg)
530 return NULL;
531
532 BLOCK(jpeg)->dtor = (destroySWFBlockMethod) destroySWFJpegAlpha_andInputs;
533 return jpeg;
534 }
535
536
537 /*
538 * Local variables:
539 * tab-width: 2
540 * c-basic-offset: 2
541 * End:
542 */
543