NecoArc 0 Posted November 26 (edited) I have a project that at some point I need to display many images on the screen at the same time These images are registered by the user, so before I didn't pay attention to the size of the images one of the users was registering 11MB png images which at some point caused the app to crash because the RAM consumption was going too high Then I did a treatment to resize the images and it worked fine... But I can't stop thinking, what if I want to use the images with the best possible resolution? even on devices with high performance, the RAM consumption is huge, eight 11MB images displayed on the screen at the same time use 500MB+ i have a loop that create frames and do something like: for product in menu do begin frame:= TFrmImageItem.create(product, 'imagePath'); layoutFrmImageItem.addObject(frame); end; constructor TFrmImageItem.create(product:TProduct, imagepath:string); var bitmap:TBitmap begin lbName.text:=product.name; bitmap := tbitmap.create; bitmap.setSize(TSize.create(200,200)); bitmap. LoadFromFile(imagePath); Timage.bitmap.assign(bitmap); bitmap.free; end i wonder what else can be done to reduce the memory consuption without resizing the images i've alredy implemented a virtualization method to set frameVisible:=false when the frame is not on the screen also a double buffer method (wich didn't work well) i wonder if you guys can provide me any ideas maybe the memory is skyrocketing because i'm using frames? Edited November 26 by NecoArc Share this post Link to post
Rollo62 539 Posted November 27 (edited) Perhaps its possible to read and show the images partly, as memory mapped files, depending on the Zom factor. See this as example for large text files, from jaenicke in the german DP. https://www.delphipraxis.net/151898-sj-mmf-file-reader-0-2-schneller-textdatei-reader.html https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile Edited November 27 by Rollo62 Share this post Link to post
Anders Melander 1815 Posted November 27 38 minutes ago, Rollo62 said: Perhaps its possible to read and show the images partly, as memory mapped files Why would making an image file memory mapped reduce RAM usage? Do you understand what mapping a file into memory does? Share this post Link to post
Rollo62 539 Posted November 27 42 minutes ago, Anders Melander said: Why would making an image file memory mapped reduce RAM usage? Do you understand what mapping a file into memory does? Because, if you Zoom or only want to show parts of the file, you eventually don't need to load it all. Usually a full view of such large file is way too condensed anyway, to be viewed correctly, so you only need to show the reduced data to the user until he zooms in. Why is Google Maps not showing always the whole earth, but only tiles of it? 🤔 Share this post Link to post
Anders Melander 1815 Posted November 27 Just now, Rollo62 said: Because, if you Zoom or only want to show parts of the file, you eventually don't need to load it all. Unless you actually know how to do this I don't think you should offer it as a possible solution. Assuming the image file is uncompressed, you would need to at least load the header. Then you would need to locate and load the partial image rows and then you would need to reassemble this into something that can be processed as a bitmap and then that would need to be scaled to fit the viewport. I doubt this would improve the performance. If the image is compressed then it will have to be decompressed into memory before it can be displayed. The RAM has already been allocated; Game over. 6 minutes ago, Rollo62 said: Why is Google Maps not showing always the whole earth, but only tiles of it? 🤔 Is that a serious question? Google Maps, and other GIS systems, display tiles because that is how their data is organized. As far as I can tell we are not dealing with tiled image data in this case. Anyway, back to memory mapping; If anything, using memory mapped files would increase the RAM usage, so I still fail to see how that would improve the situation. Share this post Link to post
Anders Melander 1815 Posted November 27 15 hours ago, NecoArc said: var bitmap:TBitmap begin lbName.text:=product.name; bitmap := tbitmap.create; bitmap.setSize(TSize.create(200,200)); bitmap. LoadFromFile(imagePath); Timage.bitmap.assign(bitmap); bitmap.free; end There's no point in sizing the bitmap just before you load something into it. Instead of loading into a TBitmap and then copying that into TImage, load directly into the destination bitmap. but this isn't the cause of you problems. Your source images are compressed PNGs. Once they are loaded into a TBitmap they have been decompressed so they will use a lot more memory that what their size is on disk. The images probably also have a resolution higher that what you can display. So instead of displaying the image in their original size/resolution, resize (resample is the correct term) them on load to fit the destination viewport. Keep the resized bitmap in memory and discard the original (from memory that is. You still have it wherever you loaded it from). So you are basically displaying thumbnails of the original images. Share this post Link to post
Rollo62 539 Posted November 27 (edited) 31 minutes ago, Anders Melander said: Assuming the image file is uncompressed, you would need to at least load the header. Then you would need to locate and load the partial image rows and then you would need to reassemble this into something that can be processed as a bitmap and then that would need to be scaled to fit the viewport. I doubt this would improve the performance. Yes, the OP is concerned about the in-memory use, of his many bitmaps at the same time in his app, which were already decompressed into TBitmaps, as far as I understand him right. These TBitmaps might work with a Paged memory mapped file for certain operations, to save in-memory space, what is so wrong to think about that? A Linear, decompressed Bitmap-File should be possible to handle, without loading it completely into memory first. Yes it might be terrible slow, but the images were probably more or less statically shown only, with very little operations to zoom and pan. Edited November 27 by Rollo62 Share this post Link to post
Anders Melander 1815 Posted November 27 36 minutes ago, Rollo62 said: A Linear, decompressed Bitmap-File should be possible to handle, without loading it completely into memory first. You haven't thought this through. Try it - at least on paper. Share this post Link to post
Rollo62 539 Posted November 27 Well I said it should be possible, I didn't say it will be easy 🙂 https://en.wikipedia.org/wiki/BMP_file_format#DIBs_in_memory https://upload.wikimedia.org/wikipedia/commons/7/75/BMPfileFormat.svg The PixelArray should be more or less linear. Quote Pixel storage The bits representing the bitmap pixels are packed in rows (also known as strides or scan lines). The size of each row is rounded up to a multiple of 4 bytes (a 32-bit DWORD) by padding.[18] For images with height above 1, multiple padded rows are stored consecutively, forming a Pixel Array. The total number of bytes necessary to store one row of pixels can be calculated as: RowSize = ⌈ BitsPerPixel ⋅ ImageWidth 32 ⌉ ⋅ 4 = ⌊ BitsPerPixel ⋅ ImageWidth + 31 32 ⌋ ⋅ 4 , ImageWidth is expressed in pixels. The equation above uses the floor and ceiling functions. The total number of bytes necessary to store an array of pixels in an n bits per pixel (bpp) image, with 2n colors, can be calculated by accounting for the effect of rounding up the size of each row to a multiple of 4 bytes, as follows: PixelArraySize = RowSize ⋅ | ImageHeight | ImageHeight is expressed in pixels. The absolute value is necessary because ImageHeight is expressed as a negative number for top-down images. It depends how much pressure you have from your client, if its worth it, or if you better purchase a larger PC. The task sound a little, as if it is a kind of control system, where the purchase option is out of reach. Anyway, I know not much about the task yet, so also a kind of pre-conversion of those images into a better manageable "custom pixel-array" could be possible, from where you can more easy pan and zoom, and covert back into a real TBitmaps then, from a virtual viewport moving over a memory mapped file. Ok, if all this is nonsense, then I'm looking forward to see better proposals from others now. Share this post Link to post
NecoArc 0 Posted November 27 4 hours ago, Rollo62 said: Perhaps its possible to read and show the images partly, as memory mapped files, depending on the Zom factor. See this as example for large text files, from jaenicke in the german DP. https://www.delphipraxis.net/151898-sj-mmf-file-reader-0-2-schneller-textdatei-reader.html https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-mapviewoffile thanks i'll give it try first time i've heard of this method Share this post Link to post
NecoArc 0 Posted November 27 3 hours ago, Anders Melander said: There's no point in sizing the bitmap just before you load something into it. Instead of loading into a TBitmap and then copying that into TImage, load directly into the destination bitmap. but this isn't the cause of you problems. Your source images are compressed PNGs. Once they are loaded into a TBitmap they have been decompressed so they will use a lot more memory that what their size is on disk. The images probably also have a resolution higher that what you can display. So instead of displaying the image in their original size/resolution, resize (resample is the correct term) them on load to fit the destination viewport. Keep the resized bitmap in memory and discard the original (from memory that is. You still have it wherever you loaded it from). So you are basically displaying thumbnails of the original images. that code was just a small exemple i have a generic function that returns me a lot of diferent types of bitmaps depending on my object, but there was no point into showing everything also, you're right in point 1. i took off the bitmap.setsize and it made no difference at all i'll give a try on your suggestion Share this post Link to post
NecoArc 0 Posted November 27 thanks for the suggestions guys i'll see what i can do now (also this website is really annoying it was saying my IP was blocked because of spam but it's the first time i'm using this community ) Share this post Link to post
Anders Melander 1815 Posted November 27 1 hour ago, Rollo62 said: Ok, if all this is nonsense It is. There is zero benefit in memory mapping a bitmap file. None. Zip. Share this post Link to post
Rollo62 539 Posted November 27 1 minute ago, Anders Melander said: It is. There is zero benefit in memory mapping a bitmap file. None. Zip. Ok then, another approach would be to pre-chop the large BMP into smaller BMP tiles, and show, pan and zoom through these smaller chunks only. Anyway, it depends if the images are more or less fixed data, like train tracks or city streets, or of this is realtime data, the latter would work neither way. My point is, that its not necessary to keep huge images in memory completely, if you only need a smaller fraction actively. I have seen an SVG of a chinese city, which really make no sense to load completely in the smallest zoom. You are better off with a smaller PNG of this view, because you can only see the overview and no details. Once you need the details, then you could switch to the next level of zoom and bring only those onto the viewport. Maybe something like Prezi is doing, only that this is vector based which make it much easier than multi-zoom tiles. Share this post Link to post
Anders Melander 1815 Posted November 27 Just now, Rollo62 said: pre-chop the large BMP into smaller BMP tiles, and show, pan and zoom through these smaller chunks only Sure, that'd work. Not a small task though. Share this post Link to post