Results 1 to 21 of 21

Thread: [RESOLVED] WIA Automation

  1. #1

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Resolved [RESOLVED] WIA Automation

    The following code is used to load into a PictureBox using WIA:
    Code:
    Dim Img 'As ImageFile
    Set Img = CreateObject("WIA.ImageFile")
    Img.LoadFile "C:\Bliss.bmp"
    Picture1.Picture = Img.FileData.Picture
    Is there a reverse option to load an image from a PictureBox into a WIA.ImageFile?

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

    Re: WIA Automation

    I'm not sure why you'd use this library late-bound. Did you copy this from some old VBScript example?

    In any case:

    No, there is not a direct way to load a StdPicture's bitmap into a WIA ImageFile instance.

    You can use GetDIBits() on the StdPicture.Handle to retrieve a Long array. Assign that array to a WIA Vector's .BinaryData property. Then you can use the Vector's .ImageFile(WidthPx, HeightPx) method to create a new ImageFile instance.

    The documentation in wiaaut.chm is very helpful. Sadly, most people never downloaded the WIA 2.0 SDK before Microsoft stopped hosting it years ago.

  3. #3

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: WIA Automation

    Quote Originally Posted by dilettante View Post
    I'm not sure why you'd use this library late-bound. Did you copy this from some old VBScript example?
    Yes. I used the examples from Microsoft that I could find.
    Thanks for the answer.
    I liked WIA for its simplicity of loading and capturing images without requiring multi-line code.

  4. #4

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: WIA Automation

    Using GetDIBits (), I get an array of bytes. To check it, I copy it to another PictureBox using the SetDIBits () function. Everything works fine.
    I try to assign the resulting array to a vector, I get an error "the parameter is set incorrectly".
    Code:
    Public pixels() As Byte   'Or As Long
        ReDim pixels(1 To 4, 1 To Pict.ScaleWidth, 1 To Pict.ScaleHeight)
        result = GetDIBits(Pict.hdc, Pict.image, 0, Pict.ScaleHeight, pixels(1, 1, 1), _
                        bitmap_info, DIB_RGB_COLORS)
    Pict - PictureBox
    Code:
    Dim oVectNew              As Object 'As WIA.Vector
    Set oVectNew = CreateObject("WIA.Vector") 
    oVectNew.BinaryData = pixels
    What's my mistake?

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

    Re: WIA Automation

    If we are starting with a PictureBox we can take a lot of shortcuts. It has an hDC and when AutoRedraw = False its Image property is selected into it, so:

    Code:
    Option Explicit
    
    Private Const DIB_RGB_COLORS As Long = 0&
    Private Const BI_RGB As Long = 0&
    
    Private Type BITMAPINFOHEADER '40 bytes
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As Long
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
    End Type
    
    Private Type BITMAPINFO
        bmiHeader As BITMAPINFOHEADER
        'bmiColors(0 to 255) As RGBQUAD
    End Type
    
    Private Declare Function GetDIBits Lib "gdi32" ( _
        ByVal hDC As Long, _
        ByVal hBitmap As Long, _
        ByVal nStartScan As Long, _
        ByVal nNumScans As Long, _
        ByRef Bits As Byte, _
        ByRef BMI As BITMAPINFO, _
        ByVal wUsage As Long) As Long
    
    Private Sub Form_Load()
        Const Green As Long = &H8000&
        Const Brown As Long = &H4080&
        Dim WidthPx As Long
        Dim HeightPx As Long
        Dim BMI As BITMAPINFO
        Dim Triples() As Byte
        Dim ImageFile As WIA.ImageFile
        
        With Picture1
            'Draw something:
            .AutoRedraw = True
            .Cls
            .DrawWidth = 1
            Picture1.Line (.ScaleWidth / 4, .ScaleHeight / 4)- _
                          ((.ScaleWidth / 4#) * 3, (.ScaleHeight / 4) * 3), _
                          Green, _
                          BF
            .DrawWidth = 2
            Picture1.Circle ((.ScaleWidth / 8) * 3, (.ScaleHeight / 8) * 5), _
                            .ScaleWidth / 5, _
                            vbRed, _
                            -1, _
                            -5.5
            .CurrentX = .ScaleWidth / 5
            .CurrentY = (.ScaleHeight / 5) * 4
            .ForeColor = Brown
            Picture1.Print "Hello World!"
            .AutoRedraw = False
    
            'PictureBox's persistent bitmap to an ImageFile object:
            WidthPx = .ScaleX(.ScaleWidth, .ScaleMode, vbPixels)
            HeightPx = .ScaleY(.ScaleHeight, .ScaleMode, vbPixels)
            With BMI.bmiHeader
                .biSize = Len(BMI.bmiHeader)
                .biWidth = WidthPx
                .biHeight = HeightPx
                .biPlanes = 1
                .biCompression = BI_RGB
                .biBitCount = 24
            End With
            ReDim Triples((((3 * WidthPx + 3) \ 4) * 4) * HeightPx - 1)
            GetDIBits .hDC, .Image.Handle, 0, HeightPx, Triples(0), BMI, DIB_RGB_COLORS
        End With
        With New WIA.Vector
            .BinaryData = Triples
            Erase Triples
            Set ImageFile = .ImageFile(WidthPx, HeightPx)
        End With
    
        'Show in second PictureBox:
        Set Picture2.Picture = ImageFile.FileData.Picture
    End Sub
    Note that we have no reason to request a 32 bits/pixel DIB since we have no transparency. So skip using quads and just grab triples (24 bits).

  6. #6

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: WIA Automation

    Quote Originally Posted by dilettante View Post
    Note that we have no reason to request a 32 bits/pixel DIB since we have no transparency. So skip using quads and just grab triples (24 bits).
    Many thanks!

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

    Re: [RESOLVED] WIA Automation

    I found a bug, but one that we get lucky with in this case.

    This line:

    Code:
    .biSize = Len(BMI.bmiHeader)
    Should, by rights, be:

    Code:
    .biSize = LenB(BMI.bmiHeader)
    Sorry. A common mistake that eventually can bite us.

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

    Re: [RESOLVED] WIA Automation

    If you really, really wanted to work in quads instead of triples there are issues. Sometimes, such as when processing a PNG with alpha channel values, we need to do this.

    While we can write a triples Byte array using a simple assignment, we can't assign quads that way.

    To use quads we must have a Vector of Long, and there is no fast assignment for that. So we'd have to loop and call Vector.Add multiple times. BUT... in the system copy of wiaaut.dll the Add method has been slowed... way... down... for some reason. I think it had something to do with DRM protection, which is also why WIA 2.0 had video support removed.

    Another reason to despise the script kiddies who make all our lives harder.


    There is a workaround, but it gets a little tricky.

    You must have the redist version of wiaaut.dll that came in the SDK package. Then you must use an isolation manifest to redirect your program to use that copy instead of the system copy. Don't just try to plop it over the system copy, Windows will quickly heal itself of that because this is a protected system file.

    By using the redist version as an isolated private assembly Vector.Add runs at full speed once more.


    However for most purposes triples are plenty good enough.

  9. #9

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    Thanks. I replaced the line but did not visually see the change. Perhaps due to the fact that I have a small image (711X598).
    Quote Originally Posted by dilettante View Post
    If you really, really wanted to work in quads instead of triples there are issues. Sometimes, such as when processing a PNG with alpha channel values, we need to do this.
    I'm interested in working with photos taken with a smartphone. This is unlikely to require transparency.
    Photos taken by a smartphone, in my case, have a size of 3120 X 4160. It will not be possible to fit such an entire image into a standard PictureBox. The best option would be to place a part of the image in the PictureBox and after manipulating these parts, save the modified image to disk.
    You wrote:
    Quote Originally Posted by dilettante View Post
    You can use GetDIBits() on the StdPicture.Handle to retrieve a Long array.
    If I create a class:
    Code:
    Dim Photo As StdPicture
    and place the original image in it, then how can I get an array of bytes from it, if it does not have an hBitmap property for the GetDIBits function?

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

    Re: [RESOLVED] WIA Automation

    When I wrote:

    You can use GetDIBits() on the StdPicture.Handle to retrieve a Long array.
    I was writing on the fly. That was incorrect.

    Well, except when it is correct. This works fine, though it is subject to the "slow Add method" problem:

    Code:
    Option Explicit
    
    Private Const DIB_RGB_COLORS As Long = 0&
    Private Const BI_RGB As Long = 0&
    
    Private Type BITMAPINFOHEADER '40 bytes
        biSize As Long
        biWidth As Long
        biHeight As Long
        biPlanes As Integer
        biBitCount As Integer
        biCompression As Long
        biSizeImage As Long
        biXPelsPerMeter As Long
        biYPelsPerMeter As Long
        biClrUsed As Long
        biClrImportant As Long
    End Type
    
    Private Type BITMAPINFO
        BITMAPINFOHEADER As BITMAPINFOHEADER
        'bmiColors(0 to 255) As RGBQUAD
    End Type
    
    Private Declare Function GetDIBits Lib "gdi32" ( _
        ByVal hDC As Long, _
        ByVal hBitmap As Long, _
        ByVal nStartScan As Long, _
        ByVal nNumScans As Long, _
        ByRef Bits As Long, _
        ByRef BMI As BITMAPINFO, _
        ByVal wUsage As Long) As Long
    
    Private Sub Form_Load()
        Const Green As Long = &H8000&
        Const Brown As Long = &H4080&
        Dim WidthPx As Long
        Dim HeightPx As Long
        Dim BMI As BITMAPINFO
        Dim Quads() As Long
        Dim X As Long
        Dim Y As Long
        Dim ImageFile As WIA.ImageFile
        
        With Picture1
            'Draw something:
            .AutoRedraw = True
            .Cls
            .DrawWidth = 1
            Picture1.Line (.ScaleWidth / 4, .ScaleHeight / 4)- _
                          ((.ScaleWidth / 4#) * 3, (.ScaleHeight / 4) * 3), _
                          Green, _
                          BF
            .DrawWidth = 2
            Picture1.Circle ((.ScaleWidth / 8) * 3, (.ScaleHeight / 8) * 5), _
                            .ScaleWidth / 5, _
                            vbRed, _
                            -1, _
                            -5.5
            .CurrentX = .ScaleWidth / 5
            .CurrentY = (.ScaleHeight / 5) * 4
            .ForeColor = Brown
            Picture1.Print "Hello World!"
            .AutoRedraw = False
    
            'PictureBox's persistent bitmap to an ImageFile object:
            WidthPx = .ScaleX(.ScaleWidth, .ScaleMode, vbPixels)
            HeightPx = .ScaleY(.ScaleHeight, .ScaleMode, vbPixels)
            With BMI.BITMAPINFOHEADER
                .biSize = LenB(BMI.BITMAPINFOHEADER)
                .biWidth = WidthPx
                .biHeight = -HeightPx
                .biPlanes = 1
                .biCompression = BI_RGB
                .biBitCount = 32
            End With
            ReDim Quads(WidthPx - 1, HeightPx - 1)
            GetDIBits .hDC, .Image.Handle, 0, HeightPx, Quads(0, 0), BMI, DIB_RGB_COLORS
        End With
        With New WIA.Vector
            For Y = 0 To HeightPx - 1
                For X = 0 To WidthPx - 1
                    .Add Quads(X, Y)
                Next
            Next
            Erase Quads
            Set ImageFile = .ImageFile(WidthPx, HeightPx)
        End With
    
        'Show in second PictureBox:
        Set Picture2.Picture = ImageFile.FileData.Picture
    End Sub
    Last edited by dilettante; Sep 17th, 2021 at 05:03 PM. Reason: marked in red

  11. #11

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    Quote Originally Posted by dilettante View Post
    Well, except when it is correct. This works fine, though it is subject to the "slow Add method" problem:
    As I understand it, this example shows loading an ARGB image into an array?

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

    Re: [RESOLVED] WIA Automation

    As far as I can tell there is no alpha, so 8 bits are just reserved and should be 0.

    ARGB is a different thing, and the byte order is reversed. I don't think a PictureBox ever holds an ARGB bitmap. The only GDI support for ARGB involves the AlphaBlend() API, but WIA uses GDI+ internally.
    Last edited by dilettante; Sep 18th, 2021 at 03:41 AM.

  13. #13

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    Quote Originally Posted by dilettante View Post
    but WIA uses GDI+ internally.
    It is interesting.
    Is it possible in this case for the interaction of the WIA and GDI + handles?
    For example, image rotation in WIA is only possible by angles that are multiples of 90 degrees. If you rotate with GDI + and then return the image to WIA, then this can expand the functionality.
    I understand that almost any action with any image can be done using GDI +, but this requires a lot of code. Interfacing WIA with GDI +, I think, should reduce the amount of code.

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

    Re: [RESOLVED] WIA Automation

    You would be probably better off with your own (simple) custom GDI+ wrapper class instead of trying to transfer byte-arrays back and forth between WIA and GDI+ I suppose.

    For instance Olaf has a fairly complete GDI+ wrapper cGDIPlusCache class in the CodeBank.

    cheers,
    </wqw>

  15. #15

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    Quote Originally Posted by wqweto View Post
    trying to transfer byte-arrays back and forth between WIA and GDI+ I suppose.
    The strangeness is that from WIA to standard controls - no problem. The problem is in the return shipment.
    Which is strange.

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

    Re: [RESOLVED] WIA Automation

    Not strange really. WIA 2.0 is for acquiring images from still cameras and scanners and doing some simple processing of the images. Most people don't even install their camera drivers, so it is almost down to scanner acquisition alone.

    Everything else is just incidental. It is best used for the cases intended, but since most programs need only minimal graphics support it can still be useful in VB6 programs. Rotating a photo by 13 degrees just isn't needed very often while 90 degrees is a far more common requirement.

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

    Re: [RESOLVED] WIA Automation

    Quote Originally Posted by Argus19 View Post
    If I create a class:
    Code:
    Dim Photo As StdPicture
    and place the original image in it, then how can I get an array of bytes from it, if it does not have an hBitmap property for the GetDIBits function?
    All of these things have answers.

    In this case the StdPicture object does have what you'd need. If the image type is bitmap, then its Handle property is an hBitmap value. Other types (icon, metafile) have different Handle values.

    Seriously, this stuff is all documented. That's why all legal copies of VB6 came with MSDN Library documentation CDs and a 3 year subscription to quarterly updates. Just use the final set of CDs supporting VB6 for the best information: October 2001.

    Fine rotation? You have several options. One of them being PlgBlt() as demonstrated along with clip regions in examples posted here at Cookie twist which also shows image scaling for working with very large images extending beyond screen limits.


    Another good thread: Reading Proficiency and Programming exposes the truth behind copy/paste coders. They simply don't have the fundamental skills. But I have faith in you, you can do it too!
    Last edited by dilettante; Sep 18th, 2021 at 10:31 PM.

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

    Re: [RESOLVED] WIA Automation

    I just tested one of my PlgBlt() demos with a 5808x4096 JPEG ("Cookie twist" as linked in the previous post here).

    Works just fine. But it isn't using WIA 2.0 for anything.

  19. #19

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    Quote Originally Posted by dilettante View Post
    I just tested one of my PlgBlt() demos with a 5808x4096 JPEG ("Cookie twist" as linked in the previous post here).

    Works just fine. But it isn't using WIA 2.0 for anything.
    I loaded the original image into the PictureBox using VB tools. Then, using GDI +, I loaded a transparent .png, rotated it with GdipRotateWorldTransform and superimposed it on the original image, changed the brightness level, etc. Then I wrote the result to a file using GDI +.
    This is a lot of code.
    There was an idea to use WIA to load a transparent image. Rotation and brightness functions are done with GDI or GDI +. Also at WIA, when the image is enlarged 2 times, the color is lost. And write it down by means of WIA. All this is intended to reduce lines of code.
    StdPicture can store a transparent image. Problem using StdPicture with WIA.
    You gave me the code to return an image from a PicrureBox to WIA.

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

    Re: [RESOLVED] WIA Automation

    If you are writing JPEG photo processing programs don't forget about maintaining EXIF and other JPEG file metadata. Everything from original timestamps and geolocation data to camera make/model/settings as well as identification of your processing program and its version to a thumbnail image. WIA 2.0 supports reading and updating such info, while most 3rd party whizbang libraries don't bother.

  21. #21

    Thread Starter
    Hyperactive Member
    Join Date
    Jul 2020
    Posts
    370

    Re: [RESOLVED] WIA Automation

    I `m a pensioner. I am engaged in programming for myself.
    I change topics often. For example, now I found an example of using the dx7vb.dll library. Interesting to try, but I don't have a manifest file for it. You do not have?

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