In my program, I compress a BMP into a JPEG like this:
private void ConvertBmpToStreamJPG30(Bitmap b, Stream s)
{
s.Flush();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 30L);
b.Save(s, GetEncoder(ImageFormat.Jpeg), encoderParameters);
}
Then a function is receiving the JPEG in a MemoryStream, I transform it into a Bitmap by doing
Bitmap b = new Bitmap(stream);
When I display the image, there are a lot of lines like this :
What am I doing wrong, people?
Edit 1
Here a small visual studio solution showing the problem: http://www.fast-files.com/getfile.aspx?file=79311
It is the beginning of a screen sharing software. What it does: It takes screenshots, compare them, compress the difference and send it to another part of the program that decompress it and recompose an image with everything received. It opens a window displaying what is "sent" on the left and the recomposed image on the right.
Three things come to mind:
Try setting a better quality than 30 and see if that helps;
Check your RAM (and possibly video RAM, though I doubt that GDI+ might use VGA for compression) for hardware problems;
I've had a similar weird problem where I loaded some JPEG file, modified it a bit, and then saved it again. That produced an exception. The solution was to make a new bitmap based on the old one and save the copy. Try that.
Related
in my c# application load form i make load like 30 picture and this make my memory full and if I add more pictures I'll get the message "that my memory is full"
how can I free my memory or increase the maximum used memory?
is there are any another way to get all my pictures to picture box without filling my memory?
1) how can I free my memory or increase the maximum used memory?
Are you receiving an OutOfMemoryException and your memory isn't filled up in your machine? This might be due to x86 compilation and you should change it to x64.
2) is there are any another way to get all my pictures to picture box without filling my memory?
Yes and no. If you are using Bitmap it will allocate the image in the memory. If you are recreating the image later with all the images together without compressing it, then you could be also losing some memory if you are not disposing the Bitmaps correctly. You could load them, compress them, and then dispose the original one, keeping the compressed/optimized one in memory.
Besides, remember to always dispose your Bitmap after using it. The GC usually takes care of them, but you should always dispose them:
using (Bitmap bitmap = new Bitmap("file.jpg")
{
// bitmap handling here
}
Of course, if you are displaying it in a picturebox you can't dispose it, but again, you are not being completely clear in your question.
Without your code I cannot provide you a better answer, and I'll gladly edit this one if you update your question.
Read:
Compress bitmap before sending over network
When do I need to use dispose() on graphics?
Update
Upon fixing your thread I've noticed you've given an image but the formatting was broken.
Read my answer and it should help you (specially the part of compression). You can also change to x64.
Update 2 - Compression code example
public void ExampleMethod()
{
pictureBox1.Image = GetCompressedFile("file.jpg", quality: 10);
}
private Image GetCompressedFile(string fileName, long quality)
{
using (Bitmap bitmap = new Bitmap(fileName))
{
return GetCompressedBitmap(bitmap, quality);
}
}
private Image GetCompressedBitmap(Bitmap bmp, long quality)
{
using (var mss = new MemoryStream())
{
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);
ImageCodecInfo imageCodec = ImageCodecInfo.GetImageEncoders().FirstOrDefault(o => o.FormatID == ImageFormat.Jpeg.Guid);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = qualityParam;
bmp.Save(mss, imageCodec, parameters);
return Image.FromStream(mss);
}
}
In the quality parameter you set the quality. 100 means 100%, 50 means 50%.
Try setting quality as 10 and see if it works.
Remove all Bitmap bmp = new Bitmap from the code, and display with your PictureBoxInstance.Image = GetCompressedFile(...);
Check the ExampleMethod().
Code based from: https://stackoverflow.com/a/48274706/4352946
You have to remember though, that even using Dispose, the memory won’t be freed right away, you should wait the GC for that.
P.S: compressing the file on-the-go you MIGHT end up with both images (the compressed and uncompressed) in the memory
I am working on screen sharing project. I am sending only screen differences over socket comparing previous and actual buffer. It working
I am sending 8 to 9 FPS to client using Format16bppRgb555 to reduce overall bytes size of Bitmap
byte[] wholescreensize= new byte[1360 * 768 * 2];// Its around 2 Mb
My problem Is when full screen is changed.
I am getting about 45-60 kb of PNG image using below function
45kb * 10 (FPS) = 450 kb
It is possible to reduce beyond 45 kb.
I am not interested to reduce FPS as it live screen sharing app.
JPEG Compression or LZ4/GZIP also not making much difference as PNG image already compressed
private void SendImgDiffToClient(byte[] contents,Rectangle rectangle)
{
//Converting Small Portion to Bitmap.Bcoz Image.FromStrem not working here error Parameter is not Valid
byte[] byteArrayout = new byte[contents.Length];
var bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format16bppRgb555);
var bitmap_data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
Marshal.Copy(contents, 0, bitmap_data.Scan0, byteArrayout.Length);
bitmap.UnlockBits(bitmap_data);
//Converting Small Bitmap to Png Byte Array and Sending to Client
using (MemoryStream ms = new MemoryStream())
{
Image msImage = (Image)bitmap;
msImage.Save(ms, ImageFormat.Png);
msImage.Dispose();
byteArrayout = ms.ToArray();
}
SendtoClient(byteArrayout);
}
My Questing is what is a best approach to reduce bytes in such scenario.
Video streaming is essentially what you're doing; and modern video compression algorithms have lots of enhancements. Perhaps they can track or move an artifact, or otherwise distort said artifact as part of their functionality. Perhaps they can stream the data in a progressively building manner, so that static items eventually acquire more detail (similar to progressive jpeg images.) They do lots of things all at the same time. You can try to research them further, and take inspiration from them, or you could pick and use one.
This is to say that many people here seem to prefer the solution of using a readily available video compression library. Especially if you are worried about streaming bandwidth.
If you don't want to use an existing video library, then you have to decide how much effort you want to put in, versus how sloppy you want to be with consuming more bandwidth than otherwise necessary.
I am developing a program for image processing, and I need to save some pictures from a video and do some processing on them.
When dealing with 1 picture it doesn't really take time,
But when I'm dealing with 100 pictures it makes difference
I'm saving the files to my hard disk, and that's why it takes time
the thing is, the function I'm using is a ready made function and it only accepts (file name)
the function is really complicated so i cannot build my own function ( if that's what you are thinking )
I'm thinking of 2 things right now and would like to have your opinions about them:
change the input of the function, but how ? is there a way to change this input from a ( file name ) to an array which holds these pictures ?
save the file to ram. but how to save files to ram by names, and be able to use them as ( file name ) in the function ?
I appreciate your help , thanks so much
this is my code but i still have problems:
Capture video = new Capture("c:\\5.avi");
Image<Bgr, Byte> Imageframe ;
Dictionary<string, MemoryStream> dict = new Dictionary<string, MemoryStream>();
Imageframe = video.QueryFrame();
Bitmap bmp = Imageframe.ToBitmap();
dict.Add("mypicture.png", new MemoryStream());
bmp.Save(dict["mypicture.png"],imageformat.png);
its saying imageformat does not exist in the context
and this is the function im using :
Image<Bgr, byte> result;
result = DrawMatches.Draw("box.png", "box_in_scene.png", out matchTime,i);
You could save to RAM (in the loosest of senses) using a MemoryStream. If you wanted to name them you could use a Dictionary<string,MemoryStream>, such as:
Dictionary<string,MemoryStream> dict = new Dictionary<string,MemoryStream>();
dict.Add("mypicture.png",new MemoryStream());
image.Save(dict["mypicture.png"]);
However you'll need to write cleanup code for these streams and this doesn't take into account that eventually you could use up all the physical RAM and then start going into the paging file, which is disk based anyhow.
As an aside, if this is on a server you control and you're not releasing this software to end users you could get a RAM disk drive (plenty around just Google) that uses physical RAM as an actual disk available to Windows. Then you could just load/save to that.
Very very rough EmguCv variant:
// Global dictionary of memory streams
Dictionary<string,MemoryStream> dict = new Dictionary<string,MemoryStream>();
// Add image memory stream to dictionary
dict.Add("mypicture.png",new MemoryStream());
// Get bitmap from EmguCv
Bitmap bmp = image.ToBitmap();
// Save bitmap to image memory stream
bmp.Save(dict["mypicture.png"],ImageFormat.Png);
// Get bitmap from memory stream
dict["mypicture.png"].Seek(0,SeekOrigin.Begin);
Bitmap new_bmp = Image.FromStream(dict["mypicture.png"]);
// Convert bitmap to EmguCv image
Image<Bgr,Byte> new_img = new Image<Bgr,Byte>(new_bmp);
Try to use MemoryStream for work with memmory like with file,
and try to save files on harddisk by thread
I understand you are using a DLL you dont have the source for.
You might be able to load it into a reflector, and modify it to take the image as an argument instead of the file name.
I used Red Gate's reflector in the past and it worked for me: http://www.reflector.net/
I want to build a Screen Sharing program in C#.(with TCP)
I sniffed around the web and found out that the most efficient way to do it is by sending alot of screenshots from the client to the server.
The point is - how can I compress a Bitmap to Jpeg - receive it on the server and decompress again to Bitmap (so I can show it in a form) ?
I've tried using the JpegBitmapEncoder with no luck, here's my code:
Bitmap screen = TakeScreenshot();
MemoryStream ms = new MemoryStream();
byte[] Bytes = BmpToBytes_Unsafe(screen);
ms.Write(Bytes, 0, Bytes.Length);
Jpeg = new JpegBitmapEncoder();
Jpeg.Frames.Add(BitmapFrame.Create(ms));
Jpeg.QualityLevel = 40;
Jpeg.Save(ms);
BinaryReader br = new BinaryReader(ms);
SendMessage(br.ReadBytes((int)ms.Length));
It throws an NotSupportedException at Jpeg.Frames.Add(BitmapFrame.Create(ms));
No imaging component suitable to complete this operation was found.
So I need a way to convert a Bitmap to Jpeg, then to byte[], then send it over TCP.
And on the other end, do the exact opposite. Any suggestions ?
Thank you.
JPEG was designed for photographs, not for screen captures. Also, most of the screen doesn't change so better to just send the changed portions and only a full screen when much of the screen has changed.
Unless you're just doing this for fun, you are going about this all wrong. VNC has been doing this for years and the source code is free so you could look to see how that's done.
Is it possible to use the FromStream method of System.Drawing.Image without having to keep the stream open for the lifetime of the image?
I have an application which loads a bunch of toolbar graphics from resource files, using a combination of Image.FromStream and Assembly.GetManifestResourceStream.
The problem I'm having is while this works fine on Windows 7, on Windows XP the application crashes if a user interface element linked to one of these images is disabled. On Windows 7, the image is rendered in grayscale. On XP, it crashes with an out of memory exception.
After a load of hairpulling I have finally traced it to the initial loading of the image. As a matter of course, if I create any object implementing IDisposable that is also destroyed in the same method, I wrap it in a using statement, for example
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
image = Image.FromStream(resourceStream);
}
If I remove the using statement so that the stream isn't disposed, then the application no longer crashes on XP. But I now have a bunch of "orphan" streams hanging about - the images are stored in command classes and these correctly dispose of the images when they themselves are disposed, but the original stream isn't.
I checked the documentation for FromStream and it confirms the stream needs to remain open. Why this hasn't crashed and burned on the Windows 7 development system is a mystery however!
I really don't want this stream hanging around, and I certainly don't want to have to store a reference to this stream as well as the image so I can dispose of it later. I only have need of that stream once so I want to get rid of it :)
Is it possible to create the image and then kill of the stream there and then?
The reason the stream needs to be open is the following:
GDI+, and therefore the System.Drawing namespace, may defer the decoding of raw image bits until the bits are required by the image. Additionally, even after the image has been decoded, GDI+ may determine that it is more efficient to discard the memory for a large Bitmap and to re-decode later. Therefore, GDI+ must have access to the source bits for the image for the life of the Bitmap or the Image object.
The documented workaround is to create either a non-indexed image using Graphics.DrawImage or to create an indexed Bitmap from the original image as described here:
Bitmap and Image constructor dependencies
According to the documentation of Image.FromStream, the stream must be kept open while the image is in use. Therefore, even if closing worked (and there's nothing to say you can't close a stream before it's disposed, as far as the stream object itself goes) it may not be a very reliable approach.
You could copy the image to another image object, and use that. However, this is likely to be more memory intensive than just keeping the stream open.
You could save the stream to a temporary file and use the Image.FromFile method. Or simply don't embed the image, keep it as a file and load it from this file at runtime.
I'am sure this will help someone :)
I used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}