WebImageView Woes

I am working on a Web app for intranet use that retrieves image paths from a database that are thumbnails of book pages. I’m having several woes regarding using the WebImageView. The first is speed of loading the images is extremely slow. each WebPage may have between 100 to 300 images on it. I’m using a container control and control sets to display the pictures that I pre-load into a picture array.
First I create all the controls and then assign the pictures to them:

[code]Sub ThumbsCoreCreate
Dim ImgBox As WebImageView
Dim Desc As WebLabel
Dim pic As Picture
Dim i,picWidth,picHeight As Integer
Dim b As Boolean

// Dimension the number of pictures in the Picture Array ThumbsCore()
Dim ImageCount As Integer = Ubound(ThumbsCore)

// Add the correct number of additional WebImageView controls to the…
// ContainerControl’s control sets ImageViewThumb and LabelThumb
For i = 1 To ImageCount
ImgBox = AddImageViewThumb
Desc = AddLabelThumb
Next

//assign the pictures and descriptions to the control sets
For i = 0 To ImageCount
pic = ThumbsCore(i)
picWidth = pic.Width
picHeight = pic.Height
ImageViewThumb(i).Width = picWidth
ImageViewThumb(i).Height = picHeight
ImageViewThumb(i).Picture = pic
LabelThumb(i).Text = ThumbsCoreData(i,0)
Next

// Arrange the thumbnail images control sets in the ContainerControl
b = ThumbsCoreArrange

// Make the Progress wheel invisible and the ContainerControl visible
If b = True Then
WebPage1.ProgressWheel1.Visible = False
Self.Visible = True
End If
End Sub[/code]

I use a separate method for arranging the controls so it can be re-used on resize:

Sub ThumbsCoreArrange As Boolean
  // Dimension the variables that need to be calculated
  Dim idx,column,row,columnLeft,rowTop,rowCount,columnCount As Integer
  
  // Dimension the number of pictures in the Picture Array ThumbsCore()
  Dim ImageCount As Integer = Ubound(ThumbsCore)
  
  // calculate the desired image spacing variables
  Dim Hspacing As Integer = 20
  Dim Vspacing As Integer = 44
  Dim posLeft As Integer = 20
  Dim posTop As Integer = 0
  Dim MaxWidth As Integer = 144
  Dim MaxHeight As Integer = 192
  Dim columnWidth As Integer = MaxWidth + Hspacing
  Dim rowHeight As Integer = MaxHeight + Vspacing
  
  // Calculate the number of columns
  columnCount = Self.Width / columnWidth
  If (Self.Width - (columnCount * columnWidth)) > (columnWidth / 2) Then
    columnCount = columnCount + 1
  End If
  
  // Calculate the number of columns
  rowCount = (ImageCount / columnCount)
  If (ImageCount - (rowCount * columnCount)) > 0 Then
    rowCount = rowCount +1
  End If
  
  // Set the image index to zero
  idx = 0
  
  // Arange the ContainerControl's control sets in a grid og rows and columns
  for row = 0 to rowCount
    rowTop = (posTop + (row * rowHeight))
    for column = 0 to columnCount -1
      columnLeft = (posLeft + (column * columnWidth))
      ImageViewThumb(idx).Left = ColumnLeft + ((MaxWidth - ImageViewThumb(idx).Width) / 2)
      LabelThumb(idx).Left = ColumnLeft
      ImageViewThumb(idx).Top = RowTop + (MaxHeight - ImageViewThumb(idx).Height) / 2
      LabelThumb(idx).Top = (RowTop + 198)
      ImageViewThumb(idx).Visible = True
      LabelThumb(idx).Visible = True
      If idx = ImageCount Then
        Return True
      Else
        idx = idx + 1
      End If
    next column
  next row
End Sub

The controls themselves display in a reasonable amount of time but the actual pictures take an extraordinary time to load. If they at least loaded one at a time it would be better than waiting many seconds to over a minute for them to load. Any ideas how I can speed this up? The Images are stored on NAS and not the web server which is why I load them into an array first and that happens very quickly.

The second issue I have is when I close the current set of controls so that the only one remaining is control 0 and then create new controls for a different set of thumbnails it appears that the new set starts index numbering where the old set left off instead of at 1 because I get a nil object exception. How can I insure the new controls indexes are numbered correctly. I’ve also tried closing the ContainerControl and creating a new instance but I get duplicate sets of controls on top of the new ones which is weird.

Are you serving all of the images through the app as well? If you were to offload that to a web server (Apache, IIS), things would move a long a little faster.

I built a custom SpriteSheet class and a WebSpriteButton that works great. You can send all your thumb-images over as a single sprite sheet if you want. The core functionality is working great but I’m still working on some optimizations and additional features, but feel free to check it out.

https://www.dropbox.com/s/r3w69l2jg0n0kg4/spritesheet-2014-10-01.zip?dl=0

Greg, I am serving them up through the app. At the moment using a second webserver to serve them up is not on my radar for the purpose I have in mind. Realistically I could use my Storage Cluster’s Web API to serve them up but I was trying to stay within the Xojo application framework. It appears to have some limitations OR I just need a better understanding of the how to serve up images within that framework.

Brock, Thanks for the sample. I’ll take a look at it and see if it will be useful. I’m currently working on trying the WebPicture.Preload method to see if it helps. That will require me to not use an array of pictures so I’m reworking my code.

With hundreds of images to load the first thing you are to do is to use URL to the picture files instead of managing them inside your app. Just test each method on a dozen, and you will see the difference is striking. You do not need an cluster to serve the picture files ; just a folder on the same web space as your app.

Michael there are many many terabytes of millions of thumbnail and medium res images from tens of thousands of books I need to serve up. The image storage and organization is already established on a 600TB clustered storage system. Putting them on the web server is not an option.

I’ve now switched my code around to using the WebPicture.Preload method and it vastly improves the performance. But since I’m no longer using a thread to retrieve the images I can’t get my ProgressWheel to show up. I’m making my ControlSet invisible but the web page does not refresh until it paints the new set of images. The wait is only a couple of seconds now for 300 images but I want to indicate to the user the images are being retrieved. Any thoughts on that would be appreciated. Here is the code I’m now using:

[code]Sub ThumbsCoreCreate
Dim rs As RecordSet
Dim sqlStrng As String
Dim i,n,picWidth,picHeight As Integer
Dim b As Boolean
Dim img As FolderItem
Dim FilePath As String
Dim ImgBox As WebImageView
Dim Desc As WebLabel
Dim pic As WebPicture

// Re-dimension the Jobs Thumbnail and Medium Res image data for the core book pages
ReDim ThumbsCoreData(-1,-1)

// Query the DB for the Job image data into a recordset
sqlStrng = “SELECT FILE_NAME, THUMBNAIL_PATH, MEDIUM_RES_PATH, PAGE_TYPE, PAGE_NUMBER FROM page_data WHERE JOB_ARCHIVE_ID = '” + dbJobID + “’ AND PAGE_TYPE = ‘Core’”
// FILE_NAME=0 THUMBNAIL_PATH=1 MEDIUM_RES_PATH=2 PAGE_TYPE=3 PAGE_NUMBER=4

rs = MySQLDB.SQLSelect(sqlStrng)

//Append each record into the ThumbsCoreData array
If rs <> NIL Then
n = rs.RecordCount - 1
i = rs.FieldCount -1
ReDim ThumbsCoreData(n,i)
n = 0
While Not rs.EOF
For i = 1 To rs.FieldCount
ThumbsCoreData(n,(i - 1)) = rs.IdxField(i).StringValue
Next
n = n + 1
rs.MoveNext
wend

// Retrieve the thumbnail paths and add WebPictures to the ControlSet creating controls if they don't already exist
For i = 0 to UBound(ThumbsCoreData,1)
  If  ImageViewThumb(i) = Nil Then
    ImgBox = AddImageViewThumb
    Desc = AddLabelThumb
  End If
  FilePath = ThumbsCoreData(i,1)
  img = GetFolderItem(FilePath)
  If Not (img  = Nil) Then
    If img .Exists Then
      pic = WebImageView.Picture.Open(img)
      // Preload the images to the web browser as the images are retrieved
      If Not pic.Preload Then
        // Browser was unable to preload the picture
        // Not handling False for now
      End If
    Else
      // Not Available images based on book Trim Size
      If dbJobTrimSize = "7" Then
        pic = NA7
      ElseIf dbJobTrimSize = "8" Then
        pic = NA8
      ElseIf dbJobTrimSize = "9" Then
        pic = NA9
      End If
    End If
  End If
  picWidth = pic.Width
  picHeight = pic.Height
  ImageViewThumb(i).Width = picWidth
  ImageViewThumb(i).Height = picHeight
  ImageViewThumb(i).Picture = pic
  LabelThumb(i).Text = ThumbsCoreData(i,0)
Next

Else
ShowAlert(“Database Error”,"Database Error " + EndOfLine + MySQLDB.ErrorMessage + “.”,“Caution”)
End If

// Arrange the thumbnail images control sets in the ContainerControl
b = ThumbsCoreArrange

// Make the Progress wheel invisible and the ContainerControl visible
If b = True Then
WebPage1.ProgressWheel1.Visible = False
Self.Visible = True
End If
End Sub[/code]

Can the user see all of the images at the same time?

The UI does not update until an event is over, Display the ProgressWheel in a timer Action event. That way it will show.

Thanks for the tip Michael. That worked.

Greg, With the preload the user sees all the thumbnails show almost instantaneously AFTER a wait for them to process into the controls on the server. I hide the container control and they see a progress wheel until the processing completes and I unhide the container so all the thumbnails appear.