Load and scale image

10 posts / 0 new
Last post
mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Load and scale image

In my program I load and scale 20+ images at startup, and potentially dozens more later. I thought I had some nice working code, until I realized the ScaleBM is not being freed and I was losing 1.6MB of RAM.

Load it at startup

  1. ImgObjects[IMG_DEF_DRAWER_16]=LoadImageScale((STRPTR)"ENVARC:Sys/def_drawer.info",20,18,FALSE,TRUE,FALSE);

Free image when quit

  1. DisposeImage(ImgObjects[IMG_DEF_DRAWER_16]);

The code below is a stripped out version of how I load and make an image into a BitMapClass object

  1. Object *
  2. LoadImageScale(STRPTR Path,uint32 w,uint32 h,BOOL UpScale,BOOL KeepAspect,BOOL HalfAlpha)
  3. {
  4. Object *DTO, *Img;
  5. struct BitMapHeader *bmhd=NULL;
  6. struct BitMap *OrigBM, *ScaleBM;
  7. APTR Lock;
  8. APTR Memory;
  9. uint32 BytesPerRow;
  10. struct pdtBlitPixelArray pdtBlitPixelArrayBuffer;
  11. uint32 ScaleWidth, ScaleHeight;
  12. float32 ScaleFactorX, ScaleFactorY;
  13.  
  14. if (!(DTO=IDataTypes->NewDTObject(Path,
  15. DTA_GroupID, GID_PICTURE,
  16. PDTA_Screen, DefaultPubScreen,
  17. PDTA_PromoteMask, TRUE,
  18. PDTA_DestMode, PMODE_V43,
  19. TAG_END)))
  20. {
  21. return(NULL);
  22. }
  23.  
  24. if (!(OrigBM=IGraphics->AllocBitMapTags(bmhd->bmh_Width,bmhd->bmh_Height,32,
  25. BMATags_PixelFormat, PIXF_A8R8G8B8,
  26. BMATags_Clear, TRUE,
  27. BMATags_Displayable, TRUE,
  28. TAG_DONE)))
  29. {
  30. if (DTO != NULL)
  31. {
  32. IDataTypes->DisposeDTObject(DTO);
  33. DTO=NULL;
  34. }
  35.  
  36. return(NULL);
  37. }
  38.  
  39. // figure out new scaled sizes
  40.  
  41. if (!(ScaleBM=IGraphics->AllocBitMapTags(ScaleWidth,ScaleHeight,32,
  42. BMATags_PixelFormat, PIXF_A8R8G8B8,
  43. // BMATags_BitmapInvisible, TRUE,
  44. BMATags_Clear, TRUE,
  45. BMATags_Displayable, TRUE,
  46. TAG_DONE)))
  47. {
  48. IGraphics->FreeBitMap(OrigBM);
  49.  
  50. return(NULL);
  51. }
  52.  
  53. // scale it
  54.  
  55. IGraphics->FreeBitMap(OrigBM);
  56.  
  57. if (!(Img=IIntuition->NewObject(BitMapClass,NULL,
  58. BITMAP_BitMap, ScaleBM,
  59. BITMAP_Width, ScaleWidth,
  60. BITMAP_Height, ScaleHeight,
  61. BITMAP_HasAlpha, TRUE,
  62. BITMAP_Screen, DefaultPubScreen,
  63. BITMAP_Precision, PRECISION_EXACT,
  64. BITMAP_Masking, TRUE,
  65. TAG_DONE)))
  66. {
  67. IGraphics->FreeBitMap(ScaleBM);
  68.  
  69. return(NULL);
  70. }
  71.  
  72.  
  73. // This line is what I need, but can't be here.
  74. // It clears the BitMapClass image.
  75. // It will crash when DisposeImage().
  76.  
  77. IGraphics->FreeBitMap(ScaleBM);
  78.  
  79. return(Img);
  80. }
  81.  
  82.  
  83. VOID
  84. DisposeImage(Object *Img)
  85. {
  86. if (Img != NULL)
  87. {
  88. IIntuition->DisposeObject(Img);
  89. Img=NULL;
  90. }
  91. }

The ScaleBM is not being freed so losing a lot of RAM.

I don't want to make an array like
struct BitMap *ScaleBM[20];
That is not an option.

How do I fix this?

thomas
thomas's picture
Offline
Last seen: 2 hours 7 min ago
Joined: 2011-05-16 14:23
Re: Load and scale image

I don't think that ScaleBM is your problem. It's rather the datatype object. If all goes well you never DisposeDTObject(DTO).

You've already proven that ScaleBM *is* freed by saying that DisposeImage crashes if you free it explicitly.

mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Re: Load and scale image

I am doing DisposeDTObject(DTO) just didn't show it. Ripped out a bunch of code to make it smaller. Everything works, just not when disposing of the image.

  1. // This line is what I need, but can't be here.
  2. // It clears the BitMapClass image.
  3. // It will crash when DisposeImage().
  4.  
  5. IGraphics->FreeBitMap(ScaleBM);

This is the problem area. When I do DisposeImage() it is not freeing all the memory for the images (the ScaleBM bitmap). That line can't be there, just showing what the issue is.

When I load and scale the images and quit I lose 1.6MB of RAM. If totally skip the loading/scaling I don't. So it is something with the way I am loading/freeing them.

What would be nice is if the BitMapClass could copy the supplied bitmap and release it's private one when disposed. Like ChooserClass has CNA_CopyText. Then I could IGraphics->FreeBitMap(ScaleBM); right after making the BitMapClass object.

  1. if (!(Img=IIntuition->NewObject(BitMapClass,NULL,
  2. BITMAP_CopyBitMap, TRUE,
  3. BITMAP_BitMap, ScaleBM,
  4. BITMAP_Width, ScaleWidth,
  5. BITMAP_Height, ScaleHeight,
  6. BITMAP_HasAlpha, TRUE,
  7. BITMAP_Screen, DefaultPubScreen,
  8. BITMAP_Precision, PRECISION_EXACT,
  9. BITMAP_Masking, TRUE,
  10. TAG_DONE)))
  11.  
  12. IGraphics->FreeBitMap(ScaleBM);

Problem solved. But, doesn't exist. Hint hint....

salass00
salass00's picture
Offline
Last seen: 1 year 1 month ago
Joined: 2011-02-03 11:27
Re: Load and scale image

Just make sure you call FreeBitMap(ScaleBM) after you call DisposeObject().

If you don't want to keep track of the bitmap pointer yourself you can just query it with GetAttr() in your DisposeImage() function as BITMAP_BitMap tag supports OM_GET.

mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Re: Load and scale image

That is working out great! Thanks!

It also helped me track down another issue I was having in a previous post.

mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Re: Load and scale image

After doing some checking, the memory is still not being freed, even when I

  1. IIntuition->GetAttrs(Img,
  2. BITMAP_BitMap, &BM,
  3. TAG_DONE);
  4.  
  5. IIntuition->DisposeObject(Img);
  6.  
  7. if (BM)
  8. IGraphics->FreeBitMap(BM);

BroadBlues replied to me on Amigans.net that maybe the images are being cached. The more I think about it, I doubt that they are. Because ever run loses more RAM.

I just don't get why this works/frees correctly

  1. return(IIntuition->NewObject(BitMapClass,NULL,
  2. BITMAP_SourceFile, Render,
  3. BITMAP_SelectSourceFile, Select,
  4. BITMAP_DisabledSourceFile, Disabled,
  5. BITMAP_Screen, DefaultPubScreen,
  6. BITMAP_Precision, PRECISION_EXACT,
  7. BITMAP_Masking, TRUE,
  8. TAG_DONE));

but this does not

  1. if (!(Img=IIntuition->NewObject(BitMapClass,NULL,
  2. BITMAP_BitMap, ScaleBM,
  3. BITMAP_Width, ScaleWidth,
  4. BITMAP_Height, ScaleHeight,
  5. BITMAP_HasAlpha, TRUE,
  6. BITMAP_Screen, DefaultPubScreen,
  7. BITMAP_Precision, PRECISION_EXACT,
  8. BITMAP_Masking, TRUE,
  9. TAG_DONE)))

Did a bug sneak in to the BitMapClass that isn't freeing the object and/or BITMAP_BitMap?

Grabbing at straws now.......

broadblues
broadblues's picture
Offline
Last seen: 4 years 1 month ago
Joined: 2012-05-02 21:48
Re: Load and scale image

Did a bug sneak in to the BitMapClass that isn't freeing the object and/or BITMAP_BitMap?

You are passing bitmap.image a bitmap. *You* are responsible for freeing it.

I'm doing just this in a context where I generate cached text images, I delete my own bitmaps (after I dispose of the bitmap.image naturally).

BTW you do realise that bitmap.image will load the datatype image and scale if for you? No need for the dedicated datatypes load and ScaleBM step.

[edit]
Reading the thread again you probably are aware that you need to free the bitmap yourself.

Futher thinking you realise that the bitmap data is in video ram? (unless you very specifically set it as BMF_PRIVATE, but that wouldn't display properly. So losing 1.6 Mb of main ram is not goinf to be because of the bitmap.

1.6Mb is not very much, it could be from memory fragmentation, rather than any real loss. How are you measuring this loss?

Do you use direct calls to AllocVecTags() or do you have wrapper function? Have you got any kind of memory allocation / freeing tracking? This would show up anything you didn't release at prgram quit.

Eg in MultiViewer / MultiEdit I have a alternate set of memory code that will print out any unfreed memory at exit and tell me where I allocated it.

I only compile this in whilst testing, recompiling for release.

mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Re: Load and scale image
  1. VOID
  2. DisposeImage(Object *Img)
  3. {
  4. struct BitMap *BM=NULL;
  5.  
  6. if (Img==NULL)
  7. return;
  8.  
  9. IIntuition->GetAttrs(Img,
  10. BITMAP_BitMap, &BM,
  11. TAG_DONE);
  12.  
  13. IIntuition->DisposeObject(Img);
  14.  
  15. if (BM)
  16. IGraphics->FreeBitMap(BM);
  17. }

I am freeing the bitmap after I dispose of the BitMapClass object like salass00 said to do. I put in some Printf()'s to make sure it was actually doing the FreeBitMap() call.

Workbench Explorer loads 50+ AISS images at start up. It is up to 2MB+ RAM loss now. I use both loading methods because I do some manipulation to several of the images. And use IconClass for loading icon images (the icon datatype isn't 100% and not installed by default).

To test for memory loss I disable loading with my custom code. Avail. Run. Quit. Avail. Not much loss.
Do opposite, enable my code, disable simple BitMapClass (no manipulation, straight loading) loading (maybe 15 images). Avail. Run. Quit. Avail. 2MB+ memory loss.

If I browse some drawers, more RAM is lost, like 3MB total.

I have made sure the
if (!(DTO=IDataTypes->NewDTObject(Path,
is freed.

Using AllocVecTags() and AllocBitMapTags(). No weird custom wrappers.

I am at a loss. Everything looks right, does all the steps, just won't free the memory.

broadblues
broadblues's picture
Offline
Last seen: 4 years 1 month ago
Joined: 2012-05-02 21:48
Re: Load and scale image

Avail. Run. Quit. Avail. 2MB+ memory loss.

This not a reliable method on AmigaOS 4, there caches and many different ways that memory may not be returned to the system until the system runs really short of memory and calls the various memory release hooks (forget the proper name for them just at the moment).

The memory might be cached by the datatypes system, it might be cached in the filesystem, or any of a number of options.

I wouldn't worry.

mritter0
mritter0's picture
Offline
Last seen: 1 year 10 months ago
Joined: 2014-04-21 21:15
Re: Load and scale image

I have worked on and walked away from this several times in the last 2 years. Walking away again.

On my X5000 with 2GB RAM it's not big deal. But in WinUAE and real A1200 with 128MB RAM, there isn't much left to lose.

Log in or register to post comments