fix build for --disable-gtk-doc
[swfdec.git] / swfdec / swfdec_image.c
blob375de6a74c07692a29cf142f4eb200ef9a86a82b
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2008 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <stdio.h>
27 #include <zlib.h>
28 #include <string.h>
30 #include "jpeg.h"
31 #include "swfdec_image.h"
32 #include "swfdec_cache.h"
33 #include "swfdec_cached_image.h"
34 #include "swfdec_debug.h"
35 #include "swfdec_renderer_internal.h"
36 #include "swfdec_swf_decoder.h"
38 G_DEFINE_TYPE (SwfdecImage, swfdec_image, SWFDEC_TYPE_CHARACTER)
40 static void
41 swfdec_image_dispose (GObject *object)
43 SwfdecImage * image = SWFDEC_IMAGE (object);
45 if (image->jpegtables) {
46 swfdec_buffer_unref (image->jpegtables);
47 image->jpegtables = NULL;
49 if (image->raw_data) {
50 swfdec_buffer_unref (image->raw_data);
51 image->raw_data = NULL;
54 G_OBJECT_CLASS (swfdec_image_parent_class)->dispose (object);
57 static void
58 swfdec_image_class_init (SwfdecImageClass * g_class)
60 GObjectClass *object_class = G_OBJECT_CLASS (g_class);
62 object_class->dispose = swfdec_image_dispose;
65 static void
66 swfdec_image_init (SwfdecImage * image)
70 int
71 swfdec_image_jpegtables (SwfdecSwfDecoder * s, guint tag)
73 SwfdecBits *bits = &s->b;
75 SWFDEC_DEBUG ("swfdec_image_jpegtables");
77 if (s->jpegtables) {
78 SWFDEC_FIXME ("duplicate DefineJPEGTables tag. Deleting first one");
79 swfdec_buffer_unref (s->jpegtables);
81 s->jpegtables = swfdec_bits_get_buffer (bits, -1);
83 return SWFDEC_STATUS_OK;
86 int
87 tag_func_define_bits_jpeg (SwfdecSwfDecoder * s, guint tag)
89 SwfdecBits *bits = &s->b;
90 int id;
91 SwfdecImage *image;
93 SWFDEC_LOG ("tag_func_define_bits_jpeg");
94 id = swfdec_bits_get_u16 (bits);
95 SWFDEC_LOG (" id = %d", id);
97 image = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_IMAGE);
98 if (!image)
99 return SWFDEC_STATUS_OK;
101 image->type = SWFDEC_IMAGE_TYPE_JPEG;
102 if (!s->jpegtables) {
103 SWFDEC_ERROR("No global JPEG tables available");
104 } else {
105 image->jpegtables = swfdec_buffer_ref (s->jpegtables);
107 image->raw_data = swfdec_bits_get_buffer (bits, -1);
109 return SWFDEC_STATUS_OK;
112 static gboolean
113 swfdec_image_validate_size (SwfdecRenderer *renderer, guint width, guint height)
115 gsize size;
117 if (width == 0 || height == 0)
118 return FALSE;
120 if (renderer) {
121 size = swfdec_renderer_get_max_cache_size (renderer);
122 size = MIN (size, G_MAXUINT);
123 } else {
124 size = G_MAXUINT;
126 if (size / 4 / width < height) {
127 SWFDEC_ERROR ("%ux%u image doesn't fit into %zu bytes of cache",
128 width, height, size);
129 return FALSE;
132 return TRUE;
136 * swfdec_jpeg_decode_argb:
138 * This is a wrapper around jpeg_decode_argb() that takes two segments,
139 * strips off (sometimes bogus) start-of-image and end-of-image codes,
140 * concatenates them, and puts new SOI and EOI codes on the resulting
141 * buffer. This makes a real JPEG image out of the crap in SWF files.
143 static gboolean
144 swfdec_jpeg_decode_argb (SwfdecRenderer *renderer,
145 unsigned char *data1, int length1,
146 unsigned char *data2, int length2,
147 void *outdata, guint *width, guint *height)
149 gboolean ret;
151 if (data2) {
152 unsigned char *tmpdata;
153 int tmplength;
155 tmplength = length1 + length2;
156 tmpdata = g_malloc (tmplength);
158 memcpy (tmpdata, data1, length1);
159 memcpy (tmpdata + length1, data2, length2);
160 ret = jpeg_decode_argb (tmpdata, tmplength, outdata, width, height);
162 g_free (tmpdata);
163 } else if (data1) {
164 ret = jpeg_decode_argb (data1, length1, outdata, width, height);
165 } else {
166 ret = FALSE;
169 if (ret)
170 ret = swfdec_image_validate_size (renderer, *width, *height);
171 return ret;
174 static cairo_surface_t *
175 swfdec_image_create_surface_for_data (SwfdecRenderer *renderer, guint8 *data,
176 cairo_format_t format, guint width, guint height, guint rowstride)
178 cairo_surface_t *surface;
180 if (renderer) {
181 surface = swfdec_renderer_create_for_data (renderer, data, format, width, height, rowstride);
182 } else {
183 static const cairo_user_data_key_t key;
184 surface = cairo_image_surface_create_for_data (data,
185 format, width, height, rowstride);
186 cairo_surface_set_user_data (surface, &key, data, g_free);
188 return surface;
191 static cairo_surface_t *
192 swfdec_image_jpeg_load (SwfdecImage *image, SwfdecRenderer *renderer)
194 gboolean ret;
195 guint8 *data;
197 if (image->jpegtables) {
198 ret = swfdec_jpeg_decode_argb (renderer,
199 image->jpegtables->data, image->jpegtables->length,
200 image->raw_data->data, image->raw_data->length,
201 (void *) &data, &image->width, &image->height);
202 } else {
203 ret = swfdec_jpeg_decode_argb (renderer,
204 image->raw_data->data, image->raw_data->length,
205 NULL, 0,
206 (void *)&data, &image->width, &image->height);
209 if (!ret)
210 return NULL;
212 SWFDEC_LOG (" width = %d", image->width);
213 SWFDEC_LOG (" height = %d", image->height);
215 return swfdec_image_create_surface_for_data (renderer, data,
216 CAIRO_FORMAT_RGB24, image->width, image->height, 4 * image->width);
220 tag_func_define_bits_jpeg_2 (SwfdecSwfDecoder * s, guint tag)
222 SwfdecBits *bits = &s->b;
223 int id;
224 SwfdecImage *image;
226 id = swfdec_bits_get_u16 (bits);
227 SWFDEC_LOG (" id = %d", id);
229 image = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_IMAGE);
230 if (!image)
231 return SWFDEC_STATUS_OK;
233 image->type = SWFDEC_IMAGE_TYPE_JPEG2;
234 image->raw_data = swfdec_bits_get_buffer (bits, -1);
236 return SWFDEC_STATUS_OK;
239 static cairo_surface_t *
240 swfdec_image_jpeg2_load (SwfdecImage *image, SwfdecRenderer *renderer)
242 gboolean ret;
243 guint8 *data;
245 ret = swfdec_jpeg_decode_argb (renderer, image->raw_data->data, image->raw_data->length,
246 NULL, 0,
247 (void *)&data, &image->width, &image->height);
248 if (!ret)
249 return NULL;
251 SWFDEC_LOG (" width = %d", image->width);
252 SWFDEC_LOG (" height = %d", image->height);
254 return swfdec_image_create_surface_for_data (renderer, data,
255 CAIRO_FORMAT_RGB24, image->width, image->height, 4 * image->width);
259 tag_func_define_bits_jpeg_3 (SwfdecSwfDecoder * s, guint tag)
261 SwfdecBits *bits = &s->b;
262 guint id;
263 SwfdecImage *image;
265 id = swfdec_bits_get_u16 (bits);
266 SWFDEC_LOG (" id = %d", id);
268 image = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_IMAGE);
269 if (!image)
270 return SWFDEC_STATUS_OK;
272 image->type = SWFDEC_IMAGE_TYPE_JPEG3;
273 image->raw_data = swfdec_bits_get_buffer (bits, -1);
275 return SWFDEC_STATUS_OK;
278 static void
279 merge_alpha (SwfdecImage * image, unsigned char *image_data,
280 unsigned char *alpha)
282 unsigned int x, y;
283 unsigned char *p;
285 for (y = 0; y < image->height; y++) {
286 p = image_data + y * image->width * 4;
287 for (x = 0; x < image->width; x++) {
288 p[SWFDEC_COLOR_INDEX_ALPHA] = *alpha;
289 p[SWFDEC_COLOR_INDEX_RED] = MIN (*alpha, p[SWFDEC_COLOR_INDEX_RED]);
290 p[SWFDEC_COLOR_INDEX_GREEN] = MIN (*alpha, p[SWFDEC_COLOR_INDEX_GREEN]);
291 p[SWFDEC_COLOR_INDEX_BLUE] = MIN (*alpha, p[SWFDEC_COLOR_INDEX_BLUE]);
292 p += 4;
293 alpha++;
298 static cairo_surface_t *
299 swfdec_image_jpeg3_load (SwfdecImage *image, SwfdecRenderer *renderer)
301 SwfdecBits bits;
302 SwfdecBuffer *buffer;
303 int jpeg_length;
304 gboolean ret;
305 guint8 *data;
307 swfdec_bits_init (&bits, image->raw_data);
309 jpeg_length = swfdec_bits_get_u32 (&bits);
310 buffer = swfdec_bits_get_buffer (&bits, jpeg_length);
311 if (buffer == NULL)
312 return NULL;
314 ret = swfdec_jpeg_decode_argb (renderer,
315 buffer->data, buffer->length, NULL, 0,
316 (void *)&data, &image->width, &image->height);
317 swfdec_buffer_unref (buffer);
319 if (!ret)
320 return NULL;
322 buffer = swfdec_bits_decompress (&bits, -1, image->width * image->height);
323 if (buffer) {
324 merge_alpha (image, data, buffer->data);
325 swfdec_buffer_unref (buffer);
326 } else {
327 SWFDEC_WARNING ("cannot set alpha channel information, decompression failed");
330 SWFDEC_LOG (" width = %d", image->width);
331 SWFDEC_LOG (" height = %d", image->height);
333 return swfdec_image_create_surface_for_data (renderer, data,
334 CAIRO_FORMAT_ARGB32, image->width, image->height, 4 * image->width);
337 static cairo_surface_t *
338 swfdec_image_lossless_load (SwfdecImage *image, SwfdecRenderer *renderer)
340 int format;
341 unsigned char *ptr;
342 SwfdecBits bits;
343 guint8 *data;
344 int have_alpha = (image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2);
346 swfdec_bits_init (&bits, image->raw_data);
348 format = swfdec_bits_get_u8 (&bits);
349 SWFDEC_LOG (" format = %d", format);
350 image->width = swfdec_bits_get_u16 (&bits);
351 SWFDEC_LOG (" width = %d", image->width);
352 image->height = swfdec_bits_get_u16 (&bits);
353 SWFDEC_LOG (" height = %d", image->height);
355 SWFDEC_LOG ("format = %d", format);
356 SWFDEC_LOG ("width = %d", image->width);
357 SWFDEC_LOG ("height = %d", image->height);
359 if (!swfdec_image_validate_size (renderer, image->width, image->height))
360 return NULL;
362 if (format == 3) {
363 SwfdecBuffer *buffer;
364 guchar *indexed_data;
365 guint32 palette[256], *pixels;
366 guint i, j;
367 guint palette_size;
368 guint rowstride = (image->width + 3) & ~3;
370 palette_size = swfdec_bits_get_u8 (&bits) + 1;
371 SWFDEC_LOG ("palette_size = %d", palette_size);
373 data = g_malloc (4 * image->width * image->height);
375 if (have_alpha) {
376 buffer = swfdec_bits_decompress (&bits, -1, palette_size * 4 + rowstride * image->height);
377 if (buffer == NULL) {
378 SWFDEC_ERROR ("failed to decompress data");
379 memset (data, 0, 4 * image->width * image->height);
380 goto out;
382 ptr = buffer->data;
383 for (i = 0; i < palette_size; i++) {
384 palette[i] = SWFDEC_COLOR_COMBINE (ptr[i * 4 + 0], ptr[i * 4 + 1],
385 ptr[i * 4 + 2], ptr[i * 4 + 3]);
387 indexed_data = ptr + palette_size * 4;
388 } else {
389 buffer = swfdec_bits_decompress (&bits, -1, palette_size * 3 + rowstride * image->height);
390 if (buffer == NULL) {
391 SWFDEC_ERROR ("failed to decompress data");
392 memset (data, 0, 4 * image->width * image->height);
393 goto out;
395 ptr = buffer->data;
396 for (i = 0; i < palette_size; i++) {
397 palette[i] = SWFDEC_COLOR_COMBINE (ptr[i * 3 + 0],
398 ptr[i * 3 + 1], ptr[i * 3 + 2], 0xFF);
400 indexed_data = ptr + palette_size * 3;
402 if (palette_size < 256)
403 memset (palette + palette_size, 0, (256 - palette_size) * 4);
405 /* cast is safe, we malloc'd the memory above */
406 pixels = (guint32 *) (gpointer) data;
407 for (j = 0; j < (guint) image->height; j++) {
408 for (i = 0; i < (guint) image->width; i++) {
409 *pixels = palette[indexed_data[i]];
410 pixels++;
412 indexed_data += rowstride;
415 swfdec_buffer_unref (buffer);
416 } else if (format == 4) {
417 guint i, j;
418 guint c;
419 unsigned char *idata;
420 SwfdecBuffer *buffer;
422 if (have_alpha) {
423 SWFDEC_INFO("16bit images aren't allowed to have alpha, ignoring");
424 have_alpha = FALSE;
427 buffer = swfdec_bits_decompress (&bits, -1, 2 * ((image->width + 1) & ~1) * image->height);
428 data = g_malloc (4 * image->width * image->height);
429 idata = data;
430 if (buffer == NULL) {
431 SWFDEC_ERROR ("failed to decompress data");
432 memset (data, 0, 4 * image->width * image->height);
433 goto out;
435 ptr = buffer->data;
437 /* 15 bit packed */
438 for (j = 0; j < image->height; j++) {
439 for (i = 0; i < image->width; i++) {
440 c = ptr[1] | (ptr[0] << 8);
441 idata[SWFDEC_COLOR_INDEX_BLUE] = (c << 3) | ((c >> 2) & 0x7);
442 idata[SWFDEC_COLOR_INDEX_GREEN] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7);
443 idata[SWFDEC_COLOR_INDEX_RED] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7);
444 idata[SWFDEC_COLOR_INDEX_ALPHA] = 0xff;
445 ptr += 2;
446 idata += 4;
448 if (image->width & 1)
449 ptr += 2;
451 swfdec_buffer_unref (buffer);
452 } else if (format == 5) {
453 SwfdecBuffer *buffer;
454 guint i, j;
455 guint32 *p;
457 buffer = swfdec_bits_decompress (&bits, -1, 4 * image->width * image->height);
458 if (buffer == NULL) {
459 SWFDEC_ERROR ("failed to decompress data");
460 data = g_malloc0 (4 * image->width * image->height);
461 goto out;
463 data = buffer->data;
464 p = (void *) data;
465 /* image is stored in 0RGB format. We use ARGB/BGRA. */
466 for (j = 0; j < image->height; j++) {
467 for (i = 0; i < image->width; i++) {
468 *p = GUINT32_FROM_BE (*p);
469 p++;
472 data = g_memdup (buffer->data, buffer->length);
473 swfdec_buffer_unref (buffer);
474 } else {
475 SWFDEC_ERROR ("unknown lossless image format %u", format);
476 return NULL;
479 out:
480 return swfdec_image_create_surface_for_data (renderer, data,
481 have_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
482 image->width, image->height, image->width * 4);
486 tag_func_define_bits_lossless (SwfdecSwfDecoder * s, guint tag)
488 SwfdecImage *image;
489 int id;
490 SwfdecBits *bits = &s->b;
492 id = swfdec_bits_get_u16 (bits);
493 SWFDEC_LOG (" id = %d", id);
495 image = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_IMAGE);
496 if (!image)
497 return SWFDEC_STATUS_OK;
499 image->type = SWFDEC_IMAGE_TYPE_LOSSLESS;
500 image->raw_data = swfdec_bits_get_buffer (bits, -1);
502 return SWFDEC_STATUS_OK;
506 tag_func_define_bits_lossless_2 (SwfdecSwfDecoder * s, guint tag)
508 SwfdecImage *image;
509 int id;
510 SwfdecBits *bits = &s->b;
512 id = swfdec_bits_get_u16 (bits);
513 SWFDEC_LOG (" id = %d", id);
515 image = swfdec_swf_decoder_create_character (s, id, SWFDEC_TYPE_IMAGE);
516 if (!image)
517 return SWFDEC_STATUS_OK;
519 image->type = SWFDEC_IMAGE_TYPE_LOSSLESS2;
520 image->raw_data = swfdec_bits_get_buffer (bits, -1);
522 return SWFDEC_STATUS_OK;
525 static cairo_status_t
526 swfdec_image_png_read (void *bitsp, unsigned char *data, unsigned int length)
528 SwfdecBits *bits = bitsp;
529 const guint8 *ptr;
531 ptr = bits->ptr;
532 if (swfdec_bits_skip_bytes (bits, length) != length)
533 return CAIRO_STATUS_READ_ERROR;
535 memcpy (data, ptr, length);
536 return CAIRO_STATUS_SUCCESS;
539 static cairo_surface_t *
540 swfdec_image_png_load (SwfdecImage *image, SwfdecRenderer *renderer)
542 SwfdecBits bits;
543 cairo_surface_t *surface;
545 swfdec_bits_init (&bits, image->raw_data);
546 surface = cairo_image_surface_create_from_png_stream (
547 swfdec_image_png_read, &bits);
548 if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
549 SWFDEC_ERROR ("could not create PNG image: %s",
550 cairo_status_to_string (cairo_surface_status (surface)));
551 cairo_surface_destroy (surface);
552 return NULL;
555 image->width = cairo_image_surface_get_width (surface);
556 image->height = cairo_image_surface_get_height (surface);
557 if (!swfdec_image_validate_size (renderer, image->width, image->height)) {
558 cairo_surface_destroy (surface);
559 return NULL;
561 if (renderer)
562 surface = swfdec_renderer_create_similar (renderer, surface);
563 return surface;
566 static gboolean
567 swfdec_image_find_by_transform (SwfdecCached *cached, gpointer data)
569 const SwfdecColorTransform *trans = data;
570 SwfdecColorTransform ctrans;
572 swfdec_cached_image_get_color_transform (SWFDEC_CACHED_IMAGE (cached),
573 &ctrans);
574 if (trans->mask != ctrans.mask)
575 return FALSE;
576 if (trans->mask)
577 return TRUE;
578 return (trans->ra == ctrans.ra &&
579 trans->rb == ctrans.rb &&
580 trans->ga == ctrans.ga &&
581 trans->gb == ctrans.gb &&
582 trans->ba == ctrans.ba &&
583 trans->bb == ctrans.bb &&
584 trans->aa == ctrans.aa &&
585 trans->ab == ctrans.ab);
588 static cairo_surface_t *
589 swfdec_image_lookup_surface (SwfdecImage *image, SwfdecRenderer *renderer,
590 const SwfdecColorTransform *trans)
592 if (renderer) {
593 SwfdecCached *cached = swfdec_renderer_get_cache (renderer, image,
594 swfdec_image_find_by_transform, (gpointer) trans);
595 if (cached) {
596 swfdec_cached_use (cached);
597 return swfdec_cached_image_get_surface (SWFDEC_CACHED_IMAGE (cached));
600 return NULL;
603 cairo_surface_t *
604 swfdec_image_create_surface (SwfdecImage *image, SwfdecRenderer *renderer)
606 SwfdecColorTransform trans;
607 SwfdecCachedImage *cached;
608 cairo_surface_t *surface;
610 g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL);
611 g_return_val_if_fail (renderer == NULL || SWFDEC_IS_RENDERER (renderer), NULL);
613 if (image->raw_data == NULL)
614 return NULL;
616 swfdec_color_transform_init_identity (&trans);
617 surface = swfdec_image_lookup_surface (image, renderer, &trans);
618 if (surface)
619 return surface;
621 switch (image->type) {
622 case SWFDEC_IMAGE_TYPE_JPEG:
623 surface = swfdec_image_jpeg_load (image, renderer);
624 break;
625 case SWFDEC_IMAGE_TYPE_JPEG2:
626 surface = swfdec_image_jpeg2_load (image, renderer);
627 break;
628 case SWFDEC_IMAGE_TYPE_JPEG3:
629 surface = swfdec_image_jpeg3_load (image, renderer);
630 break;
631 case SWFDEC_IMAGE_TYPE_LOSSLESS:
632 surface = swfdec_image_lossless_load (image, renderer);
633 break;
634 case SWFDEC_IMAGE_TYPE_LOSSLESS2:
635 surface = swfdec_image_lossless_load (image, renderer);
636 break;
637 case SWFDEC_IMAGE_TYPE_PNG:
638 surface = swfdec_image_png_load (image, renderer);
639 break;
640 case SWFDEC_IMAGE_TYPE_UNKNOWN:
641 default:
642 g_assert_not_reached ();
643 break;
645 if (surface == NULL) {
646 SWFDEC_WARNING ("failed to decode image");
647 return NULL;
649 if (renderer) {
650 /* FIXME: The size is just an educated guess */
651 cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
652 swfdec_renderer_add_cache (renderer, FALSE, image, SWFDEC_CACHED (cached));
653 g_object_unref (cached);
656 return surface;
659 cairo_surface_t *
660 swfdec_image_create_surface_transformed (SwfdecImage *image, SwfdecRenderer *renderer,
661 const SwfdecColorTransform *trans)
663 SwfdecColorTransform mask;
664 SwfdecCachedImage *cached;
665 cairo_surface_t *surface, *source;
666 SwfdecRectangle area;
668 g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL);
669 g_return_val_if_fail (renderer == NULL || SWFDEC_IS_RENDERER (renderer), NULL);
670 g_return_val_if_fail (trans != NULL, NULL);
671 /* The mask flag is used for caching image surfaces.
672 * Instead of masking with images, code should use color patterns */
673 g_return_val_if_fail (!swfdec_color_transform_is_mask (trans), NULL);
675 surface = swfdec_image_lookup_surface (image, renderer, trans);
676 if (surface)
677 return surface;
678 /* obvious optimization */
679 if (swfdec_color_transform_is_identity (trans))
680 return swfdec_image_create_surface (image, renderer);
682 /* need to create an image surface here, so we can modify it. Will upload later */
683 /* NB: we use the mask property here to inidicate an image surface */
684 swfdec_color_transform_init_mask (&mask);
685 source = swfdec_image_lookup_surface (image, renderer, &mask);
686 if (source == NULL) {
687 source = swfdec_image_create_surface (image, NULL);
688 if (source == NULL)
689 return NULL;
690 if (renderer) {
691 cached = swfdec_cached_image_new (source, image->width * image->height * 4);
692 swfdec_cached_image_set_color_transform (cached, &mask);
693 swfdec_renderer_add_cache (renderer, FALSE, image, SWFDEC_CACHED (cached));
694 g_object_unref (cached);
698 area.x = area.y = 0;
699 area.width = image->width;
700 area.height = image->height;
701 surface = swfdec_renderer_transform (renderer, source, trans, &area);
702 cairo_surface_destroy (source);
703 if (renderer) {
704 surface = swfdec_renderer_create_similar (renderer, surface);
705 /* FIXME: The size is just an educated guess */
706 cached = swfdec_cached_image_new (surface, image->width * image->height * 4);
707 swfdec_cached_image_set_color_transform (cached, trans);
708 swfdec_renderer_add_cache (renderer, FALSE, image, SWFDEC_CACHED (cached));
709 g_object_unref (cached);
711 return surface;
714 /* NB: must be at least SWFDEC_DECODER_DETECT_LENGTH bytes */
715 SwfdecImageType
716 swfdec_image_detect (const guint8 *data)
718 g_return_val_if_fail (data != NULL, SWFDEC_IMAGE_TYPE_UNKNOWN);
720 if (data[0] == 0xFF && data[1] == 0xD8)
721 return SWFDEC_IMAGE_TYPE_JPEG2;
722 else if (data[0] == 0x89 && data[1] == 'P' &&
723 data[2] == 'N' && data[3] == 'G')
724 return SWFDEC_IMAGE_TYPE_PNG;
725 else
726 return SWFDEC_IMAGE_TYPE_UNKNOWN;
729 SwfdecImage *
730 swfdec_image_new (SwfdecBuffer *buffer)
732 SwfdecImage *image;
733 SwfdecImageType type;
735 g_return_val_if_fail (buffer != NULL, NULL);
737 /* check type of the image */
738 if (buffer->length < 4)
739 goto fail;
740 type = swfdec_image_detect (buffer->data);
741 if (type == SWFDEC_IMAGE_TYPE_UNKNOWN)
742 goto fail;
744 image = g_object_new (SWFDEC_TYPE_IMAGE, NULL);
745 image->type = type;
746 image->raw_data = buffer;
748 return image;
750 fail:
751 swfdec_buffer_unref (buffer);
752 return NULL;