I am trying to display a bitmap that is stored in a binary file.
The binary file is set up like so:
A Header structure that is 1024 bytes.
Pixels for the bitmap image (width * height * bytesperpixel - the header struct contains this info).
First I create a byte array:
var headerArray = new byte[Marshal.SizeOf(typeof(TestClass.BMPStruct))]; //size of the struct here is 1024
Then I create a FileStream on the file and read in the header first. I get bitmap's width + height + bytesperpixel from the header struct, and then read in the right amount of bytes after the header.
I then create a memory stream on those bytes and try creating a new bitmap.
using (FileStream fs = new FileStream(#"C:\mydrive\testFile.onc", FileMode.Open))
{
fs.Position = 0; //make sure the stream is at the beginning
fs.Read(headerArray, 0, 1024); //filestream position is 1024 after this
var headerStruct = StructsHelper.ByteArrayToStructure<TestClass.BMPStruct>(headerArray);
int bytesperpixel = headerStruct.BitsPerPixel / 8; //headerStruct.BitsPerPixel is 8 here
int pixelscount = headerStruct.BitmapWidth * headerStruct.BitmapHeight * bytesperpixel; //BitmapWidth = 296, BitmapHeight = 16, bytesperpixel = 1
var imageArray = new byte[pixelscount]; //pixelscount = 4736
try //now read in the bitmap's bytes
{
fs.Read(imageArray, 0, pixelscount); //filestream position is 5760 after this line
}
catch (Exception ex)
{
}
Bitmap bmp;
using (var ms = new MemoryStream(imageArray))
{
try
{
bmp = new Bitmap(ms); //error thrown here Exception thrown: 'System.ArgumentException' in System.Drawing.dll
//Parameter is not valid
}
catch (Exception ex)
{
}
}
}
On the line bmp = new Bitmap(ms), I get a System.ArgumentException in System.Drawing.dll. My try/catch shows a Parameter is not valid. exception.
I've seen a few other questions on this site with the same error, but none of the solutions have worked from the ones I've seen.
Related
I'm having some trouble converting an image to a video using the SharpAVI.dll.
I have managed to produce a video file using a randomly generated byte array by using the documentation on SharpAVI's website:
Getting Started with SharpAVI
So the next step I thought I would take was to take an Image, create a Bitmap image, convert the bitmap to a byte array and then simply save the byte array to each frame of the video file. When I run the program, I get no errors or anything and a video file of an appropriate file size is produced however the video file is unreadable and will not open. I'm really struggling to see why this won't work. Any help would be greatly appreciated!
My Code:
private void GenerateSingleImageVideo()
{
string imagePath = textBoxImagePath.Text;
Bitmap thisBitmap;
//generate bitmap from image file
using (Stream BitmapStream = System.IO.File.Open(imagePath, FileMode.Open))
{
Image img = Image.FromStream(BitmapStream);
thisBitmap = new Bitmap(img);
}
//convert the bitmap to a byte array
byte[] byteArray = BitmapToByteArray(thisBitmap);
//creates the writer of the file (to save the video)
var writer = new AviWriter(textBoxFileName.Text + ".avi")
{
FramesPerSecond = int.Parse(textBoxFrameRate.Text),
EmitIndex1 = true
};
var stream = writer.AddVideoStream();
stream.Width = thisBitmap.Width;
stream.Height = thisBitmap.Height;
stream.Codec = KnownFourCCs.Codecs.Uncompressed;
stream.BitsPerPixel = BitsPerPixel.Bpp32;
int numberOfFrames = ((int.Parse(textBoxFrameRate.Text)) * (int.Parse(textBoxVideoLength.Text)));
int count = 0;
while (count <= numberOfFrames)
{
stream.WriteFrame(true, byteArray, 0, byteArray.Length);
count++;
}
writer.Close();
MessageBox.Show("Done");
}
private byte[] BitmapToByteArray(Bitmap img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
You're wrong in assuming that you should pass a Bitmap object to WriteFrame method. It expects pixel data in bottom to top 32bpp format. See example in
// Buffer for pixel data
var buffer = new byte[width * height * 4];
...
// Copy pixels from Bitmap assuming it has expected 32bpp pixel format
var bits = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
bitmap.UnlockBits(bits);
You can see code of a sample app as a reference
https://github.com/baSSiLL/SharpAvi/blob/master/Sample/Recorder.cs
I have 10-bits and 12-bits rawbayer (.raw) file. And i want to convert it to Bitmap image but i am unable to change it. 8-bits or 16-bits raw file changed easily but 10-bits or 12-bits can't be changed.
here is the code for 8-bits raw file to Bitmap.
private void DisplayImage08(string fileName) //Raw file name
{
// Open a binary reader to read in the pixel data.
// We cannot use the usual image loading mechanisms since this is raw
// image data.
try
{
BinaryReader br = new BinaryReader(File.Open(fileName, FileMode.Open));
byte pixByte;
int i;
int iTotalSize = (int)br.BaseStream.Length;
// Get the dimensions of the image from the user
ID = new ImageDimensions(iTotalSize);
width = Convert.ToInt32(ID.txtwidth);
height = Convert.ToInt32(ID.txtheight);
//panel1.Width = width;
//panel1.Height = height;
pictureBox1.Width = width;
pictureBox1.Height = height;
pix08 = new byte[iTotalSize];
//pix08 = new byte[iTotalSize];
for (i = 0; i < iTotalSize; ++i)
{
pixByte = (byte)(br.ReadByte());
pix08[i] = pixByte;
}
br.Close();
int bitsPerPixel = 8;
stride = (width * bitsPerPixel + 7) / 8;
// Single step creation of the image
bmps = BitmapSource.Create(width, height, 96, 96, PixelFormats.Gray8, null,
pix08, stride);
//Bitmap bmp = new Bitmap();
// img.Source = bmps;
Bitmap bt = BitmapFromSource(bmps); //Change Bitmap source to Bitmap
pictureBox1.Image = bt; //Display on pictureBox
pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
}
catch (Exception e)
{
}
}
But i want to change 12-bits or 10 bits raw file to Bitmap.
So please help me on this, that how can i change it?
Thanks
This isn't a complete answer by no means, but this code will convert a 12 or 10 bit image, depending on how the data is packed, to a 8 bit image.
// Input data read from file
var pixels = ...
// Output
var bytes = new byte[width * height];
// Sort data
for (var i = 0; i < bytes.Length; i++)
{
if (i % 2 == 0)
{
var index = i * 3 / 2;
bytes[i] = pixels[index];
}
else
{
var index = (i * 3 + 1) / 2;
bytes[i] = pixels[index];
}
}
I have a problem.
I´m generating a dynamic BMP image and trying to send this to a ZEBRA printer by ZPL commands.
I need to convert my BMP to a GRF image. I think that my Hexadecimal extracted by the BMP image isn´t correct.
The printed image is blurred and incorrect.
This is my code:
string bitmapFilePath = #oldArquivo; // file is attached to this support article
byte[] bitmapFileData = System.IO.File.ReadAllBytes(bitmapFilePath);
int fileSize = bitmapFileData.Length;
Bitmap ImgTemp = new Bitmap(bitmapFilePath);
Size ImgSize = ImgTemp.Size;
ImgTemp.Dispose();
// The following is known about test.bmp. It is up to the developer
// to determine this information for bitmaps besides the given test.bmp.
int width = ImgSize.Width;
int height = ImgSize.Height;
int bitmapDataOffset = 62; // 62 = header of the image
int bitmapDataLength = fileSize - 62;// 8160;
double widthInBytes = Math.Ceiling(width / 8.0);
// Copy over the actual bitmap data from the bitmap file.
// This represents the bitmap data without the header information.
byte[] bitmap = new byte[bitmapDataLength];
Buffer.BlockCopy(bitmapFileData, bitmapDataOffset, bitmap, 0, (bitmapDataLength));
// Invert bitmap colors
for (int i = 0; i < bitmapDataLength; i++)
{
bitmap[i] ^= 0xFF;
}
// Create ASCII ZPL string of hexadecimal bitmap data
string ZPLImageDataString = BitConverter.ToString(bitmap).Replace("-", string.Empty);
string comandoCompleto = "~DG" + nomeImagem + ".GRF,0" + bitmapDataLength.ToString() + ",0" + widthInBytes.ToString() + "," + ZPLImageDataString;
Try the following code. Not tested!
public static string CreateGRF(string filename, string imagename)
{
Bitmap bmp = null;
BitmapData imgData = null;
byte[] pixels;
int x, y, width;
StringBuilder sb;
IntPtr ptr;
try
{
bmp = new Bitmap(filename);
imgData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
width = (bmp.Width + 7) / 8;
pixels = new byte[width];
sb = new StringBuilder(width * bmp.Height * 2);
ptr = imgData.Scan0;
for (y = 0; y < bmp.Height; y++)
{
Marshal.Copy(ptr, pixels, 0, width);
for (x = 0; x < width; x++)
sb.AppendFormat("{0:X2}", (byte)~pixels[x]);
ptr = (IntPtr)(ptr.ToInt64() + imgData.Stride);
}
}
finally
{
if (bmp != null)
{
if (imgData != null) bmp.UnlockBits(imgData);
bmp.Dispose();
}
}
return String.Format("~DG{0}.GRF,{1},{2},", imagename, width * y, width) + sb.ToString();
}
One thing to point out is that the bitmap being converted must be monochrome (that is, 1 bit per pixel). There is an example on Zebra's knowledgebase that demonstrates printing a simple monochrome image in ZPL: https://km.zebra.com/kb/index?page=answeropen&type=open&searchid=1356730396931&answerid=16777216&iqaction=5&url=https%3A%2F%2Fkm.zebra.com%2Fkb%2Findex%3Fpage%3Dcontent%26id%3DSA304%26actp%3Dsearch%26viewlocale%3Den_US&highlightinfo=4194550,131,153#. If you can convert your images into monochrome bitmaps, then you should be able to follow that example.
// Given a monochrome bitmap file, one can read
// information about that bitmap from the header
// information in the file. This information includes
// bitmap height, width, bitsPerPixel, etc. It is required
// that a developer understands the basic bitmap format and
// how to extract the following data in order to proceed.
// A simple search online for 'bitmap format' should yield
// all the needed information. Here, for our example, we simply
// declare what the bitmap information is, since we are working
// with a known sample file.
string bitmapFilePath = #"test.bmp"; // file is attached to this support article
byte[] bitmapFileData = System.IO.File.ReadAllBytes(bitmapFilePath);
int fileSize = bitmapFileData.Length;
// The following is known about test.bmp. It is up to the developer
// to determine this information for bitmaps besides the given test.bmp.
int bitmapDataOffset = 62;
int width = 255;
int height = 255;
int bitsPerPixel = 1; // Monochrome image required!
int bitmapDataLength = 8160;
double widthInBytes = Math.Ceiling(width / 8.0);
// Copy over the actual bitmap data from the bitmap file.
// This represents the bitmap data without the header information.
byte[] bitmap = new byte[bitmapDataLength];
Buffer.BlockCopy(bitmapFileData, bitmapDataOffset, bitmap, 0, bitmapDataLength);
// Invert bitmap colors
for (int i = 0; i < bitmapDataLength; i++)
{
bitmap[i] ^= 0xFF;
}
// Create ASCII ZPL string of hexadecimal bitmap data
string ZPLImageDataString = BitConverter.ToString(bitmap);
ZPLImageDataString = ZPLImageDataString.Replace("-", string.Empty);
// Create ZPL command to print image
string[] ZPLCommand = new string[4];
ZPLCommand[0] = "^XA";
ZPLCommand[1] = "^FO20,20";
ZPLCommand[2] =
"^GFA, " +
bitmapDataLength.ToString() + "," +
bitmapDataLength.ToString() + "," +
widthInBytes.ToString() + "," +
ZPLImageDataString;
ZPLCommand[3] = "^XZ";
// Connect to printer
string ipAddress = "10.3.14.42";
int port = 9100;
System.Net.Sockets.TcpClient client =
new System.Net.Sockets.TcpClient();
client.Connect(ipAddress, port);
System.Net.Sockets.NetworkStream stream = client.GetStream();
// Send command strings to printer
foreach (string commandLine in ZPLCommand)
{
stream.Write(ASCIIEncoding.ASCII.GetBytes(commandLine), 0, commandLine.Length);
stream.Flush();
}
// Close connections
stream.Close();
client.Close();
Please add 2 to widthInBytes - it works!!!
int bitmapDataOffset = int.Parse(bitmapFileData[10].ToString()); ;
int width = 624;// int.Parse(bitmapFileData[18].ToString()); ;
int height = int.Parse(bitmapFileData[22].ToString()); ;
int bitsPerPixel = int.Parse(bitmapFileData[28].ToString()); // Monochrome image required!
int bitmapDataLength = bitmapFileData.Length - bitmapDataOffset;
double widthInBytes = Math.Ceiling(width / 8.0)+2;
I made this code to receive an image and convert it to bitmap image but it doesn't work.
Here is the code:
public void ReceiveImage()
{
NetworkStream stream = new NetworkStream(socket);
byte[] data = new byte[4];
stream.read(data,0,data.length,0)
int size = BitConverter.ToInt32(data,0);
data = new byte[size];
stream.read(data,0,data.length)
MemoryStream imagestream = new MemoryStream(data);
Bitmap bmp = new Bitmap(imagestream);
picturebox1.Image = bmp;
}
It gets to:
Bitmap bmp = new Bitmap(imagestream);
And gives me this error:
Parameter is not valid
This is an alternative method
int w= 100;
int h = 200;
int ch = 3; //number of channels (ie. assuming 24 bit RGB in this case)
byte[] imageData = new byte[w*h*ch]; //you image data here
Bitmap bitmap = new Bitmap(w,h,PixelFormat.Format24bppRgb);
BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat);
IntPtr pNative = bmData.Scan0;
Marshal.Copy(imageData,0,pNative,w*h*ch);
bitmap.UnlockBits(bmData);
You are probably not receiving enough bytes in stream.read(data,0,data.length) since Read does not ensure that it will read data.length bytes. you have to check its return value and continue to read till data.Length bytes are read.
See : Stream.Read Method's return value
int read = 0;
while (read != data.Length)
{
read += stream.Read(data, read, data.Length - read);
}
PS: I am assuming lengths and reads are typos.
I assume you have a table and want to receive the picture from database.
int cout = ds.Tables["TableName"].Rows.Count;
if (cout > 0)
{
if (ds.Tables["TableName"].Rows[cout - 1]["Image"] != DBNull.Value)
{
var data = (byte[])(ds.Tables["TableName"].Rows[cout - 1]["Image"]);
var stream = new MemoryStream(data);
pictureBox1.Image = Image.FromStream(stream);
}
else
{
pictureBox1.Image = null;
}
}
Try this:
int size = BitConverter.ToInt32(data.Reverse().ToArray(),0);
I have a byte[] array received in TCP Client.The array contains a 24-bit RGB Bitmap file.How to create that bitmap file with given Width ,Height and data?
In C++ I use this
int WriteBitmapFile(const char *filename, int width, int height, unsigned char *imageData)
{
FILE *filePtr; // file pointer
BITMAPFILEHEADER bitmapFileHeader; // bitmap file header
BITMAPINFOHEADER bitmapInfoHeader; // bitmap info header
DWORD imageIdx; // used for swapping RGB->BGR
unsigned char tempRGB; // used for swapping
// open file for writing binary mode
filePtr = fopen(filename, "wb");
if (!filePtr)
return 0;
// define the bitmap file header
bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER);
bitmapFileHeader.bfType = 0x4D42;
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
// define the bitmap information header
bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 32; // 24-bit
bitmapInfoHeader.biCompression = BI_RGB; // no compression
bitmapInfoHeader.biSizeImage = width * abs(height) * 4; // width * height * (RGB bytes)
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
bitmapInfoHeader.biWidth = width; // bitmap width
bitmapInfoHeader.biHeight = height; // bitmap height
// switch the image data from RGB to BGR
for(imageIdx = 0; imageIdx < bitmapInfoHeader.biSizeImage; imageIdx+=4)
{
tempRGB = imageData[imageIdx];
imageData[imageIdx] = imageData[imageIdx + 2];
imageData[imageIdx + 2] = tempRGB;
}
// write the bitmap file header
fwrite(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), filePtr);
// write the bitmap info header
fwrite(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), filePtr);
// write the image data
fwrite(imageData, 1, bitmapInfoHeader.biSizeImage, filePtr);
// close our file
fclose(filePtr);
// Success
return 1;
}
How could I do that in C#?
If the array actually contains a bitmap file, then you can just save the bytes as a file:
File.WriteAllBytes(fileName, imageData);
If the array contains only raw pixel data, you can create a Bitmap object using the data:
unsafe {
fixed (byte* ptr = imageData) {
using (Bitmap image = new Bitmap(width, height, stride, PixelFormat.Format24bppRgb, new IntPtr(ptr))) {
image.Save(fileName);
}
}
}
The stride value is the number of bytes between the scan lines. If there is no padding between the scan lines, it's width * 3 for a 24bpp format.
This method uses the data in the array without creating another copy of the entire image in memory (which is why it needs the stride value).
If the bitmap data is stored upside down in the array, the stride value should be negative, and the pointer should be the start of the last scan line in memory (ptr + stride * (height - 1)).
I can't test it using the stream you will be receiving, but this should work.
int WriteBitmapFile(string filename, int width, int height, byte[] imageData)
{
using (var stream = new MemoryStream(imageData))
using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width,
bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
Marshal.Copy(imageData, 0, bmpData.Scan0, imageData.Length);
bmp.UnlockBits(bmpData);
bmp.Save(filename);
}
return 1;
}
I'd recommend making a Bitmap in C#, and letting it save itself.
For an example, see this post. (Particularly, the last response is correct.)
this is one way of doing it, here i have created a custom Event args that contains the size at which the image was stored as a byte array. You may not need to bother with this, this was code i created to retreive images from a byte array that a gige camera was storing to so for me this made sence.
public Bitmap ShowImage(byte[] sender, EventImageParams e)
{
Bitmap bitmap = new Bitmap(e.width, e.height, PixelFormat.Format24bppRgb);
BitmapData bmData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
IntPtr pNative = bmData.Scan0;
Marshal.Copy(sender, 0, pNative, (e.width * e.height * 3));
//
bitmap.UnlockBits(bmData);
return bitmap;
}