Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic Is it possible to access the REAL Graphics object from a custom Draw() method? (Read 2230 times)
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Is it possible to access the REAL Graphics object from a custom Draw() method?
Jun 6th, 2013 at 3:56am
Print Post  
I have a custom node where I'm trying to simply draw a 16 x 16 icon in a 16 x 16 ImageComponent, and it becomes fuzzy. Measure unit is pixels, and the DPI of the Image is set to the screen's DPI.

I assume this is due to a resizing being done by the IGraphics wrapper for Graphics. This is fine when it's necessary, for example if the user has zoomed in or out, then resizing is needed. But when there is no zoom and I know the image size and the bounding box size are the same then I can't understand that a resize is apparently being done anyway.

Anyway, to avoid this problem, is it possible to bypass the IGraphics wrapper and get directly to the Graphics object instead? Or do you have another suggestion?

Thanks.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Is it possible to access the REAL Graphics object from a custom Draw() method?
Reply #1 - Jun 6th, 2013 at 7:22am
Print Post  
You can access it like this:

Code
Select All
var gdiGraphics = iGraphics as GdiGraphics;
if (gdiGraphics != null)
{
	var sysGraphics = gdiGraphics.Graphics;
} 


However GdiGraphics delegates Draw* calls directly to the Graphics object and you won't see any difference if drawing through the wrapped Graphics. Better check if the coordinates you draw the image at are integer. You can ensure that a diagram point aligns to a device pixel, regardless of current measure unit and zoom level, by setting point = view.ClientToDoc(view.DocToClient(point));

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Re: Is it possible to access the REAL Graphics object from a custom Draw() method?
Reply #2 - Jun 7th, 2013 at 6:04am
Print Post  
Thanks for your answer.

> Better check if the coordinates you draw the image at are integer.

Yes, "that is where the dog is buried", as they say in Danish.

This is an ImageComponent nested several levels down inside StackPanels inside a CompositeNode. When I looked at base.Bounds in the ImageComponent, X is an integer but Y is 4.5.

So I created a new bounds Rectangle containing only integers and used that with the Graphics.DrawImage() method. The icon became less fuzzy, but was still not being rendered pixel-for-pixel.

I think maybe the Graphics object is itself anchored at a non-integer origin, although I can't see that - it says RenderingOrigin X = 20, Y = 20. But it also says ClipBounds X = -52.5, Y = -36.

In desperation I've tried setting

sysGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
sysGraphics.SmoothingMode = SmoothingMode.None;

This resulted in a non-fuzzy rendering, but for some crazy reason the left-most column of pixels is gone, i.e., the icon is now 15 x 16 instead of 16 x 16.

I'm thinking the various StackPanel components in the CompositeNode are not being layed out on pixel / integer boundries. Is there some way to force that to happen? And how can I see these bounds? In the debugger they always seem to be 0, 0.

I realize that if the user zooms in or out that all bets are off, and that's OK. But I would like to have the icons rendered 100% pixel-for-pixel when no zooming has been applied.

Hope you have another good suggestion. Thanks.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Is it possible to access the REAL Graphics object from a custom Draw() method?
Reply #3 - Jun 7th, 2013 at 7:07am
Print Post  
The position of the image component in the stack panel depends on the positions and heights of any previous components, and the padding set for the panel. Check which component from the stack starts at integer Y coordinate but ends at a float coordinate and see if you can specify fixed Height value for it, instead of relying on auto-sizing. Alternatively, you could create a custom component to draw images, and align the image origin to pixels using the above code.

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Re: Is it possible to access the REAL Graphics object from a custom Draw() method?
Reply #4 - Jun 8th, 2013 at 3:36am
Print Post  
Thank you very much for your help. I finally got it to work.

I'd hate to admit how many hours I've used on this silly little problem. So I'd like to suggest a possible improvement for a future version: some kind of property for CompositeNode or StackPanel and ImageComponent that specifies

LayoutPixelOnly = true;

or

LayoutGranularity = 1.0;

or something similar, so you can use the default automatic layout (which is a good feature) but avoid the fuzzy graphics that occur when ImageComponents get placed on non-integer locations.

Thanks.

Edit:

Thinking about this, shouldn't this simply be the default way for component layout to work when measure unit = pixels? Then you don't need to add an option.

Edit 2:

The more I think about this, the more I think this should simply be considered to be a bug. An ImageComponent at a non-integer pixel location - what is that supposed to mean? It guarantees that the image will be blurry, and I can't think of what service it provides?
« Last Edit: Jun 9th, 2013 at 12:45am by Rennie »  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint