VB.NET

Moderators: seancampbell
Number of threads: 4020
Number of posts: 10026

This Forum Only
Post New Thread
Single Post View       Linear View       Threaded View      f

Report
Addressing pixels? Posted by Joe2003 on 19 Feb 2006 at 12:27 PM
Hi

I have a form and I want to create an area on the form in which I can address certain pixels. I want to be able to change the colour of certain pixels, thats all really. Is there a way to do this?

thanks

Joe
Report
Re: Addressing pixels? Posted by CyGuy on 19 Feb 2006 at 7:31 PM
: Hi
:
: I have a form and I want to create an area on the form in which I can address certain pixels. I want to be able to change the colour of certain pixels, thats all really. Is there a way to do this?
:
: thanks
:
: Joe
:
Hi Joe,
There are several ways to do it, the easiest and most publicized is activeX.
Report
Re: Addressing pixels? Posted by Joe2003 on 21 Feb 2006 at 8:25 AM
: : Hi
: :
: : I have a form and I want to create an area on the form in which I can address certain pixels. I want to be able to change the colour of certain pixels, thats all really. Is there a way to do this?
: :
: : thanks
: :
: : Joe
: :
: Hi Joe,
: There are several ways to do it, the easiest and most publicized is activeX.
:

Thanks, but is ther more of a vb-ish (just made that up!) way to do it? Im doing a VB .net module so im not sure how that would go down. Im not trying to get you all to do my assignments for me, just wanted a few clues to get me reading in the right area.

thanks some much for your help!
Report
Re: Addressing pixels? Posted by iwilld0it on 22 Feb 2006 at 8:43 AM
This message was edited by iwilld0it at 2006-2-22 8:46:0

This message was edited by iwilld0it at 2006-2-22 8:45:32

There is a slow and fast way to access pixels in VB.NET. However, even the fast way in VB is surpassed by C# because it can use unsafe code w/ memory pointers.

Fortunately I have some code for you to look over and then I suggest you look up some articles, because graphics maniupulation is a vast topic.

Slow Way

Dim newBmp As New Bitmap(100, 100, Imaging.PixelFormat.Format32bppArgb)
Dim g As Graphics = Graphics.FromImage(newBmp)
g.FillRectangle(Brushes.Blue, New Rectangle(20, 20, 60, 60))

For y As Integer = 0 To newBmp.Height - 1
    For x As Integer = 0 To newBmp.Width - 1
        Dim c As Color = newBmp.GetPixel(x, y)

        newBmp.SetPixel(x, y, _
            Color.FromArgb(c.A Mod 100, c.R Mod 100, c.G Mod 100, c.B Mod 100))
    Next
Next

pic.Image = DirectCast(newBmp.Clone, Bitmap)
g.Dispose()
newBmp.Dispose()


This example creates a 32-bit Bitmap image w/ an alpha channel and scrolls through each pixel one-by-one. This is very slow even though the GetPixel and SetPixel functions are thin wrappers around the gdiplus GdipBitmapGetPixel() and GdipBitmapSetPixel() API functions. The bottle neck is in these API functions (prob written w/ C++), so there is no way to speed up this routine.

BTW: pic is a PictureBox that I placed on the form.

Fast Way

For this example, I created a wrapper class called BitmapBits.

Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

Public Class BitmapBits
    Implements IDisposable

    Private mBitmap As Bitmap
    Private mBitmapData As BitmapData
    Private mBounds As Rectangle
    Private mData() As Byte

    Sub New(ByVal bm As Bitmap)
        mBitmap = bm
        mBounds = New Rectangle(0, 0, bm.Width, bm.Height)
    End Sub

    Public Sub Lock()
        Dim totalBytes As Integer
        mBitmapData = mBitmap.LockBits(mBounds, ImageLockMode.ReadWrite, mBitmap.PixelFormat)
        totalBytes = mBitmapData.Stride * mBitmapData.Height
        ReDim mData(totalBytes - 1)
        Marshal.Copy(mBitmapData.Scan0, mData, 0, totalBytes)
    End Sub

    Public ReadOnly Property Data() As Byte()
        Get
            Return mData
        End Get
    End Property

    Public Sub Unlock()
        If mBitmapData Is Nothing Then Return
        Dim totalBytes As Integer = mBitmapData.Stride * mBitmapData.Height
        Marshal.Copy(mData, 0, mBitmapData.Scan0, totalBytes)
        mBitmap.UnlockBits(mBitmapData)
        mBitmapData = Nothing
        mData = Nothing
    End Sub

    Public Sub Dispose() Implements System.IDisposable.Dispose
        If Not mBitmap Is Nothing Then
            mBitmap.Dispose()
        End If
    End Sub
End Class


The .NET Bitmap class has a function called LockBits which returns a BitmapData object. This object is a wrapper for the pixel data. The BitmapData object has a property called Scan0, which is a memory pointer that points to the begining of the pixel data. Unfortunately, Visual Basic does not intrinsically support memory pointers, so we have to perform a few tricks w/ the System.Runtime.Marshal.Copy() function.

Here is code that uses the wrapper class I created. It essentially does the same thing as the first example.

Dim newBmp As New Bitmap(100, 100, Imaging.PixelFormat.Format32bppArgb)
Dim g As Graphics = Graphics.FromImage(newBmp)
g.FillRectangle(Brushes.Blue, New Rectangle(20, 20, 60, 60))

Dim bits As New BitmapBits(newBmp)
Dim pix As Integer = 0
bits.Lock()

For y As Integer = 0 To newBmp.Height - 1
    For x As Integer = 0 To newBmp.Width - 1
        bits.Data(pix + 0) = CByte((bits.Data(pix + 0) Mod 100))
        bits.Data(pix + 1) = CByte((bits.Data(pix + 1) Mod 100))
        bits.Data(pix + 2) = CByte((bits.Data(pix + 2) Mod 100))
        bits.Data(pix + 3) = CByte((bits.Data(pix + 3) Mod 100))
        pix += 4
    Next
Next

bits.Unlock()

pic.Image = DirectCast(newBmp.Clone, Bitmap)
g.Dispose()
newBmp.Dispose()


I even tried it this way:

Add this win32 API declaration to the top of your Form class.

Private Declare Sub GetQuads Lib "kernel32" Alias "RtlMoveMemory" ( _
    ByRef pDst As RGBQuad, ByVal pSrc As IntPtr, ByVal ByteLen As Long)

Private Declare Sub SetQuads Lib "kernel32" Alias "RtlMoveMemory" ( _
    ByVal pDst As IntPtr, ByRef pSrc As RGBQuad, ByVal ByteLen As Long)

<StructLayout(LayoutKind.Sequential)> _
Public Structure RGBQuad
    Public R As Byte
    Public G As Byte
    Public B As Byte
    Public A As Byte
End Structure


Dim newBmp As New Bitmap(100, 100, Imaging.PixelFormat.Format32bppArgb)
Dim g As Graphics = Graphics.FromImage(newBmp)
g.FillRectangle(Brushes.Blue, New Rectangle(20, 20, 60, 60))

Dim totalBytes As Integer
Dim bdata As BitmapData = newBmp.LockBits( _
    New Rectangle(0, 0, 100, 100), _
    ImageLockMode.ReadWrite, newBmp.PixelFormat)

totalBytes = (bdata.Stride * bdata.Height)
Dim data(totalBytes >> 2 - 1) As RGBQuad
Dim pix As Integer = 0
GetQuads(data(0), bdata.Scan0, totalBytes)

For i As Integer = 0 To data.GetUpperBound(0)
    data(i).A = CType(data(i).A Mod 100, Byte)
    data(i).R = CType(data(i).R Mod 100, Byte)
    data(i).G = CType(data(i).G Mod 100, Byte)
    data(i).B = CType(data(i).B Mod 100, Byte)
Next

SetQuads(bdata.Scan0, data(0), totalBytes)
newBmp.UnlockBits(bdata)
pic.Image = DirectCast(newBmp.Clone, Bitmap)
g.Dispose()
newBmp.Dispose()


This is just about as fast as the last technique and is simpler because we are representing a pixel as a RGBQuad object. Also, it turns out that the GetQuads (RtlMoveMemory) API function is as fast as the Marshal.Copy function (which essentially does the same thing.)

Finally, for completion, I am going to supply an even faster pixel manipulation written in C#. You may choose to wrap your pixel manipulation in a C# DLL and reference it in your VB project.

Bitmap newBmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
Graphics g  = Graphics.FromImage(newBmp);
g.FillRectangle(Brushes.Blue, new Rectangle(20, 20, 60, 60));

BitmapData bdata = newBmp.LockBits(
	new Rectangle(0, 0, 100, 100), 
	ImageLockMode.ReadWrite, 
	PixelFormat.Format32bppArgb);

int stride = bdata.Stride;
IntPtr scan = bdata.Scan0;

unsafe
{
	byte *p = (byte *)scan.ToPointer();

	int nWidth = newBmp.Width;

	for(int y=0; y < newBmp.Height; ++y)
	{
		for (int x = 0; x < nWidth; ++x)
		{
			p[0] %= 100;
			p[1] %= 100;
			p[2] %= 100;
			p[3] %= 100;
			p += 4;
		}
	}
}

newBmp.UnlockBits(bdata);
		
pic.Image = (Bitmap)newBmp.Clone();
g.Dispose();
newBmp.Dispose();


This uses straight pointer arithematic, which is much faster than navigating a byte array. Also, there is no Marshal.Copy operation needed neither. This is roughly twice as fast as the fastest VB method.

Even though we have pushed the limits here, there are still much faster ways to manipulate pixels. There is still the GDI32 functions that I have not explored w/ .NET yet and graphics libraries like Direct-X. However, the techniques I gave here are sufficiently fast.

You should be able to adapt this code to write pixel manipulation functions at your whim. Please ask any questions about the code, considering the code is not trivial.







 

Recent Jobs

Official Programmer's Heaven Blogs
Web Hosting | Browser and Social Games | Gadgets

Popular resources on Programmersheaven.com
Assembly | Basic | C | C# | C++ | Delphi | Flash | Java | JavaScript | Pascal | Perl | PHP | Python | Ruby | Visual Basic
© Copyright 2011 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Operated by CommunityHeaven, a BootstrapLabs company.