Skip to main content

Draw vs Fill

5 replies [Last post]
mgrev
Offline
Joined: 2003-08-12

G'day Mates.

If you create a Shape, say a Rectangle, and fill and then to get an outline, draw it, you'll get the drawn rectangle to be one pixel larger than the filled one. This is as stated in the docs, and I understand this, and why. Though this is creating quite some problem for me since I'm creating an API that excepts shapes and the paint to fill and outline them (among other things) and are supposed to procuce an image of the result.

The problem is that if you want the shape to be outlined with a translucent color, it looks really bad since generally the top left pixels touches the shape but the bottom right don't (they are painted outside the shape).

I've tried the following:

1) Setting stroke-hint to PURE. Works, but since it creates two pixel outlines (as it should) it's a no-go.

2) Auto transformation of shapes for draw/fill to scale down i pixel for draw. Works sometimes but due to rounding in the Sun API when a custom transform is used, creates inconsistent results. The outline jumps on/off the edges of the filled shape.

3) Trying different BasicStroke()s. Doesn't work.

Some of the above DO work in certain circumstances, but then there's the problem with turning anti aliasing on/off, which usually foils some work arounds.

My API has no control over anti-aliasing, stroke or grpahics transform, all that is parameterized. I just want to outline shapes in a good looking, pixel correct way.

Now, is there a simple (or complicated for that matter) way to get a Stoke, transform, rendering hint, or whatever, that always creates equally sized shapes dring fill/draw?

If not (which I'm almost sure of), is this how it works on other platforms (non Java) as well?

ps. I noticed sketsa (SVG editor) has the same problem. As do every other app i've seen.

ps2. Also drawing/filling cirlces don't even paint the same pixels, sometimes there are "unpainted" pixels between the drawn orcle and the filled one.

Cheers,
Mikael

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
zander
Offline
Joined: 2003-06-13

I have not ever seen the problem you describe and have certainly seen some applications do this correctly (Karbon is a good example for that).
This implies there is/are bugs somewhere.

But just from a fresh perspective here is an idea that should always work:
create a new BufferedImage.
fill the inner shape in white.
set the xor mode (the one to unset already painted pixels)
fill the same shape again; but a little bigger this time.

What you should end up with is an outline of the circle that fits exactly around the inner circle.
You can then use that bigmap to paint over the original circle in your painting.
I'm not sure what the best approach is to using that shape; you can either use a transparent bufferedImage, or you can try to set the clipmask from the binary image..

Hope this new approach gives you some idea..

ps; "G'day Mates" is a strange thing to say for someone from Sweden. It surely is a long way from Australia... :)

mgrev
Offline
Joined: 2003-08-12

That would work yes, but I'm making a shape-based framework, AttributedShape. The AttributedShape, and subclasses, normally contains a reference to a shape and some attributes that denotes how it should be drawn, filled, filtered, cropped, clipped, positioned and such. That's why I need a very generic solution. :-|

I basically know that this is impossible, with a reservation for me being even more stupid than I believe. ;-)
I just wanted to hear some other views and if other have had the same problems.

Right now I have splitted the outline/fill shapes so that the user of the framework can make the choises, adding some JavaDoc to adress the discrepancies.

I tried to check Karbon out, but I only found a Karbon that was for KDE and made in C++, for Linux.

It is not bug, it is supposed to do like this, it is just annoying since it makes a very simple thing very hard, if you are abit anal about pixels that is. ;-)

You can check it out in Sketsa (www.kiyut.com/products/sketsa/). Just make a circe, fill it with red and outline it with black set to transparency 0.5.

This pseudo code should visualize things:

[code]
Rectangle r = new Rectangle(50, 50, 100, 100);
g2.setColor(new Color(255, 0, 0));
g2.fill(r);
g2.setColor(new Color(0, 0, 0, 128));
g2.draw(r);
[/code]

ps. Well, I do live in Adelaide, Australia right now, and will for a year or so. But I am a swede.

zander
Offline
Joined: 2003-06-13

> It is not bug, it is supposed to do like this.

If you say that; then obviously you are aware that javas Graphics system does not count on pixels, but between pixels. This seems to cause the problem you are seeing.
If I paint a circle:

[code]
g2.setColor(new Color(255, 0, 0));
g2.fillArc(100, 100, 50, 50, 0, 360);
g2.setColor(new Color(0, 0, 0, 128));
g2.drawArc(100, 100, 50, 50, 0, 360);
[/code]

The inner (red) circle has pixels outside the outline; darn ugly.
If, however, I add a stroke of 1.5 pixels wide:
[code]
g2.setColor(new Color(255, 0, 0));
g2.fillArc(100, 100, 50, 50, 0, 360);
g2.setColor(new Color(0, 0, 0, 128));
g2.setStroke( new BasicStroke(1.5f) );
g2.drawArc(100, 100, 50, 50, 0, 360);
[/code]

The problem goes away. Its the rounding errors of the halve-pixles that Graphics2D uses that cause the problem. (I believe)

> I'm making a shape-based framework
I suggest you look at java.awt.BasicStroke.createStrokedShape(Shape s);

> I tried to check Karbon out, but I only found a Karbon that was for KDE and made in C++, for Linux.
Yes; I seem to assume that more people are using Linux then is really the case :-)

This application does not have the above described problems making me believe more that the problem is in Java, or its design, not in the concept of what you are trying to do.

I also suggest you take a look at an EPS creater from a Graphics2D environment: http://www.jibble.org/epsgraphics/
Hopefully you can find some ideas there.

mgrev
Offline
Joined: 2003-08-12

Setting the stroke to 1.5f solves the problem but then if you (or rather the user if my framework) set the stroke hint to PURE or turn on anti anlialiasing the outline looks crap again. :-|

The bottom line is that I would like to turn off this between the pixels calculations and match pixels to pixels with the weight in the middle of the pixel, as intuition suggests (my intuition that is).

Can anyone from the Java2D team comment on this? I mean this had to be thought about when the Java2D framework was designed, including a way around?

> I also suggest you take a look at an EPS creater from a Graphics2D environment: http://www.jibble.org/epsgraphics/

Will do, thanks.

Cheers,
Mikael

mgrev
Offline
Joined: 2003-08-12

Well Zander, I got a little dirty with some Suse Linux (9.1) and tried Open Office 1.1.1. Their draw app had the same problem... Outline is drawn one pixel wider and higher than the filled shape. Maybe this is how it's supposed to be done?

Doesn't anyone know how Microsoft are doing it in C#?
(I'm too lazy (or wise) to install Visual Studio .NET)

Cheers,
Mikael