Click here to Skip to main content
15,892,927 members
Articles / Programming Languages / Visual Basic
Article

Applying a texture to a bitmap

Rate me:
Please Sign up or sign in to vote.
3.96/5 (20 votes)
14 Sep 2003 91.5K   37   5
Shows you how to apply a texture to a bitmap.

Introduction

I thought this code might be useful to someone. I'm basically copy-pasting it from some post in VBForums (my own post). Here's what I do: I convert the texture to grayscale. The white-most pixels (highest r, g, or b value) will have the most transparency. The dark-most pixels will be the least transparent pixels when you are applying the texture.

My code may technically not be right, or not the most efficient way to do this. I just wanted to share the idea of how you can apply a texture. Hope this helps.

Details

Call ApplyTexture() to apply a texture to your bitmap. Here's the code:

VB.NET
' REMEMBER to add this to the class file that contains
 ' this code: Imports System.Drawing.Imaging

 ' Modifies the ORIGINAL bitmap
 ' textureTransparency  has to be between 0 and 1,
 ' with 0 being the least transparent, and 1 the most transparent
 Public Shared Sub ApplyTexture(ByRef bmp As Bitmap, _
        ByVal texture As Bitmap, _
        ByVal textureTransparency As Single)

     If (bmp Is Nothing) OrElse (texture Is Nothing) _
        Then Throw New ArgumentNullException
     If textureTransparency < 0 OrElse textureTransparency > 1 Then
         Throw New ArgumentOutOfRangeException( _
           "textureTransparency must be between 0 and 1.")
     End If

     ' Convert the texture to grayscale before using it
     MakeImageGrayscale(texture)

     Dim x, y, alpha As Integer

     ' Adjust the alpha value of each pixel in the texture bitmap.
     ' The white-most pixels will have the the
     ' most transparency (highest alpha),
     ' and the dark-most pixels will have the least transparency.
     For x = 0 To texture.Width - 1
         For y = 0 To texture.Height - 1
             Dim c As Color = texture.GetPixel(x, y)
             ' c.R -> all of the RGB values are the same
             ' since the image is in grayscale
             alpha = CInt(c.R * textureTransparency)
             c = Color.FromArgb(alpha, c)

             texture.SetPixel(x, y, c)
         Next
     Next

     Dim gr As Graphics = Graphics.FromImage(bmp)
     Dim myBrush As New TextureBrush(texture)

     ' Draw the texture over the original bitmap
     gr.FillRectangle(myBrush, bmp.GetBounds(GraphicsUnit.Pixel))
     myBrush.Dispose()
     gr.Dispose()
 End Sub

 ' Converts the image to grayscale
 Public Shared Sub MakeImageGrayscale(ByVal bmp As Bitmap)
     Dim cMatrix As New ColorMatrix(New Single()() _
         {New Single() {0.299, 0.299, 0.299, 0, 0}, _
         New Single() {0.587, 0.587, 0.587, 0, 0}, _
         New Single() {0.114, 0.114, 0.114, 0, 0}, _
         New Single() {0, 0, 0, 1, 0}, _
         New Single() {0, 0, 0, 0, 1}})

     Dim imageAttrib As New ImageAttributes
     imageAttrib.SetColorMatrix(cMatrix)


     Dim gr As Graphics = Graphics.FromImage(bmp)
     ' Apply the grayscale image attribute
     gr.DrawImage(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height), _
       0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, imageAttrib)
     gr.Dispose()
 End Sub

I don't know how to program in C#, but I managed to convert that to C# and used pointers instead of SetPixel and GetPixel. I used one of Christian Graus's articles on CodeProject to figure out how to use pointers to read the RGB data from a bitmap, and changed that a bit around to be able to read ARGB values. I hope I did everything right :)

Here it is, faster than the VB version:

C#
// REMEMBER to add this to the class file that contains your code
// using System.Drawing.Imaging;

// Modifies the ORIGINAL bitmap
// textureTransparency  has to be between 0 and 1, 
// with 0 being the least transparent, and 1 the most transparent 
public static void ApplyTexture (Image img, Image texture, 
    float textureTransparency)
{
    if ( (img ==null) || (texture==null) ) 
        throw new ArgumentNullException();
    if (textureTransparency < 0 || textureTransparency > 1) 
        throw new ArgumentOutOfRangeException(
              "Value must be between 0 and 1.");

    // Convert the texture to grayscale before using it
    MakeImageGrayscale (texture);


    Bitmap txtr = new Bitmap(texture);
    BitmapData bmData = txtr.LockBits(new Rectangle(0, 0, 
                 txtr.Width, txtr.Height), 
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); 
    int stride = bmData.Stride; 
    System.IntPtr Scan0 = bmData.Scan0; 
    // Adjust the alpha value of each pixel in the texture bitmap.
    // The white-most pixels will have the the 
    // most transparency (highest alpha), 
    // and the dark-most pixels will have the least transparency.
    unsafe
    {
        byte * p = (byte *)(void *)Scan0;
        int nOffset = stride - txtr.Width*4;


        for (int y=0; y < txtr.Height; ++y)
        {
            for (int x=0; x < txtr.Width; ++x)
            {
                // p[3] is alpha  -  array is BGRA (blue, green , 
                // red, alpha)
                p[3] = (byte)(p[0] * textureTransparency);
                p += 4; // Move to the next pixel
            }
            p += nOffset;
        }
    }
    txtr.UnlockBits(bmData);

    Graphics gr = Graphics.FromImage(img);
    TextureBrush myBrush = new TextureBrush(txtr);
    gr.FillRectangle (myBrush,0,0,img.Width, img.Height);
    myBrush.Dispose();
    gr.Dispose();
    txtr.Dispose();
}



// Converts the image to grayscale
public static void MakeImageGrayscale (Image img)
{
    ColorMatrix cMatrix = new ColorMatrix ( 
       new float[][]  { 
         new float[] {0.299F, 0.299F, 0.299F, 0, 0},
         new float[] {0.587F, 0.587F, 0.587F, 0, 0},
         new float[] {0.114F, 0.114F, 0.114F, 0, 0},
         new float[] {0, 0, 0, 1, 0},
         new float[] {0,  0,  0,  1, 0}});

    ImageAttributes imageAttrib = new ImageAttributes();
    imageAttrib.SetColorMatrix(cMatrix);

    Graphics gr = Graphics.FromImage (img);
    // Apply the grayscale image attribute
    gr.DrawImage (img, new Rectangle(0, 0, img.Width, img.Height), 
                    0, 0, img.Width, img.Height, GraphicsUnit.Pixel, 
                    imageAttrib);
    gr.Dispose();
}

Thanks Greg Ingelmo for correcting me :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralVB.NET kinda slow Pin
MrPolite11-Sep-03 13:27
MrPolite11-Sep-03 13:27 
GeneralRe: VB.NET kinda slow Pin
LaMusaraigne8-Jul-04 22:16
sussLaMusaraigne8-Jul-04 22:16 
GeneralRe: VB.NET kinda slow Pin
syed shujaat hussain24-Apr-07 0:29
syed shujaat hussain24-Apr-07 0:29 
GeneralGreyscale Pin
GIngelmo3-Sep-03 3:28
GIngelmo3-Sep-03 3:28 
GeneralRe: Greyscale Pin
MrPolite3-Sep-03 17:38
MrPolite3-Sep-03 17:38 
aah thanks a lotSmile | :) I actually got the matrix from some other website that I cant remember... I checked those 2 links, mine was incorrect.

Updated the functionCool | :cool:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.