You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-users@xmlgraphics.apache.org by Stephen Drake <st...@drakenz.com> on 2006/11/07 05:48:01 UTC

Effect of shape-rendering property

Hi,

I am creating svg documents that contain raster images, included with the
<image> tag, and displaying them with Batik.  Some of the images are
rotated, and I would like their edges to be anti-aliased against the
background.  I tried setting shape-rendering="geometricPrecision" on the
image element, but it doesn't seem to have any effect - on Mac OS X 10.4
some of the edges are anti-aliased regardless and on Windows XP and Ubuntu
Edgy the edges are always jagged (I am using Batik trunk updated today).

I tried three work-arounds:

i) Apply a clip-path to the image.  This improves the appearance on Windows
and Linux, but doesn't look as good as (ii) or (iii).  On OS X the edges are
smooth, but horizontal and vertical lines appear, as if the image has been
broken into tiles and not quite aligned properly.

ii)  Apply a mask to the image.  This looks great on Windows and Linux, but
on OS X the "tiling" lines appear again, and the edges are a bit strange -
it looks like gradients that would smooth the edge out have been applied the
wrong way around, mirrored.

iii)  Draw a line over the edge of the image, the same colour as the
background.  Draws nice smooth edges on all platforms, but gets tricky if
the background is complex.

The same behaviour applies to the svg element when the content exceeds the
viewBox and overflow is hidden.  The example below demonstrates the problem:

<?xml version="1.0" encoding="UTF-8"?>

<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 400 100"
shape-rendering="optimizeSpeed">

  <defs>
    <svg id="img" width="98" height="98">
      <rect x="-1" y="-1" width="100" height="100" fill="#505050"/>
    </svg>

    <image id="img2" width="98" height="98" xlink:href="your-image.jpg"
preserveAspectRatio="xMidYMid slice"/>

    <rect id="clipShape" x="0.5" y="0.5" width="97" height="97"/>

    <clipPath id="clip" shape-rendering="geometricPrecision">
      <use xlink:href="#clipShape"/>
    </clipPath>

    <mask id="mask" shape-rendering="geometricPrecision">
      <rect x="0.5" y="0.5" width="97" height="97" fill="white"/>
    </mask>
  </defs>

  <g transform="translate(1.7,0) rotate(1)">
    <use xlink:href="#img" shape-rendering="geometricPrecision"/>
  </g>

  <g transform="translate(101.7,0) rotate(1)">
    <use xlink:href="#img" clip-path="url(#clip)"/>
  </g>

  <g transform="translate(201.7,0) rotate(1)">
    <use xlink:href="#img" mask="url(#mask)"/>
  </g>

  <g transform="translate(301.7,0) rotate(1)">
    <use xlink:href="#img"/>
    <rect width="98" height="98" fill="none" stroke="white" stroke-width="1"
shape-rendering="geometricPrecision"/>
  </g>

</svg>

Thanks in advance to anyone who replies!

Regards,

Steve Drake

-- 
View this message in context: http://www.nabble.com/Effect-of-shape-rendering-property-tf2586765.html#a7212549
Sent from the Batik - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Effect of shape-rendering property

Posted by Andrew Plotkin <er...@eblong.com>.
On Mon, 6 Nov 2006, Stephen Drake wrote:

> i) Apply a clip-path to the image.  This improves the appearance on Windows
> and Linux, but doesn't look as good as (ii) or (iii).  On OS X the edges are
> smooth, but horizontal and vertical lines appear, as if the image has been
> broken into tiles and not quite aligned properly.
>
> ii)  Apply a mask to the image.  This looks great on Windows and Linux, but
> on OS X the "tiling" lines appear again, and the edges are a bit strange -
> it looks like gradients that would smooth the edge out have been applied the
> wrong way around, mirrored.

This is a bug with all masking and clipping operations on OSX.

--Z

-- 
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
Making a saint out of Reagan is sad. Making an idol out of Nixon ("If the
President does it then it's legal") is contemptible.

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Effect of shape-rendering property

Posted by Stephen Drake <st...@drakenz.com>.
Hi Thomas,

I have done some further testing of the problems I was seeing last week,
based on your feedback.   I am using the patch at the bottom of this post
and have not noticed any ill effects - I will post again if I see any
problems.


thomas.deweese wrote:
> 
>    Hmm, I wonder if we can eliminate the clip completely.  It's
> introduced in the 'GraphicsUtil.createGraphics'  We used to use
> this so we could calculate the size of the output rendering buffer.
> I think most of that has moved to using 'getDestination'/
> 'getDestinationBounds'.
> 
Not setting the clip in GraphicsUtil.createGraphics fixes the tile edge
anti-aliasing issue on the Mac and has no obvious effect on Windows.


thomas.deweese wrote:
> 
>> I guess this kind of thing is also what causes lines to appear
>> sometimes when a dynamic document is updated on the Mac.
> 
>    Possible.
> 
Expanding the clip one pixel up and to the left in MacRenderer.repaint
prevents spurious lines from appearing around the edge of the repaint area
after changes to the svg document.


thomas.deweese wrote:
> 
>    You go a little bit too far though.  The divide out of alpha is
> important, It's the middle part of your patch (the construction of
> destBI) that can safely be skipped (as well as the copyBand at the 
> end), the coerceData calls are still needed I think.
> 
I've tracked this down a bit more accurately now.  The problem occurs when
ColorModel.isAlphaPremultiplied doesn't match the data and / or value of
isRasterPremultiplied in the BufferedImage constructor.  If the source
ColorModel is replaced by one returned by ColorModel.coerceData the problem
goes away.


thomas.deweese wrote:
> 
>    Once again thanks for the time to track this stuff down!
> 
Glad to be able to help - Batik has been tremendously useful to me.

Regards,
Steve Drake


Index: sources/org/apache/batik/gvt/renderer/MacRenderer.java
===================================================================
--- sources/org/apache/batik/gvt/renderer/MacRenderer.java	(revision 471963)
+++ sources/org/apache/batik/gvt/renderer/MacRenderer.java	(working copy)
@@ -335,7 +335,7 @@
                     Rectangle r = (Rectangle)iter.next();
                     if (!dr.intersects(r)) continue;
                     r = dr.intersection(r); 
-                    g2d.setClip     (r.x, r.y, r.width, r.height);
+                    g2d.setClip     (r.x - 1, r.y - 1, r.width + 1,
r.height + 1);
                     g2d.setComposite(AlphaComposite.Clear);
                     g2d.fillRect    (r.x, r.y, r.width, r.height);
                     g2d.setComposite(AlphaComposite.SrcOver);
@@ -350,7 +350,7 @@
                 if (!dr.intersects(r)) continue;
                 r = dr.intersection(r);
                 g2d.setTransform(IDENTITY);
-                g2d.setClip(r.x, r.y, r.width, r.height);
+                g2d.setClip(r.x - 1, r.y - 1, r.width + 1, r.height + 1);
                 g2d.setComposite(AlphaComposite.Clear);
                 g2d.fillRect(r.x, r.y, r.width, r.height);
                 g2d.setComposite(AlphaComposite.SrcOver);
Index: sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java
===================================================================
--- sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java
(revision 471963)
+++ sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java	(working
copy)
@@ -90,7 +90,7 @@
             // the color convert may not be a linear operation which may 
             // lead to out of range values.
             if (srcCM.hasAlpha())
-                GraphicsUtil.coerceData(srcWr, srcCM, false);
+                srcCM = srcCM.coerceData(srcWr, false);
 
             BufferedImage srcBI, dstBI;
             srcBI = new BufferedImage(srcCM, 
Index: sources/org/apache/batik/ext/awt/image/GraphicsUtil.java
===================================================================
--- sources/org/apache/batik/ext/awt/image/GraphicsUtil.java	(revision
471963)
+++ sources/org/apache/batik/ext/awt/image/GraphicsUtil.java	(working copy)
@@ -473,7 +473,6 @@
             g2d.addRenderingHints(hints);
         g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
                              new WeakReference(bi));
-        g2d.clip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
         return g2d;
     }
 
@@ -482,7 +481,6 @@
         Graphics2D g2d = bi.createGraphics();
         g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
                              new WeakReference(bi));
-        g2d.clip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
         return g2d;
     }
 
-- 
View this message in context: http://www.nabble.com/Effect-of-shape-rendering-property-tf2586765.html#a7427822
Sent from the Batik - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Effect of shape-rendering property

Posted by th...@kodak.com.
Hi Stephen,

Stephen Drake <st...@drakenz.com> wrote on 11/09/2006 02:03:12 AM:

> Thanks for your help - I have had some success now in displaying
> smooth-edged, rotated images with several of the methods described.

   Glad to help (if I did ;).

> thomas.deweese wrote:
> > 
> >    So the image is broken into tiles, but they are aligned properly. I
> > suspect that the anti-aliasing you see on Mac OS X is causing the
> > tile edges to be visible even when they shouldn't be.
> > 
> Indeed - I displayed each tile scaled up in a separate window, and it 
was
> clear that they were anti-aliased along the top and left edges.  I think
> I've seen this behaviour on the Mac before.  One way around it is to 
extend
> the clip area as in the patch below:

   Hmm, I wonder if we can eliminate the clip completely.  It's
introduced in the 'GraphicsUtil.createGraphics'  We used to use
this so we could calculate the size of the output rendering buffer.
I think most of that has moved to using 'getDestination'/
'getDestinationBounds'.

> This stops the tile edges from showing in clip and mask operations. 

    Thanks for tracking this down, I'll try at least outsetting 
the clip for Mac.

> I guess this kind of thing is also what causes lines to appear
> sometimes when a dynamic document is updated on the Mac.

   Possible.

> thomas.deweese wrote:
> > 
> >    Another method to try would be to put the image with the mask in
> > a pattern and fill a rotated rect with that.  You might not even need
> > to mask the image in this case.
> > 
> This works perfectly wrt shape rendering (no mask required), but on the 
Mac
> the image is blocky - it looks like it is rendered at the size of the
> pattern and then scaled up.

   Hmm, this would be very odd.  I have a hard time imagining what
would cause that.

> I wrote in my original post:
> > ii)  Apply a mask to the image.  This looks great on Windows and 
Linux,
> > but on OS X ... it looks like gradients that would smooth the edge out 
have
> > been applied the wrong way around, mirrored.

> This problem appears to arise when the mask is converted to a luminance
> colorspace using Any2LumRed.  I have attached a patch below which works 
for
> me on Mac, Windows and Linux, all with various revisions of Java 1.5. 
The
> source code mentions a bug in ColorConvertOp, and my patch attempts to
> remove the workaround for that bug.

   You go a little bit too far though.  The divide out of alpha is
important, It's the middle part of your patch (the construction of
destBI) that can safely be skipped (as well as the copyBand at the 
end), the coerceData calls are still needed I think.

> I don't know the history though, so I can't tell if the bug has 
> been fixed in a subsequent Java release or if it applies to a 
> situation other than what I am testing.

   Once again thanks for the time to track this stuff down!


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Effect of shape-rendering property

Posted by Stephen Drake <st...@drakenz.com>.
Hi Thomas, Andrew,

Thanks for your help - I have had some success now in displaying
smooth-edged, rotated images with several of the methods described.


thomas.deweese wrote:
> 
>    So the image is broken into tiles, but they are aligned properly.  I
> suspect that the anti-aliasing you see on Mac OS X is causing the
> tile edges to be visible even when they shouldn't be.
> 
Indeed - I displayed each tile scaled up in a separate window, and it was
clear that they were anti-aliased along the top and left edges.  I think
I've seen this behaviour on the Mac before.  One way around it is to extend
the clip area as in the patch below:

Index:
xml-batik/sources/org/apache/batik/gvt/filter/GraphicsNodeRed8Bit.java
===================================================================
--- xml-batik/sources/org/apache/batik/gvt/filter/GraphicsNodeRed8Bit.java
(revision 471963)
+++ xml-batik/sources/org/apache/batik/gvt/filter/GraphicsNodeRed8Bit.java
(working copy)
@@ -125,6 +125,7 @@
                                 null);
 
         Graphics2D g = GraphicsUtil.createGraphics(offScreen, hints);
+        if (onMacOSX) g.setClip(-1, -1, wr.getWidth() + 1, wr.getHeight() +
1); // prevent anti-aliasing at edges of tiles
         g.setComposite(AlphaComposite.Clear);
         g.fillRect(0, 0, wr.getWidth(), wr.getHeight());
         g.setComposite(AlphaComposite.SrcOver);

This stops the tile edges from showing in clip and mask operations. 
Removing the "if (onMacOSX)" bit doesn't appear to have any affect in
Windows.  I guess this kind of thing is also what causes lines to appear
sometimes when a dynamic document is updated on the Mac.


thomas.deweese wrote:
> 
>    Another method to try would be to put the image with the mask in
> a pattern and fill a rotated rect with that.  You might not even need
> to mask the image in this case.
> 
This works perfectly wrt shape rendering (no mask required), but on the Mac
the image is blocky - it looks like it is rendered at the size of the
pattern and then scaled up.

I wrote in my original post:
> ii)  Apply a mask to the image.  This looks great on Windows and Linux,
> but
> on OS X ... it looks like gradients that would smooth the edge out have
> been
> applied the wrong way around, mirrored.
This problem appears to arise when the mask is converted to a luminance
colorspace using Any2LumRed.  I have attached a patch below which works for
me on Mac, Windows and Linux, all with various revisions of Java 1.5.  The
source code mentions a bug in ColorConvertOp, and my patch attempts to
remove the workaround for that bug.  I don't know the history though, so I
can't tell if the bug has been fixed in a subsequent Java release or if it
applies to a situation other than what I am testing.

Regards,

Steve Drake


Index:
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java
===================================================================
---
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java
(revision 471963)
+++
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/Any2LumRed.java
(working copy)
@@ -86,65 +86,18 @@
         } else {
             WritableRaster srcWr  = (WritableRaster)srcRas;
 
-            // Divide out alpha if we have it.  We need to do this since
-            // the color convert may not be a linear operation which may 
-            // lead to out of range values.
-            if (srcCM.hasAlpha())
-                GraphicsUtil.coerceData(srcWr, srcCM, false);
-
             BufferedImage srcBI, dstBI;
             srcBI = new BufferedImage(srcCM, 
                                      
srcWr.createWritableTranslatedChild(0,0),
-                                      false, 
+                                      srcCM.isAlphaPremultiplied(), 
                                       null);
             ColorModel dstCM = getColorModel();
-            if (!dstCM.hasAlpha()) {
-                // No alpha ao we don't have to work around the bug
-                // in the color convert op.
-                dstBI = new BufferedImage
-                    (dstCM, wr.createWritableTranslatedChild(0,0),
-                     dstCM.isAlphaPremultiplied(), null);
-            } else {
-                // All this nonsense is to work around the fact that the
-                // Color convert op doesn't properly copy the Alpha from
-                // src to dst.
-                PixelInterleavedSampleModel dstSM;
-                dstSM = (PixelInterleavedSampleModel)wr.getSampleModel();
-                SampleModel smna = new PixelInterleavedSampleModel
-                    (dstSM.getDataType(),    
-                     dstSM.getWidth(),       dstSM.getHeight(),
-                     dstSM.getPixelStride(), dstSM.getScanlineStride(),
-                     new int [] { 0 });
+            dstBI = new BufferedImage
+                (dstCM, wr.createWritableTranslatedChild(0,0),
+                 dstCM.isAlphaPremultiplied(), null);
 
-                WritableRaster dstWr;
-                dstWr = Raster.createWritableRaster(smna,
-                                                    wr.getDataBuffer(),
-                                                    new Point(0,0));
-                dstWr = dstWr.createWritableChild
-                    (wr.getMinX()-wr.getSampleModelTranslateX(),
-                     wr.getMinY()-wr.getSampleModelTranslateY(),
-                     wr.getWidth(), wr.getHeight(),
-                     0, 0, null);
-                
-                ColorModel cmna = new ComponentColorModel
-                    (ColorSpace.getInstance(ColorSpace.CS_GRAY),
-                     new int [] {8}, false, false,
-                     Transparency.OPAQUE, 
-                     DataBuffer.TYPE_BYTE);
-
-                dstBI = new BufferedImage(cmna, dstWr, false, null);
-            }
-
             ColorConvertOp op = new ColorConvertOp(null);
             op.filter(srcBI, dstBI);
-
-            // Have to 'fix' alpha premult
-            if (dstCM.hasAlpha()) {
-                copyBand(srcWr, sm.getNumBands()-1,
-                         wr,    getSampleModel().getNumBands()-1);
-                if (dstCM.isAlphaPremultiplied())
-                    GraphicsUtil.multiplyAlpha(wr);
-            }
         }
         return wr;
     }

-- 
View this message in context: http://www.nabble.com/Effect-of-shape-rendering-property-tf2586765.html#a7253364
Sent from the Batik - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org


Re: Effect of shape-rendering property

Posted by th...@kodak.com.
Hi Stephen,

Stephen Drake <st...@drakenz.com> wrote on 11/06/2006 11:48:01 PM:

> I am creating svg documents that contain raster images, included with 
the
> <image> tag, and displaying them with Batik.  Some of the images are
> rotated, and I would like their edges to be anti-aliased against the
> background.  I tried setting shape-rendering="geometricPrecision" on the
> image element, but it doesn't seem to have any effect - on Mac OS X 10.4
> some of the edges are anti-aliased regardless and on Windows XP and 
Ubuntu
> Edgy the edges are always jagged (I am using Batik trunk updated today).

   This is tricky, I consider this a bit of a bug in the JDK.
We do what we can to ensure that the images are anti-aliased but the
edges are not on the Sun JVM.   Part of the issue is also that
the image has a clip associated with it and the JVM's clipping code
is hard edged (although shape-rendering can convert that to anti-aliased).


> I tried three work-arounds:
> 
> i) Apply a clip-path to the image.  This improves the appearance on 
Windows
> and Linux, but doesn't look as good as (ii) or (iii).  On OS X the edges 
are
> smooth, but horizontal and vertical lines appear, as if the image has 
been
> broken into tiles and not quite aligned properly.

   So the image is broken into tiles, but they are aligned properly.  I
suspect that the anti-aliasing you see on Mac OS X is causing the
tile edges to be visible even when they shouldn't be.

> ii)  Apply a mask to the image.  This looks great on Windows and Linux, 
but
> on OS X the "tiling" lines appear again, and the edges are a bit strange 
-
> it looks like gradients that would smooth the edge out have been applied 
the
> wrong way around, mirrored.

   Once again I suspect that the tiling lines are a side effect of 
anti-aliasing the images.  You might try changing the image-rendering
hint to see if this goes away.

> iii)  Draw a line over the edge of the image, the same colour as the
> background.  Draws nice smooth edges on all platforms, but gets tricky 
if
> the background is complex.
> 
> The same behaviour applies to the svg element when the content exceeds 
the
> viewBox and overflow is hidden.  The example below demonstrates the 
problem:

   Another method to try would be to put the image with the mask in
a pattern and fill a rotated rect with that.  You might not even need
to mask the image in this case.

   Good luck!



---------------------------------------------------------------------
To unsubscribe, e-mail: batik-users-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: batik-users-help@xmlgraphics.apache.org