image zoom memory problem

Discussion in 'Questions (Windows Mobile)' started by BerndB, Jan 6, 2009.

  1. BerndB

    BerndB Member Licensed User

    b4PPC V 6.5 optimized compilation

    I am working on an app to view files related to OziExplorerCE

    http://www.basic4ppc.com/forum/share-your-creations/3654-ozi-files-viewer.html

    Zooming with ImageLibEx.dll is still not really clear to me.

    @Klaus:
    In your scaledMap project
    http://www.basic4ppc.com/forum/chit-chat/3553-mapping.html :sign0188:
    for zooming you use the dzImage DLL instead of mapDisplay.Zoom(zoom.Value) from ImageLibEx.

    Is that because the increasing memory consumption with every zoom action?
    That is what happens with my FS Loox 720 Win 2003 SE. and as well on the desktop.

    So for zooming I use dzImage as well.
    But with it I have also problems.
    The jpg map inflatet to bitmap is about 1.3 MByte.
    With a zoom of 160 % I get a "OutOfMemoryException"

    With a zoom of 100 % i have 22 MB of free memory.
    With a zoom of 120 % i have 21.6 MB of free memory.
    With a zoom of 140 % i have 20.9 MB of free memory.
    With a zoom of "160 %" (which didn't zoom) i have 20.9 MB of free memory as well after the error message.

    The same image viewed and zoomed with other apps as "TCPMP" or "Album für Pocket PC" is no problem at all.

    With this apps a zoom doesn't even change the use of memory.
    As well they don't keep a copy of the original image for zooming.
    (if I load the image with my app memory decreases by ~2.6 MB.
    with these other apps by ~1.3 MB) (the used image is included in the above project:"Ozi Files Viewer")

    :sign0085:
    Are there different strategies with zooming?
    Am I doing something wrong?
    and does anybody know a way for me to achieve higher zoom levels without needing an other image file?


    ZPktX is the zoom point (middle of screen)
    Code:
    mapDisplay.New3(il1.Item(0))
    drwDisplay.New2(mapDisplay.Value)    
    ' DrawerEx drawer object to draw onto the map image
    drwMap.New1("frmMap",False)       ' drawer object to draw the part of the map image onto the form
    BiExZoom.New3(mapDisplay.Value) ' BitmapEx copy for zooming
    frmMap.Refresh

    .
    .
    .

    'zoom:
    mapDisplay.Value=dzImage.ZoomImage(BiExZoom.Value,numZoom.Value)  
    rectSrc.x = -(ZPktX -ZPktX *numZoom.Value/
    100)  ' keep centering on the zoom point
    rectSrc.y = -(ZPktY -ZPktY *numZoom.Value/100 )
    drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,
    False)
    frmMap.Refresh


    Thanks a lot for any hints

    Bernd
     
  2. klaus

    klaus Expert Licensed User

    Hi BerndB,

    I have also the Out of memory problem with bigger zoom factors on the device, but have not yet looked at it in detail. Will be done quite soon.

    I use the dzImage library because I had already used it in my first Map programm. And I didn't remember that the ImageLibEx has alson a Zoom function. I remembered having seen it once, but didn't find it in the help file of the ImageLibEx library, so I used what I knew.

    I have now entered the Zoom function of the ImageLibEx library in the ScaledMap programm.

    Using the dzImage library or the ImageLibEx library will have no difference from the memory point of view, both generate a bigger bitmap and nothing else.

    One question about your code:
    What image do you have in il1.Item(0) ?
    Code:
    mapDisplay.New3(il1.Item(0))
    If it is the original image you don't need this extra bitmap
    Code:
    BiExZoom.New3(mapDisplay.Value) ' BitmapEx copy for zooming
    you can directly use:
    Code:
    mapDisplay.Value=dzImage.ZoomImage(il1.Item(0),numZoom.Value)
    instead of
    Code:
    mapDisplay.Value=dzImage.ZoomImage(BiExZoom.Value,numZoom.Value)
    This saves you 1 image !

    As soon as I have some other news I will post it here.

    Best regards.
     
  3. BerndB

    BerndB Member Licensed User

    Hi Klaus,

    thanks for your quick response.

    The code snippet is a bit simplified.
    in il1.Item(0) is the original image.

    but before zooming there are drawn Circles onto the image.
    So image + circles are in BiExZoom.New3 to be zoomed.


    Concerning memory with dzImage or ImageLibEx I found a funny thing:

    In scaledMap as well as in OziFilesView I alternatively used the two zoom methods.
    At first dzImage was active. (The left part of each Thumbnail.)
    I quickly clicked 5 zoom steps up and then 5 zoom steps down.
    This I repeated several times.

    scaledMap:
    Code:
    Sub Zoom(Fact)
       ZoomFact=ZoomFact*Fact

       bmpDisplay.New3(IL3.Item(
    0))      ' ImageLibEx 
       bmpDisplay.Zoom(ZoomFact*100)
       
    'bmpDisplay.Value=dzImage.ZoomImage(IL3.Item(0),ZoomFact*100) 'dzImage
       
           InitMap
       DrawElements
    End Sub
    (by the way: in DrawElements is done zooming as well)


    OziFilesView:
    Code:
    Sub numZoom_ValueChanged
       mapDisplay.New3(BiExZoom.Value)
            mapDisplay.Zoom(numZoom.Value) 
       
    'mapDisplay.Value= dzImage.ZoomImage(BiExZoom.Value,numZoom.Value)  
           
            rectSrc.x = -(ZPktX -ZPktX *numZoom.Value/
    100)  ' keep centering on the zoom point
            rectSrc.y = -(ZPktY -ZPktY *numZoom.Value/100 )

       drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,
    False)
           frmMap.Refresh
          
    End Sub
    This was done on the desktop

    The thumbnails are taken from the XP-taskmanager.

    Using ImageLibEx you can see a increasing of used memory in both apps.

    Using dzImage with OziFilesView shows increasing while zoom in
    and decreasing while zoom out.
    With scaledMap it shows continued increasing again.

    funny, but no idea at present

    cheers
    Bernd
     
  4. agraham

    agraham Expert Licensed User

    Try the new version 1.4 of ImageLibEx that I have just posted. It has a one line change in BitmapEx.Zoom to dispose the old pre-zoom butmap object which I missed including. All the other methods that generate a new Bitmap do it but I missed it on the Zoom method. I don't know whether it will make a difference as the .NET garbage collector might have picked it up anyway but it is worth trying.
     
  5. klaus

    klaus Expert Licensed User

    Hi Andrew,

    Thank's for the update.

    One question,
    After the creation with BitmapEx1.New3(IL1.Item(0)) ,
    what is the best practice to assign a new image to a BitmapEx ?
    Using
    BitmapEx1.Value=IL1.Item(0) or
    BitmapEx1.New3(IL1.Item(0))

    Thank you in advance for your answer and Best regards.
     
  6. klaus

    klaus Expert Licensed User

    Hi BerndB,

    The zooming in the DrawElements routine is necessary because when I redraw the graphic elements I need to assign a new image to the form without any drawings on it and as I memorize only the original image and not the zoomed image I must zoom it before assigning it to the form.
    The DrawElements routine is in fact a Redraw routine also used when I delete drawing elements and not only after zooming.

    Best regards.
     
  7. agraham

    agraham Expert Licensed User

    The answer is - it depends!

    BitmapEx1.New3 - disposes of any old Bitmap and saves a reference to the new. This is best if the old Bitmap is not in use anywhere

    BitmapEx1.Value - just saves a reference to the new Bitmap. This is best if the old Bitmap is in use anywhere (like in an Image control) as disposing of it is probably not you want as the Bitmap might disappear if only a reference to the Bitmap was assigned when it was "used" rather than the contents being copied to another Bitmap.

    If in doubt I would use New3 and see if any images vanish unexpectedly.
     
  8. klaus

    klaus Expert Licensed User

    Thank you for the explanations.
    It has become more clear to me now.

    Best regards.
     
  9. BerndB

    BerndB Member Licensed User

    Hi Andrew,

    thank you for the new version of ImageLibEx.

    For the memory behavior I am sorry to say that nothing has changed.
    Still with every zoom action regardless of zooming in or out, free memory is shrinking.
    and still the OutOfMemoryException is coming very soon.

    regards
    Bernd
     
  10. agraham

    agraham Expert Licensed User

    Can you post a test app that shows this behaviour and I will see if I can find where the memory is going?

    Do you get "Out of memory" with both dzImage and ImageLibEx?
     
    Last edited: Jan 8, 2009
  11. klaus

    klaus Expert Licensed User

    Hi Andrew,

    Here is a small program that should show the problem.

    On my Qtek 9090 I get an out of memory message:
    - with dzImage already with a zoom factor of 2
    - with ImageLibEx zoom factor 2 OK , error message with the zoom factor of 4

    So for me, on my device, the ImageLibEx zoom function has a better performance than the dzImage one.

    The out of memory message with the zoom factor of 4 seems normal to me because the map.jpg file represents 2 MByte as a bitmap.
    And with the increase in size of the zoomed bitmap this is possible.

    @BerndB
    Could you make your tests with this program to see if you get the same behaviour as before.

    Best regards.
     
  12. klaus

    klaus Expert Licensed User

    Hi Andrew,

    I am coming back to the question in post #5.

    It must be
    BitmapEx1.New3(IL1.Item(0))

    in optimized compiled exe's BitmapEx1.Value=IL1.Item(0) generates an error !

    Best regards.
     
  13. agraham

    agraham Expert Licensed User

    What is the error message. I've just tried and it works fine for me on a desktop optimised compiled exe. I haven't tried a device exe but I see no reason why that should error either.
     
  14. klaus

    klaus Expert Licensed User

    I noticed the problem in the ScaledMap program and not in the TestZoomMemory program.

    I looked a bit further, and modified the TestZoomMemory program.
    I added a button to assign the same image once again to the bitmap with bmpDisplay.Value instead of bmpDisplay.New3, and zooming it.
    Clicking on the button the first time OK, but the 2nd time an error is generated even in the IDE, in the zooming line.
    This doesn't happen with bmpDisplay.New3.

    That's the problem I had in the ScaledMap program, and replacing bmpDisplay.Value by bmpDisplay.New3 solved the problem.

    Best regards.
     
  15. agraham

    agraham Expert Licensed User

    You have to remember that bitmaps are usually passed round by reference. There is a reference to a bitmap in IL1. You assign a copy of that reference to BitmapEx.Value and zoom it, in the process creating a new bitmap in bitmapEx.value. The original bitmap pointed to by the reference in BitmapEx is disposed after the zoom. As it is the same reference to the bitmap in IL1 it is that that is disposed and so is no longer available after that. Your second assignment then fails. To get a copy of a bitmap instead of a reference you can use BitmapEx.Clone which returns a reference to a new bitmap.
     
  16. agraham

    agraham Expert Licensed User

    The memory problem appears to be caused by an accumulation of unreleased unmanaged memory.

    A .NET bitmap may be thought of as a reference or pointer to a section of unmanaged (by .NET) memory outside the .NET framework that belongs to the OS graphics code and contains the actual bitmap data. The .NET garbage collector looks after clearing up the reference and in the process should release the unmanaged memory.

    What is happening is that, despite me adhering to the .NET guidelines on disposing of graphics items within BitmapEx.Zoom, the unmanaged memory that contained the bitmap data is not being reclaimed when bitmaps within the Zoom method are Disposed. They are however recovered when the BitmapEx object is itself Disposed. I cannot explain this :confused: I assume a similar problem afflicts dzImage.

    It seems as though that memory is being treated as belonging to a BitmapEx and not the Bitmap inside it. The workaround is to Dispose of the BitmapEx and recreate it when a new zoom level is required. This probably applies to all the BitmapEx methods, such as the rotates, which operate on the internal bitmap.
    Code:
    If rbtImageLibEx.Checked=True Then
      bmpDisplay.Dispose
      AddObject(
    "bmpDisplay""BitmapEx")
      bmpDisplay.New1(AppPath & 
    "\CapeTown.jpg")
      bmpDisplay.Zoom(ZoomFact)
     
    Else
      bmpDisplay.New3=dzImage.ZoomImage(IL1.Item(
    0),ZoomFact)
     
    End If
     
  17. BerndB

    BerndB Member Licensed User

    Here is an alternative to the libraries zoom functions.
    And it's quite simple.

    For me it looks like, that the problem is connected to the increase of
    destination.width and .height (rectDest.Value) of drawImage.
    Code:
    drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,False)
    In the following I do zooming by my own.

    The destination rectangle remains at all zoom levels the same:
    Code:
    rectDest.New1(0,0,ScreenW,ScreenH)
    Width and height of the source rectangle changes with the zoom factor.
    x and y of source rectangle is changed that way, that the zoom point keeps staying in screen middle.
    Code:
    rectSrc.Width = ScreenW /(numZoom.Value/100)
      rectSrc.Height = ScreenH /(numZoom.Value/
    100)
      rectSrc.X = ZpktX -rectSrc.Width/
    2   'change rectSrc.X so that the zoom point remains
      rectSrc.Y = ZpktY -rectSrc.Height/2
    No memory errors anymore.

    Code:
    Sub Globals
       
    'Declare the global variables here.
       
       
    Dim mDn, mDnX, mDnY
     
    ' Zoom
       numZoom.Increment =20
       numZoom.Minimum =
    10
       numZoom.Maximum =
    450
       
       ScreenW= 
    240                ' width of the screen on the form  pixels
       ScreenH= 275'275            ' height of the screen on the form  pixels
       
       zPktX = 
    500    ' ZoomPoint
       zPktY = 250
       
     SrcW=ZpktX -ScreenW/
    2
       SrcH=ZPktY -ScreenH/
    2 
    End Sub

    Sub App_Start
           BrushEx.New1(cRed)
       NumZoom.Value =
    100  ' put Zoom to 100%
       mapDisplay.New3(il1.Item(0))
       drwDisplay.New2(mapDisplay.Value)      
    ' DrawerEx drawer object to draw onto the map image
       drwMap.New1("frmMap",False)               ' drawer object to draw the part of the map image onto the form
     
       
    ' RectangleEx
       rectDest.New1(0,0,ScreenW,ScreenH)   ' destination rectangle = screen area on the form
       rectSrc.New1(SrcW,SrcH,ScreenW,ScreenH)                        ' source rectangle on the map image according to the scroll positions
       ' define a circle
       rectCircle.New1(ZPktX-Round(20/2),ZPktY-Round(20/2),20,20)
     
    ' draw the circle on the map image
       drwDisplay.FillEllipse(brushEx.Value, rectCircle.Value) 
     
    ' draw the map image
       drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,False)
       BiExZoom.New3(mapDisplay.Value)  
    '  BitmapEx copy for zooming

       frmMap.Show
    End Sub

    ' Z O O M
    Sub NumZoom_ValueChanged
      rectSrc.Width = ScreenW /(numZoom.Value/
    100)
      rectSrc.Height = ScreenH /(numZoom.Value/
    100)
      rectSrc.X = ZpktX -rectSrc.Width/
    2   'change rectSrc.X so that the zoom point remains
      rectSrc.Y = ZpktY -rectSrc.Height/2
          
      drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,
    False)
      frmMap.Refresh
    End Sub

    Sub frmMap_MouseDown(x,y)
      mDn =
    1
      mDnX =x
      mDnY =y
    End Sub

    Sub frmMap_MouseUp(x,y)
      mDn =
    0
    End Sub

    Sub frmMap_MouseMove (x,y) 

      
    If mDn = 1 Then
       ZpktX = ZpktX +(mDnX -x)/(numZoom.Value/
    100)
       ZpktY = ZpktY +(mDnY -y)/(numZoom.Value/
    100)
       rectSrc.X = ZpktX -rectSrc.Width/
    2 
       rectSrc.Y = ZpktY -rectSrc.Height/
    2
             
          drwMap.DrawImage(mapDisplay.Value,rectSrc.Value,rectDest.Value,
    False)
          frmMap.Refresh
          mDnX =x
          mDnY =y
      
    End If

    End Sub
    cheers
    Bernd
     
  18. klaus

    klaus Expert Licensed User

    Thank you Andrew for your help and detailed explanations.
    I will add your code modification in my programs.

    Best regards.
     
  19. klaus

    klaus Expert Licensed User

    Hi Bernd,

    I had a look at your code, it's very interesting, I tried it in the TestZoomMemory program.

    For my ScaledMaps application, the first problem is that I want also to draw onto the bitmap in zoomed mode and the 2nd one is that the texts and bitmaps keep their original size independant of the zoom factor.

    In your full program do you draw your drawing before any zooming ?

    Best regards.
     
  20. BerndB

    BerndB Member Licensed User

    Hi Klaus,

    right, in my program I just draw at the beginning with 100 %.
    To draw onto the zoomed image should be possible, but its more effort then to determine place and size.

    So it depends on the needs, which strategy is best.

    But together with Andrews solution we have the choice ...


    An advantage with stretching between source and destination is that you don't need a copy of the image for zooming, and after loading the image the memory is not affected anymore.

    Thank you for your and Andrews posts.
    Kind regards
    Bernd
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice