summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Michael Moore <cmoore@src.gnome.org>2004-07-17 16:52:01 +0000
committerCaleb Michael Moore <cmoore@src.gnome.org>2004-07-17 16:52:01 +0000
commit8541d92e9b6a7ef615786eb804c42e54605b68dc (patch)
tree0a7ecff7e7b1437b95515945107884d23d93d213
parent4187301e36e70e0b12ee1016073ddcaa0d1fd8d3 (diff)
downloadlibrsvg-8541d92e9b6a7ef615786eb804c42e54605b68dc.tar.gz
image fix
-rw-r--r--ChangeLog4
-rw-r--r--rsvg-filter.c16
-rw-r--r--rsvg-filter.h4
-rw-r--r--rsvg-shapes.c266
4 files changed, 120 insertions, 170 deletions
diff --git a/ChangeLog b/ChangeLog
index b54031c2..aead36df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2004-07-17 Caleb Moore <c.moore@student.unsw.edu.au>
+ * rsvg-shapes.c: rewrote some of the image code so it transforms the image correctly, pitty about loosing bilinear filtering, but we can get that back I suppose
+
+2004-07-17 Caleb Moore <c.moore@student.unsw.edu.au>
+
* rsvg-shapes.c, rsvg-styles.c, rsvg-private.h: Made it remember how bit the vboxes of discrete layers are for alpha optimisations and better filter positioning
2004-07-12 Dom Lachowicz <cinamod@hotmail.com>
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 1e6e8282..77631399 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -226,9 +226,9 @@ gdk_pixbuf_get_interp_pixel(guchar * src, gdouble ox, gdouble oy, guchar ch, FPB
return (guchar)c;
}
-static void
-alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
- gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty)
+void
+rsvg_alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
+ gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty)
{
gint rightx;
gint bottomy;
@@ -432,8 +432,8 @@ rsvg_filter_render (RsvgFilter * self, GdkPixbuf * source, GdkPixbuf * output,
bounds = rsvg_filter_primitive_get_bounds (NULL, ctx);
- alpha_blt (ctx->lastresult.result, bounds.x1, bounds.y1, bounds.x2 - bounds.x1,
- bounds.y2 - bounds.y1, output, bounds.x1, bounds.y1);
+ rsvg_alpha_blt (ctx->lastresult.result, bounds.x1, bounds.y1, bounds.x2 - bounds.x1,
+ bounds.y2 - bounds.y1, output, bounds.x1, bounds.y1);
context->bbox.x0 = bounds.x1;
context->bbox.y0 = bounds.y1;
context->bbox.x1 = bounds.x2;
@@ -2029,9 +2029,9 @@ rsvg_filter_primitive_merge_render (RsvgFilterPrimitive * self,
for (i = 0; i < mself->nodes->len; i++)
{
in = rsvg_filter_get_in (g_ptr_array_index (mself->nodes, i), ctx);
- alpha_blt (in, boundarys.x1, boundarys.y1, boundarys.x2 - boundarys.x1,
- boundarys.y2 - boundarys.y1, output, boundarys.x1,
- boundarys.y1);
+ rsvg_alpha_blt (in, boundarys.x1, boundarys.y1, boundarys.x2 - boundarys.x1,
+ boundarys.y2 - boundarys.y1, output, boundarys.x1,
+ boundarys.y1);
g_object_unref (G_OBJECT (in));
}
diff --git a/rsvg-filter.h b/rsvg-filter.h
index dd031eae..0ab19d58 100644
--- a/rsvg-filter.h
+++ b/rsvg-filter.h
@@ -120,6 +120,10 @@ void
rsvg_filter_adobe_blend(gint modenum, GdkPixbuf *in, GdkPixbuf *bg, GdkPixbuf *output,
RsvgHandle * ctx);
+void
+rsvg_alpha_blt (GdkPixbuf * src, gint srcx, gint srcy, gint srcwidth,
+ gint srcheight, GdkPixbuf * dst, gint dstx, gint dsty);
+
G_END_DECLS
#endif
diff --git a/rsvg-shapes.c b/rsvg-shapes.c
index 99ae61eb..613a12b1 100644
--- a/rsvg-shapes.c
+++ b/rsvg-shapes.c
@@ -34,6 +34,7 @@
#include "rsvg-bpath-util.h"
#include "rsvg-path.h"
#include "rsvg-defs.h"
+#include "rsvg-filter.h"
#include <libart_lgpl/art_affine.h>
#include <libart_lgpl/art_vpath_bpath.h>
@@ -1124,46 +1125,6 @@ rsvg_start_ellipse (RsvgHandle *ctx, RsvgPropertyBag *atts)
g_string_free (d, TRUE);
}
-static void
-size_prepared_cb (GdkPixbufLoader *loader,
- int width,
- int height,
- gpointer data)
-{
- struct {
- int width;
- int height;
- gboolean keep_aspect_ratio;
- } *info = data;
-
- if (info->keep_aspect_ratio)
- {
- if (width < 0)
- width = 512;
- if (height < 0)
- height = 512;
-
- if ((double)height * (double)info->width >
- (double)width * (double)info->height)
- {
- width = 0.5 + (double)width * (double)info->height / (double)height;
- height = info->height;
- }
- else
- {
- height = 0.5 + (double)height * (double)info->width / (double)width;
- width = info->width;
- }
- }
- else
- {
- width = info->width;
- height = info->height;
- }
-
- gdk_pixbuf_loader_set_size (loader, width, height);
-}
-
static const char s_UTF8_B64Alphabet[64] = {
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, /* A-Z */
@@ -1327,26 +1288,6 @@ static gboolean utf8_base64_decode(char ** binptr, size_t * binlen, const char *
}
static GdkPixbuf *
-rsvg_pixbuf_ensure_alpha_channel(GdkPixbuf * pixbuf)
-{
- if (gdk_pixbuf_get_has_alpha(pixbuf))
- return pixbuf;
- else {
-#if 0
- /* why doesn't this work properly?? */
- GdkPixbuf *alpha;
-
- alpha = gdk_pixbuf_add_alpha(pixbuf, FALSE, 255, 255, 255);
- g_object_unref(pixbuf);
-
- return alpha;
-#else
- return pixbuf;
-#endif
- }
-}
-
-static GdkPixbuf *
rsvg_pixbuf_new_from_data_at_size (const char *data,
int width,
int height,
@@ -1359,12 +1300,6 @@ rsvg_pixbuf_new_from_data_at_size (const char *data,
char * buffer, *bufptr;
size_t buffer_len, buffer_max_len, data_len;
- struct {
- gint width;
- gint height;
- gboolean keep_aspect_ratio;
- } info;
-
g_return_val_if_fail (data != NULL, NULL);
g_return_val_if_fail (width > 0 && height > 0, NULL);
@@ -1385,12 +1320,6 @@ rsvg_pixbuf_new_from_data_at_size (const char *data,
buffer_len = buffer_max_len - buffer_len;
loader = gdk_pixbuf_loader_new ();
-
- info.width = width;
- info.height = height;
- info.keep_aspect_ratio = keep_aspect_ratio;
-
- g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
if (!gdk_pixbuf_loader_write (loader, buffer, buffer_len, error)) {
gdk_pixbuf_loader_close (loader, NULL);
@@ -1420,7 +1349,7 @@ rsvg_pixbuf_new_from_data_at_size (const char *data,
g_free(buffer);
- return rsvg_pixbuf_ensure_alpha_channel(pixbuf);
+ return pixbuf;
}
static gchar *
@@ -1460,14 +1389,8 @@ rsvg_pixbuf_new_from_file_at_size (const char *filename,
guchar buffer [4096];
int length;
FILE *f;
- struct {
- gint width;
- gint height;
- gboolean keep_aspect_ratio;
- } info;
-
+
g_return_val_if_fail (filename != NULL, NULL);
- g_return_val_if_fail (width > 0 && height > 0, NULL);
path = rsvg_get_file_path (filename, base_uri);
f = fopen (path, "rb");
@@ -1484,12 +1407,6 @@ rsvg_pixbuf_new_from_file_at_size (const char *filename,
loader = gdk_pixbuf_loader_new ();
- info.width = width;
- info.height = height;
- info.keep_aspect_ratio = keep_aspect_ratio;
-
- g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
-
while (!feof (f)) {
length = fread (buffer, 1, sizeof (buffer), f);
if (length > 0)
@@ -1508,8 +1425,8 @@ rsvg_pixbuf_new_from_file_at_size (const char *filename,
return NULL;
}
- pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-
+ pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+
if (!pixbuf) {
g_object_unref (loader);
g_set_error (error,
@@ -1524,7 +1441,7 @@ rsvg_pixbuf_new_from_file_at_size (const char *filename,
g_object_unref (loader);
- return rsvg_pixbuf_ensure_alpha_channel(pixbuf);
+ return pixbuf;
}
#ifdef HAVE_GNOME_VFS
@@ -1546,11 +1463,6 @@ rsvg_pixbuf_new_from_vfs_at_size (const char *filename,
GnomeVFSFileSize length;
GnomeVFSHandle *f = NULL;
GnomeVFSResult res;
- struct {
- gint width;
- gint height;
- gboolean keep_aspect_ratio;
- } info;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (width > 0 && height > 0, NULL);
@@ -1583,12 +1495,6 @@ rsvg_pixbuf_new_from_vfs_at_size (const char *filename,
loader = gdk_pixbuf_loader_new ();
- info.width = width;
- info.height = height;
- info.keep_aspect_ratio = keep_aspect_ratio;
-
- g_signal_connect (loader, "size-prepared", G_CALLBACK (size_prepared_cb), &info);
-
while (TRUE) {
res = gnome_vfs_read (f, buffer, sizeof (buffer), &length);
if (res == GNOME_VFS_OK && length > 0) {
@@ -1626,7 +1532,7 @@ rsvg_pixbuf_new_from_vfs_at_size (const char *filename,
g_object_unref (loader);
- return rsvg_pixbuf_ensure_alpha_channel(pixbuf);
+ return pixbuf;
}
#endif
@@ -1671,10 +1577,20 @@ rsvg_start_image (RsvgHandle *ctx, RsvgPropertyBag *atts)
GdkPixbuf *img;
GError *err = NULL;
- guchar *rgb = NULL;
- int dest_rowstride;
double tmp_affine[6];
RsvgState *state;
+
+ double tmp_tmp_affine[6];
+ double inv_tmp_affine[6];
+ double raw_inv_tmp_affine[6];
+ GdkPixbuf * intermediate;
+ int intstride;
+ int basestride;
+ int basex, basey;
+ double rawx, rawy;
+ guchar * intpix;
+ guchar * basepix;
+ int i, j, k, basebpp;
/* skip over defs entries for now */
if (ctx->in_defs) return;
@@ -1704,21 +1620,14 @@ rsvg_start_image (RsvgHandle *ctx, RsvgPropertyBag *atts)
rsvg_parse_style_attrs (ctx, state, "image", klazz, id, atts);
}
- if (!href || x < 0. || y < 0. || w <= 0. || h <= 0.)
+ if (!href || w <= 0. || h <= 0.)
return;
+
/* figure out if image is visible or not */
if (!state->visible || !state->cond_true)
return;
-
- w *= state->affine[0];
- h *= state->affine[3];
-
img = rsvg_pixbuf_new_from_href (href, rsvg_handle_get_base_uri (ctx), w, h, (aspect_ratio != RSVG_ASPECT_RATIO_NONE), &err);
-
- /* w & h might've been adjusted by preserveAspectRatio */
- w = gdk_pixbuf_get_width (img);
- h = gdk_pixbuf_get_height (img);
if (!img)
{
@@ -1730,70 +1639,103 @@ rsvg_start_image (RsvgHandle *ctx, RsvgPropertyBag *atts)
return;
}
- has_alpha = gdk_pixbuf_get_has_alpha (img);
- if(0 /* !has_alpha */)
+ if (aspect_ratio)
{
- GdkPixbuf *tmp_pixbuf;
-
- tmp_pixbuf = gdk_pixbuf_add_alpha(img, FALSE, 0, 0, 0);
- g_object_unref(img);
- img = tmp_pixbuf;
- has_alpha = TRUE;
+ if ((double)gdk_pixbuf_get_height (img) * (double)w >
+ (double)gdk_pixbuf_get_width (img) * (double)h)
+ {
+ w = 0.5 + (double)gdk_pixbuf_get_width (img) * (double)h
+ / (double)gdk_pixbuf_get_height (img);
+ }
+ else
+ {
+ h = 0.5 + (double)gdk_pixbuf_get_height (img) * (double)w
+ / (double)gdk_pixbuf_get_width (img);
+ }
}
- dest_rowstride = (int)(w * (has_alpha ? 4 : 3) + 3) & ~3;
- rgb = g_new (guchar, h * dest_rowstride);
-
- /* we handle scaling above. we handle translation below. we don't handle rotation very well at all */
- tmp_affine[0] = tmp_affine[3] = 1;
- tmp_affine[4] = tmp_affine[5] = 0;
- tmp_affine[1] = state->affine[1];
- tmp_affine[2] = state->affine[2];
-
- if(has_alpha)
- art_rgb_rgba_affine (rgb, 0, 0, w, h, dest_rowstride,
- gdk_pixbuf_get_pixels (img),
- w, h, gdk_pixbuf_get_rowstride (img),
- tmp_affine,
- ART_FILTER_NEAREST,
- NULL);
- else
- art_rgb_affine (rgb, 0, 0, w, h, dest_rowstride,
- gdk_pixbuf_get_pixels (img),
- w, h, gdk_pixbuf_get_rowstride (img),
- tmp_affine,
- ART_FILTER_NEAREST,
- NULL);
-
- g_object_unref (G_OBJECT (img));
- img = gdk_pixbuf_new_from_data (rgb, GDK_COLORSPACE_RGB, has_alpha, 8, w, h, dest_rowstride, NULL, NULL);
-
- if (!img)
+ has_alpha = gdk_pixbuf_get_has_alpha (img);
+
+ for (i = 0; i < 6; i++)
+ tmp_affine[i] = state->affine[i];
+
+ /*translate to x and y*/
+ tmp_tmp_affine[0] = tmp_tmp_affine[3] = 1;
+ tmp_tmp_affine[1] = tmp_tmp_affine[2] = 0;
+ tmp_tmp_affine[4] = x;
+ tmp_tmp_affine[5] = y;
+
+ art_affine_multiply(tmp_affine, tmp_tmp_affine, tmp_affine);
+
+ art_affine_invert(raw_inv_tmp_affine, tmp_affine);
+
+ /*scale to w and h*/
+ tmp_tmp_affine[0] = (double)gdk_pixbuf_get_width (img) / (double)w;
+ tmp_tmp_affine[3] = (double)gdk_pixbuf_get_height (img) / (double)h;
+ tmp_tmp_affine[1] = tmp_tmp_affine[2] = tmp_tmp_affine[4] = tmp_tmp_affine[5] = 0;
+ art_affine_multiply(inv_tmp_affine, raw_inv_tmp_affine, tmp_tmp_affine);
+
+ intermediate = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 1, 8,
+ gdk_pixbuf_get_width (ctx->pixbuf),
+ gdk_pixbuf_get_height (ctx->pixbuf));
+
+
+ if (!intermediate)
{
- g_free (rgb);
+ g_object_unref (G_OBJECT (img));
return;
}
+ basestride = gdk_pixbuf_get_rowstride (img);
+ intstride = gdk_pixbuf_get_rowstride (intermediate);
+ basepix = gdk_pixbuf_get_pixels (img);
+ intpix = gdk_pixbuf_get_pixels (intermediate);
+ basebpp = has_alpha ? 4 : 3;
+
+ /*apply the transformation*/
+ for (i = 0; i < gdk_pixbuf_get_width (intermediate); i++)
+ for (j = 0; j < gdk_pixbuf_get_height (intermediate); j++)
+ {
+ basex = inv_tmp_affine[0] * i + inv_tmp_affine[2] * j + inv_tmp_affine[4];
+ basey = inv_tmp_affine[1] * i + inv_tmp_affine[3] * j + inv_tmp_affine[5];
+ rawx = raw_inv_tmp_affine[0] * i + raw_inv_tmp_affine[2] * j + raw_inv_tmp_affine[4];
+ rawy = raw_inv_tmp_affine[1] * i + raw_inv_tmp_affine[3] * j + raw_inv_tmp_affine[5];
+ if (basex < 0 || basey < 0
+ || basex >= gdk_pixbuf_get_width (img)
+ || basey >= gdk_pixbuf_get_height (img)
+ || rawx < 0 || rawy < 0 || rawx >= w || rawy >= h)
+ {
+ for (k = 0; k < 4; k++)
+ intpix[i * 4 + j * intstride + k] = 0;
+ }
+ else
+ {
+ for (k = 0; k < basebpp; k++)
+ intpix[i * 4 + j * intstride + k] = basepix[basebpp * basex + basey * basestride + k];
+ if (!has_alpha)
+ intpix[i * 4 + j * intstride + 3] = 255;
+ }
+ }
+ g_object_unref (G_OBJECT (img));
+
rsvg_push_discrete_layer(ctx);
- gdk_pixbuf_copy_area (img, 0, 0,
- gdk_pixbuf_get_width (img),
- gdk_pixbuf_get_height (img),
- ctx->pixbuf,
- state->affine[4] + x, /* translate */
- state->affine[5] + y);
+ /*slap it down*/
+ rsvg_alpha_blt (intermediate, 0, 0,
+ gdk_pixbuf_get_width (intermediate),
+ gdk_pixbuf_get_height (intermediate),
+ ctx->pixbuf,
+ 0, 0);
rsvg_pop_discrete_layer(ctx);
- temprect.x0 = state->affine[4] + x;
- temprect.y0 = state->affine[5] + y;
- temprect.x1 = state->affine[4] + x + gdk_pixbuf_get_width (img);
- temprect.y1 = state->affine[5] + y + gdk_pixbuf_get_height (img);
+ /*fix me, this is not the propper rectangle*/
+ temprect.x0 = 0;;
+ temprect.y0 = 0;;
+ temprect.x1 = gdk_pixbuf_get_width (intermediate);
+ temprect.y1 = gdk_pixbuf_get_height (intermediate);
art_irect_union(&ctx->bbox, &ctx->bbox, &temprect);
-
- g_object_unref (G_OBJECT (img));
- g_free (rgb);
}
void