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
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
)
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
);
58 swfdec_image_class_init (SwfdecImageClass
* g_class
)
60 GObjectClass
*object_class
= G_OBJECT_CLASS (g_class
);
62 object_class
->dispose
= swfdec_image_dispose
;
66 swfdec_image_init (SwfdecImage
* image
)
71 swfdec_image_jpegtables (SwfdecSwfDecoder
* s
, guint tag
)
73 SwfdecBits
*bits
= &s
->b
;
75 SWFDEC_DEBUG ("swfdec_image_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
;
87 tag_func_define_bits_jpeg (SwfdecSwfDecoder
* s
, guint tag
)
89 SwfdecBits
*bits
= &s
->b
;
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
);
99 return SWFDEC_STATUS_OK
;
101 image
->type
= SWFDEC_IMAGE_TYPE_JPEG
;
102 if (!s
->jpegtables
) {
103 SWFDEC_ERROR("No global JPEG tables available");
105 image
->jpegtables
= swfdec_buffer_ref (s
->jpegtables
);
107 image
->raw_data
= swfdec_bits_get_buffer (bits
, -1);
109 return SWFDEC_STATUS_OK
;
113 swfdec_image_validate_size (SwfdecRenderer
*renderer
, guint width
, guint height
)
117 if (width
== 0 || height
== 0)
121 size
= swfdec_renderer_get_max_cache_size (renderer
);
122 size
= MIN (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
);
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.
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
)
152 unsigned char *tmpdata
;
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
);
164 ret
= jpeg_decode_argb (data1
, length1
, outdata
, width
, height
);
170 ret
= swfdec_image_validate_size (renderer
, *width
, *height
);
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
;
181 surface
= swfdec_renderer_create_for_data (renderer
, data
, format
, width
, height
, rowstride
);
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
);
191 static cairo_surface_t
*
192 swfdec_image_jpeg_load (SwfdecImage
*image
, SwfdecRenderer
*renderer
)
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
);
203 ret
= swfdec_jpeg_decode_argb (renderer
,
204 image
->raw_data
->data
, image
->raw_data
->length
,
206 (void *)&data
, &image
->width
, &image
->height
);
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
;
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
);
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
)
245 ret
= swfdec_jpeg_decode_argb (renderer
, image
->raw_data
->data
, image
->raw_data
->length
,
247 (void *)&data
, &image
->width
, &image
->height
);
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
;
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
);
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
;
279 merge_alpha (SwfdecImage
* image
, unsigned char *image_data
,
280 unsigned char *alpha
)
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
]);
298 static cairo_surface_t
*
299 swfdec_image_jpeg3_load (SwfdecImage
*image
, SwfdecRenderer
*renderer
)
302 SwfdecBuffer
*buffer
;
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
);
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
);
322 buffer
= swfdec_bits_decompress (&bits
, -1, image
->width
* image
->height
);
324 merge_alpha (image
, data
, buffer
->data
);
325 swfdec_buffer_unref (buffer
);
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
)
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
))
363 SwfdecBuffer
*buffer
;
364 guchar
*indexed_data
;
365 guint32 palette
[256], *pixels
;
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
);
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
);
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;
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
);
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
]];
412 indexed_data
+= rowstride
;
415 swfdec_buffer_unref (buffer
);
416 } else if (format
== 4) {
419 unsigned char *idata
;
420 SwfdecBuffer
*buffer
;
423 SWFDEC_INFO("16bit images aren't allowed to have alpha, ignoring");
427 buffer
= swfdec_bits_decompress (&bits
, -1, 2 * ((image
->width
+ 1) & ~1) * image
->height
);
428 data
= g_malloc (4 * image
->width
* image
->height
);
430 if (buffer
== NULL
) {
431 SWFDEC_ERROR ("failed to decompress data");
432 memset (data
, 0, 4 * image
->width
* image
->height
);
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;
448 if (image
->width
& 1)
451 swfdec_buffer_unref (buffer
);
452 } else if (format
== 5) {
453 SwfdecBuffer
*buffer
;
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
);
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
);
472 data
= g_memdup (buffer
->data
, buffer
->length
);
473 swfdec_buffer_unref (buffer
);
475 SWFDEC_ERROR ("unknown lossless image format %u", format
);
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
)
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
);
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
)
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
);
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
;
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
)
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
);
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
);
562 surface
= swfdec_renderer_create_similar (renderer
, surface
);
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
),
574 if (trans
->mask
!= ctrans
.mask
)
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
)
593 SwfdecCached
*cached
= swfdec_renderer_get_cache (renderer
, image
,
594 swfdec_image_find_by_transform
, (gpointer
) trans
);
596 swfdec_cached_use (cached
);
597 return swfdec_cached_image_get_surface (SWFDEC_CACHED_IMAGE (cached
));
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
)
616 swfdec_color_transform_init_identity (&trans
);
617 surface
= swfdec_image_lookup_surface (image
, renderer
, &trans
);
621 switch (image
->type
) {
622 case SWFDEC_IMAGE_TYPE_JPEG
:
623 surface
= swfdec_image_jpeg_load (image
, renderer
);
625 case SWFDEC_IMAGE_TYPE_JPEG2
:
626 surface
= swfdec_image_jpeg2_load (image
, renderer
);
628 case SWFDEC_IMAGE_TYPE_JPEG3
:
629 surface
= swfdec_image_jpeg3_load (image
, renderer
);
631 case SWFDEC_IMAGE_TYPE_LOSSLESS
:
632 surface
= swfdec_image_lossless_load (image
, renderer
);
634 case SWFDEC_IMAGE_TYPE_LOSSLESS2
:
635 surface
= swfdec_image_lossless_load (image
, renderer
);
637 case SWFDEC_IMAGE_TYPE_PNG
:
638 surface
= swfdec_image_png_load (image
, renderer
);
640 case SWFDEC_IMAGE_TYPE_UNKNOWN
:
642 g_assert_not_reached ();
645 if (surface
== NULL
) {
646 SWFDEC_WARNING ("failed to decode image");
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
);
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
);
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
);
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
);
699 area
.width
= image
->width
;
700 area
.height
= image
->height
;
701 surface
= swfdec_renderer_transform (renderer
, source
, trans
, &area
);
702 cairo_surface_destroy (source
);
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
);
714 /* NB: must be at least SWFDEC_DECODER_DETECT_LENGTH bytes */
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
;
726 return SWFDEC_IMAGE_TYPE_UNKNOWN
;
730 swfdec_image_new (SwfdecBuffer
*buffer
)
733 SwfdecImageType type
;
735 g_return_val_if_fail (buffer
!= NULL
, NULL
);
737 /* check type of the image */
738 if (buffer
->length
< 4)
740 type
= swfdec_image_detect (buffer
->data
);
741 if (type
== SWFDEC_IMAGE_TYPE_UNKNOWN
)
744 image
= g_object_new (SWFDEC_TYPE_IMAGE
, NULL
);
746 image
->raw_data
= buffer
;
751 swfdec_buffer_unref (buffer
);