[Mono-list] OutOfMemoryException after scale transform a Region

Sebastien Pouliot sebastien.pouliot at gmail.com
Mon Sep 22 13:42:50 EDT 2008


Hello Pablo,

On Mon, 2008-09-22 at 08:46 -0700, Pablo Lecea wrote:
> Hello there,
> I have an application which takes two Regions and gets the intersection
> between both in order to get the closest point... Before the intersect
> operation is figured out I'm scaling the regions to avoid roundings. But
> after the regions are scaled (100) any operation against the regions can be
> done without get a OutOfMemoryException.

The region stuff can be *very* complex and libgdiplus took a few
shortcuts to get things working.

A long time ago (well about 2.5 year ago) only region with rectangle
shapes were supported inside libgdiplus. This was a big limitation but
was much simpler to implement (first shortcut).

To get around this libgdiplus implements binary operations on
non-rectangular regions using a (1bbp) bitmap. This (second shortcut)
works very well unless you (a) need more than pixel accuracy or (b) have
very large regions.

Your example that have a region of 2936 x 3647 pixels (see WARNING)
which exceed the amount of memory that libgdiplus is willing to allocate
to compute the region - problem (b). This would (probably) work without
scaling but then you loose your "hacked" accuracy - problem (a).

>  This is happening just on Mac OS, I
> tested on Windows XP via mono and it works fine.

This is because Mono use MS GDI+ on Windows. Your code would not be
working on Linux, Solaris or anywhere else (but Windows).

> The exception message is : 
> ** (/Users/pablolecea/closest/closest/bin/Debug/closest.exe:604): WARNING
> **: Path conversion requested 42830368 bytes (2936 x 3647). Maximum size is
> 8388608 bytes.
> 
> Unhandled Exception: System.OutOfMemoryException: Not enough memory to
> complete operation [GDI+ status: OutOfMemory]
>   at System.Drawing.GDIPlus.CheckStatus (Status status) [0x000be] in
> /private/tmp/monobuild/build/BUILD/mono-1.9.1/mcs/class/System.Drawing/System.Drawing/gdipFunctions.cs:222 
>   at System.Drawing.Region.Intersect (System.Drawing.Region region)
> [0x00024] in
> /private/tmp/monobuild/build/BUILD/mono-1.9.1/mcs/class/System.Drawing/System.Drawing/Region.cs:148 
>   at (wrapper remoting-invoke-with-check) System.Drawing.Region:Intersect
> (System.Drawing.Region)
>   at closest.MainClass.GetClosestPoint () [0x00030] in
> /Users/pablolecea/closest/closest/Main.cs:171 
>   at closest.MainClass.Main (System.String[] args) [0x00000] in
> /Users/pablolecea/closest/closest/Main.cs:154 
> 
> Here the code:
> 
> static void Main(string[] args)
>         {
>             GetClosestPoint();
>         }
> 
> 
> private static void GetClosestPoint()
>         {
>             //get the regions
>             Region firstRegion = CreateFirstRegion();
>             Region secondRegion = CreateSecondRegion();
> 
>             //This scaling is done to avoid rounding in bounds values
>             Matrix matrix = new Matrix();
>             matrix.Scale(100, 100);
>             firstRegion.Transform(matrix);
>             secondRegion.Transform(matrix);
> 
>             //intersect the regions
>             firstRegion.Intersect(secondRegion); //an OutOfMemoryException
> is thrown on mac OS
> 
>             System.Windows.Forms.Control control = new
> System.Windows.Forms.Control();
>             System.Drawing.Graphics graph = control.CreateGraphics();
>             graph.PageUnit = GraphicsUnit.Pixel;
>             System.Drawing.RectangleF bounds = firstRegion.GetBounds(graph);
> 
>         }
> 
> private static Region CreateFirstRegion()
>         {
>             GraphicsPath gp = new GraphicsPath();
> 
>             gp.StartFigure();
>             gp.AddLine(new PointF(193.24475f, 189.1613f), new
> PointF(221.7687f, 225.011f));
>             gp.AddLine(new PointF(221.7687f, 225.011f), new
> PointF(222.5512f, 224.38869f));
>             gp.AddLine(new PointF(222.5512f, 224.38869f), new
> PointF(194.0272f, 188.53869f));
>             gp.CloseFigure();
> 
>             Region result = new Region(gp);
>             return result;
>         }
> 
>         private static Region CreateSecondRegion()
>         {
>             GraphicsPath gp = new GraphicsPath();
>             string text = "Cl";
>             int platformStyle = (int)System.Drawing.FontStyle.Regular;
>             float fontSize = 12;
>             string fontName = "Times New Roman";
> 
>             System.Drawing.Font platformFont = new
> System.Drawing.Font(fontName, fontSize, System.Drawing.FontStyle.Regular,
> GraphicsUnit.Pixel);
>             gp.AddString(text, platformFont.FontFamily, platformStyle,
> platformFont.Size, new System.Drawing.Rectangle(),
> StringFormat.GenericTypographic);
> 
>             Matrix translationMatrix = new Matrix();
>             translationMatrix.Translate(187.222f, 182.8066f);
>             gp.Transform(translationMatrix);
> 
>             Region result = new Region(gp);
>             return result;
>         }
> 
> Can you help me to figure out what is happening.
> Thanks, 
> Pablo
> -- 
> View this message in context: http://www.nabble.com/OutOfMemoryException-after-scale-transform-a-Region-tp19610028p19610028.html
> Sent from the Mono - General mailing list archive at Nabble.com.
> 
> _______________________________________________
> Mono-list maillist  -  Mono-list at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-list



More information about the Mono-list mailing list