there a way to determine that I am passing the right byte array to the MemoryStream if I want to create an Image out of byte array.
MemoryStream mStream = new MemoryStream();
mStream.Write(byteArray, 0, byteArray.Lenth);
Image imgObj = Image.FromStream(mStream);
How can I, if possible Correct the byteArray that it is a valid byteArray for an Image?
This is a really ominous question, surely you must know where you are reading your data from? When you create an image using Image.FromStream, an ArgumentException will be thrown if it cannot recognise the format. Why don't you use that mechanism for identifying an incorrect stream of data, rather than re-invent the wheel?
I've done a bit of programatic image manipulation myself. The thing you'll want to do is find the spec for the image format that you are modifying and make sure you do everythign you should. For example png files are chunked and have checksums on each section so if you change something in that chunk you have to recalculate the checksum at the end of the section.
After reading your questions and your comments, i think what you're trying is to manipulate the image by manipulating the byte array before you put it into the Image class. And now you claim that your byte array is corrupt for this image format and how you can correct it.
So the answer to this question would be: You corrupted it, you'll fix it.
But to really solve your problem, if your goal is to manipulate the picture itself, just load it into an interims Image and use the Graphics class to manipulate your picture. Afterwards put the result into the real image object you like. Ready, without any hassle about working on the byte array.
here's the answer Image Processing for Dummies with C# and GDI+
OT: i don't know how to put links on comments so I put it in the answers.
Related
I am trying to validate an image submitted to backend in Base64 string format by parsing it into an Image object, extracting it from the same Image object and finally comparing input byte array and output byte array assuming these two should be the same or there was something wrong in the input image. Here is the code:
private void UpdatePhoto(string photoBase64)
{
var imageDataInBytes = Convert.FromBase64String(photoBase64);
ValidateImageContent(imageDataInBytes);
}
private void ValidateImageContent(byte[] imageDataInBytes)
{
using (var inputMem = new MemoryStream(imageDataInBytes))
{
var img = Image.FromStream(inputMem, false, true);
using (MemoryStream outputMemStream = new MemoryStream())
{
img.Save(outputMemStream, img.RawFormat);
var outputSerialized = outputMemStream.ToArray();
if (!outputSerialized.SequenceEqual(imageDataInBytes))
throw new Exception("Invalid image. Identified extra data in the input. Please upload another photo.");
}
}
}
and it fails on an image that I know is a valid one.
Is my assumption wrong that output of Image.Save must be the same as what Image.FromStream is fed with? Is there a way to correct this logic to achieve this way of validation correctly?
If you compare the original image with the created image, you will notice a few differences in the metadata: For my sample image, I could observe that some metadata was stripped (XMP data was completely removed). In addition, while the EXIF data was preserved, the endianness it is written in was reversed from little endian to big endian. This alone explains why the data won’t match.
In my example, the actual image data was identical but you won’t be able to tell easily from just looking at the bytes.
If you wanted to produce a result identical to the source, you would have to produce the metadata in the exact same way as the source did. You won’t be able to do so without actually looking closely at the metadata of the original photo though. .NET’s Image simply isn’t able to pertain all the metadata that a file could contain. And even if you were able to extract all the metadata and store it in the right format again, there are lots of fine nuances between metadata serializers that make it very difficult to produce the exact same result.
So if you wanted to compare the images, you should probably strip the metadata and just compare the image data. But then, when you think about how you save the image (Raw), then you will just get the exact same blob of data again, so I wouldn’t expect differences there.
I'm using the following code to Decode Jpge image
UnmanagedMemoryStream^ mStream = gcnew UnmanagedMemoryStream(_jpegDataBuff, _buffLength);
JpegBitmapDecoder^ decoder = gcnew JpegBitmapDecoder(mStream, BitmapCreateOptions::PreservePixelFormat, BitmapCacheOption::OnLoad);
BitmapSource^ bitmapSource = decoder->Frames[0];
I use the bitmapSource to display on control of WPF, but sometimes the the result as below
I have searched very much on internet, but I did not solve it yet!
Someone can help me?
Many Thanks,
T&T
From the looks of it I would say that either JPEG source is incomplete or invalid. The only exceptions JpegBitmapDecoder throws are ArgumentNullException (stream is null) and FileFormatException. The file format is most probably detected by analyzing file header. The JIF/JFIF file structure holds image description information in a relatively small header followed by a "raw" data.
I guess that decoder is built resilient to ignore invalid (rendered last before gray) and/or missing (rendered gray) blocks. I think the only way to detect is to either analyze final image (maybe checking that last 8x8px block doesn't have same color?) or source (maybe counting data blocks?).
I find when I use the Bitmap.Save method with format ImageFormat.Bmp that the bitmap header info in the file has zero in the biSizeImage field.
From what I can see this is ok according to the specs, but unfortunately the crappy embedded device I am forced to work with insists on it being set correctly.
So the question is how to go about getting this header info field always set when the bitmap is saved?
The issue, as you suspect, is that 0 is a perfectly allowable value for the image size field of an RGB bitmap. The MSDN documentation for the BITMAPINFOHEADER structure confirms this fact:
biSizeImage
The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.
If biCompression is BI_JPEG or BI_PNG, biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.
So the implementation in the .NET Framework is simply doing things the standard, documented way. Since you need something else, you'll have to handle the save to file process yourself, which will allow you to manually modify the biSizeImage member of the BITMAPINFOHEADER structure.
A pretty comprehensive example is available here: Saving a Control Image to a Bitmap File. Of course, it's written for the Compact Framework, but most of the individual components are still applicable. You'll need to P/Invoke several functions from the Windows API (visit www.pinvoke.net for the definitions), and work with a DC.
Taking the drawing into your own hands will probably also be faster, because you're using the GDI subsystem, rather than GDI+. An article on that general approach is available here: 1bpp in C#, and it appears to demonstrate taking matters into your own hands with the BITMAPINFOHEADER struct as well.
If you understand unmanaged C++ code, there's a tutorial available here that might give you some idea of what you'd have to implement in C# to do the same thing: Loading and Saving Bitmaps. As you can see, the code required really isn't that long, albeit still more than the one line Bitmap.Save method.
I encountered with this problem too and it solved with a simple trick.
save the bitmap, then open it as a file stream and change the biSizeimage field manually.
picbpp.Save("pic.bmp", ImageFormat.Bmp);
string path = "pic.bmp";
FileStream fs = File.Open(path, FileMode.Open, FileAccess.Write, FileShare.None);
// Change biSizeimage field manually.
Byte[] info = new byte[] {0x10,0x59};
fs.Seek(34, SeekOrigin.Begin);
fs.Write(info, 0, info.Length);
fs.Close();
I have an application that use the image captured by the mobile camera and sends it to a webservice. Currently I am putting the image in a byte[] which then will be transmitted. This is done by:
filename = cameracapturedialog.FileName;
FileStream fs = new FileStream(filename, FileMode.Open);
byte[] ImageByte = new byte[fs.Length]; //file to send
fs.Read(ImageByte, 0, Convert.ToInt32(fs.Length));
But now I would like to perform some processing (resizing), hence I had to put the image into a BITMAP object, and after the processing I will convert it back to JPEG.
Is there a way to convert a JPEG into Bitmap and then back to JPEG without having no changes in the pixels (for testing I will perform no processing on the Bitmap)? Hence if I compare the first JPEG with the second JPEG I need that the files will be exactly the same.
What do you think the best solution is? Can I use something else instead of Bitmap. Any suggestion with some code will be greatly appreciated.
JPG is a lossy format. It will ALWAYS lose information because of the way the encoding algorithm works. So you'll never get the original image from a jpg, no matter what encoder you use.
No. You can save it with Quality=100 which would be almost like the original image. However, the resulting file will be huge.
I have a byte[] array, the contents of which represent a TIFF file (as in, if I write out these bytes directly to a file using the BinaryWriter object, it forms a perfectly valid TIFF file) and I'm trying to turn it into a System.Drawing.Image object so that I can use it for later manipulation (feeding into a multipage TIFF object)
The problem I'm having is that the commonly accepted code for this task:
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms, true);
return returnImage;
}
doesn't work for me. The second line of the above method where it calls the Image.FromStream method dies at runtime, saying
Parameter Not Valid
I believe that the method is choking on the fact that this is a TIFF file but I cannot figure out how to make the FromStream method accept this fact.
How do I turn a byte array of a TIFF image into an Image object?
Also, like I said the end goal of this is to have a byte array representing a multipage TIFF file, which contains the TIFF files for which I have byte array objects of right now. If there's a much better way to go about doing this, I'm all for it.
OK, I found the issue, and it was from a part of the code unrelated to the part of the code I was asking about. The data was being passed as a string, I was converting it to a byte array (this was a test rig so I was trying to simulate the byte array that I get in the main app), then converting that to a MemoryStream, then making an Image from that.
What I failed to realize was that the string was Base64 encoded. Calling Convert.FromBase64String() caused it to turn into a byte array which wouldn't kill the Image.FromStream() method.
So basically it boiled down to a stupid mistake on my part. But hey, the code above is still useful and this page will probably serve as a Google result as to how to avoid this mistake to someone else.
Also, I found an easy way to construct a Multi-Page TIFF from my byte arrays here.
Edit: The assumption below is not correct, I had a chance to fire up my IDE later and tested with and without Write and both populated the MemoryStream correctly.
I think you need to write to your MemeoryStream first.
As if my memory (no pun intended) serves me correctly this:
MemoryStream ms = new MemoryStream(byteArrayIn);
Creates a memory stream of that size.
You then need to write your byte array contents to the memory stream:
ms.Write(byteArrayIn, 0, byteArrayIn.Length);
See if that fixes it.
All these were clues that helped me figure out my problem which was the same problem as the question asks. So i want to post my solution which i arrived at because of these helpful clues. Thanks for all the clues posted so far!
As Time Saunders posted in his answer, that Write method to actually write the bytes to the memory stream is essential. That was my first mistake.
Then my data was bad TIFF data too, but in my case, i had an extra character 13 at the beginning of my image data. Once i removed that, it all worked fine for me.
When i read about some basic TIFF file format specs, i found that TIFF files must begin with II or MM (two bytes with values of either 73 or 77). II means little-endian byte order ('Intel byte ordering') is used. MM means big-ending ('Motorola byte ordering') is used. The next two bytes are a two byte integer value ( = Int16 in .NET) of 42, binary 101010.
Thus a correct TIFF stream of bytes begins with the decimal byte values of: 73, 73, 42, 0 or 77, 77, 0, 42. I encourage anyone with the same problem that we experienced to inspect your TIFF data byte stream and make sure your data is valid TIFF data!
Thanks Schnapple and Tim Saunders!!