INTELLIGENT WORK FORUMS
FOR COMPUTER PROFESSIONALS

Log In

Come Join Us!

Are you a
Computer / IT professional?
Join Tek-Tips Forums!
  • Talk With Other Members
  • Be Notified Of Responses
    To Your Posts
  • Keyword Search
  • One-Click Access To Your
    Favorite Forums
  • Automated Signatures
    On Your Posts
  • Best Of All, It's Free!

*Tek-Tips's functionality depends on members receiving e-mail. By joining you are opting in to receive e-mail.

Posting Guidelines

Promoting, selling, recruiting, coursework and thesis posting is forbidden.

Jobs

Problem loading a picture from an array

Problem loading a picture from an array

(OP)
I have a webcam bmp that I can convert nicely to a jpg OK within my app using scraps of software I gleaned from another site.

The jpg picture at this point ends up as a simple byte array that has one element for each byte of the picture. It reduces the original file size by 20 and still gives a very good picture.
Eg if the picture size if 50,000 bytes. ? Ubound(MyArray) = 49999

When saved to a file (using Put) then read back using Loadpicture(Filename) it will show perfectly on an image box.

My problem is how to load the picture array directly into a picturebox without having to save and read it to temporary file as done in one example I found on another site.

Eg. MyPicture.Picture=MyArray obviously does not work

It would appear that Loadpicture is doing something more than just loading the file data into the picture property

How do I convert the array to a picture so I can load it to the imagebox?

I seem to remember an old post that had a suggestion something like this but I cant find it.
 

RE: Problem loading a picture from an array

Unfortunately, we have two different (unconnected) networks here at work.  On one of them I can reach the TT forum.  On the other I have VB installed and all my VB code is there, and we have quite restricted capacity to move data between the two.  So forgive me if I can't give you some worked examples.

However, I have a related app which can read raw data, manipulate it in various ways, and then display the output array as an image.  It sounds like the last step is what you are after.

What I do is:

create an array where the bytes represent the r,g,b values of the picture
assign the pixel data to the picturebox image using the API sub SetBitMapBits.

strongm has also posted a lot of stuff using GDI+ which you might find interesting.

I hope that helps.

Tony

RE: Problem loading a picture from an array

I've just re-read your post.  Ignore what I said above.  

What you are really asking is how can you take an array which represents all the bytes of a jpg image and convert it in memory (without going via a .bmp file or similar) to a bitmap in memory, which can then be assigned to a picturebox.

Hmm, sorry, that one's currently beyond me.  I think I'll just slink qietly into a corner and lurk until strongm or somebody similar takes pity and provides the answer.  

Then I think I'll have another thread to go into my archive winky smile

Tony

RE: Problem loading a picture from an array

I have a response - just not time to post currently.

Worth pointing out that we did cover most of this for Ted about 5 years ago.

RE: Problem loading a picture from an array

WIA 2.0 makes easy work of many small image processing tasks.  Here is an example that does this for you, and also retrieves the dimensions and uses them:

CODE

Option Explicit

Private Sub Form_Load()
    'Get a JPEG file format image as a Byte array.
    Dim Bytes() As Byte
    Dim F As Integer
    
    F = FreeFile(0)
    Open "some.jpg" For Binary Access Read As #F
    ReDim Bytes(LOF(F) - 1)
    Get #F, , Bytes
    Close #F
    
    'Convert to a StdPicture object and use it, making use
    'of the image's dimensions as we go too.  Here we assume
    'ScaleMode = vbTwips.
    With New WIA.Vector
        .BinaryData = Bytes
        With .ImageFile
            Width = (Width - ScaleWidth) + ScaleX(.Width, vbPixels, vbTwips)
            Height = (Height - ScaleHeight) + ScaleY(.Height, vbPixels, vbTwips)
        End With
        Set Picture = .Picture
    End With
End Sub

RE: Problem loading a picture from an array

(OP)
Will WIA work in Windows XP or even 98? ALl the docs seem to refer to Vista and beyond. Some of my workstations are still Windows 98.

Yes while years ago I posted a problem of how to convert a BMP to JPG and send it on a LAN to an imagebox in another computer.
This had a similar question as part of it as well.

The discussion got completely bogged down with speed of LAN vs speed of BMP to JPG conversion.
I could easily send the BMP as a propertybag, accumulate it in a stream and feed the pb.readproperty to the receiving imagebox

I gave up on trying to send the JPG.
I never did get a proper solution that worked without crashing the computer so I put up with transmitting raw BMPs using propertybags and streams.

So I am looking at improving my original app that is currently working without a hitch at about 40 remote sites and growing.
The BMPs are about 1meg while the JPGS are around 40k.

With the march of time, I now however now have a fast BMP to JPG conversion that doesn't crash. This accumulates the jpg into an array.
 
Now I can get the jpg as an array and send it as an array but how do I convert the array back to a picture once I receive it?
The array is identical to the contents of a jpg.file (the asc value of each byte is the same)

One unsophisticated way would be to use a Ramdisk and loadpicture but I was hoping a more elegant solution could be found.

Any help directly related to this subject would be appreciated.

Like most things, it is probably quite simple once you know how!

(By the way I am 76 this week)

RE: Problem loading a picture from an array

Quote:

Will WIA work in Windows XP or even 98? ALl the docs seem to refer to Vista and beyond. Some of my workstations are still Windows 98.
The docs mention Vista and newer because everything prior is basically considered unsupported anymore.

WIA 2.0 has always been available for redistribution to XP SP1 or later, and comes preinstalled starting With Vista.


Here's an attempt at a WIA-less demo.  Perhaps this will do what you need:

CODE

Option Explicit

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
    ByRef Destination As Any, _
    ByRef Source As Any, _
    ByVal Length As Long)
Private Declare Function CreateStreamOnHGlobal Lib "ole32" ( _
    ByVal hGlobal As Long, _
    ByVal fDeleteOnRelease As Long, _
    ByRef ppstm As Any) As Long
Private Declare Function GlobalAlloc Lib "kernel32" ( _
    ByVal uFlags As Long, _
    ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" ( _
    ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" ( _
    ByVal hMem As Long) As Long
Private Declare Function OleLoadPicture Lib "olepro32" ( _
    ByRef pStream As Any, _
    ByVal lSize As Long, _
    ByVal fRunmode As Long, _
    ByRef riid As Any, _
    ByRef ppvObj As Any) As Long

Private Function Bytes2StdPicture(ByRef Bytes() As Byte) As StdPicture
    Const GMEM_MOVEABLE = &H2&
    Const WIN32_TRUE = 1
    Const WIN32_FALSE = 0
    Const WIN32_NULL = 0
    Const S_OK = 0
    Dim GUID(0 To 3) As Long
    Dim Size As Long
    Dim hMem  As Long
    Dim lpMem  As Long
    Dim IIStream As Object
    
    'GUID for StdPicture:
    GUID(0) = &H7BF80980
    GUID(1) = &H101ABF32
    GUID(2) = &HAA00BB8B
    GUID(3) = &HAB0C3000
    
    Size = UBound(Bytes) - LBound(Bytes) + 1
    hMem = GlobalAlloc(GMEM_MOVEABLE, Size)
    If hMem <> WIN32_NULL Then
        lpMem = GlobalLock(hMem)
        If lpMem <> WIN32_NULL Then
            CopyMemory ByVal lpMem, Bytes(LBound(Bytes)), Size
            GlobalUnlock hMem
            If CreateStreamOnHGlobal(hMem, WIN32_TRUE, IIStream) = S_OK Then
                  OleLoadPicture ByVal ObjPtr(IIStream), _
                                 0, _
                                 WIN32_FALSE, _
                                 GUID(0), _
                                 Bytes2StdPicture
            End If
        End If
    End If
End Function

Private Sub Form_Load()
    'Get a JPEG file format image as a Byte array.
    Dim Bytes() As Byte
    Dim F As Integer
    
    F = FreeFile(0)
    Open "some.jpg" For Binary Access Read As #F
    ReDim Bytes(LOF(F) - 1)
    Get #F, , Bytes
    Close #F
    
    'Convert to a StdPicture object and use it.
    Set Picture = Bytes2StdPicture(Bytes)
End Sub

RE: Problem loading a picture from an array

dilettante, the PictureFromRawBits I pointed is based on the same code.

I checked the documentation, MSDN states that CreateStreamOnHGlobal and OleLoadPicture are supported on Windows 2000 and later.

Ted, did you try the PictureFromRawBits function? I don't have any older OS to test if it works or not.

RE: Problem loading a picture from an array

>Windows XP

Yes, although you may need to download the WIA 2.0 library

>or even 98?

No. It was introduced with Windows ME.

 

RE: Problem loading a picture from an array

Quote:

WIA 1.0 was introduced in Windows Me and Windows XP and supports scanners, digital cameras and digital video equipment. WIA 2.0 was released with Windows Vista. WIA 2.0 is targeted towards scanners but continues to offer support for legacy WIA 1.0 applications and devices through a WIA 1.0 to WIA 2.0 compatibility layer provided by the WIA service. However, video content support was removed from WIA for Windows Vista. We recommend Windows Portable Devices (WPD) API for digital cameras and digital video equipment in the future. WIA 1.0 as well as STI TWAIN drivers are still supported directly on Windows Vista and Windows 7 alongside native WIA 2.0 device drivers and imaging applications.
And WIA 2.0 can be back-installed into XP SP1 or later to get the newer image processing features you'd want in this case.

I keep a VM around for Win9x testing: Win95 OSR2 with the Desktop Update.  My Bytes2StdPicture() example runs fine there so Win98 should be no problem.

RE: Problem loading a picture from an array

(OP)
Thanks Hypetia
PictureFromRawBits works perfectly

I also got GetBitmaBits and SetBitmapBits to work but only to a picturebox

What exactly is the difference between .Image and .Picture properties in a picturebox?

RE: Problem loading a picture from an array

(OP)
For those interested the original BMP to JPG conversion was written in 2003 by a John Korejwa and was available at planetsourcecode.com

This was quite a bit more featured than I needed so I stripped out only the essential code to convert my bmp

When compiled it takes less than 1/10 second to reduce a 640x480 1 meg BMP to a 20k JPG with only a barely perceptible loss in quality. (3.4g Dual core)

With a 50k JPG it looks the same as the original.  

You can experiment with different compressions.

Thank you all for your help.

RE: Problem loading a picture from an array

.Picture is the read/write picture property which holds a static picture object. It might be loaded at design time or runtime.

.Image is a read-only property available at runtime only and returns overall output rendered on a picture box. This output covers all graphics related output drawn on the picture box. This includes circles, lines, rectangles, printed text or any output rendered on the picture box using API functions (like DrawIcon). You must use persistent drawing mode (AutoRedraw = True) to use the Image property.

If you load a picture in a picture box and draw something on the picture using drawing methods (Circle, Line, PSet etc.) or API calls, the Image property will return a picture object which contains the drawing output superimposed on the original picture in the picture property, just as you see the picture box. Picture property will continue to return the original picture without any changes.

See Image and AutoRedraw properties for further details.

RE: Problem loading a picture from an array

> the original BMP to JPG

Still a shame that you can't use WIA 2.0, as all of this is really easy to do there. The code below demonstrates directly grabbing images from a video camera as either bitmap or a jpeg array, and then displaying the jpeg array in a picturebox. I only provide the code as an example of how trivial this all is with WIA

CODE

Option Explicit

' Requires that you add the
' Microsoft Windows Image Acquisition Library v2.0
' as a control allowing you to place a VideoPreview on the form
' and automatically adds trhe necessary reference as well


Private Sub Command1_Click()
    ' Grab a bitmap array representation of a single frame captured from the video camera
    ' convert it to a JPG array, and display it

    DisplayArray BMPtoJPGArray(GrabArray(wiaFormatBMP))
End Sub

Private Sub Command2_Click()
    ' No need to bother with a bitmap though ...
    ' Grab a jpeg array representation of a single frame captured from the video camera
    ' and display it

    DisplayArray GrabArray(wiaFormatJPEG) 'spoon
End Sub

Private Sub DisplayArray(GraphicsArray() As Byte)
    With New wia.Vector
        .BinaryData = GraphicsArray
        Set Picture1.Picture = .ImageFile.FileData.Picture
    End With
End Sub

Private Function BMPtoJPGArray(BMPArray() As Byte) As Byte()
    Dim ImgProc As wia.ImageProcess
    
    Set ImgProc = New wia.ImageProcess
    With ImgProc.Filters
        .Add ImgProc.FilterInfos("Convert").FilterID
        .Item(1).Properties("FormatID").Value = wiaFormatJPEG
        .Item(1).Properties("Quality").Value = 20 ' 1 to 100%
    End With
    
    With New wia.Vector
            .BinaryData = BMPArray
            BMPtoJPGArray = ImgProc.Apply(.ImageFile).FileData.BinaryData
    End With
End Function

Private Function GrabArray(GrabStyle As String) As Byte()
    'Get captured image as a byte array
    GrabArray = VideoPreview1.Device.ExecuteCommand(wiaCommandTakePicture).Transfer(GrabStyle).FileData.BinaryData
End Function

RE: Problem loading a picture from an array

Hypetia: Have a star.  Until now I thought I more or less understood the difference, or at least managed to muddle by, sometimes through trial and error.  But that seems like a much clearer and more practical description than any I've seen from MS.

Have you ever considered working for the MS help dept? smile

BTW I added a note last night, saying more or less the above, but it does not seem to have appeared for some reason.  Hmm.  Odd.

Tony
 

RE: Problem loading a picture from an array

(OP)
I haven't got a 98 machine handy to try WIA but will when I get the chance to reinstall my old drive.

Interestingly I am using the old clipboard.getdata routine to retrieve the webcam picture.
This works fine in XP and WIN7 64 BIT except if I ever unplug the camera before stopping the app properly, only in WIN 7 it freezes the app in the computer and even though you can select the task bar and other programs, nothing will unload the app except removing the power to the computer! Rather odd?

I saw another alternative to the clipboard method somewhere but can't find it. Any suggestions (apart from WIA)?

RE: Problem loading a picture from an array

>I saw another alternative to the clipboard method

I believe I may have mentioned capVideoStreamCallback as a possible alternative

RE: Problem loading a picture from an array

(OP)
Thanks for your continued interest.
I see you did mention that but I am afraid I have no idea how to implement it!
I only want to see the camera once a second.

Basically the picture part of my software current exists as you originally suggested -

CODE

'In Module
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Public Declare Function SendMessageAsLong Lib "user32" Alias "SendMessageA" _
                                            (ByVal hwnd As Long, _
                                            ByVal wMsg As Long, _
                                            ByVal wParam As Long, _
                                            ByVal lParam As Long) As Long
Public Const WM_USER As Long = &H400
Public Const WM_CAP_START As Long = WM_USER
Public Const WM_CAP_DLG_VIDEOSOURCE As Long = WM_CAP_START + 42


'In Form
Const ConnectCam As Long = 1034         'variables for API camera routine
Const DisconnectCam As Long = 1035
Const GET_FRAME As Long = 1084
Const COPY As Long = 1054

Sub StartCam()
'start USB camera being able to capture
SendMessage mCapHwnd, ConnectCam, 0, 0
End Sub

Sub StopCam()
'close USB Camera capture before ending otherwise application crashes on close.
SendMessage mCapHwnd, DisconnectCam, 0, 0
Clipboard.Clear
End Sub

Private Sub Timer1_Timer()
'every second
PluggedInFlag = SendMessage(mCapHwnd, GET_FRAME, 0, 0) 'get cam picture. (Win7 crashes here when camera unplugged)
If PluggedInFlag = 0 Then
   CameraStatusLabel.Caption = "NO Camera"
Else
   CameraStatusLabel.Caption = "Camera OK"
End If
SendMessage mCapHwnd, COPY, 0, 0 'put camera on clipoard
ImageCamera.Picture = Clipboard.GetData 'show in an image box
End Sub

I notice my PlugInFlag is initially zero until I plug in a camera but if I pull out the plug while it is showing, it doesn't change back to a zero. The picture in the clipboard just freezes and resumes when I plug it back in after stopping and starting again.
Is there another way of detecting if the camera has been unplugged? (this is aside from the issue of not using the clipboard which might be neater anyway)

It would be nice to have it detect a no camera so it could black out the screen and disconnect possibly avoiding the Win7 crash?

In Win7 only, it crashes at the point noted the next second it is read if the StopCam has not been activated.

RE: Problem loading a picture from an array

Hi Ted,
Sorry for unsolicited interference. I didn't see what you are doing in your above code (never got to work with camera API myself).

I just saw function declarations of SendMessage and its variant SendMessageAsLong and wanted to talk about that. Although you are not using SendMessageAsLong in your above code, some other part of program might be using it.

See thread713-1343185: Sendmessage and GETTEXTEX in vb/vba (my second post in particular).

RE: Problem loading a picture from an array

(OP)
Sorry
The SendMessageAsLong has nothing to do with the matter in question.

It is used in another part of the program for a different purpose.

I extracted only the vital parts for simplicity in this question  but left this one in accidently

RE: Problem loading a picture from an array

Ted, I did not mean to ask WHY did you leave SendMessageAsLong in your above code.

What I meant was that you don't need it (or any other variant of SendMessage) at all, even if you are using it somewhere else. SendMessage function alone can be used in all situations.

Perhaps you didn't see the thread I referenced above.

RE: Problem loading a picture from an array

(OP)
Thanks for that info.

Like many people I use recommended routines from a wide variety of sources and modify or enlarge on them to suit the circumstances- after all, we all do in some way when we uses the examples from Microsoft.

This app uses a number of different routines gleaned from other suggestions and examples and it just happens that the long version was in one of them.

So I wonder why a difference exists?

RE: Problem loading a picture from an array

>So I wonder why a difference exists?

Given that you are not entirely certain how this API works (given my long and not entirely fruitful discussion with you about wParam and lParam in the past) I'm not sure it is worth worrying about ...

But basically 'As Any' means exactly that. Any variable type can be passed. VB6 therefore relinquishes any responsibility for type checking (i.e. it doesn't do any at all), meaning that the developer can spectacularly crash their app if they pass a variable type that the function is not expecting. Many code examples, therefore, provide typed declarations of such calls to avoid the problems that may arise with people simply using the example code without understanding what is going on.

SendMessageLong is a typical example of this effort to be type-safe.

RE: Problem loading a picture from an array

(OP)
Thanks.
I understood the reasons for specifying precisions etc and thought I knew why there was a difference.

When I asked "why the difference exists" I was responding to the assertion that SendMessage could be "used in all situations" and the long version was not needed at all

From what you say would appear then that the previous statement is not correct

Any idea yet on the "Unplugged warning" question?

RE: Problem loading a picture from an array

> that SendMessage could be "used in all situations"

Shades of the lParam/wParam thread are now coming back to haunt me...

Nothing I said suggests that "SendMessage could be 'used in all situations'" was not correct.
 
SendMessage can indeed be used in all situations, but the onus is then on the programmer to ensure that the correct type as well as value of parameter is passed.

RE: Problem loading a picture from an array

>Any idea yet on the "Unplugged warning" question?

You should be able to use a SysInfo control, and monitor the DeviceRemoveComplete event.

RE: Problem loading a picture from an array

>SendMessage could be 'used in all situations'

SendMessage is a classical example where a single parameter can assume different data types (depending upon the individual message being sent). I can recall an earlier discussion on use of Any keyword in SendMessage function in thread222-752892: WindProc.

But SendMessage is not the only case. There are other functions, in which the argument type changes in different conditions. For instance, LoadIcon and LoadBitmap functions may specify a 32-bit resource identifier as Long, or a named resource as String. Considering this, it is better to specify the resource identifier as Any, instead of Long or String.

Another example is RegQueryValueEx function, in which the type of lpData changes with the type of data being received. It might be a Long, a Byte array or a String depending upon the type of the value being queried (REG_DWORD, REG_BINARY or REG_SZ). Declaring it 'As Any' makes it compatible with all data types.

RE: Problem loading a picture from an array

(OP)
Thanks all
First the good news. WIA works great with XP except I haven't yet  found a way of setting the resolution to 640x480 (some posts say you can't anyway)

The bad news is that it doesn't work or even show the viewer in Windows 7

I can't download Virtual XP for Windows 7 because I only have Home Premium

Any suggestions?
Is there another way of writing software to show web pictures in Win7?

RE: Problem loading a picture from an array

(OP)
Also I cant get any response with sysinfo on plugging in a web camera.
Is there something other than the event sub that you have to do first?

RE: Problem loading a picture from an array

This thread has gotten a bit long for answering a simple question and it seems to be wandering all over now.

Remember, the purpose of these forums isn't merely to answer your question but also to add to the searchable repository of answers to questions to benefit all.

Deviating all over the board as you so often do may work well for those who try to treat this as an unpaid custom programming service.  That isn't how things work here.

Please start a new thread when asking a new question.

RE: Problem loading a picture from an array

(OP)
I'm sorry that this does happen but it is because WIA and Sysinfo are related to answers to my original question and if I don't respond to the success or otherwise of these answers, others think I am ignoring them.

Often the thread wanders because different people suggest alternative methods. I feel obliged to explain why it did or if I had trouble with it.

You may have noted that I have tried to bring some threads back on track in the past.

At least nobody can claim that my threads are not challenging and attract interest!

I am really a 'long retired programmer' and doing it for interest more than financial gain and I do try to help learners if I know an answer to their problem before someone else gets to it first.
 

RE: Problem loading a picture from an array

So now we're talking about image capture and detecting the comings and going of devices?


While I'm a bit of a WIA fan myself, there are things you should be aware of.

From Vista onward WIA was stripped of video-handling to become more of a scanner API.  In most cases a webcam won't work with WIA anymore even for still-image capture.

If you think you can run on XP forever I'd wait for those chickens to hatch before placing any bets on it.

Quote:

WIA 1.0 was introduced in Windows Me and Windows XP and supports scanners, digital cameras and digital video equipment. WIA 2.0 was released with Windows Vista. WIA 2.0 is targeted towards scanners but continues to offer support for legacy WIA 1.0 applications and devices through a WIA 1.0 to WIA 2.0 compatibility layer provided by the WIA service. However, video content support was removed from WIA for Windows Vista. We recommend Windows Portable Devices (WPD) API for digital cameras and digital video equipment in the future. WIA 1.0 as well as STI TWAIN drivers are still supported directly on Windows Vista and Windows 7 alongside native WIA 2.0 device drivers and imaging applications.


Now, WPD is supposed to be the way forward, but there was no VB6-friendly interface to WPD in XP or Vista.  This led to some blood-curdling screams, so:

Quote:

The WPD Application Programming Interface is supported in Windows 7, Windows Vista, and Windows XP operating systems. The WPD Automation Object Model is only supported in Windows 7.
That's right, WPD is useless to you until Windows 7.  MS refused to create a back-installable "automation" interface for earlier Windows versions.  But even so the "Automation Object Model" is an ugly thing oriented toward JScript and clumsy to use in VB6, VBScript, or much of anything else.

Maybe for portability you're back to using avicap32.dll?

RE: Problem loading a picture from an array

(OP)
Thanks. One thing usually leads to another!

It is a pity that WIA is so neat!  But I do really want to use W764 bit. I do a bit of HD video editing and it is so much better.

avicap32.dll works well in Wndows7 64 bit but my big problem with this is the complete computer crashes if you pull out the USB camera plug while it is running.

Then you can't even shut the app down with the taskbar or the computer power button and you eventually get a white screen.

The only way to unfreeze it is to remove the power to the computer plug! (nasty)

I have not been able to find a way to intercept the plug being pulled out before it freezes. That's why I tried Sysinfo but cant get any response from that in W7-64 when I unplug the camera even without the capture running.(probably because I am not using it properly)

That's why I asked if there was anyone who knew how to detect a USB webcam using Sysinfo.

 

Red Flag This Post

Please let us know here why this post is inappropriate. Reasons such as off-topic, duplicates, flames, illegal, vulgar, or students posting their homework.

Red Flag Submitted

Thank you for helping keep Tek-Tips Forums free from inappropriate posts.
The Tek-Tips staff will check this out and take appropriate action.

Reply To This Thread

Posting in the Tek-Tips forums is a member-only feature.

Click Here to join Tek-Tips and talk with other members!

Resources

Close Box

Join Tek-Tips® Today!

Join your peers on the Internet's largest technical computer professional community.
It's easy to join and it's free.

Here's Why Members Love Tek-Tips Forums:

Register now while it's still free!

Already a member? Close this window and log in.

Join Us             Close