Datagrid form slow data load time

Anything beyond the basics in using the LiveCode language. Share your handlers, functions and magic here.

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Datagrid form slow data load time

Post by Simon Knight » Mon Oct 09, 2023 9:28 pm

Hi,
I decided it was time to experiment with a datagrid form so I have put together a simple form that displays a thumbnail image and a text field in each row. I populate the datagrid by setting the dgdata which contains the image URL and the text string to be displayed.

It all works o.k. when its given a folder of ten images, however, when I try it with a folder of five hundred images it populates the visible rows (as expected) and then appears to stop working as it sorts its life out. If I give it time it starts working so I guess that some form of caching is going on behind the scenes. I wonder if there is a way of monitoring the progress of the data loading so that a progress indicator may be displayed.

Any thoughts?
best wishes
Skids

stam
Posts: 2686
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Datagrid form slow data load time

Post by stam » Tue Oct 10, 2023 12:44 am

Simon Knight wrote:
Mon Oct 09, 2023 9:28 pm
It all works o.k. when its given a folder of ten images, however, when I try it with a folder of five hundred images it populates the visible rows (as expected) and then appears to stop working as it sorts its life out. If I give it time it starts working so I guess that some form of caching is going on behind the scenes. I wonder if there is a way of monitoring the progress of the data loading so that a progress indicator may be displayed.

Any thoughts?
Are you able to share the code you use to populate the DG and the fillIn handler of the row’s behaviour?
Also out of curiosity, what is the total size of your image folder?

Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Re: Datagrid form slow data load time

Post by Simon Knight » Tue Oct 10, 2023 9:59 am

Hi Stam,

The folder of images is 1.2Gbytes and comprises full size jpegs and smaller but still quite large thumbnails that are 500 pixels on their longest sides. The image in my datagrid is 300 x 300 pixels and the images are being resized in the handler "LayOutControl". This is where I suspect the initial pause is occurring. Once fully built the datagrid scrolls quickly which suggests that the reduced images are being cached in memory.

An additional bug has become apparent : when scrolling top to bottom and back to top the images move a few pixels to the left.
Screenshot 2023-10-09 at 21.36.21.png
When first populated
Screenshot 2023-10-09 at 21.37.27.png
After several scrolls
It seems that LayOutControl is recalled every time a row comes into view which means that the rescale code is called. This code uses rounding which I suspect causes the images to edge to the left.

The main script parses a given folder and builds a list of jpeg images. This list is converted into an array which is passed into the datagrid :

Code: Select all

On ProcessTSVData pTSVData
   local tProgressCount
   put the number of lines of pTSVData into tRowCount
   
   put 0 into tProgressCount
   
   set itemdel to tab
   put the right of me into tRightMargin
   put the top of me into tMyTop
   put the files into tFileList
   put empty into tImageDataA
   put empty into tCounter
   repeat for each line tRec in pTSVData
      add one to tCounter
      put item 1 of tRec into tFileName
      put item 2 of tRec into tTitle
      put item 3 of tRec into tCaption
      
      put the directory & "/" & tFileName into tFullImageFileName
      put NameOfThumbnail(tFileName) into tThumbNail
      
      put tFullImageFileName into tImageDataA[tCounter]["ImageURL"]
      put tThumbnail into tImageDataA[tCounter]["ThumbURL"]
      put tTitle into tImageDataA[tCounter]["Title"]
      put tCaption into tImageDataA[tCounter]["Caption"]
   end repeat
   
   set the dgdata of group "dgImages" of card id 1002 of me to tImageDataA
   put "Complete" into field "debug"
   
end ProcessTSVData

(I start with TSV because the initial sort order is being set by my image catalog application PhotoMechanic which outputs the initial TSV file).
FillInData is straight forward:

Code: Select all

on FillInData pDataArray
   -- This message is sent when the Data Grid needs to populate
   -- this template with the data from a record. pDataArray is an
   -- an array containing the records data.
   -- You do not need to resize any of your template's controls in
   -- this message. All resizing should be handled in resizeControl.
   
   if the length of pDataArray["Title"] >0 then
      set the text of field "Title" of me to pDataArray["Title"]
   end if
   set the filename of image "thumbnail" of me to pDataArray["ThumbURL"]
end FillInData
LayOutControl is where the issues start:

Code: Select all

on LayoutControl pControlRect, pWorkingRect
-- left top right bottom
   
   ## Read the size of the image object then scale the image bitmap to size
   
   # Read the size of the image object, so that we can scale the image.
   --Put the width of image "thumbnail" of me into tMaxWidth
   --Put the height of image "thumbnail" of me into tMaxHt
   
   put 300 into tMaxWidth
   put 300 into tMaxHt
   put pControlRect into tControlRectOld
   
   set the resizeQuality of image "thumbnail" of me to "Good" //normal/good/best
   
   ## read the pixel dimensions of image (data)
   put the FormattedWidth of image  "thumbnail" of me into tFormattedWidth
   put the FormattedHeight of image "thumbnail" of me into tFormattedHeight
   
   ## Call handler to calculate the scale factor required to rezize the image data to the size of image control
   put  ScaledImageSize (tMaxWidth, tMaxHt , tFormattedWidth, tFormattedHeight) into tNewImageSize
   
   set the width of image  "thumbnail" of me to item 1 of tNewImageSize
   set the height of image  "thumbnail" of me to item 2 of tNewImageSize
   
   ## Now reposition the controls and resize the row
   
   ## - image control
   
   put item 2 of pControlRect into tCellTop
   set the top of image "thumbnail" of me to tCellTop+4
   
   put the height of image "thumbnail" of me into tNewCellHt
   put tCellTop + 4 + tNewCellHt+4 into item 4 of pControlRect
   
   ## - Now the text field
   
   put the rect of field "Title" of me into tTitleRect
   put item 3 of pControlRect into tRightEdge
   put tRightEdge-5 into item 3 of tTitleRect
   set the rect of field "Title" of me to tTitleRect
   
   ## - background
   
   set the rect of graphic "Background" of me to pControlRect
   
end LayoutControl

Function ScaledImageSize pMaxWidth, pMaxHt , pFormattedWidth, pFormattedHt
   ##############################################################
   #
   # pMaxWidth and pMaxHt are the maximum sizes wanted in pixels. 
   # pFormatted wideth and height are the actual size of the image in pixels .
   # Handler returns a scaling factor that when applied by the calling routine
   # results in the longest edge of the image being set to the values of Maxwith/Maxheight
   # without any distortion.
   #
   # thanks to Klaus for the forum post
   # S.Knight May 2018
   ##############################################################
   
   local tScaleFactor
   put min (pMaxWidth/pFormattedWidth,pMaxHt/pFormattedHt) into tScaleFactor
   return round(pFormattedWidth * tscaleFactor) & comma & round(pFormattedHt * tscaleFactor)
   
end ScaledImageSize
The background to this experiment is an older application that was written to help me manage a small camera club's website. The members would send me images to publish on the site but a number of them were unable to reliably reduce the size of their images or to populate useful iptc fields such as Headline and Copyright. This original application was distributed and provided a simple interface to add a caption to each image plus it produced a CSV file that was used by the web site to match thumbnail images with their respective larger sized version, determine the display order and list the captions.

This original application uses a group control that is populated with smaller image groups, known as polaroids based on a template control. It works well but has a limitation in that each so called polaroid is placed below the first in a long list/line. It turns out that a group control does have a maximum size limit of 32768 pixels (2 pwr 15 or 16 bits if you will). This limit equates to 148 copies of the polaroid at its present default size meaning that no more than 148 images may be processed in one sitting. In reality this is more than enough as most web galleries are no more than ten or twenty images per gallery.

I decided to give the new datagrid version 2 a try especially as it now allows the drag and drop reordering of rows. Well it does but it has to be switched on and off and all my attempts to get rid of the icons by following the instructions in the tutorial have failed. In the present version the edit mode has now stopped working for unknown reasons.

All my prejudice against the datagrid have been re-enforced, the principle one being that the normal debugging tools become unreliable with the message path getting complex and eventually lost. Its not possible to always step through code or to get break points to work reliably. I do wonder if I should just extend my present custom control possibly storing polaroids in a pair of "piles" or "decks" and deal the polaroids as necessary.

I have attached a zip file that contains the two stacks. Both applications work on a folder of jpeg images which contain large and thumbnail versions named like this "Any Old Image.jpg" and "Any Old Image_Thumb.jpg".
Attachments
Archive.zip
Two stack files
(27.67 KiB) Downloaded 47 times
best wishes
Skids

stam
Posts: 2686
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Datagrid form slow data load time

Post by stam » Wed Oct 11, 2023 11:14 pm

sorry been having late nights at work and this is the earliest I've been able to look at your stacks.
There are some serious errors in your script - the obvious and immediate one is a divide by zero error in the handler that resizes stuff and it crashes on stack startup.

One obvious optimisation would be to not do what you wanted if I've understood your code correctly - i.e. not have variable height rows because the DG will be bogged down constantly recalculating these - a very costly process. And not sure it would be easier on the eyes anyway? I mean if you have a tiny pic and huge pic it's going to be weird scrolling through them when really this is meant to be a list of thumbnails isn't it? So why not just scale the image to fit a fixed-height row?

Anyway, I'll play around with it and see...

stam
Posts: 2686
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Datagrid form slow data load time

Post by stam » Thu Oct 12, 2023 2:52 am

Well, as I have no repository of images that have associated thumbnails I tried with 5 high resolution jpg's (some image app's stock photography included as a tutorial) that I duplicated several times so that the image folder was about 2Gb (file sizes vary between 5.5 and 6 Mb each)

There is a lot of stuff in your stack that you process that aren't relevant to the task and I don't have time to digest these - so I made a simple stack with a data grid that has a thumbnail (fixed height but resizeable width) and a field for the title extracted from the filename (I know you get the metadata for this but again I have no time/interest ;) )

With fixed row height there was acceptable (although admittedly not stellar) performance resizing the full size images on the fly to fit the row height.
Almost certainly performance will be better if actually working with thumbnails as opposed to full size images.

The handler to resize proportionally to a certain height is in the stack script (pSource/pDestination are the long ID's):

Code: Select all

command resizeProportionalByHeight pHeight, pSource, pDestination
    local tRatio
    put the height of pSource / the width of pSource into tRatio
    set the height of pDestination to pHeight
    if tRatio < 0 then
        set the width of pDestination to pHeight * tRatio
    else
        set the width of pDestination to pHeight / tRatio
    end if
end resizeProportionalByHeight
I appreciate that your data array has more keys/data, for the simple process of this test I just grabbed file paths/file names. This almost certainly not suitable for your purposes since it doesn't check for thumbnail images or metadata, but you already do this. For this test:

Code: Select all

function createArrayFromFolder pFolder
    local tFiles, tOldFolder, tArray, x, tFileName
    put the defaultFolder into tOldFolder
    set the defaultFolder to pFolder
    put the files into tFiles
    lock screen
    repeat for each line tFile in tFiles
        if char 1 of tFile = "." then next repeat
        add 1 to x
        set the itemDelimiter to slash
        put the defaultFolder & slash & item -1 of tFile into tArray[x]["filepath"]
        put tFile into tArray[x]["name"]
        set the itemDelimiter to "."
        put item 1 of tArray[x]["name"] into tArray[x]["title"]
    end repeat
    set the defaultFolder to tOldFolder
    return tArray
end createArrayFromFolder
and in the behaviour script:

Code: Select all

on FillInData pDataArray
    set the text of field "title" of me to pDataArray["title"]
    set the filename of image "imgThumbnail" of me to pDataArray["filePath"]
    resizeProportionalByHeight the dgProp["row height"] of me, the long id of image "imgThumbnail" of me, \
          the long id of image "imgThumbnail" of me
end FillInData


on LayoutControl pControlRect, pWorkingRect    
    set the left of image "imgThumbnail" of me to 0
    set the rect of graphic "Background" of me to pControlRect
end LayoutControl
The stack is attached below (obviously due to size restrictions on the forum, images aren't included).

I hope this is a helpful starting point... but do let me know if I'm 1,000,000 miles off the mark!
Stam
Attachments
DatagridForImages.livecode.zip
(7.38 KiB) Downloaded 45 times

Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Re: Datagrid form slow data load time

Post by Simon Knight » Thu Oct 12, 2023 5:37 am

A big THANKYOU for spending so much time on this and posting your own stack. I apologise for the divide by zero error; I thought I had fixed it but may have zipped and posted the wrong version.

Your example is much quicker to load 500 images but oddly seems a little hesitant when scrolling: I guess this is the non stellar performance you mention.

I think the solution will be to create a thumbnail copy of each image just for displaying in the datagrid and save these in a sub folder thus removing the time consuming rescaling that presently occurs on first load and when the datagrid is scrolled. Its an extra step at the start of the display process but I'm guessing it will make the datagrid far more fluid.

I'll report back my findings.

Thanks again,
best wishes

Simon
best wishes
Skids

Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Re: Datagrid form slow data load time

Post by Simon Knight » Thu Oct 12, 2023 6:22 am

Just discovered the following tutorial : https://livecode-lessons-copy.screenste ... age-viewer

One interesting point that I learnt from the tutorial is that rescaling an image does not reduce the size of the data, meaning that a rescaled 20Mbyte image is still 20Mbytes. To create a truly small thumbnail a snapshot has to be taken of the scaled image to produce a file/data size of approximately 200 kilobytes or so. I suspect that doing this will increase the render speed.
best wishes
Skids

stam
Posts: 2686
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Datagrid form slow data load time

Post by stam » Thu Oct 12, 2023 7:27 am

Hi Simon, yes that’s the “non stellar” performance although it doesn’t seem change with increasing number of images.

I remember there was a lesson somewhere on resizing images where the advice was to run this code to permanent resize images after scaling them:

Code: Select all

Set the kmageData if img “myImage” to the imageData of img “myImage”

And you can probably set the imageQuality to “low” or some such before resizing images, although I haven’t tested that.

My code only scales an existing image, it doesn’t actually resize it. If you put the scaled image into another image, the result will be a full sized image.

Of course if you already have thumbnail images that may be easier ;)

Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Re: Datagrid form slow data load time

Post by Simon Knight » Fri Oct 13, 2023 9:41 am

It appears that the slight stutter may be related to the scroll bar. I state this because I can make it worse by intercepting the ScrollBarDrag message and reading its value. Interestingly (well to me!) is that when displaying 500 thumbnails the final scrollbar position is 99207.

I have no proof but I'm guessing that a stutter indicates that a few more rows have been added just out of view in the direction of scroll and equally others have been deleted from the opposite direction. Its quite possible that the whole form is redrawn every n rows, with a few extra rows above and below the group "window".
best wishes
Skids

stam
Posts: 2686
Joined: Sun Jun 04, 2006 9:39 pm
Location: London, UK

Re: Datagrid form slow data load time

Post by stam » Fri Oct 13, 2023 12:27 pm

Hmmm, well I have zero stutter when crating large, complex rows in a DG form (usually about 200 px with anywhere between 10-20 controls). I’ve only ever seen this with these images which to me suggests it’s the full size images (even if scaled they are still full size) that is causing the issue.

I was toying with the idea of actually generating small thumbnails on processing the folder and storing these in the array rather than as files. Not sure if that would speed up things but it might…

As to reading the scrollbar position, I presume you read the property dgVScroll of the data grid?

The scroll bar itself can be accessed as scrollBar “dgDcroll” of group “<datagrid name>”, but manipulating this directly is of little use. Much better to use dgVScroll and dgHScroll…

Simon Knight
Posts: 854
Joined: Wed Nov 04, 2009 11:41 am
Location: Gunthorpe, North Lincs, UK

Re: Datagrid form slow data load time

Post by Simon Knight » Fri Oct 13, 2023 6:14 pm

I think we are probably both correct in that rescaling a large image takes time and I'm guessing it occurs when needed i.e. when the scroll bar is moved.
I presume you read the property dgVScroll of the data grid?
Yes by intercepting the scrollbarDrag message
best wishes
Skids

Post Reply

Return to “Talking LiveCode”