I have been trying to set the alpha values manually for a Bitmap with the format of Format32bppArgb . In this code example, I am setting them all to 0.5f, however, they will be different values in the future and not all 0.5f/128 (as this is my test case to just get this working). How can I properly set the alpha values for a bitmap quickly? I could use SetPixel(), however, SetPixel() is horrifically slow for large images compared to just locking/unlocking the bitmap.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
for (int counter = 0; counter < rgbValues.Length; counter += 4)
{
rgbValues[counter] = 255;
rgbValues[counter + 1] = 255;
rgbValues[counter + 2] = 255;
rgbValues[counter + 3] = 128;
}
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
The best way to do this, providing you want to have the same alpha value on your entire bitmap, is to use a ColorMatrix. Check out this example by Microsoft:
http://msdn.microsoft.com/en-us/library/w177ax15(v=vs.71).aspx
Related
I want to change the specified pixel in a bitmap to transparent.
The method is as follows:
Bitmap bt = new Bitmap(Mybitmap);
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Mybitmap.Width, Mybitmap.Height);
BitmapData bmpdata = bt.LockBits(rect, ImageLockMode.ReadWrite, bt.PixelFormat);
IntPtr ptr = bmpdata.Scan0;
int bytes = Math.Abs(bmpdata.Stride) * bt.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
int len = rgbValues.Length;
for (int i = 0; i < len; i += 4)
{
//Some colors are already stored in this SpecificColor1ist, and pixels with the same color will be changed to transparent
foreach (var item in SpecificColor1ist)
{
if ((rgbValues[i]==item.B)&&(rgbValues[i+1] == item.G)&&(rgbValues[i+2] == item.R))
{
rgbValues[i + 3] = (byte)0;
}
}
}
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bt.UnlockBits(bmpdata);
return bt;
But the speed is too slow. Is there any way to make it faster? Unsafe code is also acceptable.
You have a pointer to the pixel data array, why not use it Scan0 (you will need to set your method as unsafe, and set it appropriately in the build options for your project)
you could make sure your pixel format is 32 bits.
You could compare your rbg values in one go with in int
Use a HashSet for a faster lookup
Clear the apha-channel using a bitwise &
Example
var colorHash = SpecificColor1ist
.Select(x => x.ToArgb())
.ToHashSet();
...
var data = bt.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppPArgb);
var length = (int*)data.Scan0 + Mybitmap.Height * Mybitmap.Width;
for (var p = (int*)data.Scan0; p < length; p++)
if(colorHash .Contains(*p))
*p = (*p & 0xFFFFFF) // i think sets the alpha to 0
...
Hello guys i saw this code in microsoft docs and i need to use it like getpixel and setpixel , clean code examples thanks .
private void LockUnlockBitsExample(PaintEventArgs e){
// Create a new bitmap.
Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbValues = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// Draw the modified image.
e.Graphics.DrawImage(bmp, 0, 150);
}
I need i way to use this code like getpixel and setpixel functions with good explanation and clean code thanks .
I am trying to get all the pixels in an image using a Bitmap and GetPixels. Now I know that it is very inefficient so I have been looking into LockBits. I have successfully made what I think locks the bits but I can not get each and every pixels. My Code so far is...
//Creates Rectangle for holding picture
Rectangle bmpRec = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(bmpRec, ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr Pointer = bmpData.Scan0; //Scans the first line of data
int DataBytes = Math.Abs(bmpData.Stride) * bmp.Height; //Gets array size
byte[] rgbValues = new byte[DataBytes]; //Creates array
string Pix = " ";
Marshal.Copy(Pointer, rgbValues, 0, DataBytes); //Copies of out memory
bmp.UnlockBits(bmpData);
for (int p = 0; p < DataBytes; p++)
{
Pix += " " + rgbValues[p];
}
I would like to use Lockbits, as it is the best way to get pixels. Any help?
Thank you.
When accessing the data directly from LockBits, the storage order is B-G-R, not RGB... that is why you are getting the values in the reverse order.
I am copying from one 1bpp bitmap to a smaller 1bpp bitmap. I just want to clip out a region so I can count the number of black pixels.
I use the following to make the copies:
private Bitmap Copy(Bitmap srcBitmap, Rectangle section)
{
BitmapData SourceLockedData;
BitmapData DestLockedData;
Rectangle DestRect;
byte[] SrcImageData;
byte[] DestImageData;
int ByteCount;
int WidthCount = 0;
int CurrentLine = 0;
int DestStride;
int SrcStride = 0;
// Create the new bitmap and associated graphics object
Bitmap Newbmp = new Bitmap(section.Width, section.Height, PixelFormat.Format1bppIndexed);
Newbmp.SetResolution(srcBitmap.HorizontalResolution, srcBitmap.VerticalResolution);
//Lock the bits
SourceLockedData = srcBitmap.LockBits(section, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
SrcStride = SourceLockedData.Stride;
//Get a count of the number of bytes to copy. Remember, bytes are not pixels.
ByteCount = SourceLockedData.Stride * SourceLockedData.Height;
//Initialize the source byte array
SrcImageData = new byte[ByteCount];
//Copy the data to the source byte array
Marshal.Copy(SourceLockedData.Scan0, SrcImageData, 0, ByteCount);
//Unlock the bits
srcBitmap.UnlockBits(SourceLockedData);
//Set a rectangle to the size of the New bitmap
DestRect = new Rectangle(new Point(0, 0), Newbmp.Size);
//Lock the bits
DestLockedData = Newbmp.LockBits(DestRect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
DestStride = DestLockedData.Stride;
//Get a count of the number of bytes to copy. Remember, bytes are not pixels.
ByteCount = DestLockedData.Stride * DestLockedData.Height;
//Initialize the source byte array
DestImageData = new byte[ByteCount];
//Copy the data to the destination byte array
Marshal.Copy(DestLockedData.Scan0, DestImageData, 0, ByteCount);
//Unlock for now
Newbmp.UnlockBits(DestLockedData);
for (int ArrayIndex = 0; ArrayIndex < ByteCount; ArrayIndex++)
{
if (WidthCount == Newbmp.Width)
{
//increment the line and push the index by the stride
ArrayIndex = (++CurrentLine) * DestStride;
continue;
}
DestImageData[ArrayIndex] = SrcImageData[ArrayIndex];
WidthCount++;
}
//Lock the bits again
DestLockedData = Newbmp.LockBits(DestRect, ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
//Copy data from byte array to IntPtr
Marshal.Copy(DestImageData, 0, DestLockedData.Scan0, ByteCount);
//Unlock bits
Newbmp.UnlockBits(DestLockedData);
// Return the bitmap
return Newbmp;
}
The biggest problem I am having is that both the SourceLockedData.Stride and DestLockedData.Stride are smaller than the width of the respective images. How can that be? From everything I know about stride it's the number of bits from one scan line of data to the next scan line of data. How is it mathematically possible for this to be less than the width?
Am I using LockBits or BitmapData wrong? Can BitmapData not be trusted? Should I calculate the stride by hand?
Tom P.
I figured out that the stride can be less than the width if you are dealing with RLE bitmaps. Since the bitmaps that I am loading are TIFFs they are RLE8 encoded.
This is the 3rd part to this topic. Part 1, Part 2..
I was successfully able to print my monochrome bitmap to my printer, however there is a large black stripe along the right of the image when the item prints.
Here is the original
(Scanned in)What the printer printed
Code to generate binary blob
Rectangle rect = new Rectangle(0, 0, Bitmap.Width, Bitmap.Height);
System.Drawing.Imaging.BitmapData bmpData = null;
byte[] bitVaues = null;
int stride = 0;
try
{
bmpData = Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, Bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
stride = bmpData.Stride;
int bytes = bmpData.Stride * Bitmap.Height;
bitVaues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, bitVaues, 0, bytes);
}
finally
{
if (bmpData != null)
Bitmap.UnlockBits(bmpData);
}
string str = String.Format("GW{0},{1},{2},{3},", X, Y, stride, Bitmap.Height);
byte[] ascii = Encoding.ASCII.GetBytes(str);
byte[] buffer = new byte[ascii.Length + bitVaues.Length + 1];
Buffer.BlockCopy(ascii, 0, buffer, 0, ascii.Length);
Buffer.BlockCopy(bitVaues, 0, buffer, ascii.Length, bitVaues.Length);
buffer[buffer.Length - 1] = (byte)'\n';
return buffer;
My initial theory is the BMP format is adding that line as a end of line marker and is not viable when rendered. I am thinking I may have to reparse the file after I have the binary array and take out the 00 00 00 at the end of every line. But I am posting here in case anyone thinks of a better way.
Microsoft bitmaps are always padded to an even 32 bits. When you generate the bitmap, round the width up to a multiple of 32 and you should be fine.