-
Sep 16th, 2021, 01:15 PM
#1
Thread Starter
Hyperactive Member
[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?
-
Sep 16th, 2021, 01:38 PM
#2
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.
-
Sep 16th, 2021, 04:04 PM
#3
Thread Starter
Hyperactive Member
Re: WIA Automation
Originally Posted by dilettante
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.
-
Sep 17th, 2021, 07:47 AM
#4
Thread Starter
Hyperactive Member
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?
-
Sep 17th, 2021, 01:48 PM
#5
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).
-
Sep 17th, 2021, 03:49 PM
#6
Thread Starter
Hyperactive Member
Re: WIA Automation
Originally Posted by dilettante
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!
-
Sep 17th, 2021, 03:57 PM
#7
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.
-
Sep 17th, 2021, 04:15 PM
#8
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.
-
Sep 17th, 2021, 04:51 PM
#9
Thread Starter
Hyperactive Member
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).
Originally Posted by dilettante
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:
Originally Posted by dilettante
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?
-
Sep 17th, 2021, 04:59 PM
#10
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
-
Sep 18th, 2021, 02:25 AM
#11
Thread Starter
Hyperactive Member
Re: [RESOLVED] WIA Automation
Originally Posted by dilettante
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?
-
Sep 18th, 2021, 03:38 AM
#12
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.
-
Sep 18th, 2021, 04:46 AM
#13
Thread Starter
Hyperactive Member
Re: [RESOLVED] WIA Automation
Originally Posted by dilettante
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.
-
Sep 18th, 2021, 06:02 AM
#14
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>
-
Sep 18th, 2021, 09:24 AM
#15
Thread Starter
Hyperactive Member
Re: [RESOLVED] WIA Automation
Originally Posted by wqweto
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.
-
Sep 18th, 2021, 01:03 PM
#16
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.
-
Sep 18th, 2021, 09:24 PM
#17
Re: [RESOLVED] WIA Automation
Originally Posted by Argus19
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.
-
Sep 18th, 2021, 10:29 PM
#18
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.
-
Sep 19th, 2021, 02:06 AM
#19
Thread Starter
Hyperactive Member
Re: [RESOLVED] WIA Automation
Originally Posted by dilettante
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.
-
Sep 19th, 2021, 10:19 AM
#20
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.
-
Sep 19th, 2021, 02:10 PM
#21
Thread Starter
Hyperactive Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|