C# How image is stored in MemoryStream - c#

I work on a project where i need to process a image i receive from a socket and to display it.
I'm getting the image in jpeg format,and i cannot just use the Image.FromStream()); method for retrieving the image,because it contains more data and i want to process it while i'm reading the data-for efficiency reasons.(Basically what i want is to read the image from the stream manually).
Is there any source which explaines how these image are stored in the MemoryStream?
The MemoryStream is built on a byte[] buffer,i resuse the same buffer also and i do not create a new MemoryStream everytime the method called.
A sample of code:
private byte[] BlockToJpeg()
{
Bitmap block=new Bitmap("...");
MemoryStream ms=new MemoryStream();
block.Save(ms, ImageFormat.Jpeg);
return ms.GetBuffer();
}
So the call would look like this
byte[] buffer=BlockToJpeg();
sck.Send(buffer);//sending the buffer...not the full code because this is not our problem.
Now in the Reciver side,when i'll get that buffer:
Byte[] RecieveBuffer=sck.Recieve();//again,kind of pseudo code,because this is not the relevant part.
i have to processes it's pixels,so i'll prefer to read them from the byte[] array one by one manually...
Is there any structure for reading this(in our case-reading a jpeg image stored as byte array)?
For example- first 4 bytes are width,second are height...3rd are PixelFormat and the rest are the pixels values...or somthing...?
Thanks.

jpeg is type of compression method usually on images.
you can read more about it here:http://www.ams.org/samplings/feature-column/fcarc-image-compression

Related

What is the simplest way to decompress a ZIP buffer in C#?

When I use zlib in C/C++, I have a simple method uncompress which only requires two buffers and no more else. Its definition is like this:
int uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
uLong sourceLen);
/*
Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry,
destLen is the total size of the destination buffer, which must be
large enough to hold the entire uncompressed data. (The size of
the uncompressed data must have been saved previously by the
compressor and transmitted to the decompressor by some mechanism
outside the scope of this compression library.) Upon exit, destLen
is the actual size of the uncompressed data.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output
buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
In the case where there is not enough room, uncompress() will fill
the output buffer with the uncompressed data up to that point.
*/
I want to know if C# has a similar way. I checked SharpZipLib FAQ as follows but did not quite understand:
How do I compress/decompress files in memory?
Use a memory stream when creating the Zip stream!
MemoryStream outputMemStream = new MemoryStream();
using (ZipOutputStream zipOutput = new ZipOutputStream(outputMemStream)) {
// Use zipOutput stream as normal
...
You can get the resulting data with memory stream methods ToArray or GetBuffer.
ToArray is the cleaner and easiest to use correctly with the penalty
of duplicating allocated memory. GetBuffer returns a raw buffer raw
and so you need to account for the true length yourself.
See the framework class library help for more information.
I can't figure out if this block of code is for compression or decompression, if outputMemStream meas a compressed stream or an uncompressed stream. I really hope there is a easy-to-understand-way like in zlib. Thanks you very much if you can help me.
Check out the ZipArchive class, which I think has the features you need to accomplish in-memory decompression of zip files.
Assuming you have an array of bytes (byte []) which represent the ZIP file in memory, you have to instantiate a ZipArchive object which will be used to read that array of bytes and interpret them as the ZIP file you whish to load. If you check the ZipArchive class' available constructors in documentation, you will see that they require a stream object from which the data will be read. So, first step would be to convert your byte [] array to a stream that can be read by the constructors, and you can do this by using a MemoryStream object.
Here's an example of how to list all entries inside of a ZIP archive represented in memory as a bytes array:
byte [] zipArchiveBytes = ...; // Read the ZIP file in memory as an array of bytes
using (var inputStream = new MemoryStream(zipArchiveBytes))
using (var zipArchive = new ZipArchive(inputStream, ZipArchiveMode.Read))
{
Console.WriteLine("Listing archive entries...");
foreach (var archiveEntry in zipArchive.Entries)
Console.WriteLine($" {archiveEntry.FullName}");
}
Each file in the ZIP archive will be represented as a ZipArchiveEntry instance. This class offers properties which allow you to retrieve information such as the original length of a file from the ZIP archive, its compressed length, its name, etc.
In order to read a specific file which is contained inside the ZIP file, you can use ZipArchiveEntry.Open(). The following exemplifies how to open a specific file from an archive, if you have its FullName inside the ZIP archive:
ZipArchiveEntry archEntry = zipArchive.GetEntry("my-folder-inside-zip/dog-picture.jpg");
byte[] readResult;
using (Stream entryReadStream = archEntry.Open())
{
using (var tempMemStream = new MemoryStream())
{
entryReadStream.CopyTo(tempMemStream);
readResult = tempMemStream.ToArray();
}
}
This example reads the given file contents, and returns them as an array of bytes (stored in the byte[] readResult variable) which you can then use according to your needs.

Saving a image that was converted into byte[] without System.Drawing?

Yes you can just use:
// A byte array that contains a .jpeg data.
System.IO.Stream BitmapStream = System.IO.MemoryStream(byteBuffer);
System.Drawing.Bitmap MyImage = System.Drawing.Bitmap.FromStream(BitmapStream);
MyImage.Save("C:\Folder\Folder\image.jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
But how could you do this without System.Drawing?
I would like to write my own code to create the image.
If you have the image in bytes you don't need to use drawing to make an image, just save it as a binary file.
System.IO.File.WriteAllBytes("C:\Folder\Folder\image.png", byteBuffer);

Preserving Image quality

I have a winform C# desktop application.
I have a constant stream of jpegs coming in.
I am comparing the current image with the previous 1.
By using a 3rd party tool - Emgu - I can create a new image that contains just the differences.
I then convert that image to a memory stream and then to a byte array.
In the receiving application I take this byte array and load the image via a memory stream using these bytes.
The trouble is that the image degrades quite a lot.
If I save the image to the hard drive before converting it to a memory stream on the client side the quality of the image is good.
The problem lies when i load it as a memory stream.
I encode it as jpeg.
If I encode it as a PNG before sending to the server the quality is good again.
The trouble with encoding to PNG the size in the byte array shoots up.
What my intention was all along was to reduce the number of bytes I have to upload to improve response time.
Am I doing something wrong or can this not be done?
This is my code:
Bitmap imgContainingDifference
= GetDiffFromEmgu(CurrentJpegImage, PreviousJpegImage);
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Jpeg);
data = msIn.ToArray();
}
//test here
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//result is image is poor/degrades
If I do this instead:
using (System.IO.MemoryStream msIn = new System.IO.MemoryStream())
{
holding.Save(msIn, System.Drawing.Imaging.ImageFormat.Png);
data = msIn.ToArray();
}
using (System.IO.MemoryStream msOut = new System.IO.MemoryStream(_data))
{
Bitmap testIMG = (Bitmap)Image.FromStream(msOut);
}
//Image is good BUT the size of the byte array is
//10 times the size of the CurrentFrame right at the start.
This is what the image looks like when using the kid suggestion from :
I have now tried using a encoder from the kind suggestion from #MagnatLU and I also get the same quality of image if I use FreeImage.Net.
You can set JPEG compression level when encoding your file to value that is the best empirical tradeoff between quality and size.

NetworkStream a thing i don´t understand in my code

I got help in a previous question on how to send an image.
The thing done was to first send the lenght of the image(size), and then the actual image, then it would know when it was done.
IT looks like this:
BinaryWriter writer = new BinaryWriter(netStream);
while (someCondition) {
Image img = SomeImage();
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] buffer = new byte[ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(buffer, 0, buffer.Length);
writer.Write(buffer.Length);
writer.Write(buffer);
This code is from: Angelo Geels , who helped me in my previous question.
Now, i tried to optimize this in a way. And well, it works. But ONLY when the file is bmp (uncompressed), and i don´t know why.
using (MemoryStream ms = PrintWindow(process))
{
writer.Write((int)ms.Length);
writer.Write(ms.GetBuffer());
}
So PrintWindow save an image to a memorystream and returns it. so ms = memorystream with my image in it.
So for me this should work perfectly, cause form what i can se i do the same thing.
i send the size of the file (length of the memorystream).
Then i send the byte[] data in the memorystream.
So, it´s the same thing.
But, it only works with bmp.
The only thing i can think of is that when i save in a compressed format, the bmp is first written and then encoded, which messes up the getbuffer() or something.
But i still think it should work.
You write too many bytes, use the Write() overload that lets you specify how much to write:
using (MemoryStream ms = PrintWindow(process)) {
writer.Write((int)ms.Length);
writer.Write(ms.GetBuffer(), 0, (int)ms.Length);
}
Don't use GetBuffer. From the documentation:
Note that the buffer contains allocated bytes which might be unused.
For example, if the string "test" is written into the MemoryStream
object, the length of the buffer returned from GetBuffer is 256, not
4, with 252 bytes unused. To obtain only the data in the buffer, use
the ToArray method; however, ToArray creates a copy of the data in
memory.
Use:
writer.Write(ms.ToArray());
Or if you are in 4.0 use the CopyTo method:
ms.CopyTo(netStream);
Check this if you are not in 4.0 for a way to copy streams:
How do I copy the contents of one stream to another?

list(of byte) to Picturebox

I have a jpeg file that is being held as a list(of Byte)
Currently I have code that I can use to load and save the jpeg file as either a binary (.jpeg) or a csv of bytes (asadsda.csv).
I would like to be able to take the list(of Byte) and convert it directly to a Picturebox without saving it to disk and then loading it to the picturebox.
If you are curious, the reason I get the picture file as a list of bytes is because it gets transfered over serial via an industrial byte oriented protocol as just a bunch of bytes.
I am using VB.net, but C# example is fine too.
You could do this:
var ms = new MemoryStream(byteList.ToArray());
pictureBox.Image = Image.FromStream(ms);
The Image class has a FromStream method and you can create a MemoryStream from a byte array. So:
MemoryStream ms = new MemoryStream(byteList.ToArray());
Image image = Image.FromStream(ms);
What you need to do is take the bytes and read them into a stream. You can then use the stream to load the picture box image.
using( MemoryStream ms = new MemoryStream( byteList.ToArray() ) )
{
this.pictureBox1.Image = Image.FromStream( ms );
}

Categories

Resources