Results 1 to 24 of 24

Thread: How to use vbRichClient5 to convert VB.Picture to a byte array?

  1. #1

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    How to use vbRichClient5 to convert VB.Picture to a byte array?

    This question is a continuation of the following thread:
    http://www.vbforums.com/showthread.p...ob-Sqlite3-vb6

    I wrote an example of a Sqlite access images for @Ami_Tech. I wonder if there is a better way.

    I know that AdoStream and PropertyBag can convert VB.Picture to a byte array, and I also know the following code can do similar things. But these are all too complicated. I'd like to know how to convert VB.Picture to a byte array using vbRichClient5. Thanks.

    Code:
    Private Type BITMAP
        bmType As Long
        bmWidth As Long
        bmHeight As Long
        bmWidthBytes As Long
        bmPlanes As Integer
        bmBitsPixel As Integer
        bmBits As Long
    End Type
    
    Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
    Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
    
    Private Sub GetPictureBytes()
      Dim PicBits() As Byte, PicInfo As BITMAP
    
      GetObject Picture1.Picture, Len(PicInfo), PicInfo
    
      ReDim PicBits((PicInfo.bmWidth * PicInfo.bmHeight * 3) - 1) As Byte
    
      GetBitmapBits Picture1.Picture, UBound(PicBits), PicBits(0)
      
    End Sub
    
    Public Function ArrayToPicture(inArray() As Byte, Offset As Long, Size As Long) As IPicture
    
        ' function creates a stdPicture from the passed array
        ' Offset is first item in array: 0 for 0 bound arrays
        ' Size is how many bytes comprise the image
        Dim o_hMem  As Long
        Dim o_lpMem  As Long
        Dim aGUID(0 To 3) As Long
        Dim IIStream As IUnknown
    
        aGUID(0) = &H7BF80980    ' GUID for stdPicture
        aGUID(1) = &H101ABF32
        aGUID(2) = &HAA00BB8B
        aGUID(3) = &HAB0C3000
    
        o_hMem = GlobalAlloc(&H2&, Size)
        If Not o_hMem = 0& Then
            o_lpMem = GlobalLock(o_hMem)
            If Not o_lpMem = 0& Then
                CopyMemory ByVal o_lpMem, inArray(Offset), Size
                Call GlobalUnlock(o_hMem)
                If CreateStreamOnHGlobal(o_hMem, 1&, IIStream) = 0& Then
                      Call OleLoadPicture(ByVal ObjPtr(IIStream), 0&, 0&, aGUID(0), ArrayToPicture)
                End If
            End If
        End If
    End Function
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by dreammanor; Jan 3rd, 2018 at 04:16 PM.

  2. #2
    Frenzied Member
    Join Date
    Apr 2012
    Posts
    1,253

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    This should work - though I don't have time to test it right now...

    Code:
    Function PictureToBytes(pPic As StdPicture) As Byte
    Dim DIB As cDIB
    
        Set DIB = New_c.DIB
        Set DIB.Picture = pPic
        DIB.CopyToByteArray PictureToBytes
    
    End Function
    If you don't know where you're going, any road will take you there...

    My VB6 love-children: Vee-Hive and Vee-Launcher

  3. #3

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Hi ColinE66, thank you very much. I'll modify the example according to your prompts.

  4. #4

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Hi ColinE66, I've modified the example, but the data isn't stored successfully. Please take a look at the example below, thanks.
    Attached Files Attached Files
    Last edited by dreammanor; Jan 3rd, 2018 at 04:54 PM.

  5. #5
    PowerPoster ChrisE's Avatar
    Join Date
    Jun 2017
    Location
    Frankfurt
    Posts
    3,046

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Hi,
    I don't know SQLite, but here a way to store a Picture to a Memo Field is Access

    Code:
    'Table structure:
    '     BI_ID       AutoWert
    '     BI_Nummer   Long
    '     BI_Bild     Memo field
    
    
    
    Option Explicit
    
    
    
    Private Cn As New ADODB.Connection
    
    
    
    Private Sub Command1_Click()
     Dim sSQL As String
       Dim Bild As String
       Dim FNr As Integer
       Dim i As Long
       Dim Rs As New ADODB.Recordset
       
          FNr = FreeFile
          Open App.Path & "\Bild1.bmp" For Binary As #FNr
          i = LOF(FNr)
          Bild = Space(i)
          Get #FNr, , Bild
          Close #FNr
          
          sSQL = "Select * From tbl_Bilder Where BI_Nummer < 0"
          With Rs
             .CursorLocation = adUseClient
             .CursorType = adOpenKeyset
             .LockType = adLockOptimistic
             .ActiveConnection = Cn
             .Open sSQL
    
             .AddNew
             .Fields("BI_Nummer").Value = 9999 'just add a No. for Picture
             .Fields("BI_Bild").Value = Bild
             .Update
             .Close
          End With
          Set Rs = Nothing
          
          MsgBox "Bild eingefügt"
    End Sub
    
    Private Sub Command2_Click()
    
       Dim Rs As New ADODB.Recordset
       Dim sSQL As String
       Dim FNr As Integer
       Dim mFile As String
       
          sSQL = "Select * From tbl_Bilder Where BI_Nummer = 9999"
          With Rs
             .CursorLocation = adUseClient
             .CursorType = adOpenKeyset
             .LockType = adLockReadOnly
             .ActiveConnection = Cn
             .Open sSQL
             
             If .RecordCount > 0 Then
                FNr = FreeFile
                
               mFile = App.Path & "\dummy.bmp"
                Open mFile For Output As #FNr
                Print #FNr, .Fields("BI_Bild").Value;
                Close #FNr
                Set Picture1.Picture = LoadPicture(mFile)
                Kill mFile
             End If
            .Close
          End With
          Set Rs = Nothing
          
    End Sub
    
    Private Sub Form_Load()
    
          With Cn
             .CursorLocation = adUseClient
             .Mode = adModeShareDenyNone
             .Provider = "Microsoft.Jet.OLEDB.4.0"
             .ConnectionString = "Data Source=" & App.Path & "\Bilder.mdb"
             .Open
          End With
          
          Command1.Caption = "Save Picture"
          Command2.Caption = "Load Picture"
    End Sub
    regards
    Chris
    to hunt a species to extinction is not logical !
    since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.

  6. #6

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Thank you, ChrisE. I know that adoDB (adoStream) can convert an image to a byte array and save it to the Sqlite Mem (Blob) field. RC5 is the most convenient and powerful tool for working with Sqlite DB, so I guess there should be a very easy way to implement SQlite image storage.

    In addition, things can be complicated by caching image data with temporary physical files.

  7. #7
    PowerPoster ChrisE's Avatar
    Join Date
    Jun 2017
    Location
    Frankfurt
    Posts
    3,046

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dreammanor View Post
    Thank you, ChrisE. I know that adoDB (adoStream) can convert an image to a byte array and save it to the Sqlite Mem (Blob) field. RC5 is the most convenient and powerful tool for working with Sqlite DB, so I guess there should be a very easy way to implement SQlite image storage.

    In addition, things can be complicated by caching image data with temporary physical files.
    where did I use adoStream ?

    regards
    Chris
    to hunt a species to extinction is not logical !
    since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.

  8. #8
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dreammanor View Post
    I'd like to know how to convert VB.Picture to a byte array using vbRichClient5.
    There should never be a need to do so in this case (since a VB-StdPicture is inferior to a cCairoSurface, which becomes available with the RC5).

    A VB.PictureBox should (if used at all) only be considered as a "Rendering-Endpoint" (fed from a cCairoSurface) - and not the other way around.

    In addition - when storing Images in a DB, always store them as Blobs in their "native Image-Format" (their RawByte-format, as they are stored in the FileSystem).
    As soon, as you are trying to serialize them into e.g. VB6-PropertyBag-Format, you will (without need) establish as platform-dependency.
    Just store the RawBytes of the Image in question - and be done with it.

    Ok, have taken a look at your code ... here a few additional comments:
    - don't use any of the old VB-File- or Directory-Functions (e.g. you used Dir() to check for the existence of a File)
    .. please use the (fully unicode-aware) File-Functions behind New_c.FSO instead (e.g. New_c.FSO.FileExists(...))
    - don't instantiate RC5-Objects with VBs own 'New' Keyword - please use New_c.Connnection instead
    .. (this will make it much easier, to turn an RC5-using App into a "regfree-deployable" one

    Here is, how I've rewritten your little Demo-App:
    RC5_SQLite_Images.zip

    ScreenShot of the App in SaveToDB-mode (using the Unicode-aware RC5-FileOpen-Dialogue... please note the chinese Image-FileName of the current Selection):


    ScreenShot of the App in LoadImageFromDB-mode (using the Unicode-aware Grid-Widget from vbWidgets.dll):



    HTH

    Olaf

  9. #9

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by ChrisE View Post
    where did I use adoStream ?

    regards
    Chris
    AdoStream is a class ADODB, the following is a small example of adoStream:

    Code:
    Dim arrBuffer() as Byte
    Dim adoStream as New ADODB.Stream
    
    adoStream.Type = adTypeBinary
    adoStream.Open
    adoStream.Write arrBuffer   
    adoStream.SaveToFile sFile, adSaveCreateOverWrite
    adoStream.Close
    
    '-----------------------------------------------------
    adoStream.Type = adTypeBinary
    adoStream.Open
    adoStream.LoadFromFile sDBFile
    arrBuffer= adoStream.Read
    adoStream.Close

  10. #10
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by ChrisE View Post
    where did I use adoStream ?
    You didn't - but the adoStream is one of the methods, to read ByteArray-content from Files which have Unicode-Chars in their FilePath.
    (the OP is on a chinese locale).

    VBs old File- Open/Read/Write commands are not Unicode-aware (and should not be used for "internationally deployed Apps").

    Olaf

  11. #11
    PowerPoster ChrisE's Avatar
    Join Date
    Jun 2017
    Location
    Frankfurt
    Posts
    3,046

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    ah right,

    (the OP is on a chinese locale).
    missed that

    regards
    Chris
    to hunt a species to extinction is not logical !
    since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.

  12. #12

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by Schmidt View Post
    There should never be a need to do so in this case (since a VB-StdPicture is inferior to a cCairoSurface, which becomes available with the RC5).

    A VB.PictureBox should (if used at all) only be considered as a "Rendering-Endpoint" (fed from a cCairoSurface) - and not the other way around.

    In addition - when storing Images in a DB, always store them as Blobs in their "native Image-Format" (their RawByte-format, as they are stored in the FileSystem).
    As soon, as you are trying to serialize them into e.g. VB6-PropertyBag-Format, you will (without need) establish as platform-dependency.
    Just store the RawBytes of the Image in question - and be done with it.
    Olaf, thank you for your detailed reply and wonderful example. I fully agree with what you have said, only files and RawByte-format binary data are used to store images to the database, not using VB.PictureBox. I know that cCairoSurface is much more powerful than VB.PictureBox, but VB.PictureBox is the basic control of VB6 and many people are accustomed to using VB.PictureBox to do something. If RC5 is able to convert a VB.StdPicture to a byte array, that would certainly greatly facilitate their work.

    I've been using RC5 to deal with SqliteDB for a long time, but I never knew how RC5 converted a VB.StdPicture to a byte array, so I've been using the FarPoint.SpreadSheet functions to do the same job:

    Code:
    Function LoadFromBuffer(Buff) As Boolean
    Function LoadFromFile(FileName As String) As Boolean
    Function LoadPicture(FileName As String, PictType As PictureTypeConstants) As StdPicture
    Function LoadPictureBuffer(Buffer, Size, PictType As PictureTypeConstants) As StdPicture
    Function LoadResPicture(hInstance As Long, ResourceName As String, ResourceType As String, PictType As PictureTypeConstants) As StdPicture
    Function LoadTabFile(FileName As String) As Boolean
    Function LoadTextFile(FileName As String, CellDelim As String, ColDelim As String, RowDelim As String, Flags As LoadTextFileConstants, LogFile As String) As Boolean
    
    Function SavePicture(Picture As StdPicture, FileName As String, PictType As PictureTypeConstants) As Boolean
    Function SavePictureBuffer(Picture As StdPicture, PictType As PictureTypeConstants, Buffer, Size) As Boolean
    Function SaveTabFile(FileName As String) As Boolean
    Function SaveTabFileU(FileName As String) As Boolean
    Function SaveToBuffer()
    Function SaveToFile(FileName As String, DataOnly As Boolean) As Boolean
    In the future, I'll try to gradually replace VB.PictureBox and GDI drawings with cCairoSurface, but this process will take some time to complete because many old systems need to be maintained.


    Quote Originally Posted by Schmidt View Post
    Ok, have taken a look at your code ... here a few additional comments:
    - don't use any of the old VB-File- or Directory-Functions (e.g. you used Dir() to check for the existence of a File)
    .. please use the (fully unicode-aware) File-Functions behind New_c.FSO instead (e.g. New_c.FSO.FileExists(...))
    - don't instantiate RC5-Objects with VBs own 'New' Keyword - please use New_c.Connnection instead
    .. (this will make it much easier, to turn an RC5-using App into a "regfree-deployable" one
    Very good advice, much appreciated.
    Last edited by dreammanor; Jan 4th, 2018 at 06:59 AM.

  13. #13
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dreammanor View Post
    If RC5 is able to convert a VB.StdPicture to a byte array, that would certainly greatly facilitate their work.
    As Olaf said byte array in your case will be platform/app dependant image file format. No need for this constraint unless this new format is better than most existing image formats.

    So basicly you want a VB.StdPicture to BMP, JPG or PNG "byte arrays" and this has been flogged to death in these forums. This and preserving/handling alpha channel in StdPicture icon hack whatever is one the most discussed topics here.

    Please don't use PropertyBags to "serialize" StdPictures -- the size overhead is 100%. Please don't use ADODB.Streams for anything (unless forced) -- speed is abysmal.

    cheers,
    </wqw>

  14. #14

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by wqweto View Post
    As Olaf said byte array in your case will be platform/app dependant image file format. No need for this constraint unless this new format is better than most existing image formats.

    So basicly you want a VB.StdPicture to BMP, JPG or PNG "byte arrays" and this has been flogged to death in these forums. This and preserving/handling alpha channel in StdPicture icon hack whatever is one the most discussed topics here.

    Please don't use PropertyBags to "serialize" StdPictures -- the size overhead is 100%. Please don't use ADODB.Streams for anything (unless forced) -- speed is abysmal.

    cheers,
    </wqw>
    Yes, I agree with you. In my own projects, the FarPoint.SpreadSheet byte array and image manipulation functions are used to instead of adoStream and PropertyBag. But in the example I wrote for @Ami_Tech, I couldn't find a good method to convert a StdPicture to a byte array. Perhaps @Ami_Tech should also accept you and Olaf's advice, using only files and RawByte-format binary data to store images into the database.

    Why I've been using FarPoint SpreadSheet, because I still can't found a replacement for it. RC5 can replace almost all Microsoft components and third-party components, but in the short term, it can't replace FarPoint.SpreadSheet. Developing a new SpreadSheet using RC5 and vbWidget may be a good choice, but the workload is too high。

    Of course, my focus in the future will gradually shift to Web applications and Cloud-Database, SpreadSheet applications will gradually be reduced.

  15. #15

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by ColinE66 View Post
    This should work - though I don't have time to test it right now...

    Code:
    Function PictureToBytes(pPic As StdPicture) As Byte
    Dim DIB As cDIB
    
        Set DIB = New_c.DIB
        Set DIB.Picture = pPic
        DIB.CopyToByteArray PictureToBytes
    
    End Function
    If the above source code could work, that would greatly facilitate many people's work.

  16. #16
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dreammanor View Post
    If the above source code could work, that would greatly facilitate many people's work.
    Colins Code (here with a slight correction, adjusting the return-type to a Byte-Array) does work:
    Code:
    Function StdPicToBytes(StdPic As StdPicture) As Byte()
      Dim DIB As cDIB
      Set DIB = New_c.DIB(, , StdPic)
          DIB.CopyToByteArray StdPicToBytes
    End Function
    ... but cDIB.CopyToByteArray was not intended for "serialization into a one-dimensional ByteArray-Stream" -
    instead, the Method fills a "self-describing two-dimensional ByteArray-DIB-replacement for 24Bit-ImageContent" - and as such:
    - it can be stored in a Collection or elsewhere
    - can describe its own (DIB) Pixel-dimensions over (UBound(B ,1) + 1) \ 3 and UBound(B, 2) +1
    - would be less resource-intensive than a DIB (not needing any GDI-Handle)
    - and can also be used directly in Image-Manipulation-Loops, as the following simple example shows:

    Code:
    Option Explicit
     
    Private Sub Form_Load()
      Set Picture = LoadPicture("c:\temp\background.jpg") 'load an Image into the Forms Picture-Prop
      Show
      MsgBox "a Darken-Operation follows..."
      Set Picture = Darken(StdPicToBytes(Picture), 0.5).Picture
    End Sub
    
    Function StdPicToBytes(StdPic As StdPicture) As Byte()
      New_c.DIB(, , StdPic).CopyToByteArray StdPicToBytes
    End Function
    
    Function Darken(B() As Byte, ByVal Factor As Double) As cDIB
      Dim dx As Long, dy As Long, x As Long, y As Long
          dx = (UBound(B, 1) + 1) \ 3: dy = (UBound(B, 2) + 1) 'get the Pixel-Dimensions from B()
          
      For y = 0 To dy - 1: For x = 0 To dx * 3 - 1 Step 3 '<- note the needed Step 3
          B(x + 0, y) = B(x + 0, y) * Factor 'influence the Blue-Channel
          B(x + 1, y) = B(x + 1, y) * Factor 'influence the Green-Channel
          B(x + 2, y) = B(x + 2, y) * Factor 'influence the Red-Channel
      Next x, y
      
      Set Darken = New_c.DIB(dx, dy) 'create a new DIB-Container-Object with the same Dimensions
          Darken.CopyFromByteArray B '... and copy the darkened Array-Content over
    End Function
    As to your "serialization-question" (into a one-dimensional ByteArray) - let's make a deal:
    - I show you how to convert a VB-StdPic-Object to a Cairo-Surface (from which you can serialize to PNG- or JPG-ByteArrays easily)
    - and you explain to me in more detail - with a small code-example, why you would need this (because I cannot really see, where that would come in handy)

    Code:
    Option Explicit
     
    Private Sub Form_Load()
      Set Picture = LoadPicture("c:\temp\background.jpg")
      
      'convert the StdPicture to a CairoSurface - and place it back in the Picture-Prop
      Set Picture = StdPicToSurface(Picture).Picture
    End Sub
    
    Function StdPicToSurface(StdPic As StdPicture) As cCairoSurface
      Dim DIB As cDIB: Set DIB = New_c.DIB(, , StdPic) 'create an RC5-DIBObj from the StdPic
      Set StdPicToSurface = Cairo.CreateWin32Surface(DIB.dx, DIB.dy) 'ensure the Dest-Surface
      DIB.DrawTo StdPicToSurface.GetDC 'hDC-based Blitting from DIB to CairoSurface
      
      'normally we would be finished here - but the above Blt-Op left out the Alpha-Channel,
      Dim CC As cCairoContext: Set CC = StdPicToSurface.CreateContext
          CC.Operator = CAIRO_OPERATOR_DEST_ATOP '...so we have to ensure one with a Paint-Op,
          CC.Paint 1, Cairo.CreateSolidPatternLng(0, 1) '<- which sets the Alpha-Channel to "fully opaque"
    End Function
    Olaf
    Last edited by Schmidt; Jan 6th, 2018 at 06:46 AM. Reason: adjusted the Darken-Loop to respect Padding

  17. #17

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by Schmidt View Post

    ...

    ... but cDIB.CopyToByteArray was not intended for "serialization into a one-dimensional ByteArray-Stream" -
    instead, the Method fills a "self-describing two-dimensional ByteArray-DIB-replacement for 24Bit-ImageContent" - and as such:
    - it can be stored in a Collection or elsewhere
    - can describe its own (DIB) Pixel-dimensions over (UBound(B ,1) + 1) \ 3 and UBound(B, 2) +1
    - would be less resource-intensive than a DIB (not needing any GDI-Handle)
    - and can also be used directly in Image-Manipulation-Loops, as the following simple example shows:

    ...

    Olaf
    Very nice, RC5 is powerful indeed. I modified the StdPicToBytes method to serialize StdPicture:

    Code:
    Function StdPicToBytes_New(StdPic As StdPicture) As Byte()
        Dim Surface As cCairoSurface
            
        Set Surface = StdPicToSurface(StdPic)
        
        'Surface.WriteContentToJpgByteArray StdPicToBytes_New
        Surface.WriteContentToPngByteArray StdPicToBytes_New
            
    End Function
    
    Function StdPicToSurface(StdPic As StdPicture) As cCairoSurface
        Dim DIB As cDIB
        
        Set DIB = New_c.DIB(, , StdPic) 'create an RC5-DIBObj from the StdPic
        
        Set StdPicToSurface = Cairo.CreateWin32Surface(DIB.dx, DIB.dy) 'ensure the Dest-Surface
        DIB.DrawTo StdPicToSurface.GetDC 'hDC-based Blitting from DIB to CairoSurface
        
        'normally we would be finished here - but the above Blt-Op left out the Alpha-Channel,
        Dim CC As cCairoContext
        
        Set CC = StdPicToSurface.CreateContext
        
        CC.Operator = CAIRO_OPERATOR_DEST_ATOP '...so we have to ensure one with a Paint-Op,
        CC.Paint 1, Cairo.CreateSolidPatternLng(0, 1) '<- which sets the Alpha-Channel to "fully opaque"
          
    End Function
    Last edited by dreammanor; Jan 8th, 2018 at 04:01 AM.

  18. #18

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by Schmidt View Post
    As to your "serialization-question" (into a one-dimensional ByteArray) - let's make a deal:
    - I show you how to convert a VB-StdPic-Object to a Cairo-Surface (from which you can serialize to PNG- or JPG-ByteArrays easily)
    - and you explain to me in more detail - with a small code-example, why you would need this (because I cannot really see, where that would come in handy)

    ...

    Olaf

    IMO, it's very userful to serialize VB.StdPicture. VB.StdPicture is heavily used in VB programming, and these StdPictures often need to be stored in a database or file. Cairo is a completely new feature for many VB developers, and they are afraid to rush to use it. If using Cairo to precess VB.StdPicture (serialization, darkening, brightening, adding alpha-channel, drawing, etc.), many VB developers will gradually accept Cairo and more and more people will love and use RC5.

    My software uses VB.PictureBox extensively. For example, I ofen need to copy pictures from Microsoft Word-Doc or web pages to the clipboard, then paste them into a VB.PictureBox and finally save the PictureBox.Picture into the database.

    Code:
    Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
    
        If Shift = 2 And KeyCode = vbKeyV Then
            PastePictureFromClipboard
        End If
        
    End Sub
    
    Private Sub PastePictureFromClipboard()
        Dim objPicture As StdPicture
        
        Set objPicture = Clipboard.GetData()
        If objPicture.Handle <> 0 Then
            Picture1.Picture = objPicture
        End If
            
    End Sub
    In addition, if WriteContentToBmpByteArray method could be added to the vbRichClient5.cCairoSurface, that would be great. RC5 is really a great and magical product, thank you, Olaf.

  19. #19
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by wqweto View Post
    So basicly you want a VB.StdPicture to BMP, JPG or PNG "byte arrays" and this has been flogged to death in these forums.
    I agree.

    All we need is a handful of API calls for extended capabilities. Here is an example that creates a series of images and stores them in a database as PNG images. Then it plays them back:

    Name:  sshot.png
Views: 886
Size:  2.2 KB

    Not much to it, no 3rd party dependencies required if you use a Jet MDB like this. These databases even have support on Android, Linux, etc. via Jackcess.

    Recorder.ctl:
    Code:
    Option Explicit
    
    Private StickmanX As Long
    Private DeltaX As Long
    Private Counter As Long
    Private Connection As ADODB.Connection
    Private Recordset As ADODB.Recordset
    
    Public Event Finished()
    
    Public Sub Run()
        Extender.Move 0, 0
        Extender.Visible = True
        BackColor = &HFFFFE0
    
        On Error Resume Next
        Kill "DB.mdb"
        On Error GoTo 0
        With CreateObject("ADOX.Catalog")
            .Create "Provider=Microsoft.Jet.OLEDB.4.0;" _
                  & "Jet OLEDB:Engine Type=5;" _
                  & "Data Source='DB.mdb';" _
                  & "Mode=Share Exclusive"
            Set Connection = .ActiveConnection
        End With
        Connection.Execute "CREATE TABLE Movie(" _
                         & "ID IDENTITY CONSTRAINT pkID PRIMARY KEY," _
                         & "Frame IMAGE)", _
                           , _
                           adCmdText Or adExecuteNoRecords
        Set Recordset = New ADODB.Recordset
        With Recordset
            .CursorLocation = adUseServer
            Set .ActiveConnection = Connection
            .Properties("Append-Only Rowset").Value = True
            .Open "Movie", , adOpenForwardOnly, adLockOptimistic, adCmdTableDirect
        End With
    
        DrawFrame
        SaveFrame
        Counter = 2
        DeltaX = 5
        Timer1.Enabled = True
    End Sub
    
    Private Sub DrawFrame()
        Cls
    
        DrawWidth = 1
        FillStyle = vbFSSolid
        Line (0, 160)-(319, 239), &H80FF80, BF
    
        ForeColor = &HC0FFFF
        FillColor = &HFFFF&
        DrawWidth = 3
        Circle (260, 40), 25
    
        DrawWidth = 3
        Line (StickmanX + 20, 120)-(StickmanX + 20, 170), vbBlue
        Line (StickmanX, 130)-(StickmanX + 40, 130), vbBlue
        Line (StickmanX + 20, 170)-(StickmanX, 190), vbBlue
        Line (StickmanX + 20, 170)-(StickmanX + 40, 190), vbBlue
        DrawWidth = 1
        ForeColor = &H404080
        FillColor = &HC0E0FF
        Circle (StickmanX + 19, 109), 12
    End Sub
    
    Private Sub SaveFrame()
        Recordset.AddNew "Frame", PicBytes.SavePicture(Image, fmtPNG)
    End Sub
    
    Private Sub Timer1_Timer()
        StickmanX = StickmanX + DeltaX
        DrawFrame
        SaveFrame
        If StickmanX = 280 Then
            DeltaX = -5
        ElseIf StickmanX = 0 Then
            Counter = Counter - 1
            If Counter > 0 Then
                DeltaX = 5
            Else
                Timer1.Enabled = False
                Extender.Visible = False
                Recordset.Close
                Connection.Close
                RaiseEvent Finished
            End If
        End If
    End Sub
    Attached Files Attached Files
    Last edited by dilettante; Jan 7th, 2018 at 11:01 AM.

  20. #20

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Hi dilettante, thank you for your reply. Your source code is very interesting. This is a good solution for AccessDB, but AccessDB has caused me too much painful memories and I rarely use AccessDB now. I don't know now whether Microsoft has solved the problem of data loss caused by AccessDB damaging. SqliteDB almost never goes wrong, just as MS SQLServer almost never makes a mistake, so I prefer to use SqliteDB.

    However, even so, I can still learn a lot from your code, thank you, dilettante.
    Last edited by dreammanor; Jan 8th, 2018 at 03:52 AM.

  21. #21
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dilettante View Post
    Here is an example that creates a series of images and stores them in a database as PNG images. Then it plays them back:
    One could (with about the same amount of code) of course implement a real Scene-Recorder/Player,
    which works BackGround-independent and in a better performance, looking like that:


    Here is the Source for the above: SceneRecording.zip

    So one has to decide for himself, whether to use a modern DB- and graphics-engine,
    or if "sticking to drawing stick-mans" is the way to go with VB6...

    Quote Originally Posted by dilettante View Post
    Not much to it, no 3rd party dependencies required if you use a Jet MDB like this.
    As already mentioned in the other thread - MS-COM-dependencies can break your App at any time
    with the next MS-System-Updates (this happened already in the past in case of ADO/JET).

    SQLite is a more powerful and faster alternative to ADO/JET - and available over
    the RC5-COM-wrapper for over a decade now.

    Quote Originally Posted by dilettante View Post
    These databases even have support on Android, Linux, etc. via Jackcess.
    Jackcess does support only a kind of "looping over existing table-content" and:
    - is dog-slow whilst doing that ...
    - but worse - it does not support the execution of any SQL

    So, no - bad recommendation that.

    A JDBC/SQLite implementation performs *much* better - and resembles ADO-Rs-usage far more (Java-code-wise).

    Out of interest I just did a little performance-test in my Java-IDE against the newest Jackcess-version
    (using a loop over the Orders-Table from NWind.mdb - then doing the same thing with JDBC-SQLite on a NWind.db-file)
    Here is the results:
    Code:
    > run TestDBaccess
     
    Jackcess-MDB Results:
    timing: 204.2 ms
    records: 830, last ID: 11077
    
    JDBC-SQLite Results:
    timing: 3.5 ms
    records: 830, last ID: 11077
    >
    For comparison, here the VB6-results over the appropriate COM-libs:
    Code:
    ADO/JET Results:
    timing: 4,3msec
    records: 830, last ID: 11077
    
    RC5/SQLite Results:
    timing: 2,1msec
    records: 830, last ID: 11077
    So. both SQLite-versions outperform the MDB-based ones - and in case of Jackcess by a huge margin (about factor 100).

    For those interested - here is the Java-testcode I was using:
    Code:
    // Jackcess-MDB specific imports
    import java.io.File;
    import com.healthmarketscience.jackcess.DatabaseBuilder;
    import com.healthmarketscience.jackcess.Database;
    import com.healthmarketscience.jackcess.Table;
    import com.healthmarketscience.jackcess.Row;
    import com.healthmarketscience.jackcess.CursorBuilder;
    import com.healthmarketscience.jackcess.Cursor;
    
    // JDBC-SQLite specific imports
    import java.sql.DriverManager;
    import java.sql.Connection;
    import java.sql.Statement;
    import java.sql.ResultSet;
    
    public class TestMDBaccess {
        public static void main(String[] args) {
            try {
                long startTime;
                
                // Jackcess-MDB related part (let's open the FileDB first)
                Database db = DatabaseBuilder.open(new File("NWind.mdb"));
     
                startTime = System.nanoTime(); // let's time the Table-Opening and the Enumeration  
              
                Table  table  = db.getTable("Orders"); 
                Cursor cursor = CursorBuilder.createCursor(table);
              
                short counter=0; Object ID=null; // just two variables, which we change inside the iteration-loop
                for(Row row : cursor) { // fastest way to iterate over the Table is a cursor-based enumeration
                    counter++;
                    ID = row.get("OrderID"); //just to access one single Col-Field whilst iterating over the Rows
                }
     
                System.out.println("Jackcess-MDB Results:");
                System.out.println("timing: " + ((System.nanoTime()-startTime) / 100000)/10. + " ms" );
                System.out.println("records: " + counter + ", last ID: " + ID );
              
              
                // JDBC-SQLite related part (let's open the FileDB first)
                Connection Cnn = DriverManager.getConnection("jdbc:sqlite:NWind.db");
                
                startTime = System.nanoTime(); // let's time the Table-Request and the Enumeration  
              
                Statement Cmd = Cnn.createStatement();
                ResultSet Rs  = Cmd.executeQuery("Select * From Orders");
                 
                int OrderID=0; counter=0;
                while (Rs.next()) {  // loop through the result-set
                    counter++;
                    OrderID = Rs.getInt("OrderID"); //just to access one single Col-Field whilst iterating over the Records
                }
                
                if (Cnn != null) Cnn.close(); // close the DB-Connection again
                
                System.out.println("JDBC-SQLite Results:");
                System.out.println("timing: " + ((System.nanoTime()-startTime) / 100000)/10. + " ms" );
                System.out.println("records: " + counter + ", last ID: " + OrderID );
                
            }
            
            catch (Exception e) {
               System.out.println(e.getMessage());
            }
     
        }
    }
    Olaf
    Last edited by Schmidt; Jan 9th, 2018 at 02:06 AM.

  22. #22
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,219

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by dreammanor View Post
    For example, I ofen need to copy pictures from Microsoft Word-Doc or web pages to the clipboard, then paste them into a VB.PictureBox and finally save the PictureBox.Picture into the database.
    Well, the RC5 has an (Unicode-aware!) ClipBoard-Class, which besides Text, RTF, HTML and Unicode-FileContainer support,
    can also hand-out already converted Image-Surfaces (even those with AlphaChannels, which e.g. FireFox supports on Image-Copy)

    Code:
    Option Explicit
    
    Private ChkPat As cCairoPattern
    
    Private Sub Form_Load()
      KeyPreview = True
      Set ChkPat = CreateCheckerPattern
    End Sub
    
    Private Sub Form_KeyUp(KeyCode As Integer, Shift As Integer)
      If Shift = 2 And KeyCode = vbKeyV Then PastePicture New_c.Clipboard.GetImageSurface, Picture1
    End Sub
    
    Private Sub PastePicture(Srf As cCairoSurface, PB As VB.PictureBox)
      If Srf Is Nothing Then Exit Sub 'if there was no Image in the ClipBoard, we get passed Nothing
      
      With Cairo.CreateSurface(ScaleX(PB.Width, PB.ScaleMode, 3), ScaleX(PB.Height, PB.ScaleMode, 3)).CreateContext
        .Paint 1, ChkPat 'draw the background-checker-pattern (in case we got PNGs)
        .RenderSurfaceContent Srf, 0, 0, .Surface.Width, .Surface.Height, , , True 'render the passed Srf so that it fits into the PBox
        Set PB.Picture = .Surface.Picture
      End With
      
      'now do additional Operations with the Pasted Srf-Variable (which still has its original dimensions)
    '  Srf.WriteContentToPngByteArray B  ' <- now you can store ByteArray B in a DB
    End Sub
    
    Function CreateCheckerPattern(Optional ByVal Size& = 8, Optional ByVal Color1& = vbWhite, Optional ByVal Color2& = &HDDDDDD) As cCairoPattern
      With Cairo.CreateSurface(2 * Size, 2 * Size).CreateContext
        .Paint 1, Cairo.CreateSolidPatternLng(Color1) 'fill the entire Mini-Surface with Color1
        .Rectangle 0, 0, Size, Size 'now, to paint over the BackColor we define a top-left rectangle
        .TranslateDrawings Size, Size 'diagonal shift of the coords, to ensure the offset for the...
        .Rectangle 0, 0, Size, Size 'final bottom-right-rectangle (which due to the above line can use the same coord-arguments)
        .Fill , Cairo.CreateSolidPatternLng(Color2) 'fill the two Rectangle-Paths with Color2
        
        Set CreateCheckerPattern = .Surface.CreateSurfacePattern 'ensure the return-value (creating a Pattern from the small Surface)
            CreateCheckerPattern.Extend = CAIRO_EXTEND_REPEAT 'with this Pattern-Property we can ensure a kind of "Brush" when larger areas are filled
      End With
    End Function
    Here is the result of a PNG-image (which was copied directly from FireFox) then pasted, size-adapted and rendered into a VB-PictureBox using the above code:


    As you see in the comments above - after the rendering-op went through, you have still the original Srf-Object available
    (not containing the Checker-Pattern-BackGround - and still in its original size) - and serialization into a ByteArray
    from a CairoSurface (then storing it in a DB) - that was already covered I think.

    So, still not a really convincing example from your side, why one would need the PictureBox-to-CairoSurface-direction.


    Quote Originally Posted by dreammanor View Post
    if WriteContentToBmpByteArray method could be added to the vbRichClient5.cCairoSurface, that would be great.
    Why would you need that (when PNG is supported - being a nice, and losless compression-format for Bitmaps).

    Olaf

  23. #23

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by Schmidt View Post
    Why would you need that (when PNG is supported - being a nice, and losless compression-format for Bitmaps).
    Olaf
    In order to be compatible with historical data, because all my historical data is saved as bmp files (jpg format will distort a picture). I guess many others will also save their images as compressed bmp files.

  24. #24

    Thread Starter
    PowerPoster
    Join Date
    Sep 2012
    Posts
    2,083

    Re: How to use vbRichClient5 to convert VB.Picture to a byte array?

    Quote Originally Posted by Schmidt View Post
    Well, the RC5 has an (Unicode-aware!) ClipBoard-Class, which besides Text, RTF, HTML and Unicode-FileContainer support,
    can also hand-out already converted Image-Surfaces (even those with AlphaChannels, which e.g. FireFox supports on Image-Copy)

    ...
    ...

    Here is the result of a PNG-image (which was copied directly from FireFox) then pasted, size-adapted and rendered into a VB-PictureBox using the above code:
    ...
    ...

    As you see in the comments above - after the rendering-op went through, you have still the original Srf-Object available
    (not containing the Checker-Pattern-BackGround - and still in its original size) - and serialization into a ByteArray
    from a CairoSurface (then storing it in a DB) - that was already covered I think.

    So, still not a really convincing example from your side, why one would need the PictureBox-to-CairoSurface-direction.

    Olaf
    Wonderful example. vbRichClient5.Cairo is amazing, it can be used to develop very complex and very advanced applications. I wonder if it's easy and simple enough to develop some simple applications.

    I made a simple test program, but I don't know how to use vbRichClient5.Cairo drawings to replace the drawing functions of VB.PictureBox.
    Attached Images Attached Images  
    Attached Files Attached Files
    Last edited by dreammanor; Jan 9th, 2018 at 01:21 PM.

Posting Permissions

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



Click Here to Expand Forum to Full Width