Display high resolution image - c#

I'm saving both high resolution and compressed version of high resolution image in the database.
When the user requests a high resolution image, i need to display that else the compressed one. here is my code.
The issue is : when i set that image byte array into a stream and bitmap, file size has compressed 2.27MB to 339kB.
What i'm doing wrong here?
private void DisplayImageFromBytes(byte[] byteArray, int resizeWidth, bool isHiResImage) {
if (isHiResImage)
{
Stream stream = new MemoryStream(byteArray);
System.Drawing.Image img = System.Drawing.Image.FromStream(stream);
Bitmap bitmap = null;
if (resizeWidth > 0 && img.Width > resizeWidth)
{
int newHeight = (int)((float)img.Height * ((float)resizeWidth / (float)img.Width));
bitmap = new Bitmap(img, resizeWidth, newHeight);
}
else
{
bitmap = new Bitmap(img);
}
Response.ContentType = "image/Jpeg";
bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Dispose();
img.Dispose();
bitmap.Dispose();
}
else
{
DisplayImageFromBytes(byteArray, resizeWidth);
}
}

You are using same image format to save it to stream for all the different format of images that came into you.
For now just replace
bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
with
bitmap.Save(Response.OutputStream, img.RawFormat);
RawFormat: will get the current file format of this Image.
N.B: You don't need to create a new bitmap that don't need any conversion. you can directly save it to stream from System.Drawing.Image img

Related

Convert files to bitmap in C#

I write this code to read files from folder in directory(#"D:\\test\\ISIC_2020_Training_JPEG"), then convert each file to bitmap in c#
foreach (string img in Directory.EnumerateFiles(#"D:\\test\\ISIC_2020_Training_JPEG"))
Bitmap bmp = new Bitmap(img);
But there is an error that appears in the last line, which is:
Out of memory Exception
what is the problem in this code?
I suppose that you have all jpeg files on provided directory, you could load image file in memory stream and check if everything okay when you load image in memory stream.
foreach (string imgPath in Directory.GetFiles(#"D:\test\ISIC_2020_Training_JPEG"))
{
Bitmap bmp;
byte[] buff = System.IO.File.ReadAllBytes(imgPath);
using(System.IO.MemoryStream ms = new System.IO.MemoryStream(buff))
{
bmp = new Bitmap(ms);
}
}
Probably the best approach would be to stream the image files so if there's a large file it won't hog up too much memory. Then check if the file is in the correct format before trying to convert to a Bitmap, hopefully this helps:
Bitmap bitmap;
Image image;
foreach (string imgFile in Directory.EnumerateFiles(#"D:\test\ISIC_2020_Training_JPEG"))
{
using (Stream bmpStream = File.Open(imgFile, FileMode.Open))
{
image = Image.FromStream(bmpStream);
if (ImageFormat.Jpeg.Equals(image.RawFormat)) // Check it's the correct format
{
bitmap = new Bitmap(image);
}
}
}

WCF: using memorystream to transfer bitmaps in C#

I am using WCF for communication between client and server program on the same machine. Earlier I used Bitmaps to transfer video frames to the client. It was successful with WCF, but I only have 6 megabytes / sec LAN. Transferring 1.2Mb every second would block the LAN. I decided to JPEG encode the captured Bitmaps from the camera. It is possible to save a JPEG on the disk from a bitmap, or to a Memorystream. I created a
[MessageContract]
public class RemoteResponse
{
[MessageBodyMember(Order = 1)]
public System.IO.MemoryStream jpegImage;
}
I return this back from the (I)LiveImageService.
As I get it out in the client: RemoteResponse ret = client.GetLiveImage();
MemoryStream returnedImage = returnedResponse.jpegImage;
returnedImage.Position = 0L;
returnedImage.Seek(0, SeekOrigin.Begin);
args.image = returnedImage;
I do this in the event handler:
args.image.Position = 0L;
args.image.Seek(0, SeekOrigin.Begin);
//bitmap = new Bitmap(args.image);
bitmap = (Bitmap)Image.FromStream(args.image);
It gives me a "parameter is not valid" exception.
I have read that this is a buggy solution of Microsoft. Actually the
retreived stream is believed to be 21 bytes long because there is a trailing
zero \0 at the end of the leading "System.Drawing.Bitmap"\0. That is why the
processing of the image is stopped.
I have read a solution that avoids this:
byte[] arr = PdfReader.FlateDecode(PdfReader.GetStreamBytesRaw((PRStream)obj), true);
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, pixelFormat);
System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new System.Drawing.Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat);
Marshal.Copy(arr, 0, bmd.Scan0, arr.Length);
bmp.UnlockBits(bmd);
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); // here it is the trick
arr = ms.GetBuffer(); // now I replace my incorrect image format bytes for the correct ones
System.Drawing.Image image = System.Drawing.Image.FromStream(ms);
image.Save(path, System.Drawing.Imaging.ImageFormat.Png);
}
How does the last arr = ... have any effect? It is not used anymore later?
So I don't understand.
update:
On a Microsoft website: https://social.msdn.microsoft.com/Forums/vstudio/en-US/f9e39595-04ca-42ae-a353-eb1a08602631/resolved-creating-image-file-parameter-is-not-valid?forum=netfxbcl
I rewrote the example so:
public static Bitmap DecodeJPEGFromMemoryStream(MemoryStream stream, int width, int height, PixelFormat pixelFormat)
{
string content = System.Text.Encoding.UTF8.GetString(stream.ToArray());
byte[] arr = Encoding.UTF8.GetBytes(content);
//byte[] arr = PdfReader.FlateDecode(PdfReader.GetStreamBytesRaw((PRStream)obj), true);
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, pixelFormat);
System.Drawing.Imaging.BitmapData bmd = bmp.LockBits(new
System.Drawing.Rectangle(0, 0, width, height),
System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat);
Marshal.Copy(arr, 0, bmd.Scan0, arr.Length);
bmp.UnlockBits(bmd);
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // here it is the trick
arr = ms.GetBuffer(); // now I replace my incorrect image format bytes for the correct ones
System.Drawing.Image image = System.Drawing.Image.FromStream(ms);
Bitmap ret = new Bitmap(image);
return ret;
}
}
I can see the image in the Picturebox, but it has only 2 lines, flickering.
If I obscure the camera I see that it darkens. So the data comes through now. But I cannot reconstruct my JPEG live data.
I was able to decode the JPEG data, only with saving it to disk.
So I've got the image without error. I tried to save the image only
temporarily and delete after.
public static Bitmap DecodeJPEGFromMemoryStream(MemoryStream stream, int width, int height, PixelFormat pixelFormat)
{
try
{
if(File.Exists("c:\\imagecache.jpg") == true)
File.Delete("c:\\imagecache.jpg");
//using (FileStream file = new FileStream("c:\\imagecache.jpg", FileMode.CreateNew, System.IO.FileAccess.ReadWrite))
using (FileStream file = File.Open("c:\\imagecache.jpg", FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite))
{
stream.WriteTo(file);
//JpegBitmapDecoder decoder = new JpegBitmapDecoder(file, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
file.Close();
file.Dispose();
}
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
//BitmapSource bitmapSource = decoder.Frames[0];
Bitmap jpeg;
{
{
FileInfo info = new FileInfo("c:\\imagecache.jpg");
if (info.Length == 0)
{
File.Delete("c:\\imagecache.jpg");
return null;
}
}
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
jpeg = (Bitmap)Image.FromFile("c:\\imagecache.jpg"); //the process cannot access the file...
}
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
if (File.Exists("c:\\imagecache.jpg") == true)
File.Delete("c:\\imagecache.jpg");
return jpeg;
}
catch(Exception ex)
{
return null;
}
}
I get the exception: The process cannot access the file "imagecache.jpg",
because it is being used by another process. Exception comes at the FromFile.
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
Bitmap retImage = (Bitmap)jpeg.Clone();
jpeg.Dispose();
if (File.Exists("c:\\imagecache.jpg") == true)
{
System.IO.FileInfo fi = new System.IO.FileInfo("c:\\imagecache.jpg");
fi.Delete();
}
return retImage;
}
catch (Exception ex)
{
return null;
}
finally
{
stream.Dispose();
}
It is fixed so. Image.FromFile: the File remains locked until the Image is disposed.
So I cloned my Image and disposed the old one.
Before I've seen my Image, now nothing is visible.

C# how to compress .png without transparent background lost?

I use the following codes to compress an image file to jpg:
// _rawBitmap = a Bitmap object
ImageCodecInfo encoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
ImageConverter imageConverter = new ImageConverter();
byte[] b = (byte[])imageConverter.ConvertTo(_rawBitmap, typeof(byte[]));
using (MemoryStream ms = new MemoryStream())
{
ms.Write(b, 0, b.Length);
ms.Seek(0, SeekOrigin.Begin);
rawBitmap.Save(ms, encoder, myEncoderParameters);
bmp = ToBitmap(ms.ToArray());
return (Bitmap)bmp.Clone();
}
but when I try to compress a png file with same way but only change:
ImageCodecInfo encoder = GetEncoder(ImageFormat.Jpeg);
to
ImageCodecInfo encoder = GetEncoder(ImageFormat.Png);
my png file lost transparent data.
so how to compress a PNG file properly?
There are a couple of problems here.
First, you don't need to set those EncoderParams for quality for PNG.
Second, you don't need ImageConverter
Third, you are writing whatever ImageConverter produces to your memory stream, rewinding, and then writing the encoded PNG over the top of it-- it is likely that you have a PNG file with a bunch of garbage at the end of it as a result.
The simplified approach should be:
using (MemoryStream ms = new MemoryStream())
{
rawBitmap.Save(ms, ImageFormat.Png);
}
If you want to load your bitmap back, open it from the stream, but don't close the stream (the stream will be disposed when your returned Bitmap is disposed):
var ms = new MemoryStream();
rawBitmap.Save(ms, ImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
return Bitmap.FromStream(ms);
You can use nQuant (https://www.nuget.org/packages/nQuant/)
With it, you convert 32 bit PNGs to high quality 8 bit PNGs
private static int alphaTransparency = 10;
private static int alphaFader = 70;
var quantizer = new WuQuantizer();
using(var bitmap = new Bitmap(sourcePath))
{
using(var quantized = quantizer.QuantizeImage(bitmap, alphaTransparency, alphaFader))
{
quantized.Save(targetPath, ImageFormat.Png);
}
}

Change format of unmanaged image byte array

I have this code (C#):
unsafe private Bitmap Test()
{
Bitmap test = null;
byte[] data = memRenderAll.CurrentData;
fixed (byte* m_pBuffer = _data)
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
Bitmap a = new Bitmap(720, 576, 2160, System.Drawing.Imaging.PixelFormat.Format24bppRgb, new IntPtr(m_pBuffer));
a.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
test =(Bitmap) Image.FromStream(ms);
a.Dispose();
}
}
return _test;
}
By saving the stream as this:
a.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
I get a 10:1 reduction is size.
Is there a way of avoiding this:
a.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
and specifying it somewhere/somehow in:
Bitmap a = new Bitmap(720, 576, 2160, System.Drawing.Imaging.PixelFormat.Format24bppRgb, new IntPtr(m_pBuffer));
as I would like to create the Bitmap only once.
thanks,
Andrew
I think its impossible todo in one code line using standard System.Drawing.
You use that constructor: http://msdn.microsoft.com/en-us/library/zy1a2d14(v=vs.110).aspx
Your code:
new Bitmap(720, 576, 2160, System.Drawing.Imaging.PixelFormat.Format24bppRgb, new IntPtr(m_pBuffer));
What does it mean? Bitmap read memory pointed by m_pBuffer using fixed width, height, stride and pixel format. You can't read it as jpeg, because jpeg - image zipping fomat. Look on it: http://en.wikipedia.org/wiki/JPEG#JPEG_codec_example . Jpeg codec need all your image for ziping, it can't zip parts and join them after.

Convert raw images to bitmap in c#

My code currently looks like this:
if (fe == "CR2")
{
Image img = null;
byte[] ba = File.ReadAllBytes(open.FileName);
using (Image raw = Image.FromStream(new MemoryStream(ba)))
{
img = raw;
}
Bitmap bm = new Bitmap(img);
pictureBox1.Image = bm;
statusl.Text = fe;
}
When I open a RAW image the program stops and Visual Studio says:
Parameter is not valid: Image raw = Image.FromStream(new MemoryStream(ba))
Please help! How can I get a RAW file to show in a PictureBox ?
Create the bitmap like this:
Bitmap bmp = (Bitmap) Image.FromFile(open.FileName);
or without using bitmap:
this.pictureBox1.Image = Image.FromFile(open.FileName);
Example WPF:
BitmapDecoder bmpDec = BitmapDecoder.Create(new Uri(origFile),
BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);
BitmapEncoder bmpEnc = new BmpBitmapEncoder();
bmpEnc.Frames.Add(bmpDec.Frames[0]);
Stream ms = new MemoryStream();
bmpEnc.Save(ms);
Image srcImage = Bitmap.FromStream(ms);
You're actually disposing an Image by specifying using (Image raw = Image.FromStream(new MemoryStream(ba))) later assigning the Disposed instance of image to picturebox which leads to this exception. To make to work you've to either don't dispose or clone the image.
Bitmap raw = Image.FromStream(new MemoryStream(ba) as Bitmap;
pictureBox1.Image = raw;
Or simply Clone
using (Image raw = Image.FromStream(new MemoryStream(ba)))
{
img = raw.Clone() as Bitmap;
}
Both of the above should work
you try this code :
private static void SaveImageToRawFile(string strDeviceName, Byte[] Image, int nImageSize)
{
string strFileName = strDeviceName;
strFileName += ".raw";
FileStream vFileStream = new FileStream(strFileName, FileMode.Create);
BinaryWriter vBinaryWriter = new BinaryWriter(vFileStream);
for (int vIndex = 0; vIndex < nImageSize; vIndex++)
{
vBinaryWriter.Write((byte)Image[vIndex]);
}
vBinaryWriter.Close();
vFileStream.Close();
}
private static void LoadRawFile(string strDeviceName, out Byte[] Buffer)
{
FileStream vFileStream = new FileStream(strDeviceName, FileMode.Open);
BinaryReader vBinaryReader = new BinaryReader(vFileStream);
Buffer = new Byte[vFileStream.Length];
Buffer = vBinaryReader.ReadBytes(Convert.ToInt32(vFileStream.Length));
vBinaryReader.Close();
vFileStream.Close();
}

Categories

Resources