No announcement yet.

Load Image Files Quickly

  • Filter
  • Time
  • Show
Clear All
new posts

  • #21
    you can't display 50 images of that size on any screen so why do you need to load 50 images of that size?

    Can you not create a small version of each image on disk which is suitable for display on the page of 50.
    Then you only load 50 small images, which is reasonably quick.

    If the user click on the small image to get it in full resolution then you still have the full resolution image on disk but only need to load one big image, which us again reasonably quick.

    The smaller version only needs to be created once when the new image is first added.


    • #22
      You use DIB more than you think you do.
      BMP/JPG/PNG/GIF are storage formats, to put image on screen they are converted to DIB.




      • #23

        Thumbnails? I think I saw that Gary was going to reduce the sizes for the 50 (or so) pick screen.



        • #24
          Hi Paul!

          Yep, in another app I've done exactly what you suggest. I created smaller versions of the large image and used those to improve loading/display time. In that particular case I created multiple smaller sizes and displayed the largest image sizes that would fit in the current dialog - no resizing employed..

          I also watched for new images and automatically created the necessary smaller images.

          I would rather have an approach that avoids the complications of that approach and that doesn't require so many files. But if I can't load the display of 50 image in about 1s or so, then I will likely fall back on the multiple image sizes approach.

          and Dale,
          Yep, thumbnails - of multiple sizes was the prior approach. I would like to resize on demand if I can get sufficient speed.


          • #25
            I'm having difficulty visualising what this application does. 500 or so images images which can be up to 2560x1440, which can change daily and a t time many times times a day and you want to display then up to 50 at a time "side by side" on a dialog which is likely to be re-sized?

            My first thought is that 50 images at a time means small thumbnails - something resembling an Explorer window showing "Large Icons".

            What is the actual purpose of the application?


            • #26
              Howdy, Stuart!

              The app itself if simply an image viewer. It displays an array of images. The users chooses the array size, from 2x2 to 9x6. When then user resizes the dialog, the array size stays the same but the images are resized. So yes, that part of the story is just like an Explorer window showing large icons.

              The folder containing the images is fed from 3 other sources, which account for the fluctuations in count. One source is from an email client, where attachments may be added throughout the day. Another source is snapshots from a camera application, which probably comes in random usage of the camera. A third source is from an app which extracts images from an inserted flash drive, where the user is provided images from other folks or where the user want to move them from on PC to another.

              So the image folder is basically an archive of images from actions a user takes.

              In this specific case, I'm dealing with low-vision users for whom folder navigation is difficult. That's the reason all images are kept in a single folder. Images captured from each of the 3 sources are placed automatically into the common folder. The low-vision users adjust the dialog and thumbnail sizes to match their eye limitations.

              My best guess is that the image archive will be kept relatively small - no more than 500 images, probably smaller. Scrolling through more than that, especially if the user uses large thumbnails would be very inconvenient. The user has to remove images from the archive as the count becomes inconvenient.

              In my current version of the app, loading of the array of images to be displayed takes many seconds, and resizing the images during dialog resizing is likewise noticeably slow.

              I thought perhaps keeping all images in memory might give a speed boost but as I mentioned in the OP that was a startup speed disaster!

              It still might be a run-time benefit when scrolling through images, one array at a time - as opposed to loading each image from it's file.

              But, that really huge startup delay is a killer, so I'm sticking with reading images from files as needed.

              If the images weren't so large, or if the user stuck with a 2x2 array, then the problem would not exist.


              • #27
                And, Stuart,

                Additional information ...

                WIndows Explorer locks the image size and requires the user to scroll through the images, where all images in the folder are displayed in the scrollable window.

                For my low-vision users, the use of a scrollbar can be quite a challenge because of the small size of the scrollbar/thumbar. In some versions of my apps I've provided extra wide scrollbars, but their default color schemes conflict with the high contrast color schemes a low-vision user might prefer. I'm still looking into making the wide scrollbar more useful, but haven't come up with an approach my users seem to like.

                The use of of the mouse wheel is perhaps a better solution and my app does allow that. But even the wheel is a problem when the display does not correspond real time to the number of turns of the wheel. If the screen continues to change, keep up to date after the user stops scrolling, it inserts some confusion.

                All that said, I'm just looking to see if there's a speed option that will make it easier for my users.

                I do have hopes that a multi-thread version of loading 9x6 images from files might speed things up quite a bit. Unfortunately I've had grandkids over the last 3 days and my computing time has been hit or miss. Everyone goes to bed at 8:30pm tonight so I should have a slot of time then to work on this some more!


                • #28
                  OK, time for a re-think off the methodology.

                  First time the program is run, populate a database with DIB thumbnails of the maximum size required for your image browser as well as file data. That will take a while, but will only happen once.
                  Use that database to populate your screens. Displaying/resizing those thumbnails will be a lot quicker than doing it with the full sized images.
                  When the user wants to view the actual image, load it from disk - one image won't take long.

                  On subsequent startups, scan the directory, compare it to the stored data and just delete and add thumbnails where the content of the directory has changed.
                  You could even run a thread to watch for folder changes and update the database with any changes while the application is running.

                  You could also give the user an option to completely rebuild the database any time they want.


                  • #29
                    Hi Stuart!

                    Yes, this is definitely true ...

                    Displaying/resizing those thumbnails will be a lot quicker than doing it with the full sized image
                    ... a one-time thumbnail creation with run-time updates of thumbnails should provide a speed improvement. That's similar to how I did it in a previous version of the app, but in that case I used files for the original and the multiple thumbnail versions. As you point out, loading and resizing the thumbnails, not the original images, would be faster.

                    And, because of the vision issues of my users, any imperfection resulting from resizing of a thumbnail won't be something they can easily see.

                    Even though I've done something along those lines previously, I'd prefer to reduce code complexity if possible. But speed is #1 in this case so I may have to go with something like it.


                    • #30
                      A common technique of many graphic/video stype apps is to fill the screen with "place holders" and as the data is loaded replace each place holder with the actual image. The Windows desktop does this. It puts all the icons on the desktop as place holders and then replaces them one by one with the actual icons as they load.

                      I notice this a lot since I tend to put a huge number of icons on my desktop, for things like apps, PDF files, document files, help files, etc. I prefer to click icons rather than select from the main menu.

                      I currently have a good 100 icons on my desktop and I recently purged a number of them off the desktop, so had more not too long ago. The Windows desktop is a bit slow in replacing the place holders with actual icons.

                      There are graphic apps which allow you to display a large number of thumbnails of images and they do the same.

                      The place holder technique helps the end user to visualize how many objects there are, while making them wait to load one by one.

                      I would use something similar and just make it work no matter how long it takes to display. Once working then go back and optimize for speed until you get to something acceptable.

                      The benefit of a database you create with DIB's in it, is that you don't have to do any decompression of images (jpg, png) when displaying to the screen. It is ready to use pixel data. Also you don't have to use any GDI drawing calls to move the images back to the screen, but you can move them just by copying blocks of pixels directly into a DIB for the screen via pointers. One BitBlt to the screen of the DIB and they are seen.

                      Create a Window class for a Canvas and use a DIB to store the Canvas. In WM_PAINT simply BitBlt to the screen. Rather than invalidate the entire Canvas (to force WM_PAINT), only invlidate the parts which need repainting. This is a technique used since the DOS days called "dirty rectangles". It speeds up the display significantly, since Windows only moves the pixels which need to be repainted when you BitBlt the image. I use this in my sprite engine and it speeds up the display significantly.

                      Chris Boss
                      Computer Workshop
                      Developer of "EZGUI"


                      • #31
                        Hi Chris!
                        The place-holder idea still means that the user has to wait, so I'm holding out for something else. In my app, I do put a grid (outline) of where each image goes so the user knows how many they are waiting for. But even with no grid, all images are the same size and always 128x128 or larger, so once they see an image or two, I don't think there is much confusion from the user about how many images it takes to fill the page.

                        However, your comment a stored DIB not requiring decompression may be a key coding approach selection criteria. I'll test to confirm but it seems that the disk access is not the primary speed driver. The creation of a database while allowing the user to freely place images of any format into a folder complicates the code a bit. I like the no-decompression part but only if the user interface doesn't get more complicated.

                        My own PC is about 12 years old. I ran some tests on a more recent i7 and saw much faster loader, below 4s. That was pretty good and almost acceptable.

                        The real visual issue is when resizing the dialog, where the delays are particularly noticeable.

                        To solve that, perhaps another option would be a variation on something Stuart suggested. I could load the images from their files, create a "500x500" or so thumbnail, then use only the 500x500 thumbnails to generate the real-time images as the user resizes. That would be much faster than dealing with the files and their large image size all the time.

                        So, there's still plenty of experimentation to do to find out what might give acceptable results. Regardless, I do want to run some tests with DIBs, but I've very rarely looked at - a knowledge gap I need to fill, just like the one I have on SQLite!

                        Thanks for the suggestion and I will consider it.


                        • #32
                          "2560x1440 size, perhaps a bit smaller."

                          That's an unrealistic size to load.
                          I have what I consider to be a big monitor but it's "only" 1920x1200. 60% of the size of your images.
                          Why do you need to load such high resolution images 50 at a time when it's difficult to even display one of them.

                          Shrink the images to something more realistic first and they'll load a lot faster.
                          If you then need to have the full resolution image then it will be a one off so won't take long to load.


                          • #33
                            Howdy, Paul!

                            2560x1440 size is in the vicinity of an image taken with a personal camera.That's a typical source for one of the images that a user might take, or be supplied with by a family member.

                            So, from those sources, I load/resize/display anywhere from 4 to 50 or so image files at a time, displayed to the maximum size that will fit on the users' screen. Like your screen, most desktop sizes are around 1920x1080. But because of their low-vision issues, my users have a disproportionate number of larger monitor screens.

                            I mentioned earlier that in the current version of my app I monitor the incoming image folders and create smaller versions of the image as needed to allow loading more quickly. That works great, but I don't like that approach because it proliferates images of many sizes, which I have to take into account when the user decides to delete a file. I'd like to work with only one set of images if possible - it's the "if possible" that this thread is discussing.

                            In your suggestion, I would only create perhaps 1 smaller image that is easier/faster to load - not several smaller versions as I now do. In your suggestion, I would still have to monitor the image folder and create resized images as the monitoring dictates, then use only use the much smaller image for loading and resizing. Even if I made the resized image only half the WxH dimensions, that ought to equate to about a 4X speed improvement.

                            So that meets the speed goal, but I was hoping to avoid the extra code complication by figuring out how to load the bigger images faster.

                            As for how unrealistic it is ... on my 12 year old i7 PC, it takes about 8s to load/resize/display around 50 images, drawing on the full size image file. That's way too slow.

                            On a newer i7 PC that I have, it takes about 3s. That's still slower than I want but not so bad, except for when the user is manually resizing the dialog.

                            I can always fall back on using the smaller base image - as I do now and as you are suggesting. I just don't think I've fully explored the options for using only the larger incoming image.

                            If use of the larger image proves unworkable, then I'll probably fall back on an approach similar to what you suggest.


                            • #34
                              Just as confirmation of the benefit of working with smaller images, if I limit the original files to images of 900x500 or smaller the load/resize/display takes only about 1s on my older PC. That's great for initial load, but not quite fast enough for no annoyance during real-time load/resize/display while the user resizes the display.

                              Somewhere around an original file image size of 300x250 load/resize/display time delay becomes much more acceptable on my older PC both on initial loading and during dialog resizing.


                              • #35
                                Sorry - in that earlier response I didn't give mention of your suggestion of using smaller images (in a database) approach as well. In a database a in file, the use of smaller images is much faster.


                                • #36
                                  Thanks everyone for the help/comments! For now I'll just go with a set of 2 images - one small for easy loading of thumbnails and one large for better quality image when viewing just one image. I'll insert some monitoring code to make sure that the original image is always available in both sizes.

                                  I still want to play with threads, DIBs and SQLite as possible speed improvement options but other things (like gbThreads) need to get some priority. I'll come back to this thread later - maybe in 2020!


                                  • #37
                                    I would break up the tasks into different sections and then benchmark each one. For example, try just loading all the images as fast as possible and don't do any drawing or display. Just benchmark the time it takes to load all the images. You need know how much time Windows needs just to find the image files and load them into memory. That will tell you how much time is spent on just finding and loading files. There won't be much you can do to change that. Then benchmark just the time to display those images.

                                    Benchmark portions of ones code is important to find where the bottleneck really is. At times, the bottleneck is not where you expect.
                                    Chris Boss
                                    Computer Workshop
                                    Developer of "EZGUI"


                                    • #38
                                      Howdy, Chris!

                                      Yep, I did that but did not report on the results. I didn't report it because I can't be certain that I was clearing the cache and so my times were suspect. Also, as I reported in another thread, the file loading times varied significantly - which I still don't understand. So not reporting suspect data seemed the safer thing.

                                      Even so --- in my tests the file load was about the same amount of time as the file conversion/display.

                                      added ...
                                      WIth 50 smaller images, limited to 300x300, load/display times were under a second. As I noted earlier, a faster single-image approach is preferred but I probably won't find anything that beats 1s - yet, I plan to keep looking!


                                      • #39
                                        You could try a different approach. Use a single database with all images as 32 bit DIBs. You can define the database yourself until you find the optimum load time.

                                        Now the user when using the app, must add images one at a time (or via group) via an IMPORT option. User could select a file (or files) using a standard Open File dialog and then select them to be imported to the database. Now once in the database every time in the future the app is used, all images would be pulled from the database. The app could do a quick scan of the default folder you store images in to see if any new images have been added and then ask the user if they would like to import them.

                                        I doubt you will get the performance you desire by always loading the images from original files (bmp,jpg,png,etc.).

                                        Now the Canvas you want to display them on, should be a custom window class which pre-allocates a single huge DIB buffer. Then read the data as pixels (bytes) directly from the database into the DIB using pointers. No GDI or GDI+ involved here, just pure pixel data.

                                        The beauty of actual pixel data, rather than a bitmap with handles is that you can store the data in a variety of data types. You could use PB variable length strings to store pixel data or arrays or any data type you feel provides easier access.
                                        Chris Boss
                                        Computer Workshop
                                        Developer of "EZGUI"