ImageLibEx library

agraham

Expert
Licensed User
Longtime User
Version 1.7 posted.

Added to DrawerEx are Draw/FillArc and Draw/FillPie methods. The "1" methods draw circles, the "2" methods draw ellipses. Although you can draw circles with the ellipse methods they are more processor intensive as they deal with two axes whereas the the circle methods do less processing as they only deal with a radius. The demo has an extra page added to show these.

Unlike the other DrawerEx methods these new methods are not native but are coded within ImagelibEx and use Draw/FillLines and Draw/FillPolygon to draw so there may be a performance penalty when using them compared to using the native methods.
 

agraham

Expert
Licensed User
Longtime User
Version 1.8 posted with some significant improvements.

The Draw/FillArc and Draw/FillPie methods added in version 7 have their zero points moved to 12 o'clock (from 3 o'clock - a bad previous decision :() to match a compass.

DrawLineDashed and DrawLineDashDot methods are added to DrawerEx to enabled various patterns of line to be drawn.

GcCollect and GetTotalMemory are added to BitmapEx. These are intended for possible diagnostic use and should not be required in normal use.

A Locked property, and LockBits, GetLockedPixel, SetLockedPixel and UnlockBits methods are added to BitmapEx to provide fast low level access to bitmap pixel data if required.
 

corwin42

Expert
Licensed User
Longtime User
GcCollect and GetTotalMemory are added to BitmapEx. These are intended for possible diagnostic use and should not be required in normal use.

As you mention this I have a question about memory handling and BitMapEx objects.

I'm currently writing an OpenStreetMap Mapviewer program for the device. OpenStreetMap Maps are generated from tiles with 256x256 pixels. For displaying the complete map I have to load several tiles and put them on an image. In the first version this was done with two BitMapEx objects. One for the tile (bmpTile) and another (bigger) for the map (bmpImage) which will be displayed.

The tiles were loaded with bmpTile.New1(filename) and then copied to the correct position on bmpImage with a DrawerEx Object with drwImage.DrawImage(bmpTile.Value, ...).

The problem with this solution was that when scrolling around, many tiles are loaded with bmpTile.New1() method and I get an OutOfMemory exception very soon.

I looked into the source of ImageLibEx and I don't understand why I get the OutOfMemory Exception because when the New1() Method is called the old bitmap gets disposed and a new one is created.

Is the GarbageCollector too slow in freeing the not used memory or is there somewhere a memory leak?

Currently I use a ControlsExDevice/NativeImage for Loading the tiles with nImgTile.LoadPicture(filename). This works well and I have no OutOfMemory exceptions any more.

As a conclusion BitMapEx.New1() method called several times on the same objects seems to eat up memory but I don't understand why. Perhaps I should try it again with calling GcCollect after calling bmpTile.New1() method.

Greetings,
Markus
 

agraham

Expert
Licensed User
Longtime User
I looked into the source of ImageLibEx and I don't understand why I get the OutOfMemory Exception because when the New1() Method is called the old bitmap gets disposed and a new one is created.
Ah, I had forgotten that was there! That Dispose in New1 actually does nothing! :( but is harmless. It is a result of my early misunderstanding of what Basic4ppc does when it sees a New method and I should have removed it a long time ago.

B4X:
BmpEx1.New1(filename) ' creates a new instance of a BitmapEx and calls New1
....
BmpEx1.New1(filename)' creates another new instance of a BitmapEx and calls New1

The first BmpEx is left floating and unreferenced and should be swept up by the GC. The second BmpEx1 is a totally new instance and so has no reference to the original bitmap that was in the first BmpEx instance so the Dispose test is unnecessary.

Most of the memory in a Bitmap is unmanaged memory which the GC knows nothing about so successive calls to New1 to the same object build up a list of floating Bitmaps but as the managed memory overhead of a Bitmap is small the GC may not run before unmanaged memory runs out. Explicitly Disposing and recreating the BitmapEx object should overcome this problem.

B4X:
BmpEx1.New1(filename) 
....
BmpEx1.Dispose
AddObject("BmpEx", "BitmapEx")
BmpEx1.New1(filename)' creates another new instance of a BitmapEx and calls New1
 

corwin42

Expert
Licensed User
Longtime User
Thanks very much for your explanation.

I have found some articles about this now in the internet and when I understand it correct, I should call Dispose() on objects which implement IDisposable when I don't need them any more.

I often call New() methods on objects to reinitialize them without disposing them first. Am I right that this is normally not a problem (because the GC will handle this) but it's a bad idea for objects that use unmanaged memory or implement IDisposable?

Thanks,
Markus
 

agraham

Expert
Licensed User
Longtime User
Am I right that this is normally not a problem (because the GC will handle this)
Yes, normally you should let the GC do its' job.
but it's a bad idea for objects that use unmanaged memory or implement IDisposable?
It's only really a problem for things like (and it's the only example I can think of) Bitmaps where the ratio of unmanaged memory used by the underlying native object is very large in relation to the small amount of managed memory used to encapsulate it for .NET use. Before reusing the same object name the only things other than Bitmap and BitmapEx that I would rooutinely Dispose would be Drawer andDrawerEx that are really GDI Graphics objects.

If you don't have problems I would not worry about memory use or using Dispose.
 

corwin42

Expert
Licensed User
Longtime User
Rotate(Fast|HQ) does not rotate around center of bitmap

Hi!

I just found out that BitmapEx.RotateFast() and BitmapEx.RotateHQ() do not rotate the bitmap correctly around its center.

I've included a small program to show this.

I don't know if this is wanted but I need a rotation around the center. Would it be possible to include it in ImageLibEx?

Greetings,
Markus
 

corwin42

Expert
Licensed User
Longtime User
BitmapEx.RotateFast and BitmapEx.RotateHQ missing Parameter in Help

Just a minor one:

In the helpfile there is the color parameter missing for BitmapEx.RotateFast and BitmapEx.RotateHQ.

Greetings,
Markus
 

agraham

Expert
Licensed User
Longtime User
Thanks for pointing out the error in the help. The rotates do rotate properly. I think that you are overlooking the fact that the bitmap grows when it is rotated, which it must do to retain the entire image. You can see what is happening in your demo by replacing cWhite as the color fill parameter with another colour. You need to calculate where the centre of the image is after being rotated to draw it where you want.
 

corwin42

Expert
Licensed User
Longtime User
I think that you are overlooking the fact that the bitmap grows when it is rotated
Ah yes, thats the problem :BangHead:. I thought the resulting bitmap has the same size and would be cropped. I changed the test program so that it calculates rectSource and rectDest sizes and positions after the rotation correctly and now it works well.

Thank you very much.
Markus
 

agraham

Expert
Licensed User
Longtime User
Version 1.9 now posted with significant changes to BitmapEx.

Bitmap use in the Compact Framework is prone to causing out of memory problems and not only for Basic4ppc. The help for ImageLibEx now has a topic describing the problem and describing how and when references are used to refer to bitmaps. The BitmapEx help now describes for each method whether it creates a new bitmap, Disposing the old, or whether it modifies the existing bitmap. You should now be able to better predict where and whether a bitmap is in use and decide whether to Release it or not.

BitmapEx has some new methods to manage bitmaps in a less clumsy way than using Dispose and AddObject on BitmapEx objects. New4 is added to allow a BitmapEx to be created without a bitmap. A new Release method allows the internal bitmap to be Disposed without having to Dispose the BitmapEx itself. Three new Create methods, similar to the existing New methods, allow a bitmap to be created without having to New a BitmapEx object again.

As I was playing with BitmapEx I also had some fun adding a BitBlit function, it might be of some use to someone some time. A demo for this is now included and of course it is documented in the help.
 

derez

Expert
Licensed User
Longtime User
Andrew
Thank you for your endless efforts to improve the basic4ppc tools !

Please help me out with this: I'm trying to use ImagelibEx instead of DZimage in my navigation program and can't find how to copy a rectangle out of an image to another image or form, like this :

CopyImage(sourceImage, x,y,width, height): Copies a part of an image. Returns the new cropped Image (part of the source).

How to do it with ImagelibEx ?

(I use this to copy the final image which is made of tiles and drawn circles and lines, sometimes after rotation and zooming, and put it on the display form).

EDIT: Found it, DrawImage with a drawerEx object !
 
Last edited:

derez

Expert
Licensed User
Longtime User
"InvaliCastException"

I am getting an error which I don't understand.
The code copies a map to a form:
B4X:
maps.item(5) = AppPath & "\maps\nim1663.jpg"
   drawer.New1("form7",False)
   mapsrc.New1(600,400,1000,1000)
   x = 0
   y = 0
   mapdst.New1(x,y,x+600,y+600)
   drawer.DrawImage(maps.Item(5),mapsrc.Value,mapdst.Value,False)
maps.item(5) is a map image of 1000*1000, it does not cause memory problems.
If I compile it as an independent program it displays the map on the evice. When integrated as part of a sub in the nav program, the drawimage line cause an error of "InvalidCastException".

:sign0085:
 
Last edited:

klaus

Expert
Licensed User
Longtime User
I think the problem is in these lines:
B4X:
mapsrc.New1(600,400,1000,1000)
mapdst.New1(x,y,x+600,y+600)
should be:
B4X:
mapdst.New1(x,y,600,600)

The RectangleEx object's New1 statement is:
New1(x As Int32, y As Int32, width As Int32, height As Int32)

I don't think that you want a variable width in mapdst.

In mapsrc with x=600 and width 1000 the rectangle's right edge is bigger than the bimap's edge.

The width and height of mapsrc is not the same as in mapdst, do you want to shrink the bitmap on the screen ?

I would suggest:
B4X:
mapsrc.New1(0,0,600,600)
mapdst.New1(0,0,600,600)

and somewhere else when needed:
B4X:
mapsrc.X=x
mapsrc.Y=y

Best regards.
 
Last edited:

derez

Expert
Licensed User
Longtime User
Klaus

Thank you for the time you looked at it, but the problem is not in the rectangles.

I sorted the x and y's and ran a program to simulate and check on the desktop and it copies the map correctly.

The problem is probably related to some interference between libraries or some characteristics of the specific map I use.
 

derez

Expert
Licensed User
Longtime User
Some more information on the error:

I run the program on the IDE and it works.
After compilation to desktop it show the attached error.

The specific code is :
B4X:
px = (x_itm - x1 )* zoom * mapwidth /(x2-x1) 
py = (y_itm - y1 )* zoom * mapheight /(y2-y1)        

drx.New1("Form7",False)

mapdst.New1(0,0,form7.Width,form7.height)
mapsrc.New1(px-center_x/zoom,PY-center_y/zoom,form7.Width/zoom,form7.height/zoom)
drx.DrawImage(mapslist.Item(5),mapsrc.Value,mapdst.Value,False)

The error is caused by the last line.
 
Last edited:
Top