How to compress bitmap to smaller size in C#? - 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);
}

Related

Need assistance with using memory stream as input for TiffBitmap decoder

I am writing a image viewer in C# and WPF for TIFF images stored in a SQL Server database image column. I have coded the retrieval of the images into a memory stream using a GetBytes loop and that works. What is not working is creating a TiffBitmapDecoder from the memory stream and using that as the BitmapSource for a WPF/XAML Image control. Here is my function to return the BitmapSource with the memory stream as input:
namespace ViewDBImages
{
public static class Utility
{
public static BitmapSource StreamToImage(MemoryStream imageMem)
{
//
// Decode the Memory Stream argument into a Bitmap with TIFF format
// First we have to set the Stream seek location to the origin
//
imageMem.Seek(0, SeekOrigin.Begin);
//
// Decode the stream into a TiffBitmap and return it as the image source
//
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageMem, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
BitmapSource source = decoder.Frames[0];
return source;
}
}
}
I believe the images are being set as the source for the image control, because I can see the scroll bars changing as they are retrieved, but they are not visible. I also see that the position of the memory stream is "8" after this function finishes, but the size of the stream is 63,083 bytes.
To help debug this, I copied the memory stream to a TIFF file and used that as the stream input for the decoder. The images are displayed correctly that way. So I suspect there must be some kind of control information that is available when the image is stored as a file, but is not found in the memory stream. Here is that code:
namespace ViewDBImages
{
public static class Utility
{
public static BitmapSource StreamToImage(MemoryStream imageMem)
{
//
// Copy the Memory Stream argument into a filestream and save as a TIF file
// First we have to set the Stream seek location to the origin
//
imageMem.Seek(0, SeekOrigin.Begin);
FileStream imageFile = new FileStream(#"C:\Image Test\Testfile.tif", FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
imageMem.CopyTo(imageFile);
//
// Decode the file to a TiffBitmap and return it as the image source
//
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageFile, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnDemand);
BitmapSource source = decoder.Frames[0];
return source;
}
}
}
Thank you for any advice.
Try to set BitmapCacheOption.OnLoad to make the decoder immediately load the bitmap:
var decoder = new TiffBitmapDecoder(
imageMem, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
return source = decoder.Frames[0];
As a note, you could also directly create a BitmapFrame from a stream. The appropriate decoder is chosen automatically.
return BitmapFrame.Create(
imageMem, BitmapCreateOptions.None, BitmapCacheOption.OnLoad)

Difficulty Saving Image To MemoryStream

I'm having some difficulty saving a stream of bytes from an image (in this case, a jpg) to a System.IO.MemoryStream object. The goal is to save the System.Drawing.Image to a MemoryStream, and then use the MemoryStream to write the image to an array of bytes (I ultimately need to insert it into a database). However, inspecting the variable data after the MemoryStream is closed shows that all of the bytes are zero... I'm pretty stumped and not sure where I'm doing wrong...
using (Image image = Image.FromFile(filename))
{
byte[] data;
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
data = new byte[m.Length];
m.Write(data, 0, data.Length);
}
// Inspecting data here shows the array to be filled with zeros...
}
Any insights will be much appreciated!
To load data from a stream into an array, you read, not write (and you would need to rewind). But, more simply in this case, ToArray():
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
data = m.ToArray();
}
If the purpose is to save the image bytes to a database, you could simply do:
byte[] imgData = System.IO.File.ReadAllBytes(#"path/to/image.extension");
And then plug in your database logic to save the bytes.
I found for another reason this article some seconds ago, maybe you will find it useful:
http://www.codeproject.com/KB/recipes/ImageConverter.aspx
Basically I don't understand why you try to write an empty array over a memory stream that has an image. Is that your way to clean the image?
If that's not the case, read what you have written in your memorystream with ToArray method and assign it to your byte array
And that's all
Try this way, it works for me
MemoryStream ms = new MemoryStream();
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, panel1.Bounds);
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] Pic_arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(Pic_arr, 0, Pic_arr.Length);
ms.Close();
Well instead of a Image control, I used a Panel Control.

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.

C#: Getting Error: "A generic error occurred in GDI+" When trying to copy imagebox.Image into memory stream. This stream is not being saved to file.

I am getting an odd error with Image.save(Stream, Format).
I tried looking around on here for a solution but everyone seems to think the error is from file permissions. That can't be it in my case case the Stream isn't going into a file. My code is below:
MemoryStream Stream = new MemoryStream();
this.Image_Box_1.Image.Save(Stream, System.Drawing.Imaging.ImageFormat.Jpeg);
TI.AlbumCover = Stream.ToArray();
Stream.Close();
TI.AlbumCover is a byte[].
Does anyone have any ideas on what the problem might be?
EDIT:
Ok, so I worked it out. The original file could sometimes come from a jpg file, sometimes from a byte array (part of an id3 tag). The problem was that when the image came from the file, I was closing the stream after creating the image box image. While the image remained visible, the data was no longer available.
Since I also later needed to overwrite that jpg file, I could not simply leave the filestream for it open so I left the rest of my code the same and changed the code to read from the jpg to the following:
FileStream FS = new FileStream(File, FileMode.Open, FileAccess.Read);//Read in the jpg file
Image IMG = Image.FromStream(FS);//Create an image from the file data
MemoryStream MS = new MemoryStream();
IMG.Save(MS, System.Drawing.Imaging.ImageFormat.Jpeg);//Save the image data to a memory stream
byte[] temp = MS.ToArray();//Copy the image data to a byte array
//close the streams
MS.Close();
FS.Close();
return temp; //was originally returning an image
Then after executing this code I change the code that placed the image into the image box to:
try
{
if (this.m_V2Tag.AlbumCover != null)
this.Image_Box_1.Image = Image.FromStream(new MemoryStream(this.m_V2Tag.AlbumCover));
//changed code
else
{
MemoryStream temp = new MemoryStream(this.getFolderJpg()); //create a memory stream from the byte[]. This stream can safely be left open.
this.Image_Box_1.Image = Image.FromStream(temp); // create image and assign it to the image box
}
}
catch
{
this.Image_Box_1.Image = null;
}

How to convert PNG to BMP at runtime?

I need to convert PNG file to BMP file on runtime.
I can't do it like
Image dummy = Image.FromFile("image.png");
dummy.Save("image.bmp", ImageFormat.Bmp);
because i can't save the bmp image on the local disk as a file.
Thanks for any help.
You can save to stream
using(MemoryStream stream = new MemoryStream())
{
Dummy.Save(stream, ImageFormat.Bmp);
}
Precise answer given here.
Image Dummy = Image.FromFile("image.png");
Dummy.Save("image.bmp", ImageFormat.Bmp);
Since you don't want to follow this method, you can do it the way Stecya answered.
Just do it this way.
Stream stream;
Dummy.save(stream, ImageFormat.Bmp)

Categories

Resources