Base64Encoded bitmap - convert to bitmap manually - c#

I know I can use
string base64Encoded = ...;
byte[] byteArray = Convert.FromBase64String(this.base64Encoded); // array size [31591]
var memoryStream = new MemoryStream(byteArray);
var bitmap = new Bitmap(memoryStream);
//byte[,] im = new byte[a.Width*a.Height,3];
// array size [891998, 3] - why this array is 90 times bigger?
but I want to do it manually.
What I really need is to know how from byteArray I can create 3dim pixel array [bitmap.width * bitmap.hight, 3 {Red,Green,Blue}]

1- size of byteArray is different from size of bitmap since bitmap is actually an uncompressed 24 bit image without a header, but byteArray is a compressed (RLE most likely) bitmap file.
2- you can use libbmp or another image processing library to load and manipulate pixels. These libraries are much better at handling that kind of stuff.
3- most bitmaps are compressed using RLE compression and bitmap is a very simple format. You can actually write a bitmap reader to read it to a byte array intead of Bitmap object.

Related

How to compress bitmap to smaller size in C#?

My bitmap is too large for uploading to the printer. I am going to compress it to smaller size so that less data will be transmit over the printer. But I don't want reduce the length and width of the bitmap. I have done some research but all of them require a stream especially as following
bitmap.compress(Bitmap.Format.jpeg,50,outputStream);
Why do I need a stream to store the file? How can I skip that and get the compressed bitmap that I want? I have tried
originalBitmap = Bitmap.decodeByteArray(imageByteData);
//Line below not working and got error
compressedBitmap = Bitmap.compress(Bitmap.Format.jpeg,50,outputStream);
In the outputStream which is my Download folder, I did see the compressed image, but how can I access the compressed image again? Unfortunately, the compress method is not that straight forward. My question is how can I compress a bitmap and use the compressed bitmap in another action? Thank you.
You can compress it to an in-memory stream:
//Compress to a stream in memory
byte[] compressedData = null;
using(var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.Format.Jpeg, 50, stream);
compressedData = stream.ToArray();
}
//load compressed bitmap from memory
using(var stream = new MemoryStream(compressedData))
{
var compressedBitmap = BitmapFactory.DecodeStream(stream);
}

Saving Bitmap as byte array results in weird file size

I am doing some testing for a future project, in which I will be creating an image encryptor. Right now I just wanted to get together a way of converting a bitmap to a byte array, save it to a text file, reload it, and resave it under a different name. I got it to work...there is just a problem with the file size afterwards. My converted image(The one that read from a byte array to create the image) is showing a larger file size than the original image. Here is my code:
public class Program
{
public static void Main( string[] args )
{
/**
* Load the bitmap and convert it to a byte array
* then save the file to the desktop
*/
byte[] imageBytes = ImageToByte( new Bitmap( "C:/Users/Krythic/Desktop/NovaEngine.png" ) );
File.WriteAllBytes( "C:/Users/Krythic/Desktop/NovaImageData.txt" , imageBytes );
/**
* Load the saved image bytes, then convert them back into an image and save it to the
* desktop under a new name.
*/
byte[] convertedImageBytes = File.ReadAllBytes("C:/Users/Krythic/Desktop/NovaImageData.txt");
Bitmap image = ConvertToBitmap(convertedImageBytes);
image.Save("C:/Users/Krythic/Desktop/ConvertedImage.png");
}
public static byte[] ImageToByte( Bitmap img )
{
ImageConverter converter = new ImageConverter();
return ( byte[] )converter.ConvertTo( img , typeof( byte[] ) );
}
private static Bitmap ConvertToBitmap( byte[] imagesSource )
{
ImageConverter imageConverter = new ImageConverter();
Image image = ( Image )imageConverter.ConvertFrom( imagesSource );
return new Bitmap( image );
}
}
I think the problem is due to the image.Save(); function, which...I think...is not picking the optimal compression for the image. Maybe I am wrong? Here is a picture of the property pages for both images:
You will also notice that the saved byte array version of the original image is showing a larger file size. Why is this? Shouldn't the size of the file remain constant across the entire span of conversion?
Update: I'm pretty sure that the functions that I am using to convert the image are using poor conversion techniques. This would explain why the size of the original png differs from the byte-array-file version, which should be equal. So to solve this, I need an efficient, or correct way of doing the same thing that those two functions do.
Most likely the original file was somehow compressed , and re-writing the file ends up saving an un-compressed file because C# is not very smart about that.
and if C# was updated somehow and got better from the last time I used it, it is possible because you are converting a PNG into a bitmap (the bitmap is not size efficient) and then you save the bitmap to a PNG

Create a VSTO shape from byte array

I have an image that is encoded in a byte array and I would like to add it as a shape in an excel document but unfortunetly the only available function I see to do this requires me to save the image to the drive and then read it. As you see this is a really slow operation and I would like to simply read the image from the byte stream and decode it into a bitmap.
I have encoded it like this :
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.QualityLevel = 100;
byte[] bit = null;
using (var ms = new MemoryStream())
{
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(ms);
bit = ms.ToArray();
}
Now, how to add it to the worksheet ?
The method Shapes.AddPicture accepts only a filename and cannot read from a stream.
The Excel object model doesn't provide any method for reading a byte array and then add it as a shape. So, the only possible solution is to save the byte array as a file on the disk and then add it as a shape as you stated earlier:
to save the image to the drive and then read it.

C# Image: To preserve image's checksum

I have the following codes to convert an image(bitmap) to byte array:
public byte[] ConvertImageToByteArray(Image imageToConvert, ImageFormat formatOfImage)
{
byte[] Ret;
try
{
using (MemoryStream ms = new MemoryStream())
{
imageToConvert.Save(ms, formatOfImage);
Ret = ms.ToArray();
}
}
catch (Exception)
{
throw;
}
return Ret;
}
and Convert byte array back to image(bitmap):
public Bitmap ConvertByteArrayToImage(byte[] myByteArray)
{
Image newImage;
using (MemoryStream ms = new MemoryStream(myByteArray, 0, myByteArray.Length))
{
ms.Write(myByteArray, 0, myByteArray.Length);
newImage = Image.FromStream(ms, true);
}
return newImage;
}
Here's my Main Program:
byte[] test = ConvertImageToByteArray(Image.FromFile("oldImage.bmp"), ImageFormat.Bmp);
Bitmap bmp = ConvertByteArrayToImage(test);
bmp.Save("newImage.bmp");
But when I compare both of the image files(old & new bitmap images), their checksum appeared to be different. Any reason for that happening? How to fix it to maintain its integrity?
Basically, there are many ways an identical image can be encoded in a BMP file. If I try your example on a random image I found, I see the .NET Bitmap class saves the file without filling the biSizeImage field in the BITMAPINFOHEADER structure in the BMP header (but the original image produced by IrfanView has it filled), which is a completely correct and documented possibility. (“This may be set to zero for BI_RGB bitmaps.”)
And this is definitely not the only variable thing in the BMP format. For instance, there are multiple possible orderings of pixel data in the image (top-to-bottom, bottom-to-top), specified in the header. (“If biHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner. If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.”)
So, if you receive any BMP file from a source not under your control and really need to produce an image using exactly the same BMP variant, you have a lot work to do, and I don’t think you could use the standard .NET helper classes for that.
See also this question: Save bitmap to file has zero in image size field
After chatting a bit, you solution comes down to reading and writing bytes, take the image object out the equation and just deal with the raw bytes.
To read the file:
MemoryStream ms = new MemoryStream(File.ReadAllBytes("filename"));
To write the file:
File.WriteAllBytes("outputfile", ms.ToArray());

Changing Bitmaps using c#

I was working on my college project where i was trying to change bit values of a Bitmap.
I am loading the bitmap to the memory stream, then extracting it to byte[] array. Now I was changing few central bits of this byte[] array and then converting it back to a bitmap image.
But i got a run time exception that "Invalid Bitmap".
Does a bitmap have some special format instead of simple bits???
Following is the code used by me:
MemoryStream mstream = new MemoryStream();
Bitmap b = new Bitmap(#"D:\my_pic.bmp");
b.Save(mstream, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] ba = mstream.ToArray();
mstream.Close();
byte[] _Buffer = null;
System.IO.FileStream _FileStream = new System.IO.FileStream(_FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader _BinaryReader = new System.IO.BinaryReader(_FileStream);
long _TotalBytes = new System.IO.FileInfo(_FileName).Length;
_Buffer = _BinaryReader.ReadBytes((Int32)_TotalBytes);
// close file reader
_FileStream.Close();
_FileStream.Dispose();
_BinaryReader.Close();
int leng1 = ba.Length;
int leng2=_Buffer.Length;
for(i=(leng1)/2;i<leng1;i++)
{
for(j=0;j<leng2;j++)
{
ba[i]=_Buffer[j];
}
if(j==(leng2-1))
{
break;
}
}
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
Bitmap bitmap1 = (Bitmap)tc.ConvertFrom(ba);
You must have your own goal to want to operate at this low level with a bitmap and that's fine. Unless you are performance bound it is way easier to do graphics at the graphics API level. Even if you are performance sensitive, other people have cut a path through the jungle already.
Back to the question. The BMP file format is simpler than some others but still comes in many varieties. Here is a detailed introduction to the gory details of the BMP format:
BMP file format
Now if you are just parsing your own BMP files and you know they are 32-bit RGB, and the header is going to be such-and-such a size which you can skip over, etc, then that might work for you. If you need to handle any old BMP it gets messy real fast which is why the libraries try to take care of everything for you.

Categories

Resources