reading jpg image pixel values

OK, here is what I have...

I have a program that scans via twain image driver.

We have what is called a routing slip similar to a scantron where people are coloring in circles.

I want to be able to read pixel values from any point.  because we are scanning at such a high resolution the image goes outside of the visible picture box.  

my problem is that I cannot read any part of an image that is not visible in a picture box.

my goal is to read pixel rgb values given an x,y coordinate in pixels for any point in the image without dealing with a picture box or external dll objects.

we are using this object as an activeX web object.

Thank you so much for all your help
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

How does the image get to the picturebox?
Are you passed any info about the image dimensions?
icredesAuthor Commented:
the only information that I have is the file path
I assume the image is hidden, though, yes?  Why not set the Picturebox AutoSize property to True?
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

icredesAuthor Commented:
the issue is that I need to be able to view the image at 100% 300 dpi

getting the image dimentions is not too difficult.

my concern is getting the pixel values

I am going to assume that the image is the correct size.
icredesAuthor Commented:
the autosize feature is interesting, but the point here is not to use the picture box

even if I get the correct size, the image is too big to fit on the screen.

is there another way....

lets assume that I were to do this in a module without the use of a form if possible.
You can use a memoryDC to load the picture into.  Then you can read the pixels using the GetPixel API.  All of the following code can be adapted for use in a module because no picturebox is used.

Option Explicit

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 CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function GetObjectAPI Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long) As Long

Private Sub Command1_Click()

    Dim pic As StdPicture
    Dim memDC As Long
    Dim px As Long
    Dim bm As BITMAP
    'Load a picture
    Set pic = LoadPicture("c:\thumb.jpg")
    'Create a DC compatible with the screen
    memDC = CreateCompatibleDC(0)
    'Select the picture into the DC
    Call SelectObject(memDC, pic.Handle)
    'Get the bitmap info
    Call GetObjectAPI(pic.Handle, LenB(bm), bm)
    Debug.Print "Picture dimensions: ", bm.bmHeight, bm.bmWidth
    'Here we read the center pixel color using GetPixel
    px = GetPixel(memDC, bm.bmWidth / 2, bm.bmHeight / 2)
    Debug.Print "The color is " & Hex(px)
    'Done, Clean Up
    Call DeleteDC(memDC)

End Sub


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
@ icredes

The following program needs a source Picbox(no matter if visible or invisible) and a destination picbox(visible).

It works without API. You will get all the r-g-b values of the picture and of each pixel.

'Needs 2 Pictureboxes
Const Pic = "C:\WINDOWS\Desktop\LAPTOP.JPG"

Private Sub Form_Activate()
AutoRedraw = -1: Picture2.ScaleMode = 3
Move 0, 0: Picture1.BackColor = vbBlue
Picture1.Move 15 * 70, 15 * 15, 15 * 360, 15 * 290
Picture1.BorderStyle = 0: Picture1.ScaleMode = 3
Picture2.BorderStyle = 0: Picture1.BackColor = vbWhite: Picture2.BackColor = vbWhite
Picture2.Move Picture1.Left + Picture1.Width + 15 * 9, 15 * 15, 15 * 30, 15 * 18
Picture1.Picture = LoadPicture("C:\WINDOWS\Desktop\LAPTOP.JPG")
For YY = 0 To Picture1.Picture.Width
For XX = 0 To Picture1.Picture.Height

Picture2.PaintPicture Picture1.Picture, 0, 0, 1, 1, XX, YY, 1, 1

col = Picture2.Point(0, 0) 'BGR
Picture2.BackColor = col

b = (col And 16711680) / 65536 '     16711680  = FF0000
g = (col And 65280) / 256 '          65280     = FF00
r = col And 255

MsgBox XX & "  ,  " & YY & vbCrLf _
       & "r , g , b" & vbCrLf & r & " , " & g & " , " & b

Next: End

End Sub
I found a good way to do this.   What it does is map an array's memory to point to a picture's memory.  But the cute thing is that you map a UDT array so that you don't have to do any maths to get the pixel values. This makes it very fast.

I took the concept from here:

(Also search goolge for safearray2d for more inhfo/examples like the same.

And then made the leap into using a UDT array. You can either use a 2 dimensional array, or in some cases for faster image processing, you can use a single dimensional array.

I renamed the class zPicArray, so for example:

Dim PA as zPicArray

Set picAnyPic.Picture = LoadPicture("C:\........jpg")
Set PA = New zPicArray
PA.LoadImage picAnyPic
Pa.ProcessImage Actions.ConvertToGreyScale

' extract from the class (single dimension version) the following converts a colour image to greay scale

Sub ProccessImage(Action As Actions)

Dim cp As Long
Dim Av As Long
Dim bt As Byte
Dim GreyFactor As Single

GreyFactor = 0.333333
cp = 0

Select Case Action
    Case Is = Actions.ConvertToGreyScale

    ' loop through image
    Do While cp < aSize ' asize is the size of the pic in pixels
        Av = (0& + Data(cp).Red + Data(cp).Green + Data(cp).Blue) * GreyFactor
        bt = Av
        ' Save the greyed pixel values back into the picture box
        Data(cp).Red = bt
        Data(cp).Green = bt
        Data(cp).Blue = bt
        cp = cp + 1
End Select

End Sub

In you case you may wish to stay with 2 dim array. So to modify the example from visualbasicforum to use UDT's you need:

Private Type PixelDef
  Blue As Byte
  Green As Byte
  Red As Byte
End Type

Private Data() As PixelDef ' was byte

And in the LoadImage sub change

.cbElements = 3 ' was 1 to point to a byte

If you need any more info with this concept.
And also in the loadimage change:

.Bounds(1).cElements = BMP.bmWidthBytes


.Bounds(1).cElements = BMP.bmWidth

So after your loadimage you can then loop image.  I posted a single dim example, here is a 2 dim example of looping through an image:

' filter out red
For y = 0 To mvarUBoundY
    For x = 0 To mvarUBoundX
       Datal(x,y).Red = 0
icredesAuthor Commented:
Erick37  you nailed it

that works great for me...thanks
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.