Image Manipulation c# - c#

I have the following code which takes an array of bytes which i generated and writes them out to this bitmap. If i set the pixel format to Format4bppIndexed, then i get a readable image repeating width wise 4 times, if i set it to Format1bppIndexed(which is the correct setting) then i get one big unreadable image.
The image was a decoded Jbig2 image , i know the bytes are correct i can't seem to figure out how to get it into a 1bpp readable format.
Does anyone have any advice on that matter
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
//Create a BitmapData and Lock all pixels to be written
BitmapData bmpData = bitmap.LockBits(
new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.WriteOnly, bitmap.PixelFormat);
//Copy the data from the byte array into BitmapData.Scan0
Marshal.Copy(newarray, 0, bmpData.Scan0, newarray.Length);
//Unlock the pixels
bitmap.UnlockBits(bmpData);

The following may work although, if I remember correctly, Stride sometimes has an effect and a simple block-copy won't suffice (line by line must be used instead).
Bitmap bitmap = new Bitmap(
width,
height,
System.Drawing.PixelFormat.Format16bppGrayScale
);
To handle the Stride you'd want:
BitmapData^ data = bitmap->LockBits(oSize,
ImageLockMode::ReadOnly, bitmap->PixelFormat);
try {
unsigned char *pData = (unsigned char *)data->Scan0.ToPointer();
for( int x = 0; x < bmpImage->Width; ++x )
{
for( int y = 0; y < bmpImage->Height; ++y )
{
// Note: Stride is data width of scan line rounded up
// to 4 byte boundary.
// Requires use of Stride, not (width * pixelWidth)
int ps = y*bmpImage->Width*(nBitsPerPixel / 8)
+ x * (nBitsPerPixel / 8);
int p = y * data->Stride + x * (nBitsPerPixel / 8);
Byte lo = newarray[ps + 1];
Byte hi = newarray[ps + 0];
pData[p + 1] = lo;
pData[p + 0] = hi;
}
}
} finally {
bmpImage->UnlockBits(data);
}
Note: This was written in C++/CLI. Let me know if you need C# equivalents for any of the operations here. (Also, I pulled it from a read from bitmap rather than a write to bitmap so it may yet be a bit rough, but should hopefully give you the idea...)

I figured this out Although i'm still not sure why it should matter.
Based on this stackoverflow posting How can I load the raw data of a 48bpp image into a Bitmap?
I used the WPF classes instead of the GDI and wrote the code like this
var bitmap = new WriteableBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.BlackWhite, null);
bitmap.WritePixels(new System.Windows.Int32Rect(0, 0, width, height), newarray, stride, 0);
MemoryStream stream3 = new MemoryStream();
var encoder = new TiffBitmapEncoder ();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
encoder.Save(stream3);
This correctly creates the image.
If anyone has any insight into why this might be the case please comment below
The port which now mostly works(lots of cleanup code) was based on a java implementation of JPedal Big2 Decoder to .NET. If anyone knows anyone interested send them here
https://github.com/devteamexpress/JBig2Decoder.NET

Related

Is it possible to achieve the actual binary numbers from a bitmap?

My professor kind of "challenged me" to create an application that draws pixel by pixel an image converted in Bitmap, where it's data is saved in some sort of binary that I can't wrap my head around.
Here's the example given to me:
const byte image[]={
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,
ect ect ect
Now, if the byte data type saves numbers that go from 0 to 255, how is this possible? In the sample code that I was given, there is also the use of "Word" data type but in my IDE it seems like it doesn't exist.
I already wrote the code that converts any image given in input into a bitmap:
FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read); //Path is image location
Byte[] bindata = new byte[Convert.ToInt32(fs.Length)];
fs.Read(bindata, 0, Convert.ToInt32(fs.Length));
Bitmap bmp;
using (var ms = new MemoryStream(bindata))
{
bmp = new Bitmap(ms);
}
pictureBox1.Image = bmp; //For now, I just display the converted image on screen
Now I suppose that the next step is to draw the image byte per byte, but I can't get my head around this binary thing and the word data type.. Any kind of help is appreciated :)
if you just want to draw a bitmap pixel at a time, you can do something like this:
Bitmap b = new Bitmap(10, 10);
b.SetPixel(0, 0, Color.Black);
b.SetPixel(1, 3, Color.Red);
pictureBox1.Image = b;
You can just copy your bytes to the Bitmap's memory buffer itself.
BitmapData bufferData = buffer.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
bufferData.SetPixel(x, y, CELL_DEAD);
buffer.UnlockBits(bufferData);
//////////
public static unsafe void SetPixel(BitmapData data, int x, int y, byte pixel)
{
*((byte*)data.Scan0 + y * data.Stride + x) = pixel;
}
I've used it as unsafe but you can play your magic with IntPtr. Of course, you must play your own with width-height synchronization.
UPD: set PixelFormat with care. PixelFormat.Format8bppIndexed is what you need if your colors are in default 256-color palette or you want to define your own palette.

C# - RGB Buffer from Bitmap different from C++

I'm using a third party DLL which has as parameter a RGB buffer.
I have used the following code to read RGB buffer from Bitmap:
private byte[] GetBGRValues(Bitmap bmp)
{
// 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.ReadOnly, PixelFormat.Format24bppRgb);
// 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);
bmp.UnlockBits(bmpData);
return rgbValues;
}
The problem is that the generated RGB buffer is not correct. If I open this buffer in IrfanView, supplying correct parameters, the generated image is not correct (looks like it is shifted).
If a get a buffer that I read using C++ code it works.
I have noticed that bmpData.Stride is 1 unity greater than what I was expecting (width * channels). (I know that .NET uses 4 bytes alignment).
The question is: why is the RGB buffer not correct?
You noticed right - you need to take Stride into account. In general you cannot simply copy image in one Copy call. Stride include both row length and padding and could be greater then row length. So you need to copy only bytes you need from each row, ignore padding bytes and advance to next row by adding Stride.
I guess this is what you see with your code:
- original image and expected result
- invalid result without stride
Here is working code:
public static byte[] GetBGRValues(Bitmap bmp)
{
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
var bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
var imgBytes = bmp.Height * rowBytes;
byte[] rgbValues = new byte[imgBytes];
var ptr = bmpData.Scan0;
for (var i = 0; i < bmp.Height; i++)
{
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
ptr += bmpData.Stride; // next row
}
bmp.UnlockBits(bmpData);
return rgbValues;
}
More details you can read in this answer: Byte Array to Image Conversion
Also maybe this image will help you to understand Stride purpose:
You need to skip white area at the right when you getting bytes from Bitmap.
Be sure you watch that the order is B-G-R instead of R-G-B
You can try this unsafe code which converts the values to uint. So you have RGB converted to uint
/// <summary>
/// Locks a Bitmap into system memory.
/// </summary>
public unsafe void LockBits()
{
var width = this.Bitmap.Width;
var height = this.Bitmap.Height;
var imageLockMode = ImageLockMode.UserInputBuffer;
// Setting imageLockMode
imageLockMode = imageLockMode | ImageLockMode.ReadOnly;
imageLockMode = imageLockMode | ImageLockMode.WriteOnly;
// Save the bouunds
this._bounds = new Rectangle(0, 0, width, height);
// Create Pointer
var someBuffer = new uint[width*height];
// Pin someBuffer
fixed (uint* buffer = someBuffer) //pin
{
// Create new bitmap data.
var temporaryData = new BitmapData
{
Width = width,
Height = height,
PixelFormat = PixelFormat.Format32bppArgb,
Stride = width*4,
Scan0 = (IntPtr) buffer
};
// Get the data
this.BitmapData = this.Bitmap.LockBits(this._bounds, imageLockMode, PixelFormat.Format32bppArgb,
temporaryData);
// Set values
this.Buffer = someBuffer;
}
}
I remember a library I working on years ago - the colors were shifted strangely. The underlying Microsoft Library had a (feature) in that the RGB had been reversed inside the library - unbeknownst to us we tried a transform and discovered that little gem.
Also do not forget the Alpha Channel in your C# buffer.
Bitmap color channels in memory are represented in the order Blue, Green, Red and Alpha despite being commonly referred to by abbreviation ARGB!
http://softwarebydefault.com/2013/03/22/bitmap-swap-argb/

Why are pixel values of an image different between reading methods?

This puzzles me for last two hours. Reading an image file results in different pixel values between imread in Matlab and Image.FromFile in C#?
aa=imread('myfile.tif')
max(aa(:)) = 248 in matlab
In C#
var image2Array = imageToByteArray((Bitmap) Image.FromFile("myfile.tif"));
byte maxx = 0;
foreach(var a in image2Array)
{
maxx = Math.Max(maxx, a);
}
//maxx = 255
Futhermore, in Matlab,
aa(1,1) = 13,
aa(1,2) = 13
but in C#
image2Array[0]=17,
image2Array[1]=0
They should be the same.
BTW, in this case, pixel type is uint8. so there is no dimensional difference.
If you ask me how I got byte array from Image, I used MSDN document to make this method.
public byte[] imageToByteArray(Bitmap bmp)
{
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(
rect,
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);
// Unlock the bits.
bmp.UnlockBits(bmpData);
return rgbValues;
}
What did I do wrong here? I suspect that they use different reading algorithms because two resulting images look same.
UPDATE:
I don't think there is anything wrong with what I was doing. I concluded that reading tif as a bitmap was the cause of the problem. To confirm this theory,
I displayed the two images and they looked exactly the same. So there is no mistake on my part, I think.
I tried to read the same file with opencv and its pixel values were exactly the same as the ones from matlab. This was surprisingly to me. I would very cautiously use Bitmap in C# from now on.
Your imageToByteArray method does return a byte array, but you can't assume each byte is a pixel. The PixelFormat determines how the pixel data is stored in the byte array.
The best site I've seen that documents this is Bob Powell's lockbits page.
If the PixelFormat is Format8bppIndexed, then this (untested) code should give you the color values for each pixel.
var bmp = (Bitmap)Bitmap.FromFile("myfile.tif");
// ******* Begin copying your imageToByteArray method
// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData bmpData = bmp.LockBits(
rect,
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[] imageData = new byte[bytes];
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, imageData, 0, bytes);
// Unlock the bits.
bmp.UnlockBits(bmpData);
// ******* End copying your imageToByteArray method
// Now loop through each pixel... The byte array contains extra bytes
// used for padding so we can't just loop through every byte in the array.
// This is done by using the Stride property on bmpData.
for (int y = 0; y < bmpData.Height; y++)
{
for (int x = 0; x < bmpData.Width; x++)
{
var offset = (y * bmpData.Stride) + x;
// The byte in the image array gives the offset into the palette
var paletteIndex = imageData[offset];
// Given the offset, find the matching color in the palette
var color = bmp.Palette.Entries[offset];
// Look at the color value here...
}
}
TIFF has many formats, you are attempting to read it as a bitmap.
I suggest reading it using a proprietary TIFF reader instead : Good Tiff library for .NET

System.Drawing.Bitmap contains more data than expected

I have a method to copy the data out of a System.Drawing.Bitmap which looks like this:
var readLock = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
byte[] data = new byte[3 * image.Width * image.Height];
if (data.Length != readLock.Stride * readLock.Height)
throw new InvalidOperationException("Incorrect number of bytes");
Marshal.Copy(readLock.Scan0, data , 0, data.Length);
image.UnlockBits(readLock);
Pretty simple, and it works for most of my images. However for a very small image (14x14) it hits the exception. In the failing case Stride is 44, not 42 (14 * 3) as expected.
The pixel format is Format24bppRgb, so there should be three bytes for every pixel in the image. Where are these extra bytes coming from, and how can I deal with them when processing the image data?
For anyone interested, I'm generating Normal data from a heightmap, so I need to be able to get each pixel and its neighbours accurately).
Every pixel line of Bitmap must be aligned, that's why stride is not always width * bytes-per-pixel. You should ignore any extra bytes. It means that if you are working with byte arrays with unaligned data, you might not always be able to copy all image data in a single Marshal.Copy() call. Every line of pixels starts at readLock.Scan0 + y * readLock.Stride and contains readLock.Width * bytes-per-pixel meaningful bytes.
Solution:
const int BYTES_PER_PIXEL = 3;
var data = new byte[readLock.Width * readLock.Height * BYTES_PER_PIXEL];
if(readLock.Stride == readLock.Width * BYTES_PER_PIXEL)
{
Marshal.Copy(readLock.Scan0, data, 0, data.Length);
}
else
{
for(int y = 0; y < readLock.Height; ++y)
{
IntPtr startOfLine = (IntPtr)((long)readLock.Scan0 + (readLock.Stride * y));
int dataOffset = y * readLock.Width * BYTES_PER_PIXEL;
Marshal.Copy(startOfLine, data, dataOffset, readLock.Width * BYTES_PER_PIXEL);
}
}

reading a jpeg file in c#

I have a doubt in c#. How to read a jpeg or bmp file using c#? and how to store the pixel's RGB values in array? Then how to check whether the value is already exist or not?
James Schek has it, but beware that GetPixel is extremely, incredibly slow.
Here's a complete sample using lockbits:
/*Note unsafe keyword*/
public unsafe Image ThresholdUA(float thresh)
{
Bitmap b = new Bitmap(_image);//note this has several overloads, including a path to an image
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);
/*This time we convert the IntPtr to a ptr*/
byte* scan0 = (byte*)bData.Scan0.ToPointer();
for (int i = 0; i < bData.Height; ++i)
{
for (int j = 0; j < bData.Width; ++j)
{
byte* data = scan0 + i * bData.Stride + j * bitsPerPixel / 8;
//data is a pointer to the first byte of the 3-byte color data
}
}
b.UnlockBits(bData);
return b;
}
There's another way to do it using marshaling though. Here's the same thing, but with marshaling:
/*No unsafe keyword!*/
public Image ThresholdMA(float thresh)
{
Bitmap b = new Bitmap(_image);
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
/* GetBitsPerPixel just does a switch on the PixelFormat and returns the number */
byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);
/*the size of the image in bytes */
int size = bData.Stride * bData.Height;
/*Allocate buffer for image*/
byte[] data = new byte[size];
/*This overload copies data of /size/ into /data/ from location specified (/Scan0/)*/
System.Runtime.InteropServices.Marshal.Copy(bData.Scan0, data, 0, size);
for (int i = 0; i < size; i += bitsPerPixel / 8 )
{
double magnitude = 1/3d*(data[i] +data[i + 1] +data[i + 2]);
//data[i] is the first of 3 bytes of color
}
/* This override copies the data back into the location specified */
System.Runtime.InteropServices.Marshal.Copy(data, 0, bData.Scan0, data.Length);
b.UnlockBits(bData);
return b;
}
Read the file using the Bitmap class.
Lock pixels.
Retrieve bytes from array.
Alternatively, you can use GetPixel if you just need one or two.
You can use Image.FromFile (http://msdn.microsoft.com/en-us/library/system.drawing.image.fromfile.aspx) to create an Image object from an image on disk.
As it was already mentioned, the fastest way to retrieve pixels is to use LockBits(), however, there's a way to do it without Marshal.Copy or unsafe code.
First, you'll need to compute Stride of your image:
var stride = ComputeStride(img.Width, format);
it is width*bytesPerPixel value rounded up to be divisible by 4. See formulas here.
Then you'll need to initialize an array of the required size:
var pixels = new byte[img.Height*stride]
Then you'll need to retrieve an unmanaged pointer to the beginning of this array.
You may use Marshal.UnsafeAddrOfPinnedArrayElement(pixels, 0), but it's safer to pin the array in memory:
var handle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
var scan0 = pixels.AddrOfPinnedObject();
You'll need to create BitmapData structure:
var bData = new BitmapData{Width = img.Width, height = img.Height, Stride = stride, Scan0 = scan0};
Then you'll pass it to LockBits method while setting ImageLockMode.UserInputBuffer flag.
img.LockBits(area, ImageLockMode.Readonly | ImageLockMode.UserInputBuffer, format, bData);
Voila! Pixels are stored in pixels array. But you'll need to unpin your buffer:
handle.Free();
This may seem cumbersome, but this is the fastest way, since only one copying of data is required.

Categories