Benjamin Otte
2007-Feb-06 03:18 UTC
[Swfdec] 21 commits - configure.ac libswfdec/swfdec_audio_event.c libswfdec/swfdec_bits.c libswfdec/swfdec_button_movie.c libswfdec/swfdec_color.c libswfdec/swfdec_color.h libswfdec/swfdec_compiler.c libswfdec/swfdec_edittext.c libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_pattern.c libswfdec/swfdec_sprite.c libswfdec/swfdec_sprite_movie.c test/image test/Makefile.am test/sound test/swfdec-extract.c
configure.ac | 1 libswfdec/swfdec_audio_event.c | 1 libswfdec/swfdec_bits.c | 4 libswfdec/swfdec_button_movie.c | 3 libswfdec/swfdec_color.c | 67 +++++- libswfdec/swfdec_color.h | 31 ++- libswfdec/swfdec_compiler.c | 5 libswfdec/swfdec_edittext.c | 2 libswfdec/swfdec_image.c | 232 ++++++++++++----------- libswfdec/swfdec_image.h | 9 libswfdec/swfdec_pattern.c | 29 +- libswfdec/swfdec_sprite.c | 7 libswfdec/swfdec_sprite_movie.c | 3 test/Makefile.am | 2 test/image/.gitignore | 11 + test/image/Makefile.am | 14 + test/image/color-transform-add80-alpha.swf |binary test/image/color-transform-add80-alpha.swf.png |binary test/image/color-transform-add80.swf |binary test/image/color-transform-add80.swf.png |binary test/image/image-lossless-alpha.swf |binary test/image/image-lossless-alpha.swf.png |binary test/image/image.c | 243 +++++++++++++++++++++++++ test/sound/sound.c | 20 +- test/swfdec-extract.c | 14 + 25 files changed, 526 insertions(+), 172 deletions(-) New commits: diff-tree bdc67ff4e611ed187083eb9a45db630eecb260dd (from af37862080c916e0792c5db1d3e298d6ea6fc7e7) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 11:55:00 2007 +0100 only unref result from _audio_event_new if there is something to unref diff --git a/libswfdec/swfdec_button_movie.c b/libswfdec/swfdec_button_movie.c index 92d40b9..e090c60 100644 --- a/libswfdec/swfdec_button_movie.c +++ b/libswfdec/swfdec_button_movie.c @@ -151,7 +151,8 @@ swfdec_button_movie_change_mouse (Swfdec audio = swfdec_audio_event_new ( SWFDEC_ROOT_MOVIE (SWFDEC_MOVIE (movie)->root)->player, movie->button->sounds[sound]); - g_object_unref (audio); + if (audio) + g_object_unref (audio); } movie->mouse_in = mouse_in; movie->mouse_button = button; diff --git a/libswfdec/swfdec_sprite_movie.c b/libswfdec/swfdec_sprite_movie.c index f303f33..2ca5877 100644 --- a/libswfdec/swfdec_sprite_movie.c +++ b/libswfdec/swfdec_sprite_movie.c @@ -264,7 +264,8 @@ swfdec_sprite_movie_iterate_end (SwfdecM if (movie->sound_frame != movie->current_frame) { for (walk = current->sound; walk; walk = walk->next) { SwfdecAudio *audio = swfdec_audio_event_new (player, walk->data); - g_object_unref (audio); + if (audio) + g_object_unref (audio); } } diff-tree af37862080c916e0792c5db1d3e298d6ea6fc7e7 (from f738d6e4e472166f379f5cb0962d96c8edfc49aa) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 11:54:21 2007 +0100 ref an audio event when reusing diff --git a/libswfdec/swfdec_audio_event.c b/libswfdec/swfdec_audio_event.c index 5895074..e0f05dc 100644 --- a/libswfdec/swfdec_audio_event.c +++ b/libswfdec/swfdec_audio_event.c @@ -132,6 +132,7 @@ swfdec_audio_event_new (SwfdecPlayer *pl (event = (SwfdecAudioEvent *) swfdec_audio_event_get (player, chunk->sound))) { SWFDEC_DEBUG ("sound %d is already playing, reusing it", SWFDEC_CHARACTER (chunk->sound)->id); + g_object_ref (event); return SWFDEC_AUDIO (event); } event = g_object_new (SWFDEC_TYPE_AUDIO_EVENT, NULL); diff-tree f738d6e4e472166f379f5cb0962d96c8edfc49aa (from ab415fae5fab598414213d603bc97721840727b0) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 11:53:54 2007 +0100 list all failed tests at end of run diff --git a/test/sound/sound.c b/test/sound/sound.c index b74f9e2..f42149f 100644 --- a/test/sound/sound.c +++ b/test/sound/sound.c @@ -245,7 +245,7 @@ error: int main (int argc, char **argv) { - guint failed_tests = 0; + GList *failed_tests = NULL; swfdec_init (); @@ -253,7 +253,7 @@ main (int argc, char **argv) int i; for (i = 1; i < argc; i++) { if (!run_test (argv[i])) - failed_tests++; + failed_tests = g_list_prepend (failed_tests, g_strdup (argv[i]));; } } else { GDir *dir; @@ -263,16 +263,24 @@ main (int argc, char **argv) if (!g_str_has_suffix (file, ".swf")) continue; if (!run_test (file)) - failed_tests++; + failed_tests = g_list_prepend (failed_tests, g_strdup (file)); } g_dir_close (dir); } if (failed_tests) { - g_print ("\nFAILURES: %u\n", failed_tests); + GList *walk; + failed_tests = g_list_sort (failed_tests, (GCompareFunc) strcmp); + g_print ("\nFAILURES: %u\n", g_list_length (failed_tests)); + for (walk = failed_tests; walk; walk = walk->next) { + g_print (" %s\n", (char *) walk->data); + g_free (walk->data); + } + g_list_free (failed_tests); + return 1; } else { g_print ("\nEVERYTHING OK\n"); + return 0; } - return failed_tests; } diff-tree ab415fae5fab598414213d603bc97721840727b0 (from 9cef35d65cdcba5be0c0bf9e395f00161a1cd37b) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 11:53:08 2007 +0100 fix failed test accumulation when using command line arguments diff --git a/test/image/image.c b/test/image/image.c index 5b5875f..85c00e1 100644 --- a/test/image/image.c +++ b/test/image/image.c @@ -210,7 +210,7 @@ main (int argc, char **argv) int i; for (i = 1; i < argc; i++) { if (!run_test (argv[i])) - failed_tests++; + failed_tests = g_list_prepend (failed_tests, g_strdup (argv[i])); } } else { GDir *dir; diff-tree 9cef35d65cdcba5be0c0bf9e395f00161a1cd37b (from f8ad5602edb3223fcc0396a60d6077ad562be7e1) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 10:05:45 2007 +0100 DO COMPILE BEFORE CHECKING STUFF IN! sheesh diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index 4463228..fc0b1f1 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -657,7 +657,7 @@ swfdec_image_create_surface_transformed for (i = 0; i < n; i++) { ((guint32 *) tdata)[i] = swfdec_color_apply_transform_premultiplied (((guint32 *) sdata)[i], trans); /* optimization: check for alpha channel to speed up compositing */ - has_alpha != tdata[4 * i + SWFDEC_COLOR_INDEX_ALPHA] != 0xFF; + has_alpha = tdata[4 * i + SWFDEC_COLOR_INDEX_ALPHA] != 0xFF; } surface = cairo_image_surface_create_for_data (tdata, has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, diff-tree f8ad5602edb3223fcc0396a60d6077ad562be7e1 (from 7ee699c59898c37528d0051fd0c25f6756338dbe) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 09:56:22 2007 +0100 add first image tests diff --git a/test/image/Makefile.am b/test/image/Makefile.am index 7e46bee..3ba1485 100644 --- a/test/image/Makefile.am +++ b/test/image/Makefile.am @@ -5,3 +5,10 @@ image_SOURCES = image.c image_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) image_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) +EXTRA_DIST = \ + color-transform-add80.swf \ + color-transform-add80.swf.png \ + color-transform-add80-alpha.swf \ + color-transform-add80-alpha.swf.png \ + image-lossless-alpha.swf \ + image-lossless-alpha.swf.png diff --git a/test/image/color-transform-add80-alpha.swf b/test/image/color-transform-add80-alpha.swf new file mode 100755 index 0000000..841ba01 Binary files /dev/null and b/test/image/color-transform-add80-alpha.swf differ diff --git a/test/image/color-transform-add80-alpha.swf.png b/test/image/color-transform-add80-alpha.swf.png new file mode 100755 index 0000000..b927273 Binary files /dev/null and b/test/image/color-transform-add80-alpha.swf.png differ diff --git a/test/image/color-transform-add80.swf b/test/image/color-transform-add80.swf new file mode 100755 index 0000000..f692312 Binary files /dev/null and b/test/image/color-transform-add80.swf differ diff --git a/test/image/color-transform-add80.swf.png b/test/image/color-transform-add80.swf.png new file mode 100755 index 0000000..7ec2ef6 Binary files /dev/null and b/test/image/color-transform-add80.swf.png differ diff --git a/test/image/image-lossless-alpha.swf b/test/image/image-lossless-alpha.swf new file mode 100755 index 0000000..3ea6d69 Binary files /dev/null and b/test/image/image-lossless-alpha.swf differ diff --git a/test/image/image-lossless-alpha.swf.png b/test/image/image-lossless-alpha.swf.png new file mode 100755 index 0000000..d1689a7 Binary files /dev/null and b/test/image/image-lossless-alpha.swf.png differ diff-tree 7ee699c59898c37528d0051fd0c25f6756338dbe (from 801292bafb7bb89ecae7a2764307fda87cb540f0) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 09:53:20 2007 +0100 make rendering more accurate - Don't premultiply images, they are already premultiplied - Use swfdec_color_apply_transform_premultiplied since the image is premultiplied diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index 224e101..4463228 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -588,24 +588,6 @@ swfdec_image_ensure_loaded (SwfdecImage return TRUE; } -static void -swfdec_image_premultiply (guint8 *data, guint n) -{ - guint i; - - for (i = 0; i < n; i++, data += 4) { - if (data[SWFDEC_COLOR_INDEX_ALPHA] == 0xFF) - continue; - if (data[SWFDEC_COLOR_INDEX_ALPHA] == 0) { - data[SWFDEC_COLOR_INDEX_RED] = data[SWFDEC_COLOR_INDEX_GREEN] = data[SWFDEC_COLOR_INDEX_BLUE] = 0; - } else { - data[SWFDEC_COLOR_INDEX_RED] = (guint) data[SWFDEC_COLOR_INDEX_RED] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; - data[SWFDEC_COLOR_INDEX_GREEN] = (guint) data[SWFDEC_COLOR_INDEX_GREEN] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; - data[SWFDEC_COLOR_INDEX_BLUE] = (guint) data[SWFDEC_COLOR_INDEX_BLUE] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; - } - } -} - static gboolean swfdec_image_has_alpha (SwfdecImage *image) { @@ -635,7 +617,6 @@ swfdec_image_create_surface (SwfdecImage /* FIXME: only works if rowstride == image->width * 4 */ data = cairo_image_surface_get_data (surface); memcpy (data, image->data, image->width * image->height * 4); - swfdec_image_premultiply (data, image->width * image->height); return surface; } else { image->surface = cairo_image_surface_create_for_data (image->data, @@ -674,11 +655,10 @@ swfdec_image_create_surface_transformed sdata = image->data; n = image->width * image->height; for (i = 0; i < n; i++) { - ((guint32 *) tdata)[i] = swfdec_color_apply_transform (((guint32 *) sdata)[i], trans); - has_alpha |= tdata[4 * i + SWFDEC_COLOR_INDEX_ALPHA] != 0xFF; + ((guint32 *) tdata)[i] = swfdec_color_apply_transform_premultiplied (((guint32 *) sdata)[i], trans); + /* optimization: check for alpha channel to speed up compositing */ + has_alpha != tdata[4 * i + SWFDEC_COLOR_INDEX_ALPHA] != 0xFF; } - if (has_alpha) - swfdec_image_premultiply (tdata, n); surface = cairo_image_surface_create_for_data (tdata, has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, image->width, image->height, image->width * 4); diff-tree 801292bafb7bb89ecae7a2764307fda87cb540f0 (from 4f17e493901cc45e47302c4fc74e1f685a32755e) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 09:50:42 2007 +0100 add swfdec_color_apply_transform_premultiplied diff --git a/libswfdec/swfdec_color.c b/libswfdec/swfdec_color.c index 73276a0..ee3a63f 100644 --- a/libswfdec/swfdec_color.c +++ b/libswfdec/swfdec_color.c @@ -56,6 +56,32 @@ swfdec_color_set_source (cairo_t *cr, Sw SWFDEC_COLOR_B (color) / 255.0, SWFDEC_COLOR_A (color) / 255.0); } +SwfdecColor +swfdec_color_apply_transform_premultiplied (SwfdecColor in, + const SwfdecColorTransform * trans) +{ + int r, g, b, a, aold; + + aold = SWFDEC_COLOR_A (in); + if (aold == 0) + return 0; + + a = (aold * trans->aa >> 8) + trans->ab; + a = CLAMP (a, 0, 255); + + r = SWFDEC_COLOR_R (in); + g = SWFDEC_COLOR_G (in); + b = SWFDEC_COLOR_B (in); + r = (r * trans->ra * a / aold >> 8) + trans->rb * a / 255; + r = CLAMP (r, 0, a); + g = (g * trans->ga * a / aold >> 8) + trans->gb * a / 255; + g = CLAMP (g, 0, a); + b = (b * trans->ba * a / aold >> 8) + trans->bb * a / 255; + b = CLAMP (b, 0, a); + + return SWFDEC_COLOR_COMBINE (r, g, b, a); +} + unsigned int swfdec_color_apply_transform (unsigned int in, const SwfdecColorTransform * trans) { diff --git a/libswfdec/swfdec_color.h b/libswfdec/swfdec_color.h index 46fdea4..54ce268 100644 --- a/libswfdec/swfdec_color.h +++ b/libswfdec/swfdec_color.h @@ -77,6 +77,8 @@ void swfdec_color_transform_chain (Swfde const SwfdecColorTransform *last, const SwfdecColorTransform *first); unsigned int swfdec_color_apply_transform (unsigned int in, const SwfdecColorTransform * trans); +SwfdecColor swfdec_color_apply_transform_premultiplied (SwfdecColor in, + const SwfdecColorTransform * trans); void swfdec_matrix_ensure_invertible (cairo_matrix_t *matrix, cairo_matrix_t *inverse); double swfdec_matrix_get_xscale (const cairo_matrix_t *matrix); diff-tree 4f17e493901cc45e47302c4fc74e1f685a32755e (from 469f29442894cdea2116ac801501057266f28727) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 09:50:11 2007 +0100 Check action data is available before trying to compile action diff --git a/libswfdec/swfdec_compiler.c b/libswfdec/swfdec_compiler.c index 737a4d9..e7b39e3 100644 --- a/libswfdec/swfdec_compiler.c +++ b/libswfdec/swfdec_compiler.c @@ -1310,6 +1310,9 @@ swfdec_compile (SwfdecPlayer *player, Sw } else { len = 0; } + if (swfdec_bits_left (bits) < len * 8) { + compile_state_error (&state, "Not enough data available to parse next action"); + } #ifndef G_DISABLE_ASSERT target = bits->ptr + len; #endif diff-tree 469f29442894cdea2116ac801501057266f28727 (from 93148116d47fcaaa7bb894dd73f8c35b555289f0) Author: Benjamin Otte <otte@gnome.org> Date: Tue Feb 6 09:48:07 2007 +0100 improve image test - list failed tests like trace.c - use imagediff (taken from cairo) to compare images - dump diff image in dump mode diff --git a/test/image/image.c b/test/image/image.c index 3200032..5b5875f 100644 --- a/test/image/image.c +++ b/test/image/image.c @@ -23,10 +23,67 @@ #include <string.h> #include <libswfdec/swfdec.h> +/* Compare two buffers, returning the number of pixels that are + * different and the maximum difference of any single color channel in + * result_ret. + * + * This function should be rewritten to compare all formats supported by + * cairo_format_t instead of taking a mask as a parameter. + */ +static gboolean +buffer_diff_core (unsigned char *buf_a, + unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride) +{ + int x, y; + gboolean result = TRUE; + guint32 *row_a, *row_b, *row; + + for (y = 0; y < height; y++) { + row_a = (guint32 *) (buf_a + y * stride); + row_b = (guint32 *) (buf_b + y * stride); + row = (guint32 *) (buf_diff + y * stride); + for (x = 0; x < width; x++) { + /* check if the pixels are the same */ + if (row_a[x] != row_b[x]) { + int channel; + static const unsigned int threshold = 3; + guint32 diff_pixel = 0; + + /* calculate a difference value for all 4 channels */ + for (channel = 0; channel < 4; channel++) { + int value_a = (row_a[x] >> (channel*8)) & 0xff; + int value_b = (row_b[x] >> (channel*8)) & 0xff; + unsigned int diff; + diff = ABS (value_a - value_b); + if (diff <= threshold) + continue; + diff *= 4; /* emphasize */ + diff += 128; /* make sure it's visible */ + if (diff > 255) + diff = 255; + diff_pixel |= diff << (channel*8); + } + + row[x] = diff_pixel; + if (diff_pixel) + result = FALSE; + } else { + row[x] = 0; + } + row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */ + } + } + return result; +} + static gboolean image_diff (cairo_surface_t *surface, const char *filename) { - cairo_surface_t *image; + cairo_surface_t *image, *diff = NULL; int w, h; char *real; @@ -49,28 +106,45 @@ image_diff (cairo_surface_t *surface, co w, h); goto dump; } + diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); g_assert (cairo_image_surface_get_stride (surface) == 4 * w); g_assert (cairo_image_surface_get_stride (image) == 4 * w); - if (memcmp (cairo_image_surface_get_data (surface), - cairo_image_surface_get_data (image), 4 * w * h) != 0) { + g_assert (cairo_image_surface_get_stride (diff) == 4 * w); + if (!buffer_diff_core (cairo_image_surface_get_data (surface), + cairo_image_surface_get_data (image), + cairo_image_surface_get_data (diff), + w, h, 4 * w) != 0) { g_print (" ERROR: images differ\n"); goto dump; } cairo_surface_destroy (image); + cairo_surface_destroy (diff); return TRUE; dump: cairo_surface_destroy (image); if (g_getenv ("SWFDEC_TEST_DUMP")) { cairo_status_t status; - char *dump = g_strdup_printf ("%s.dump.png", filename); + char *dump; + + dump = g_strdup_printf ("%s.dump.png", filename); status = cairo_surface_write_to_png (surface, dump); if (status) { g_print (" ERROR: failed to dump image to %s: %s\n", dump, cairo_status_to_string (status)); } g_free (dump); + if (diff) { + dump = g_strdup_printf ("%s.diff.png", filename); + status = cairo_surface_write_to_png (diff, dump); + if (status) { + g_print (" ERROR: failed to dump diff image to %s: %s\n", dump, + cairo_status_to_string (status)); + } + g_free (dump); + cairo_surface_destroy (diff); + } } return FALSE; } @@ -128,7 +202,7 @@ error: int main (int argc, char **argv) { - guint failed_tests = 0; + GList *failed_tests = NULL; swfdec_init (); @@ -146,16 +220,24 @@ main (int argc, char **argv) if (!g_str_has_suffix (file, ".swf")) continue; if (!run_test (file)) - failed_tests++; + failed_tests = g_list_prepend (failed_tests, g_strdup (file)); } g_dir_close (dir); } if (failed_tests) { - g_print ("\nFAILURES: %u\n", failed_tests); + GList *walk; + failed_tests = g_list_sort (failed_tests, (GCompareFunc) strcmp); + g_print ("\nFAILURES: %u\n", g_list_length (failed_tests)); + for (walk = failed_tests; walk; walk = walk->next) { + g_print (" %s\n", (char *) walk->data); + g_free (walk->data); + } + g_list_free (failed_tests); + return 1; } else { g_print ("\nEVERYTHING OK\n"); + return 0; } - return failed_tests; } diff-tree 93148116d47fcaaa7bb894dd73f8c35b555289f0 (from 42a9937af339fd582d83032e5bce71bc62b8aecf) Author: Benjamin Otte <otte@gnome.org> Date: Mon Feb 5 11:43:12 2007 +0100 Add testing framework for drawing output diff --git a/configure.ac b/configure.ac index e02adfd..f0d0dbd 100644 --- a/configure.ac +++ b/configure.ac @@ -185,6 +185,7 @@ libswfdec/jpeg/Makefile libswfdec/js/Makefile player/Makefile test/Makefile +test/image/Makefile test/sound/Makefile test/trace/Makefile test/various/Makefile diff --git a/test/Makefile.am b/test/Makefile.am index 01c4f45..e0957af 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = sound trace various +SUBDIRS = image sound trace various noinst_PROGRAMS = swfdec-extract dump parse diff --git a/test/image/.gitignore b/test/image/.gitignore new file mode 100644 index 0000000..5cb64c3 --- /dev/null +++ b/test/image/.gitignore @@ -0,0 +1,11 @@ +*~ +CVS +.cvsignore +.deps +.libs + +Makefile +Makefile.in +*.o + +image diff --git a/test/image/Makefile.am b/test/image/Makefile.am new file mode 100644 index 0000000..7e46bee --- /dev/null +++ b/test/image/Makefile.am @@ -0,0 +1,7 @@ +check_PROGRAMS = image +TESTS = $(check_PROGRAMS) + +image_SOURCES = image.c +image_CFLAGS = $(GLOBAL_CFLAGS) $(SWF_CFLAGS) $(CAIRO_CFLAGS) +image_LDFLAGS = $(SWF_LIBS) $(CAIRO_LIBS) + diff --git a/test/image/image.c b/test/image/image.c new file mode 100644 index 0000000..3200032 --- /dev/null +++ b/test/image/image.c @@ -0,0 +1,161 @@ +/* Swfdec + * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <string.h> +#include <libswfdec/swfdec.h> + +static gboolean +image_diff (cairo_surface_t *surface, const char *filename) +{ + cairo_surface_t *image; + int w, h; + char *real; + + real = g_strdup_printf ("%s.png", filename); + image = cairo_image_surface_create_from_png (real); + if (cairo_surface_status (image)) { + g_print (" ERROR: Could not load %s: %s\n", real, + cairo_status_to_string (cairo_surface_status (image))); + g_free (real); + goto dump; + } + g_free (real); + g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE); + w = cairo_image_surface_get_width (surface); + h = cairo_image_surface_get_height (surface); + if (w != cairo_image_surface_get_width (image) || + h != cairo_image_surface_get_height (image)) { + g_print (" ERROR: sizes don't match. Should be %ux%u, but is %ux%u\n", + cairo_image_surface_get_width (image), cairo_image_surface_get_height (image), + w, h); + goto dump; + } + g_assert (cairo_image_surface_get_stride (surface) == 4 * w); + g_assert (cairo_image_surface_get_stride (image) == 4 * w); + if (memcmp (cairo_image_surface_get_data (surface), + cairo_image_surface_get_data (image), 4 * w * h) != 0) { + g_print (" ERROR: images differ\n"); + goto dump; + } + + cairo_surface_destroy (image); + return TRUE; + +dump: + cairo_surface_destroy (image); + if (g_getenv ("SWFDEC_TEST_DUMP")) { + cairo_status_t status; + char *dump = g_strdup_printf ("%s.dump.png", filename); + status = cairo_surface_write_to_png (surface, dump); + if (status) { + g_print (" ERROR: failed to dump image to %s: %s\n", dump, + cairo_status_to_string (status)); + } + g_free (dump); + } + return FALSE; +} + +static gboolean +run_test (const char *filename) +{ + SwfdecLoader *loader; + SwfdecPlayer *player = NULL; + guint i, msecs; + GError *error = NULL; + int w, h; + cairo_surface_t *surface; + cairo_t *cr; + + g_print ("Testing %s:\n", filename); + + loader = swfdec_loader_new_from_file (filename, &error); + if (loader == NULL) { + g_print (" ERROR: %s\n", error->message); + goto error; + } + player = swfdec_player_new (); + swfdec_player_set_loader (player, loader); + + for (i = 0; i < 10; i++) { + msecs = swfdec_player_get_next_event (player); + swfdec_player_advance (player, msecs); + } + swfdec_player_get_image_size (player, &w, &h); + if (w == 0 || h == 0) { + g_print (" ERROR: width and height not set\n"); + goto error; + } + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h); + cr = cairo_create (surface); + swfdec_player_render (player, cr, 0, 0, w, h); + cairo_destroy (cr); + if (!image_diff (surface, filename)) { + cairo_surface_destroy (surface); + goto error; + } + cairo_surface_destroy (surface); + g_object_unref (player); + return TRUE; + +error: + if (error) + g_error_free (error); + if (player) + g_object_unref (player); + return FALSE; +} + +int +main (int argc, char **argv) +{ + guint failed_tests = 0; + + swfdec_init (); + + if (argc > 1) { + int i; + for (i = 1; i < argc; i++) { + if (!run_test (argv[i])) + failed_tests++; + } + } else { + GDir *dir; + const char *file; + dir = g_dir_open (".", 0, NULL); + while ((file = g_dir_read_name (dir))) { + if (!g_str_has_suffix (file, ".swf")) + continue; + if (!run_test (file)) + failed_tests++; + } + g_dir_close (dir); + } + + if (failed_tests) { + g_print ("\nFAILURES: %u\n", failed_tests); + } else { + g_print ("\nEVERYTHING OK\n"); + } + return failed_tests; +} + diff-tree 42a9937af339fd582d83032e5bce71bc62b8aecf (from c7ef38d8fd3cfabb9175bb7138f08dbd5b5e16bd) Author: Benjamin Otte <otte@gnome.org> Date: Mon Feb 5 11:39:25 2007 +0100 Fix refcounting issue diff --git a/test/sound/sound.c b/test/sound/sound.c index 9b7ae58..b74f9e2 100644 --- a/test/sound/sound.c +++ b/test/sound/sound.c @@ -184,7 +184,6 @@ run_test (const char *filename) dir = g_dir_open (dirname, 0, &error); if (!dir) { g_print (" ERROR: %s\n", error->message); - g_object_unref (player); return FALSE; } while ((name = g_dir_read_name (dir))) { diff-tree c7ef38d8fd3cfabb9175bb7138f08dbd5b5e16bd (from 85de571784f502c8bd405eb3043ee079fd6a011c) Author: Benjamin Otte <otte@gnome.org> Date: Mon Feb 5 10:29:23 2007 +0100 fix memleak diff --git a/test/sound/sound.c b/test/sound/sound.c index b9f54a3..9b7ae58 100644 --- a/test/sound/sound.c +++ b/test/sound/sound.c @@ -72,6 +72,7 @@ dump: g_print (" ERROR: failed to dump contents: %s\n", error->message); g_error_free (error); } + g_free (dump); } return FALSE; } diff-tree 85de571784f502c8bd405eb3043ee079fd6a011c (from d7db95f092791ed1e81ad2d2e4f9e3fb345d6f79) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 18:50:46 2007 +0100 that should be == NULL, not != NULL diff --git a/libswfdec/swfdec_compiler.c b/libswfdec/swfdec_compiler.c index 68221e3..737a4d9 100644 --- a/libswfdec/swfdec_compiler.c +++ b/libswfdec/swfdec_compiler.c @@ -559,7 +559,7 @@ compile_push (CompileState *state, guint switch (type) { case 0: /* string */ s = swfdec_bits_skip_string (state->bits); - if (s) { + if (s == NULL) { compile_state_error (state, "Push: Could not get string"); return; } diff-tree d7db95f092791ed1e81ad2d2e4f9e3fb345d6f79 (from ad56f27f4cc82a6913a7adcf05704b2cb91e6c61) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 16:14:23 2007 +0100 export images, too diff --git a/test/swfdec-extract.c b/test/swfdec-extract.c index bea068e..b4a2951 100644 --- a/test/swfdec-extract.c +++ b/test/swfdec-extract.c @@ -35,6 +35,7 @@ #include <libswfdec/swfdec_audio_stream.h> #include <libswfdec/swfdec_button.h> #include <libswfdec/swfdec_graphic.h> +#include <libswfdec/swfdec_image.h> #include <libswfdec/swfdec_player_internal.h> #include <libswfdec/swfdec_root_movie.h> #include <libswfdec/swfdec_sound.h> @@ -206,6 +207,16 @@ export_graphic (SwfdecGraphic *graphic, return surface_destroy_for_type (surface, filename); } +static gboolean +export_image (SwfdecImage *image, const char *filename) +{ + cairo_surface_t *surface = swfdec_image_create_surface (image); + + if (surface == NULL) + return FALSE; + return surface_destroy_for_type (surface, filename); +} + static void usage (const char *app) { @@ -258,6 +269,9 @@ main (int argc, char *argv[]) } else if (SWFDEC_IS_GRAPHIC (character)) { if (!export_graphic (SWFDEC_GRAPHIC (character), argv[3])) ret = 1; + } else if (SWFDEC_IS_IMAGE (character)) { + if (!export_image (SWFDEC_IMAGE (character), argv[3])) + ret = 1; } else { g_printerr ("id %ld does not specify an exportable object", id); ret = 1; diff-tree ad56f27f4cc82a6913a7adcf05704b2cb91e6c61 (from 32e4b86c8fac7b199a4f2d210f0ec6d67347091c) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 16:14:13 2007 +0100 add debugging message when parsing color transforms diff --git a/libswfdec/swfdec_sprite.c b/libswfdec/swfdec_sprite.c index 074bb37..246776a 100644 --- a/libswfdec/swfdec_sprite.c +++ b/libswfdec/swfdec_sprite.c @@ -364,6 +364,11 @@ swfdec_spriteseg_place_object_2 (SwfdecS } if (has_color_transform) { swfdec_bits_get_color_transform (bits, &content->color_transform); + SWFDEC_LOG (" color transform = %d %d %d %d %d %d %d %d", + content->color_transform.ra, content->color_transform.rb, + content->color_transform.ga, content->color_transform.gb, + content->color_transform.ba, content->color_transform.bb, + content->color_transform.aa, content->color_transform.ab); } swfdec_bits_syncbits (bits); if (has_ratio) { diff-tree 32e4b86c8fac7b199a4f2d210f0ec6d67347091c (from 2399ad61b0ffc8fcbd1c395dc841deec152e29e4) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 14:53:42 2007 +0100 rename swfdec_image_get_surface* to swfdec_image_create_surface* - The renamed functions give out a reference to the surface now. - Ensure that surfaces created by those functions get unreffed properly - Add an obvious optimization by not applying the color transform if the transform is the identity transform diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index e276508..224e101 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -647,7 +647,7 @@ swfdec_image_create_surface (SwfdecImage } cairo_surface_t * -swfdec_image_get_surface_transformed (SwfdecImage *image, const SwfdecColorTransform *trans) +swfdec_image_create_surface_transformed (SwfdecImage *image, const SwfdecColorTransform *trans) { static const cairo_user_data_key_t key; cairo_surface_t *surface; @@ -659,6 +659,10 @@ swfdec_image_get_surface_transformed (Sw g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL); g_return_val_if_fail (trans != NULL, NULL); + /* obvious optimization */ + if (swfdec_color_transform_is_identity (trans)) + return swfdec_image_create_surface (image); + if (!swfdec_image_ensure_loaded (image)) return NULL; diff --git a/libswfdec/swfdec_image.h b/libswfdec/swfdec_image.h index ad40181..3c1e71e 100644 --- a/libswfdec/swfdec_image.h +++ b/libswfdec/swfdec_image.h @@ -66,8 +66,8 @@ struct _SwfdecImageClass { GType swfdec_image_get_type (void); -cairo_surface_t * swfdec_image_get_surface (SwfdecImage * image); -cairo_surface_t * swfdec_image_get_surface_transformed +cairo_surface_t * swfdec_image_create_surface (SwfdecImage * image); +cairo_surface_t * swfdec_image_create_surface_transformed (SwfdecImage * image, const SwfdecColorTransform *trans); diff --git a/libswfdec/swfdec_pattern.c b/libswfdec/swfdec_pattern.c index 938f827..536698a 100644 --- a/libswfdec/swfdec_pattern.c +++ b/libswfdec/swfdec_pattern.c @@ -266,9 +266,10 @@ swfdec_image_pattern_paint (SwfdecPatter cairo_matrix_t mat; cairo_surface_t *surface; - surface = swfdec_image_get_surface_transformed (image->image, trans); + surface = swfdec_image_create_surface_transformed (image->image, trans); cairo_append_path (cr, (cairo_path_t *) path); pattern = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy (surface); swfdec_matrix_morph (&mat, &pat->start_transform, &pat->end_transform, ratio); cairo_pattern_set_matrix (pattern, &mat); cairo_pattern_set_extend (pattern, image->extend); @@ -626,7 +627,7 @@ swfdec_pattern_to_string (SwfdecPattern if (SWFDEC_IS_IMAGE_PATTERN (pattern)) { SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pattern); if (image->image->width == 0) - swfdec_image_get_surface (image->image); + cairo_surface_destroy (swfdec_image_create_surface (image->image)); return g_strdup_printf ("%ux%u image %u (%s, %s)", image->image->width, image->image->height, SWFDEC_CHARACTER (image->image)->id, image->extend == CAIRO_EXTEND_REPEAT ? "repeat" : "no repeat", diff-tree 2399ad61b0ffc8fcbd1c395dc841deec152e29e4 (from 180879c4af107625b53f37ba8bcc990eb20baf8b) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 14:49:54 2007 +0100 add swfdec_color_transform_is_identity useful for optimizations diff --git a/libswfdec/swfdec_color.c b/libswfdec/swfdec_color.c index 7761653..73276a0 100644 --- a/libswfdec/swfdec_color.c +++ b/libswfdec/swfdec_color.c @@ -1,7 +1,7 @@ /* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> - * 2006 Benjamin Otte <otte@gnome.org> + * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -125,6 +125,13 @@ swfdec_color_transform_init_color (Swfde trans->ab = SWFDEC_COLOR_A (color); } +gboolean +swfdec_color_transform_is_identity (const SwfdecColorTransform * trans) +{ + return trans->ra == 256 && trans->ga == 256 && trans->ba == 256 && trans->aa == 256 && + trans->rb == 0 && trans->gb == 0 && trans->bb == 0 && trans->ab == 0; +} + /** * swfdec_color_transform_chain: * @dest: #SwfdecColorTransform to take the result diff --git a/libswfdec/swfdec_color.h b/libswfdec/swfdec_color.h index b38c269..46fdea4 100644 --- a/libswfdec/swfdec_color.h +++ b/libswfdec/swfdec_color.h @@ -72,6 +72,7 @@ SwfdecColor swfdec_color_apply_morph (Sw void swfdec_color_set_source (cairo_t *cr, SwfdecColor color); void swfdec_color_transform_init_identity (SwfdecColorTransform * trans); void swfdec_color_transform_init_color (SwfdecColorTransform *trans, SwfdecColor color); +gboolean swfdec_color_transform_is_identity (const SwfdecColorTransform * trans); void swfdec_color_transform_chain (SwfdecColorTransform *dest, const SwfdecColorTransform *last, const SwfdecColorTransform *first); unsigned int swfdec_color_apply_transform (unsigned int in, diff-tree 180879c4af107625b53f37ba8bcc990eb20baf8b (from fa335acfbd3526f57dfb66c68e59334a79d90901) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 14:33:59 2007 +0100 rework images to be correctly color transformed - use new SWFDEC_COLOR_INDEX variables when decoding - avoids #if - ditch caching as we might need the unpremultiplied image for color transforms - implement swfdec_image_get_surface_transformed - use it in the image pattern diff --git a/libswfdec/swfdec_image.c b/libswfdec/swfdec_image.c index 0cf6502..e276508 100644 --- a/libswfdec/swfdec_image.c +++ b/libswfdec/swfdec_image.c @@ -50,7 +50,10 @@ swfdec_image_unload (SwfdecCached *cache if (image->surface) { cairo_surface_destroy (image->surface); image->surface = NULL; + } else if (image->data) { + g_free (image->data); } + image->data = NULL; } static void @@ -185,24 +188,9 @@ tag_func_define_bits_jpeg (SwfdecSwfDeco } static void -swfdec_image_create_surface (SwfdecImage *image, guint8 *data, gboolean has_alpha) -{ - static const cairo_user_data_key_t key; - - g_assert (image->surface == NULL); - - image->surface = cairo_image_surface_create_for_data (data, - has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, - image->width, image->height, image->rowstride); - cairo_surface_set_user_data (image->surface, &key, data, - g_free); -} - -static void swfdec_image_jpeg_load (SwfdecImage *image) { JpegRGBDecoder *dec; - unsigned char *image_data; dec = jpeg_rgb_decoder_new (); @@ -217,10 +205,9 @@ swfdec_image_jpeg_load (SwfdecImage *ima return; } swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - jpeg_rgb_decoder_get_image (dec, &image_data, + jpeg_rgb_decoder_get_image (dec, &image->data, &image->rowstride, NULL, NULL); jpeg_rgb_decoder_free (dec); - swfdec_image_create_surface (image, image_data, FALSE); SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); @@ -252,7 +239,6 @@ static void swfdec_image_jpeg2_load (SwfdecImage *image) { JpegRGBDecoder *dec; - unsigned char *image_data; dec = jpeg_rgb_decoder_new (); @@ -265,10 +251,9 @@ swfdec_image_jpeg2_load (SwfdecImage *im return; } swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - jpeg_rgb_decoder_get_image (dec, &image_data, + jpeg_rgb_decoder_get_image (dec, &image->data, &image->rowstride, &image->width, &image->height); jpeg_rgb_decoder_free (dec); - swfdec_image_create_surface (image, image_data, FALSE); SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); @@ -303,7 +288,6 @@ static void swfdec_image_jpeg3_load (SwfdecImage *image) { JpegRGBDecoder *dec; - unsigned char *image_data; unsigned char *alpha_data; SwfdecBits bits; int len; @@ -328,7 +312,7 @@ swfdec_image_jpeg3_load (SwfdecImage *im return; } swfdec_cached_load (SWFDEC_CACHED (image), 4 * image->width * image->height); - jpeg_rgb_decoder_get_image (dec, &image_data, + jpeg_rgb_decoder_get_image (dec, &image->data, &image->rowstride, &image->width, &image->height); jpeg_rgb_decoder_free (dec); @@ -336,11 +320,9 @@ swfdec_image_jpeg3_load (SwfdecImage *im alpha_data = lossless (bits.ptr, bits.end - bits.ptr, &len); - merge_alpha (image, image_data, alpha_data); + merge_alpha (image, image->data, alpha_data); g_free (alpha_data); - swfdec_image_create_surface (image, image_data, TRUE); - SWFDEC_LOG (" width = %d", image->width); SWFDEC_LOG (" height = %d", image->height); } @@ -355,11 +337,7 @@ merge_alpha (SwfdecImage * image, unsign for (y = 0; y < image->height; y++) { p = image_data + y * image->rowstride; for (x = 0; x < image->width; x++) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - p[3] = *alpha; -#else - p[0] = *alpha; -#endif + p[SWFDEC_COLOR_INDEX_ALPHA] = *alpha; p += 4; alpha++; } @@ -375,7 +353,6 @@ swfdec_image_lossless_load (SwfdecImage int len; unsigned char *endptr; SwfdecBits bits; - unsigned char *image_data = NULL; int have_alpha = (image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2); bits.buffer = image->raw_data; @@ -414,7 +391,7 @@ swfdec_image_lossless_load (SwfdecImage unsigned char *indexed_data; int i; - image_data = g_malloc (4 * image->width * image->height); + image->data = g_malloc (4 * image->width * image->height); image->rowstride = image->width * 4; color_table = g_malloc (color_table_size * 4); @@ -450,7 +427,7 @@ swfdec_image_lossless_load (SwfdecImage } indexed_data = ptr + color_table_size * 3; } - swfdec_image_colormap_decode (image, image_data, indexed_data, + swfdec_image_colormap_decode (image, image->data, indexed_data, color_table, color_table_size); g_free (color_table); @@ -467,25 +444,18 @@ swfdec_image_lossless_load (SwfdecImage have_alpha = FALSE; } - image_data = g_malloc (4 * image->width * image->height); - idata = image_data; + image->data = g_malloc (4 * image->width * image->height); + idata = image->data; image->rowstride = image->width * 4; /* 15 bit packed */ for (j = 0; j < image->height; j++) { for (i = 0; i < image->width; i++) { c = p[1] | (p[0] << 8); -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - idata[0] = (c << 3) | ((c >> 2) & 0x7); - idata[1] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); - idata[2] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); - idata[3] = 0xff; -#else - idata[3] = (c << 3) | ((c >> 2) & 0x7); - idata[2] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); - idata[1] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); - idata[0] = 0xff; -#endif + idata[SWFDEC_COLOR_INDEX_BLUE] = (c << 3) | ((c >> 2) & 0x7); + idata[SWFDEC_COLOR_INDEX_GREEN] = ((c >> 2) & 0xf8) | ((c >> 7) & 0x7); + idata[SWFDEC_COLOR_INDEX_RED] = ((c >> 7) & 0xf8) | ((c >> 12) & 0x7); + idata[SWFDEC_COLOR_INDEX_ALPHA] = 0xff; p += 2; idata += 4; } @@ -495,26 +465,17 @@ swfdec_image_lossless_load (SwfdecImage if (format == 5) { int i, j; - image_data = ptr; + image->data = ptr; image->rowstride = image->width * 4; - if (!have_alpha) { - /* image is stored in 0RGB format. We use ARGB/BGRA. */ - for (j = 0; j < image->height; j++) { - for (i = 0; i < image->width; i++) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - ptr[0] = ptr[3]; - ptr[1] = ptr[2]; - ptr[2] = ptr[1]; - ptr[3] = 255; -#endif - ptr += 4; - } + /* image is stored in 0RGB format. We use ARGB/BGRA. */ + for (j = 0; j < image->height; j++) { + for (i = 0; i < image->width; i++) { + *((guint32 *) ptr) = GUINT32_FROM_BE (*((guint32 *) ptr)); + ptr += 4; } } } - - swfdec_image_create_surface (image, image_data, have_alpha); } int @@ -592,68 +553,131 @@ swfdec_image_colormap_decode (SwfdecImag } } +static gboolean +swfdec_image_ensure_loaded (SwfdecImage *image) +{ + if (image->data == NULL) { + switch (image->type) { + case SWFDEC_IMAGE_TYPE_JPEG: + swfdec_image_jpeg_load (image); + break; + case SWFDEC_IMAGE_TYPE_JPEG2: + swfdec_image_jpeg2_load (image); + break; + case SWFDEC_IMAGE_TYPE_JPEG3: + swfdec_image_jpeg3_load (image); + break; + case SWFDEC_IMAGE_TYPE_LOSSLESS: + swfdec_image_lossless_load (image); + break; + case SWFDEC_IMAGE_TYPE_LOSSLESS2: + swfdec_image_lossless_load (image); + break; + case SWFDEC_IMAGE_TYPE_UNKNOWN: + default: + g_assert_not_reached (); + break; + } + if (image->data == NULL) { + SWFDEC_WARNING ("failed to load image data"); + return FALSE; + } + } else { + swfdec_cached_use (SWFDEC_CACHED (image)); + } + return TRUE; +} + +static void +swfdec_image_premultiply (guint8 *data, guint n) +{ + guint i; + + for (i = 0; i < n; i++, data += 4) { + if (data[SWFDEC_COLOR_INDEX_ALPHA] == 0xFF) + continue; + if (data[SWFDEC_COLOR_INDEX_ALPHA] == 0) { + data[SWFDEC_COLOR_INDEX_RED] = data[SWFDEC_COLOR_INDEX_GREEN] = data[SWFDEC_COLOR_INDEX_BLUE] = 0; + } else { + data[SWFDEC_COLOR_INDEX_RED] = (guint) data[SWFDEC_COLOR_INDEX_RED] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; + data[SWFDEC_COLOR_INDEX_GREEN] = (guint) data[SWFDEC_COLOR_INDEX_GREEN] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; + data[SWFDEC_COLOR_INDEX_BLUE] = (guint) data[SWFDEC_COLOR_INDEX_BLUE] * data[SWFDEC_COLOR_INDEX_ALPHA] / 255; + } + } +} + +static gboolean +swfdec_image_has_alpha (SwfdecImage *image) +{ + return image->type == SWFDEC_IMAGE_TYPE_LOSSLESS2 || + image->type == SWFDEC_IMAGE_TYPE_JPEG3; +} + cairo_surface_t * -swfdec_image_get_surface (SwfdecImage *image) +swfdec_image_create_surface (SwfdecImage *image) { + static const cairo_user_data_key_t key; + g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL); + if (!swfdec_image_ensure_loaded (image)) + return NULL; if (image->surface) { - swfdec_cached_use (SWFDEC_CACHED (image)); + cairo_surface_reference (image->surface); return image->surface; } - switch (image->type) { - case SWFDEC_IMAGE_TYPE_JPEG: - swfdec_image_jpeg_load (image); - break; - case SWFDEC_IMAGE_TYPE_JPEG2: - swfdec_image_jpeg2_load (image); - break; - case SWFDEC_IMAGE_TYPE_JPEG3: - swfdec_image_jpeg3_load (image); - break; - case SWFDEC_IMAGE_TYPE_LOSSLESS: - swfdec_image_lossless_load (image); - break; - case SWFDEC_IMAGE_TYPE_LOSSLESS2: - swfdec_image_lossless_load (image); - break; - case SWFDEC_IMAGE_TYPE_UNKNOWN: - default: - g_assert_not_reached (); - break; + if (swfdec_image_has_alpha (image)) { + cairo_surface_t *surface; + guint8 *data; + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + image->width, image->height); + /* FIXME: only works if rowstride == image->width * 4 */ + data = cairo_image_surface_get_data (surface); + memcpy (data, image->data, image->width * image->height * 4); + swfdec_image_premultiply (data, image->width * image->height); + return surface; + } else { + image->surface = cairo_image_surface_create_for_data (image->data, + CAIRO_FORMAT_RGB24, image->width, image->height, image->rowstride); + cairo_surface_set_user_data (image->surface, &key, image->data, g_free); + cairo_surface_reference (image->surface); + return image->surface; } - - return image->surface; } cairo_surface_t * -swfdec_image_get_surface_for_target (SwfdecImage *image, cairo_surface_t *target) +swfdec_image_get_surface_transformed (SwfdecImage *image, const SwfdecColorTransform *trans) { - cairo_surface_t *current, *similar; - cairo_t *copy; - cairo_content_t content; - - current = swfdec_image_get_surface (image); - if (cairo_surface_get_type (current) == cairo_surface_get_type (target)) - return current; - - /* FIXME: we might want to create multiple surfaces here if there's multiple - * live rendering sources. Right now, this is the quick fix, that transforms - * the cache to the most recent used type */ - if (cairo_surface_get_type (current) == CAIRO_SURFACE_TYPE_IMAGE && - cairo_image_surface_get_format (current) == CAIRO_FORMAT_RGB24) - content = CAIRO_CONTENT_COLOR; - else - content = CAIRO_CONTENT_COLOR_ALPHA; - similar = cairo_surface_create_similar (target, - content, - image->width, image->height); - copy = cairo_create (similar); - cairo_set_source_surface (copy, current, 0, 0); - cairo_paint (copy); - cairo_destroy (copy); - cairo_surface_destroy (current); - image->surface = similar; - return similar; + static const cairo_user_data_key_t key; + cairo_surface_t *surface; + guint8 *tdata; + const guint8 *sdata; + guint i, n; + gboolean has_alpha = FALSE; + + g_return_val_if_fail (SWFDEC_IS_IMAGE (image), NULL); + g_return_val_if_fail (trans != NULL, NULL); + + if (!swfdec_image_ensure_loaded (image)) + return NULL; + + tdata = g_try_malloc (image->width * image->height * 4); + if (!tdata) { + SWFDEC_ERROR ("failed to allocate memory for transformed image"); + return NULL; + } + sdata = image->data; + n = image->width * image->height; + for (i = 0; i < n; i++) { + ((guint32 *) tdata)[i] = swfdec_color_apply_transform (((guint32 *) sdata)[i], trans); + has_alpha |= tdata[4 * i + SWFDEC_COLOR_INDEX_ALPHA] != 0xFF; + } + if (has_alpha) + swfdec_image_premultiply (tdata, n); + surface = cairo_image_surface_create_for_data (tdata, + has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, + image->width, image->height, image->width * 4); + cairo_surface_set_user_data (surface, &key, tdata, g_free); + return surface; } diff --git a/libswfdec/swfdec_image.h b/libswfdec/swfdec_image.h index bcd22f0..ad40181 100644 --- a/libswfdec/swfdec_image.h +++ b/libswfdec/swfdec_image.h @@ -48,10 +48,11 @@ typedef enum { struct _SwfdecImage { SwfdecCached cached; - cairo_surface_t * surface; /* surface that is on-demand loaded */ + guint8 * data; /* image data in CAIRO_FORMAT_ARGB32 but NOT premultiplied */ int width; int height; int rowstride; + cairo_surface_t * surface; /* surface that owns the data pointer or NULL (doesn't always work) */ SwfdecImageType type; SwfdecBuffer * jpegtables; @@ -66,9 +67,9 @@ struct _SwfdecImageClass { GType swfdec_image_get_type (void); cairo_surface_t * swfdec_image_get_surface (SwfdecImage * image); -cairo_surface_t * swfdec_image_get_surface_for_target +cairo_surface_t * swfdec_image_get_surface_transformed (SwfdecImage * image, - cairo_surface_t * target); + const SwfdecColorTransform *trans); int swfdec_image_jpegtables (SwfdecSwfDecoder * s); int tag_func_define_bits_jpeg (SwfdecSwfDecoder * s); diff --git a/libswfdec/swfdec_pattern.c b/libswfdec/swfdec_pattern.c index 2a614b0..938f827 100644 --- a/libswfdec/swfdec_pattern.c +++ b/libswfdec/swfdec_pattern.c @@ -263,14 +263,11 @@ swfdec_image_pattern_paint (SwfdecPatter { SwfdecImagePattern *image = SWFDEC_IMAGE_PATTERN (pat); cairo_pattern_t *pattern; - SwfdecColor color; cairo_matrix_t mat; cairo_surface_t *surface; - surface = swfdec_image_get_surface_for_target (image->image, - cairo_get_target (cr)); + surface = swfdec_image_get_surface_transformed (image->image, trans); cairo_append_path (cr, (cairo_path_t *) path); - color = swfdec_color_apply_transform (0xFFFFFFFF, trans); pattern = cairo_pattern_create_for_surface (surface); swfdec_matrix_morph (&mat, &pat->start_transform, &pat->end_transform, ratio); cairo_pattern_set_matrix (pattern, &mat); @@ -278,14 +275,7 @@ swfdec_image_pattern_paint (SwfdecPatter cairo_pattern_set_filter (pattern, image->filter); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); - if (SWFDEC_COLOR_A (color) < 255) { - cairo_save (cr); - cairo_clip (cr); - cairo_paint_with_alpha (cr, SWFDEC_COLOR_A (color) / 255.); - cairo_restore (cr); - } else { - cairo_fill (cr); - } + cairo_fill (cr); } static void diff-tree fa335acfbd3526f57dfb66c68e59334a79d90901 (from 251f13c696e0c8c8eb10534d0ed9407d7fd26d19) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 14:29:48 2007 +0100 update SwfdecColor format from RGBA to ARGB This makes SwfdecColor match a pixel in an image in CAIRO_FORMAT_ARGB32 diff --git a/libswfdec/swfdec_color.h b/libswfdec/swfdec_color.h index 07870c3..b38c269 100644 --- a/libswfdec/swfdec_color.h +++ b/libswfdec/swfdec_color.h @@ -1,7 +1,7 @@ /* Swfdec * Copyright (C) 2003-2006 David Schleef <ds@schleef.org> * 2005-2006 Eric Anholt <eric@anholt.net> - * 2006 Benjamin Otte <otte@gnome.org> + * 2006-2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,8 @@ #include <libswfdec/swfdec_types.h> +/* Pixel value in the same colorspace as cairo - endian-dependant ARGB. + * The alpha pixel must be present */ typedef unsigned int SwfdecColor; struct _SwfdecColorTransform { @@ -46,11 +48,25 @@ struct swfdec_gradient_struct SwfdecGradientEntry array[1]; }; -#define SWFDEC_COLOR_COMBINE(r,g,b,a) (((r)<<24) | ((g)<<16) | ((b)<<8) | (a)) -#define SWFDEC_COLOR_R(x) (((x)>>24)&0xff) -#define SWFDEC_COLOR_G(x) (((x)>>16)&0xff) -#define SWFDEC_COLOR_B(x) (((x)>>8)&0xff) -#define SWFDEC_COLOR_A(x) ((x)&0xff) +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define SWFDEC_COLOR_INDEX_ALPHA (3) +#define SWFDEC_COLOR_INDEX_RED (2) +#define SWFDEC_COLOR_INDEX_GREEN (1) +#define SWFDEC_COLOR_INDEX_BLUE (0) +#elif G_BYTE_ORDER == G_BIG_ENDIAN +#define SWFDEC_COLOR_INDEX_ALPHA (0) +#define SWFDEC_COLOR_INDEX_RED (1) +#define SWFDEC_COLOR_INDEX_GREEN (2) +#define SWFDEC_COLOR_INDEX_BLUE (3) +#else +#error "Unknown byte order" +#endif + +#define SWFDEC_COLOR_COMBINE(r,g,b,a) (((a)<<24) | ((r)<<16) | ((g)<<8) | (b)) +#define SWFDEC_COLOR_A(x) (((x)>>24)&0xff) +#define SWFDEC_COLOR_R(x) (((x)>>16)&0xff) +#define SWFDEC_COLOR_G(x) (((x)>>8)&0xff) +#define SWFDEC_COLOR_B(x) ((x)&0xff) SwfdecColor swfdec_color_apply_morph (SwfdecColor start, SwfdecColor end, unsigned int ratio); void swfdec_color_set_source (cairo_t *cr, SwfdecColor color); diff-tree 251f13c696e0c8c8eb10534d0ed9407d7fd26d19 (from 12bf86eb10e873ca735fad310d7ab9e517f6662b) Author: Benjamin Otte <otte@gnome.org> Date: Sun Feb 4 13:07:18 2007 +0100 s/SWF_COLOR/SWFDEC_COLOR/ fight wrong prefixes! diff --git a/libswfdec/swfdec_bits.c b/libswfdec/swfdec_bits.c index fb18394..5013e49 100644 --- a/libswfdec/swfdec_bits.c +++ b/libswfdec/swfdec_bits.c @@ -450,7 +450,7 @@ swfdec_bits_get_color (SwfdecBits * bits g = swfdec_bits_get_u8 (bits); b = swfdec_bits_get_u8 (bits); - return SWF_COLOR_COMBINE (r, g, b, 0xff); + return SWFDEC_COLOR_COMBINE (r, g, b, 0xff); } unsigned int @@ -463,7 +463,7 @@ swfdec_bits_get_rgba (SwfdecBits * bits) b = swfdec_bits_get_u8 (bits); a = swfdec_bits_get_u8 (bits); - return SWF_COLOR_COMBINE (r, g, b, a); + return SWFDEC_COLOR_COMBINE (r, g, b, a); } SwfdecGradient * diff --git a/libswfdec/swfdec_color.c b/libswfdec/swfdec_color.c index 0d8a8be..7761653 100644 --- a/libswfdec/swfdec_color.c +++ b/libswfdec/swfdec_color.c @@ -40,20 +40,20 @@ swfdec_color_apply_morph (SwfdecColor st return end; start_ratio = 65535 - ratio; end_ratio = ratio; - r = (SWF_COLOR_R (start) * start_ratio + SWF_COLOR_R (end) * end_ratio) / 65535; - g = (SWF_COLOR_G (start) * start_ratio + SWF_COLOR_G (end) * end_ratio) / 65535; - b = (SWF_COLOR_B (start) * start_ratio + SWF_COLOR_B (end) * end_ratio) / 65535; - a = (SWF_COLOR_A (start) * start_ratio + SWF_COLOR_A (end) * end_ratio) / 65535; + r = (SWFDEC_COLOR_R (start) * start_ratio + SWFDEC_COLOR_R (end) * end_ratio) / 65535; + g = (SWFDEC_COLOR_G (start) * start_ratio + SWFDEC_COLOR_G (end) * end_ratio) / 65535; + b = (SWFDEC_COLOR_B (start) * start_ratio + SWFDEC_COLOR_B (end) * end_ratio) / 65535; + a = (SWFDEC_COLOR_A (start) * start_ratio + SWFDEC_COLOR_A (end) * end_ratio) / 65535; - return SWF_COLOR_COMBINE (r, g, b, a); + return SWFDEC_COLOR_COMBINE (r, g, b, a); } void swfdec_color_set_source (cairo_t *cr, SwfdecColor color) { cairo_set_source_rgba (cr, - SWF_COLOR_R (color) / 255.0, SWF_COLOR_G (color) / 255.0, - SWF_COLOR_B (color) / 255.0, SWF_COLOR_A (color) / 255.0); + SWFDEC_COLOR_R (color) / 255.0, SWFDEC_COLOR_G (color) / 255.0, + SWFDEC_COLOR_B (color) / 255.0, SWFDEC_COLOR_A (color) / 255.0); } unsigned int @@ -61,10 +61,10 @@ swfdec_color_apply_transform (unsigned i { int r, g, b, a; - r = SWF_COLOR_R (in); - g = SWF_COLOR_G (in); - b = SWF_COLOR_B (in); - a = SWF_COLOR_A (in); + r = SWFDEC_COLOR_R (in); + g = SWFDEC_COLOR_G (in); + b = SWFDEC_COLOR_B (in); + a = SWFDEC_COLOR_A (in); SWFDEC_LOG ("in rgba %d,%d,%d,%d", r, g, b, a); @@ -80,7 +80,7 @@ swfdec_color_apply_transform (unsigned i SWFDEC_LOG ("out rgba %d,%d,%d,%d", r, g, b, a); - return SWF_COLOR_COMBINE (r, g, b, a); + return SWFDEC_COLOR_COMBINE (r, g, b, a); } /** @@ -116,13 +116,13 @@ void swfdec_color_transform_init_color (SwfdecColorTransform *trans, SwfdecColor color) { trans->ra = 0; - trans->rb = SWF_COLOR_R (color); + trans->rb = SWFDEC_COLOR_R (color); trans->ga = 0; - trans->gb = SWF_COLOR_G (color); + trans->gb = SWFDEC_COLOR_G (color); trans->ba = 0; - trans->bb = SWF_COLOR_B (color); + trans->bb = SWFDEC_COLOR_B (color); trans->aa = 0; - trans->ab = SWF_COLOR_A (color); + trans->ab = SWFDEC_COLOR_A (color); } /** diff --git a/libswfdec/swfdec_color.h b/libswfdec/swfdec_color.h index 39e48fe..07870c3 100644 --- a/libswfdec/swfdec_color.h +++ b/libswfdec/swfdec_color.h @@ -46,11 +46,11 @@ struct swfdec_gradient_struct SwfdecGradientEntry array[1]; }; -#define SWF_COLOR_COMBINE(r,g,b,a) (((r)<<24) | ((g)<<16) | ((b)<<8) | (a)) -#define SWF_COLOR_R(x) (((x)>>24)&0xff) -#define SWF_COLOR_G(x) (((x)>>16)&0xff) -#define SWF_COLOR_B(x) (((x)>>8)&0xff) -#define SWF_COLOR_A(x) ((x)&0xff) +#define SWFDEC_COLOR_COMBINE(r,g,b,a) (((r)<<24) | ((g)<<16) | ((b)<<8) | (a)) +#define SWFDEC_COLOR_R(x) (((x)>>24)&0xff) +#define SWFDEC_COLOR_G(x) (((x)>>16)&0xff) +#define SWFDEC_COLOR_B(x) (((x)>>8)&0xff) +#define SWFDEC_COLOR_A(x) ((x)&0xff) SwfdecColor swfdec_color_apply_morph (SwfdecColor start, SwfdecColor end, unsigned int ratio); void swfdec_color_set_source (cairo_t *cr, SwfdecColor color); diff --git a/libswfdec/swfdec_edittext.c b/libswfdec/swfdec_edittext.c index d38b33a..37727eb 100644 --- a/libswfdec/swfdec_edittext.c +++ b/libswfdec/swfdec_edittext.c @@ -148,7 +148,7 @@ tag_func_define_edit_text (SwfdecSwfDeco SWFDEC_LOG (" color = %u", text->color); } else { SWFDEC_WARNING ("FIXME: figure out default color"); - text->color = SWF_COLOR_COMBINE (255, 255, 255, 255); + text->color = SWFDEC_COLOR_COMBINE (255, 255, 255, 255); } if (has_max_length) { text->max_length = swfdec_bits_get_u16 (b); diff --git a/libswfdec/swfdec_pattern.c b/libswfdec/swfdec_pattern.c index f8902ef..2a614b0 100644 --- a/libswfdec/swfdec_pattern.c +++ b/libswfdec/swfdec_pattern.c @@ -278,10 +278,10 @@ swfdec_image_pattern_paint (SwfdecPatter cairo_pattern_set_filter (pattern, image->filter); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); - if (SWF_COLOR_A (color) < 255) { + if (SWFDEC_COLOR_A (color) < 255) { cairo_save (cr); cairo_clip (cr); - cairo_paint_with_alpha (cr, SWF_COLOR_A (color) / 255.); + cairo_paint_with_alpha (cr, SWFDEC_COLOR_A (color) / 255.); cairo_restore (cr); } else { cairo_fill (cr); @@ -368,8 +368,8 @@ swfdec_gradient_pattern_paint (SwfdecPat gradient->gradient->array[i + 1].ratio * ratio; offset /= 65535 * 255; cairo_pattern_add_color_stop_rgba (pattern, offset, - SWF_COLOR_R(color) / 255.0, SWF_COLOR_G(color) / 255.0, - SWF_COLOR_B(color) / 255.0, SWF_COLOR_A(color) / 255.0); + SWFDEC_COLOR_R(color) / 255.0, SWFDEC_COLOR_G(color) / 255.0, + SWFDEC_COLOR_B(color) / 255.0, SWFDEC_COLOR_A(color) / 255.0); } } else { for (i = 0; i < gradient->gradient->n_gradients; i++){ @@ -377,8 +377,8 @@ swfdec_gradient_pattern_paint (SwfdecPat trans); offset = gradient->gradient->array[i].ratio / 255.0; cairo_pattern_add_color_stop_rgba (pattern, offset, - SWF_COLOR_R(color) / 255.0, SWF_COLOR_G(color) / 255.0, - SWF_COLOR_B(color) / 255.0, SWF_COLOR_A(color) / 255.0); + SWFDEC_COLOR_R(color) / 255.0, SWFDEC_COLOR_G(color) / 255.0, + SWFDEC_COLOR_B(color) / 255.0, SWFDEC_COLOR_A(color) / 255.0); } } cairo_set_source (cr, pattern); @@ -460,7 +460,7 @@ swfdec_pattern_parse (SwfdecSwfDecoder * if (paint_id == 65535) { /* FIXME: someone explain this magic paint id here */ pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL); - SWFDEC_COLOR_PATTERN (pattern)->start_color = SWF_COLOR_COMBINE (0, 255, 255, 255); + SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255); SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color; swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL); pattern->end_transform = pattern->start_transform; @@ -540,7 +540,7 @@ swfdec_pattern_parse_morph (SwfdecSwfDec if (paint_id == 65535) { /* FIXME: someone explain this magic paint id here */ pattern = g_object_new (SWFDEC_TYPE_COLOR_PATTERN, NULL); - SWFDEC_COLOR_PATTERN (pattern)->start_color = SWF_COLOR_COMBINE (0, 255, 255, 255); + SWFDEC_COLOR_PATTERN (pattern)->start_color = SWFDEC_COLOR_COMBINE (0, 255, 255, 255); SWFDEC_COLOR_PATTERN (pattern)->end_color = SWFDEC_COLOR_PATTERN (pattern)->start_color; swfdec_bits_get_matrix (bits, &pattern->start_transform, NULL); swfdec_bits_get_matrix (bits, &pattern->end_transform, NULL); diff --git a/libswfdec/swfdec_sprite.c b/libswfdec/swfdec_sprite.c index 9201218..074bb37 100644 --- a/libswfdec/swfdec_sprite.c +++ b/libswfdec/swfdec_sprite.c @@ -503,7 +503,7 @@ swfdec_sprite_set_n_frames (SwfdecSprite sprite->frames[i].sound_samples = 44100 * 256 / rate; } /* default bg is white */ - sprite->frames[0].bg_color = SWF_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF); + sprite->frames[0].bg_color = SWFDEC_COLOR_COMBINE (0xFF, 0xFF, 0xFF, 0xFF); SWFDEC_LOG ("n_frames = %d", sprite->n_frames); }
Maybe Matching Threads
- Branch 'interpreter' - 15 commits - configure.ac libswfdec/swfdec_audio_event.c libswfdec/swfdec_button_movie.c libswfdec/swfdec_color.c libswfdec/swfdec_color.h libswfdec/swfdec_compiler.c libswfdec/swfdec_image.c libswfdec/swfdec_sprite_movie.c
- Branch 'interpreter' - 8 commits - libswfdec/swfdec_bits.c libswfdec/swfdec_color.c libswfdec/swfdec_color.h libswfdec/swfdec_edittext.c libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_pattern.c libswfdec/swfdec_sprite.c test/dump.c
- 3 commits - libswfdec/swfdec_image.c libswfdec/swfdec_image.h
- libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_pattern.c
- Branch 'interpreter' - 18 commits - libswfdec/swfdec_image.c libswfdec/swfdec_image.h libswfdec/swfdec_js.c libswfdec/swfdec_js_color.c libswfdec/swfdec_js_sound.c libswfdec/swfdec_pattern.c libswfdec/swfdec_scriptable.c libswfdec/swfdec_script.c