Page 1 of 3 123 LastLast
Results 1 to 10 of 21

Thread: Smooth in-memory image display - what's the best method?

  1. #1

    Smooth in-memory image display - what's the best method?

    I'm trying to write a simple program that will load up several thousand .jpg images from disk into RAM (I have plenty of RAM on my PC) and then smoothly (i.e. double-buffered, without tearing) be able to display them one at a time in a window (not side-by-side, but like frames of a movie). Ideally I'd like to be able to 'play them back' as well as jump around to arbitrary images in the list at more than 30 fps.

    I've tried doing this a canvas, but I can't find a way to load a JPG into memory and then copy that into the canvas to display.

    I've tried using TImage, which can load the JPGs, but I can't get the playback smooth.

    I've tried using GDI+ into a canvas, but couldn't get that to display anything at all.

    Does anyone have any suggestions of a straightforward way to accomplish this?

    Thanks-

    *Brian

  2. #2
    thinBasic MVPs
    Join Date
    Oct 2012
    Location
    Germany
    Age
    54
    Posts
    1,529
    Rep Power
    170
    Does it have to be *.jpg-format or would you be able to convert them images to something like *.bmp*- or .png-format?

    If not, the the only solution i can offer is to use Freeimage-library.
    Attachement contains freeimage.dll + anyTexture.tBasicU, an include-file for some basic functions that can load almost any image to create a texture for TBGL-usage and some functions example-script as this:


    Uses "UI" ' needed only for Dialog_OpenFile-function
    
    
    #INCLUDE "anyTexture.tBasicU"
    
    Function TBMain()
    
      Local scrWidth, scrHeight, scrDepth As Long    '-- screen-info
      Local hWin                          As DWord   '-- handle of window
      Local lBtn, hasImage                As Boolean '-- left mousebutton, image available
      Local sFile, sPath                  As String  '-- filename & last path 
      Local lWidth, lHeight               As Long    '-- image size
      
      TBGL_GetDesktopInfo(ScrWidth, ScrHeight, ScrDepth)
        
      hWin = TBGL_CreateWindowEx( "Any texture - click to load, esc to quit",     _
                                  400, 200, scrDepth,   _
                                  %TBGL_WS_WINDOWED Or %TBGL_WS_DONTKEEPASPECTRATIO Or _
                                  %TBGL_WS_MINIMIZEBOX Or %TBGL_WS_MAXIMIZEBOX Or _
                                  %TBGL_WS_CLOSEBOX Or %TBGL_WS_DONTSIZE _ 
                                 )
      sPath = APP_ScriptPath
      
       ' -- Resets status of all keys 
      TBGL_ResetKeyState() 
      ' -- open the window 
      TBGL_ShowWindow  
      
      While TBGL_IsWindow(hWin) 
        '-- esc to end
        If TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) Then Exit While
        
        ' left-click to load something
        If TBGL_GetWindowKeyState(hWin, %VK_LBUTTON) Then
          If lBtn = 0 Then 
            If TBGL_MouseGetPosX > -1 And TBGL_MouseGetPosY > -1 Then
              hasImage = FALSE
              sFile = Dialog_OpenFile(0, 
                                      "Select an image", 
                                      sPath,
                                      "All Files (*.*)|*.*", 
                                      "*",
                                      %OFN_FILEMUSTEXIST Or %OFN_HIDEREADONLY Or %OFN_ENABLESIZING)
    
       
              ' -- simply load it to slot 1
              If TEXTURE_LoadData( sFile, 1) Then
                TBGL_GetTextureResolution(1, lWidth, lHeight) 
                If lWidth > 0 And lHeight > 0 Then
                  TBGL_SetWindowed( hWin, lWidth, lHeight )
                  TBGL_RenderMatrix2D(0, lHeight, lWidth, 0)  ' set the fitting matrix 
                  hasImage = TRUE
                  sPath = FILE_PathSplit(sFile, %PATH_ROOTPATH)
                EndIf    
              Else
                MsgBox( 0, "Unable to open this file",, "Error" )
                hasImage = FALSE
              EndIf
    
            EndIf
          EndIf
          lBtn = 1
        Else
          lBtn = 0    
        EndIf  
        
        If hasImage Then    
          ' draw it
          TBGL_ClearFrame
            TBGL_UseTexturing TRUE        
            TBGL_BindTexture(1)
            TBGL_Color 255, 255, 255
        
            TBGL_BeginPoly %GL_QUADS
              TBGL_TexCoord2D 0, 0
              TBGL_Vertex 0, lHeight
              TBGL_TexCoord2D 1, 0
              TBGL_Vertex lWidth, lHeight
              TBGL_TexCoord2D 1, 1
              TBGL_Vertex lWidth, 0
              TBGL_TexCoord2D 0, 1        
              TBGL_Vertex 0, 0
            TBGL_EndPoly
      
          TBGL_DrawFrame
        EndIf  
        
      Wend
     
      
    End Function
    
    The amount of textures (=images) in memory at once is limited to 1024 so i don't know if that serves your needs. It's also a pool so if you use the function TEXTURE_GetHandle instead of Texture_LoadData it will make sure to load each texture just once into memory.

    The code unit is able to convert & save images also to some own compressed format, recommended %TBGL_DATA_BGRA if using an alpha-channel or %TBGL_DATA_RGB so you will be able to load the image later without the need of freeImage.dll,

    just look at blocks of code inside "anyTexture.tBasicU" that are enclosed by
    ' ### {
    
    code
    code
    code
    
    ' ### }
    
    comment those blocks of code (CTRL+B if block marked in thinAir) then you can use the unit without freeImage.dll - it still will load *.bmp, *.png, uncompressed *.tga and own formats.

    If you're using thinBaisc-Version below 1.9 then you should update at least your TBGL-module, find it here:
    http://www.thinbasic.com/community/s...t-TBGL-version
    Attached Files Attached Files
    Last edited by ReneMiner; 27-08-2015 at 13:04.
    I think there are missing some Forum-sections as beta-testing and support

  3. #3
    thinBasic MVPs
    Join Date
    Oct 2012
    Location
    Germany
    Age
    54
    Posts
    1,529
    Rep Power
    170
    However if you have thousands of images, there's a simple way to have more than 1024 images in memory.
    Simply create some udt-array,

    Here is an example, but it requires at least tB-version 1.9.15.0, get it from there:
    http://www.thinbasic.com/community/showthread.php?12508

    #MINVERSION 1.9.15.0
    #INCLUDE Once "anyTexture.tBasicU"
    
    ' ###########################################################
    Type tTexturedata
      sData   As String 
      sFile   As String
      
      lWidth  As Long
      lHeight As Long
      
      GetFromSlot As Function
      SetToSlot   As Function
    End Type
    
    ' ------------------------------------------------------------
    Function tTexturedata.GetFromSlot(ByVal lSlot As Long) As Boolean
      
      Me.sData = TBGL_GetTextureData(lSlot, %TBGL_DATA_BGRA)
      
      If StrPtrLen(StrPtr(Me.sData)) Then        
        
    '    ' byref passed udt-elements can cause troubles
    '    ' so this plain long-layover to avoid such: 
        Local lWidth  As Long At VarPtr(Me.lWidth)   
        Local lHeight As Long At VarPtr(Me.lHeight)
    '    
    '    ' now can pass lWidth & lHeight byRef: 
    
        TBGL_GetTextureResolution(lSlot, lWidth, lHeight)
        
        Me.sFile = Textures_inPool(lSlot)  ' get also the filename...
      
        Function = TRUE
      Else
        Me.lWidth = 0
        Me.lHeight = 0
      EndIf
      
    End Function 
    
    ' ------------------------------------------------------------
    Function tTexturedata.SetToSlot(ByVal lSlot As Long, _
                           Optional ByVal setActive As Boolean = TRUE _
                                    ) As Boolean
      
      If All( _
              StrPtrLen(StrPtr(Me.sData)), _
              Me.lWidth > 0              , _
              Me.lHeight > 0              _
              ) Then        
      
        TBGL_MakeTexture Me.sData, %TBGL_DATA_BGRA, Me.lWidth, Me.lHeight, lSlot, %TEXTURE_Quality
        Textures_inPool(lSlot) = Me.sFile ' informs texture-pool about the filename
        
        If setActive Then TBGL_BindTexture(lSlot)
        
        Function = TRUE
      
      EndIf
      
    End Function 
    ' ------------------------------------------------------------
    
    
    ' now for example can this: 
    
    
    Dim myTexture(12345) As tTexturedata   ' now we have space for more than 1024 images in memory...
    
    
    Function TBMain()
    
      Local scrWidth, scrHeight, scrDepth As Long    '-- screen-info
      Local hWin                          As DWord   '-- handle of window
      Local lBtn                          As Boolean '-- left mousebutton
      Local Index                         As Long    '-- use 1 and 7777 for this example
      ' my shipped example-images have the same size:
      Local lWidth                        As Long = 400
      Local lHeight                       As Long = 200
        
      TBGL_GetDesktopInfo(ScrWidth, ScrHeight, ScrDepth)
        
      hWin = TBGL_CreateWindowEx( "Any texture - click to change, esc to quit",     _
                                  lWidth, lHeight, scrDepth,   _
                                  %TBGL_WS_WINDOWED Or %TBGL_WS_DONTKEEPASPECTRATIO Or _
                                  %TBGL_WS_CLOSEBOX Or %TBGL_WS_DONTSIZE _ 
                                 )
      
       ' -- Resets status of all keys 
      TBGL_ResetKeyState() 
      ' -- open the window 
      TBGL_ShowWindow                          
      
      If TBGL_IsWindow(hWin) Then
        
        ' initially load 2 images to UDT-array myTexture:
        '       always using the same slot,         which is 1
        If TEXTURE_LoadData(APP_ScriptPath & "myImage2.png", 1) Then
          myTexture(7777).GetFromSlot(1) ' Index is 7777 here
        EndIf  
        
        
        If TEXTURE_LoadData(APP_ScriptPath & "myImage1.png", 1) Then
          myTexture(1).GetFromSlot(1)   ' Index is 1 here
        EndIf  
        
        ' initially we want to see myImage1, thats why it was loaded last:
        Index = 1 
        
        ' set the fitting matrix - same to all images here:
        TBGL_RenderMatrix2D(0, lHeight, lWidth, 0)  
        
        ' TBGL_BindTexture(1) can be omitted here...  
        ' those stay as they are:
        TBGL_UseTexturing TRUE        
        TBGL_Color 255, 255, 255
         
      EndIf
      
      While TBGL_IsWindow(hWin) 
        '-- esc to end
        If TBGL_GetWindowKeyState(hWin, %VK_ESCAPE) Then Exit While
        
        ' left-click to change image
        
        If TBGL_GetWindowKeyState(hWin, %VK_LBUTTON) Then
          If lBtn = 0 Then 
            If TBGL_MouseGetPosX > -1 And TBGL_MouseGetPosY > -1 Then
              ' = clicked into the windows client-area
              Select Case Index
                Case 1   
                  Index = 7777  
                Case Else
                  Index = 1
              End Select
              myTexture(Index).SetToSlot(1)
            EndIf
          EndIf
          lBtn = 1
        Else
          lBtn = 0    
        EndIf  
        
        ' draw it
        TBGL_ClearFrame
          TBGL_BeginPoly %GL_QUADS
            TBGL_TexCoord2D 0, 0
            TBGL_Vertex 0, lHeight
            TBGL_TexCoord2D 1, 0
            TBGL_Vertex lWidth, lHeight
            TBGL_TexCoord2D 1, 1
            TBGL_Vertex lWidth, 0
            TBGL_TexCoord2D 0, 1        
            TBGL_Vertex 0, 0
          TBGL_EndPoly 
        TBGL_DrawFrame
        
      Wend
     
    End Function
    

    place content of the attachement into the extracted folder from post above.


    Edit: oh yes, my manners, welcome to the forum Brian

    Edit2: there was a type at line 50: replace comma by underscore
    Attached Files Attached Files
    Last edited by ReneMiner; 27-08-2015 at 19:46.
    I think there are missing some Forum-sections as beta-testing and support

  4. #4
    Rene- thanks so much for your replies! I'll have to study those closely. I really appreciate the suggestions.

    I did try to convert all of my .jpg files to .bmp files and came up with some code to load and display those. However, when using the 'convert' program (From ImagMagick), I created .bmp files that could not be read by ThinBasic. They displayed fine with every other program I tried, but there was some subtle difference in the .bmp files created by 'convert' that prevented them from working with ThinBasic. (a version difference in the bitmap header I think)

    As a general thought - it seems somewhat unfortunate that using the full TBGL library to load and display .jpg files is the only way to do it smoothly in ThinBasic. Because of all of the amazing power it has, TBGL is necessarily fairly complex. Your example programs that you kindly posted are much longer than the ones I came up with when I was testing out the other methods. I'm not saying anything bad about TBGL - only that it's really too bad that ThinBasic doesn't have another way to load and display non-.bmp files. Oh well - so it goes. :-)

    I'll try to digest your suggestions and see what I can come up with. Many thanks again -

    *Brian

  5. #5
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Hi Brian,

    there is a thinBasic module called GDIp that wrap some GDI+ functions.
    It's a module I started but never finished and fully documented.

    You can have a look at 2 examples into \thinBasic\SampleScripts\GDIp\

    If some GDI+ functions you need is missing I can add quite quickly and released but from sample script you can have a look at what's already in there.

    The following is the list of the functions already in the module that, more or less, wrap equivalent GDI+ functions:

    • GDIp_LoadImageFromFile
    • GDIp_CreateBitMapFromFile
    • GDIp_CreateHBitMapFromBitmap
    • GDIp_DisposeImage
    • GDIp_DeleteGraphics
    • GDIp_GetImageSizeFromFile
    • GDIP_GetImageWidth
    • GDIP_GetImageHeight
    • GDIp_ConvertImage
    • GDIp_SaveImageToFile
    • GDIp_GetImageThumbnail
    • GDIp_CreateFromHDC
    • GDIp_DrawImage
    • GDIp_GetImagePixelFormat


    More documentation can be found here: http://www.jose.it-berater.org/gdiplus/iframe/index.htm

    Ciao
    Eros
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  6. #6
    Eros,

    I'm a huge fan of ThinBasic - I really enjoy programming in it. I have tried using GDIp functions (using the examples that come with ThinBasic), but I couldn't find any way to load a graphics file and then display it in a double-buffered way (like you can with a canvas). Is there a way to load an image using a GDIp function into RAM, and then draw it to a canvas for display? (So that we get the benefit of the smooth drawing in double buffered mode) I couldn't find a way to do this.

    Or maybe you have a way that we could use GDIp_DrawImage() in a double buffered mode?

    *Brian

  7. #7
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Here a code on how to use GDIp and CANVAS mix using Canvas hDC
    Check DrawGraphics function in script

    Place this script into \thinBasic\SampleScripts\GDIp\
    It assumes it has a sub directory \images\ from which to load *.JPG images.

    Click on Redraw button to rotate on images.
    You need to adjust it on your needs.

    Let me know.

    Ciao
    Eros

    Uses "UI"
    Uses "gdip"
    Uses "File"
    
    
    Randomize
    
    
    ' -- ID numbers of controls
    Begin ControlID
      %cCanvasDB 
      %bModifyBitmap
      %bClose 
    End ControlID
    
    
    ' -- Create dialog here
    Function TBMain()
      Local hDlg As DWord
    
    
      Dialog New 0, "Managing canvas bitmap",-1,-1, 350, 300, _
                                        %WS_POPUP Or %WS_VISIBLE Or _
                                         %WS_CLIPCHILDREN Or %WS_CAPTION Or _
                                         %WS_SYSMENU Or %WS_MINIMIZEBOX, 0 To hDlg
      
      ' -- Place controls here
      Dim cx, cy As Long
      Dialog Pixels hDlg, 400, 400 To Units cx, cy
      Control Add Canvas, hDlg, %cCanvasDB, "", 0, 0, cx, cy
      
      Control Add Button, hDlg, %bModifyBitmap, "Redraw", 10+cx, 5      , 50, 14, Call bModifyBitmapProc    
      Control Add Button, hDlg, %bClose       , "Close" , 10+cx, cy+5-14, 50, 14, Call bCloseProc
     
      Dialog Show Modal hDlg, Call dlgProc
    
    
    End Function
    
    
    ' -- Callback for dialog
    CallBack Function dlgProc()
    
    
      ' -- Test for messages
      Select Case CBMSG
        Case %WM_INITDIALOG
          Canvas_Attach(CBHNDL, %cCanvasDB, %FALSE)
            DrawGraphics(CBHNDL)     
          Canvas_Redraw
         
        Case %WM_CLOSE
        ' -- Put code to be executed before dialog end here
    
    
      End Select
    
    
    End Function
     
    ' -- Callback for close button
    CallBack Function bCloseProc()
    
    
      If CBMSG = %WM_COMMAND Then       
        If CBCTLMSG = %BN_CLICKED Then
          ' -- Closes the dialog 
          Dialog End CBHNDL
        End If
      End If
    
    
    End Function
    
    
    CallBack Function bModifyBitmapProc()
    
    
      If CBMSG = %WM_COMMAND Then       
        If CBCTLMSG = %BN_CLICKED Then
    
    
          Canvas_Attach(CBHNDL, %cCanvasDB, %TRUE)
          Canvas_Clear(Rgb(0,0,0), %CANVAS_FILLSTYLE_SOLID)
          DrawGraphics(CBHNDL)      
          
        End If
      End If
    
    
    End Function
    
    
          
    Sub DrawGraphics(ByVal hDlg As DWord)
      Static lNextImage As Long
     
      Dim pGraphics As DWord
      Dim hDC       As DWord
      Dim pImage    As DWord
      Dim nFiles    As Long
      Dim sFiles()  As String
    
    
      nFiles = DIR_ListArray(sFiles, APP_ScriptPath & "images\", "*.JPG", %FILE_NORMAL Or %FILE_ADDPATH)
    
    
      If nFiles Then  
        hDC = Canvas_GetDC
        pGraphics = GDIp_CreateFromHDC(hdc)
      
        lNextImage += 1
        If lNextImage > nFiles Then
          lNextImage = 1
        End If
    
    
        Dialog Set Text hDlg, Format$(lNextImage) & " " & sFiles(lNextImage)
    
    
        pImage = GDIp_LoadImageFromFile(sFiles(lNextImage))
      
        GDIp_DrawImage(pGraphics, pImage, 1, 1)
      
        '---Release GDI image
        GDIp_DisposeImage(pImage)
        GDIp_DeleteGraphics(pGraphics)
        
        Canvas_Redraw  
      End If
      
    End Sub
    
    Last edited by ErosOlmi; 27-08-2015 at 21:49.
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  8. #8
    Eros,

    That looks fantastic! Would it even be possible to create an array of pImage variables, and load all of the .jpg files when the app first starts using GDIp_LoadImageFromFile() using the pImage array to hold the references to all of those images? Then, in the DrawGraphics() call, I can just call GDIp_DrawImage() using any one of the pImage values. This should allow all images to stay in RAM the whole time the program is running, and then the application will never have to hit the disk when it's swapping images, right? Then, when the app closes, I can call GDIp_DisposeImage() on all of the images in RAM.

    If you think that might work, I'll re-work my code based on your example. This is exciting!

    For this application, it's critical that I be able to switch between images immediately, without waiting for things to load from disk. (Loading at app startup is fine.) This is for a medical imaging application trade show demo.

    Thank you so much for helping me out-

    *Brian

  9. #9
    thinBasic author ErosOlmi's Avatar
    Join Date
    Sep 2004
    Location
    Milan - Italy
    Age
    57
    Posts
    8,777
    Rep Power
    10
    Well, I'm not an expert in this area so I'm not able to reply yes or not with enough confidence.

    The best way is to try some experimental little script able to confirm your idea.
    Changing my example loading all the files in the directory in one go into an image ptr array (it's not a big job).
    Than when clicking just draw the image into the DC taking image from the image ptr array
    This can confirm or not your idea.

    Let us know, I'm curious.
    Ciao
    Eros
    www.thinbasic.com | www.thinbasic.com/community/ | help.thinbasic.com
    Windows 10 Pro for Workstations 64bit - 32 GB - Intel(R) Xeon(R) W-10855M CPU @ 2.80GHz - NVIDIA Quadro RTX 3000

  10. #10
    Sweet, I'll give it a go and let you know how it works out.

    Thanks again!

    *Brian

Page 1 of 3 123 LastLast

Similar Threads

  1. Method to get Sprite-Pixel?
    By ReneMiner in forum TBGL module by Petr Schreiber
    Replies: 2
    Last Post: 19-11-2012, 17:10
  2. display 2 textures
    By Lionheart008 in forum TBGL module by Petr Schreiber
    Replies: 2
    Last Post: 29-07-2009, 19:31
  3. Improved donations method
    By ErosOlmi in forum Web and Forum
    Replies: 3
    Last Post: 03-12-2008, 18:40
  4. Flexible display
    By ErosOlmi in forum Technology
    Replies: 1
    Last Post: 02-11-2008, 21:53
  5. smooth and solid
    By kryton9 in forum TBGL General
    Replies: 2
    Last Post: 25-04-2007, 20:40

Members who have read this thread: 1

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •