System::Drawing::Bitmap to unsigned char * - c#

I have a C# .NET library that grabs frames from a camera. I need to send those frames to a native application that takes images from an unsigned char*.
I initially take the frames as System::Drawing::Bitmap.
So far I can retrieve a byte[] from the Bitmap. My test is done with an image of resolution 400*234, I should be getting 400*234*3 bytes to get to the 24bpp a RGB image requires.
However, I'm getting a byte[] of size 11948.
This is how I convert from Bitmap to byte[]:
private static byte[] ImageToByte(Bitmap img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
What is the proper way to convert from System::Drawing::Bitmap to RGB unsigned char*?

This has to be done using the lockBits method, here is a code example:
Rectangle rect = new Rectangle(0, 0, m_bitmap.Width, m_bitmap.Height);
BitmapData bmpData = m_bitmap.LockBits(rect, ImageLockMode.ReadOnly,
m_bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = Math.Abs(bmpData.Stride) * m_bitmap.Height;
byte[] rgbValues = new byte[bytes];
Marshal.Copy(ptr, rgbValues, 0, bytes);
m_bitmap.UnlockBits(bmpData);
GCHandle handle = GCHandle::Alloc(rgbValues, GCHandleType::Pinned);
unsigned char * data = (unsigned char*) (void*) handle.AddrOfPinnedObject();
//do whatever with data

Related

C# Linux Framebuffer Unsafe byte[] to CairoSharp ImageSurface

I am trying to create an image surface in c# CairoSharp using these two constructors:
public ImageSurface(byte[] data, Format format, int width, int height, int stride); public ImageSurface(IntPtr data, Format format, int width, int height, int stride);
I am trying to get the array of the linux framebuffer from a memorymappedfile:
var file = MemoryMappedFile.CreateFromFile("/dev/fb0", FileMode.Open, null, (3840 * 2160 * (32 / 8)));
I know I have to use an unsafe context to get it but am unsure the proper syntax to get the sequential pointer from the memeoryMapped object.
The constructors for the ImageSurface will not work with the MemoryMappedFile directly. You will have to Read bytes from the MemoryMappedFile and use those bytes to create the ImageSurface.
I never used C# on Linux before so I don't really know if all those objects are available but maybe like this?
private static void test()
{
Bitmap bmp = (Bitmap)Image.FromFile("some image");
BitmapData imgData = null;
try
{
imgData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite,
bmp.PixelFormat
);
int finalLength = imgData.Stride * imgData.Height;
byte[] buf = new byte[finalLength];
IntPtr ptr = imgData.Scan0;
System.Runtime.InteropServices.Marshal.Copy(ptr, buf, 0, finalLength);
bmp.UnlockBits(imgData);
// Pointer to first byte lives inside of fixed context.
unsafe
{
fixed (byte* p = buf)
{
// your cairo code...
}
}
// Alternative...
var ptPinned = System.Runtime.InteropServices.GCHandle.Alloc(
buf, System.Runtime.InteropServices.GCHandleType.Pinned);
IntPtr ptCairo = ptPinned.AddrOfPinnedObject();
ptPinned.Free();
}
finally
{
if (imgData != null) {
bmp.UnlockBits(imgData);
}
}
}
In any case I am certain that you have to pass the pointer of an already allocated buffer. In the test above I just loaded the image pixels of a bitmap into a byte array. In order to get the pointer you Marshal it or use fixed. That is all on Windows though.

Difference between bitmap and bitmapdata

What is the difference between System.Drawing.bitmap and System.Drawing.Imaging.bitmapdata in C#?
How to convert them to each other?
System.Drawing.Bitmap is an actual bitmap object. You can use it to draw to using a Graphics instance obtained from it, you can display it on the screen, you can save the data to a file, etc.
The System.Drawing.Imaging.BitmapData class is a helper object used when calling the Bitmap.LockBits() method. It contains information about the locked bitmap, which you can use to inspect the pixel data within the bitmap.
You can't really "convert" between the two per se, as they don't represent the same information. You can obtain a BitmapData object from a Bitmap object simply by calling LockBits(). If you have a BitmapData object from some other Bitmap object, you can copy that data to a new Bitmap object by allocating one with the same format as the original, calling LockBits on that one too, and then just copying the bytes from one to the other.
Convert bitmap to bitmap data. Also refer this link
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);
}

OpenTK Getting pixels byte array from a Bitmap

I need to port some OpenGL code to C# OpenTK.
Here is the chunk where I update a mapped PBO from an array of pixels in C++ :
GLubyte* ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
if(ptr)
{
memcpy(ptr,imageInfo.Data,IMG_DATA_SIZE);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
}
I need to do the same in OpenTK.My image data comes from an instance of Bitmap.
I tried the following:
IntPtr ptr = GL.MapBuffer(BufferTarget.PixelUnpackBuffer, BufferAccess.WriteOnly);
if(ptr != IntPtr.Zero)
{
BitmapData data = updateColorMap.LockBits(new System.Drawing.Rectangle(0, 0, updateColorMap.Width, updateColorMap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Marshal.Copy(data.Scan0, 0, ptr, IMG_DATA_SIZE);
}
But Marshal.Copy requires the first param to be of byte[] type.I didn't find how to retrieve it from the BitmapData.It returns only IntPtr (data.Scan0) .
So how can I get the byte array from the Bitmap?
UPDATE:
In the meantime I got help from the OpenTK forum and they proposed to do this instead:
unsafe
{
GL.BufferData(BufferTarget.PixelUnpackBuffer, new IntPtr(IMG_DATA_SIZE), IntPtr.Zero, BufferUsageHint.StreamDraw);
byte* ptr = (byte*)GL.MapBuffer(BufferTarget.PixelUnpackBuffer, BufferAccess.WriteOnly);
if (ptr != null)
{
BitmapData data = updateDepthMap.LockBits(new System.Drawing.Rectangle(0, 0, updateDepthMap.Width, updateDepthMap.Height),
ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte* scan0 = (byte*)data.Scan0.ToPointer();
for (int i = 0; i < IMG_DATA_SIZE; ++i)
{
*ptr = *scan0;
++ptr;
++scan0;
}
updateDepthMap.UnlockBits(data);
GL.UnmapBuffer(BufferTarget.PixelUnpackBuffer);
}
}//unsafe
Now,this works,but it is TERRIBLY SLOW! The regular texture update runs 2x faster than this,which is
wrong as async PBO transfer should speed up texture uploads.Indeed in my C++ version PBO upload causes almost 2x performance boost.
Ok so the solution is here: Copy data from from IntPtr to IntPtr
tested on linux.

Reading QR Code in an image with zxing

I'm using a C# library for reading of QRCodes. A lot of the samples I've found are based off the old version of zxing where the RGBLuminanceSource constructor still takes in bitmap. In the latest version RGBLuminanceSource only takes byte[]. I've tried to convert bitmap to byte[], but the decode result is always null.
Here's the code I used for conversion:
private byte[] GetRGBValues(Bitmap bmp)
{
// Lock the bitmap's bits.
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, 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 = 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);
bmp.UnlockBits(bmpData);
return rgbValues;
}
and for decode:
Bitmap bitmap = Bitmap.FromFile(#"C:\QRimages.jpg") as Bitmap;
LuminanceSource source = new RGBLuminanceSource(GetRGBValues(bitmap), bitmap.Width, bitmap.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
QRCodeReader reader = new QRCodeReader();
var result = reader.decode(binBitmap);
Somehow the result is always null.
Also, our requirement is that we have to use image taken by camera. I've tried this:
Bitmap bitmap = Bitmap.FromFile(#"C:\QRimages.jpg") as Bitmap;
BarcodeReader reader = new BarcodeReader { AutoRotate = true, TryHarder = true };
Result result = reader.Decode(bitmap);
It only works for the QR image I download online, but if I print out that image and take a picture of that with my phone, then try to process that image, the result is back to null.
Any suggestions would be appreciated.
Here's the image I'm using:

Win8 App Store - How to get PixelFormat?

In Win8 App Store, given a stream, how can I get the PixelFormat of the image from that stream? I can only get byte array, width, height, stride but I also need pixel format type (like how many bits per pixel, rgba32...) to create some kind of BitmapSource:
//Copy photo from camera to stream
var fPhotoStream = new InMemoryRandomAccessStream();
await mediaCaptureMgr.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), fPhotoStream);
await fPhotoStream.FlushAsync();
fPhotoStream.Seek(0);
//Convert stream to byte array
byte[] bytes = new byte[fPhotoStream.Size];
await fPhotoStream.ReadAsync(bytes.AsBuffer(), (uint)fPhotoStream.Size, InputStreamOptions.None);
//Get pointer to byte array
GCHandle pinnedArray = GCHandle.Alloc(bytes, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
//Get image width, height, stride
BitmapImage bmp = new BitmapImage();
bmp.SetSource(fPhotoStream);
int imgWidth = bmp.PixelWidth;
int imgHeight = bmp.PixelHeight;
int stride = bmp.Width * 4;
//But how to get image pixel format?
int pixelFormat = ??????
Can I do that?
I found that I can use BitmapDecoder to get the PixelFormat information:
http://msdn.microsoft.com/en-us/library/windows/apps/jj709939.aspx

Categories

Resources