C# System.AccessviolationException and using GC.Collect - c#

Here is the code sample:
ConcurrentCircularBuffer<byte[]> _cList = new ConcurrentCircularBuffer<byte[]>(10);
private Bitmap getBitmap()
{
byte[] bmpdata = _cList.Dequeue();
if (bmpdata != null && bmpdata.Length > 0)
{
GCHandle handle = GCHandle.Alloc(bmpdata, GCHandleType.Pinned);
try
{
Bitmap bmp = new Bitmap(1920, 1080, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, handle.AddrOfPinnedObject());
return bmp;
}
catch (Exception ex)
{}
finally
{
handle.Free();
}
}
return null;
}
public string GetBase64Image()
{
Bitmap bmp = getBitmap();
if (bmp != null)
{
using (var ms = new MemoryStream())
{
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png); // Here I got the System.AccessViolationException
byte[] buffer = ms.ToArray();
return Convert.ToBase64String(buffer);
}
}
}
In this case after few attempts of converting image to base64string I getting the AccessViolationException.
When I'm adding 'GC.Collect()' to my 'Finally' block, the exception doesn't appear.
What am I doing wrong?
Is there a way to avoid the using of GC.Collect()?
Source image - is the live-stream from IP-camera, that writes the byte array to implementation of ConcurrentQueue that stores last 10 images.
upd: exception thrown in the multi-thread with low latency between the executions.
upd2:
ConcurrentCircularBuffer<byte[]> _cList = new ConcurrentCircularBuffer<byte[]>(10);
public string GetBase64Image()
{
byte[] bmpdata = _cList.Dequeue();
if (bmpdata != null && bmpdata.Length > 0)
{
GCHandle handle = GCHandle.Alloc(bmpdata, GCHandleType.Pinned);
try
{
using (Bitmap bmp = new Bitmap(1920, 1080, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, handle.AddrOfPinnedObject()))
{
using (var ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Png);
return Convert.ToBase64String(ms.ToArray());
}
}
}
finally
{
handle.Free();
GC.Collect();
}
}
}
At this time is the best solution. Without GC.Collect() - accessviolation when saving bitmap to MemoryStream

Related

Convert WriteableBitmap to VideoFrame - A generic error occurred in GDI+

So i try to use ONNX file for local object detection, work great in UWP and WPF with local saved image.
Now, the problem is, to use my detection algorithm with 3D live camera.
My detection algorithm expect a (Windows.Media.)VideoFrame, and my camera give me an (System.Windows.Media.Imaging.)WriteableBitmap.
So here what i have donne already :
Convert my WriteableBitmap to Bitmap :
private System.Drawing.Bitmap BitmapFromWriteableBitmap(System.Windows.Media.Imaging.WriteableBitmap writeBmp)
{
System.Drawing.Bitmap bmp;
using (MemoryStream outStream = new MemoryStream())
{
System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)writeBmp));
enc.Save(outStream);
bmp = new System.Drawing.Bitmap(outStream);
}
return bmp;
}
Now i want to tranform my Bitmap to SoftwareBitmap (for creating a VideoFrame with VideoFrame.CreateWithSoftwareBitmap)
Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
Stream strm;
private async Task<SoftwareBitmap> SoftWareBitmapFromBitmap(Bitmap bitmap)
{
SoftwareBitmap softwareBitmap2;
strm = stream.AsStream();
bitmap.Save(strm, ImageFormat.Png);
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(stream);
softwareBitmap2 = await decoder.GetSoftwareBitmapAsync();
return softwareBitmap2;
}
But in this last function i got an error in :
bitmap.Save(strm, ImageFormat.Bmp);
I got the "A generic error occurred in GDI+."
I have try to lock/unlock the bitmap, i have try different ImageFormat, if i change to 'ImageFormat.MemoryBmp' i got an "Value cannot be null".
Thank you.
I dont know how to quotes or thumb up answer and sorry for that.
That work great just with : outStream.AsRandomAccessStream()
Here the final function :
public async Task<System.Windows.Shapes.Rectangle> GetPositionDetection(WriteableBitmap wrtBitmap, double imageWidth, double imageHeight)
{
try
{
MemoryStream outStream = new MemoryStream();
System.Windows.Media.Imaging.BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create((System.Windows.Media.Imaging.BitmapSource)wrtBitmap));
enc.Save(outStream);
Windows.Storage.Streams.InMemoryRandomAccessStream stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(outStream.AsRandomAccessStream());
SoftwareBitmap tmp2 = await decoder.GetSoftwareBitmapAsync();
VideoFrame inputImage = VideoFrame.CreateWithSoftwareBitmap(tmp2);
IList<PredictionModel> ResultsList = await objDetec.PredictImageAsync(inputImage);
if (ResultsList.Count == 0)
{
Console.WriteLine("Object not detected");
return null;
}
else
{
var itm = ResultsList.First(x => x.Probability == ResultsList.Max(y => y.Probability));
System.Windows.Shapes.Rectangle rct = new System.Windows.Shapes.Rectangle();
rct.Stroke = System.Windows.Media.Brushes.Red;// new SolidColorBrush(Windows.UI.Colors.Red);
rct.StrokeThickness = 2;
rct.Width = imageWidth * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Width) / 100);
rct.Height = imageHeight * (MappingEchellefloat(0, 1, 0, 100, itm.BoundingBox.Height) / 100);
Console.WriteLine("Object returned : " + ResultsList.Count);
return rct;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
Thank you for your help.

Error" Parameter is not valid " while converting Bytes into Image

I am converting bytes into an image but I get an error
Parameter is not valid
I am pasting my code. Kindly check the code and suggested that was I am doing right or wrong.
Image arr1 = byteArrayToImage(Bytess);
This is the function.
public static Image byteArrayToImage(byte[] byteArrayIn)
{
if (null == byteArrayIn || byteArrayIn.Length == 0)
return null;
MemoryStream ms = new MemoryStream(byteArrayIn);
try
{
Process currentProcess1 = Process.GetCurrentProcess();
Image returnImage = Image.FromStream(ms);
return returnImage;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I applied many techniques and solutions but it did not work for me
Your answer would be appreciated.
Thanks
try this
public Image byteArrayToImage(byte[] byteArrayIn)
{
System.Drawing.ImageConverter converter = new System.Drawing.ImageConverter();
Image img = (Image)converter.ConvertFrom(byteArrayIn);
return img;
}
After trying many things I found a way which has a little bit more control.
In this example you can specify the pixel format and copy the bytes to a Bitmap.
byte[] buffer = GetImageBytes();
var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
var bitmap_data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(buffer, 0, bitmap_data.Scan0, buffer.Length);
bitmap.UnlockBits(bitmap_data);
var result = bitmap as Image;
The problem is because, you are bringing it incorrectly from database. Try changing your code like this:
while (registry.Read())
{
byte[] image = (byte[])registry["Image"];
}
In my case I got the error since my base64 string had wrong encoding before calling Image.FromStream.
This worked for me in the end:
byte[] bytes = System.Convert.FromBase64String(base64ImageString);
using (MemoryStream ms = new MemoryStream(bytes))
{
var image = Image.FromStream(ms);
image.Save(filePath, System.Drawing.Imaging.ImageFormat.Png);
}
cmd.CommandText="SELECT * FROM `form_backimg` WHERE ACTIVE=1";
MySqlDataReader reader6= cmd.ExecuteReader();
if(reader6.Read())
{
code4 = (byte[])reader6["BACK_IMG"]; //BLOB FIELD NAME BACK_IMG
}
reader6.Close();
MemoryStream stream = new MemoryStream(code4); //code4 is a public byte[] defined on top
pictureBox3.Image = Image.FromStream(stream);
try this,
public Image byteArrayToImage(byte[] byteArrayIn)
{
Image returnImage = null;
using (MemoryStream ms = new MemoryStream(byteArrayIn))
{
returnImage = Image.FromStream(ms);
}
return returnImage;
}

Ink canvas byte array image binding

I have a ink canvas, where user can draw on it, and I save it as byte array into database as image:
using (MemoryStream ms = new MemoryStream())
{
if (icPad.Strokes.Count > 0)
{
icPad.Strokes.Save(ms, true);
picture = ms.ToArray();
How can I retrieve bind the byte array into image?
Edited:
I use this code below to convert to BitmapImage:
if (imageData == null || imageData.Length == 0) return null;
var image = new BitmapImage();
try
{
using (var mem = new MemoryStream(imageData))
{
mem.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
image.CacheOption = BitmapCacheOption.OnLoad;
image.UriSource = null;
image.StreamSource = mem;
image.EndInit();
}
image.Freeze();
}
catch (Exception ex)
{
}
return image;
}
I get an error:
No imaging component suitable to complete this operation was found.

pictureBox.InvokeRequired not showing img

I'm receiving from socket communication an image as byte[] and then I try to show it in a pictureBox. When I run the code it shows a message error only saying: "NullReferenceException"
The catch handling the exception is ex1 and I checked and the pic isn't null so I can't figure it out why this exception is happening.
This is my code:
try
{
if (pictureBox1.InvokeRequired)
{
try
{
pic = imageEmp;
addControlHandler c = new addControlHandler(addPic);
this.Invoke(c);
}
catch (Exception exc) { MessageBox.Show(exc.Message); }
}
else
{
pictureBox1.Image = ByteToImage(imageEmp);
}
}
catch (Exception ex1)
{
MessageBox.Show(ex1.Message);
}
public void addPic() //when invokeRequired == true
{
pictureBox1.Image = ByteToImage(pic);
}
Here is the code to convert byte[] to Image:
public Image ByteToImage(byte[] imageBytes) //convert byte[] to image
{
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
ms.Write(imageBytes, 0, imageBytes.Length);
Image image = new Bitmap(ms);
return image;
}
UPDATE 1: Regarding Hans answer, I make he following changes:
Change my ByteToImage to Hans's answer and to check where the error is I added this lines in the place where this.Invoke(c) was:
if (c != null)
{
try
{
this.Invoke(c);
}
catch (Exception e_c)
{
MessageBox.Show(e_c.Message, "exc from e_c");
}
}
This give me an exception : NullReferenceException
Thanks for any help!
UPDATE 2: Now it's working, I send JPEG images instead of JPG and it show it now. Don't know why this happens but now it's working ok.
Here is an example that you can try I have tested this just now using my own method this works so replace your code with the lines of code in my btnStudentPic_Click let me know if this works for you..
For Compact Framework try this instead
public static byte[] ReadAllBytes(string path)
{
byte[] buffer;
using (FileStream fs = new FileStream(path, FileMode.Open,
FileAccess.Read, FileShare.Read))
{
int offset = 0;
int count = (int)fs.Length;
buffer = new byte[count];
while (count > 0)
{
int bytesRead = fs.Read(buffer, offset, count);
offset += bytesRead;
count -= bytesRead;
}
}
return buffer;
}
//Windows example below don't use for CF
private void btnStudentPic_Click(object sender, EventArgs e)
{
Image picture = (Image)BrowseForPicture();
this.picStudent.Image = picture;
this.picStudent.SizeMode = PictureBoxSizeMode.StretchImage;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
private Bitmap BrowseForPicture()
{
// Bitmap picture = null;
try
{
if (this.fdlgStudentPic.ShowDialog() == DialogResult.OK)
{
byte[] imageBytes = File.ReadAllBytes(this.fdlgStudentPic.FileName);
StudentPic = new Bitmap( this.fdlgStudentPic.FileName);
StuInfo.StudentPic = imageBytes;
}
else
{
StudentPic = Properties.Resources.NoPhotoAvailable;
}
}
catch (Exception)
{
MessageBox.Show("That was not a picture.", "Browse for picture");
StudentPic = this.BrowseForPicture();
}
return StudentPic;
}

how to return null if picture box is null else return picture byte

in my following code i want to return data the null if my PictureBox(pbspic) is null else if PictureBox(pbspic) contains a picture I want data to return picture byte so that I can save null or picture in my database
using (MemoryStream stream = new MemoryStream())
{
Bitmap bmp = new Bitmap(pbspic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
cmd.Parameters.Add("#Photo", SqlDbType.VarChar).Value = data;
dm2.ExecActQuery("StudentsInsert", cmd);
Have you tried something like the following? :
else if(pbspic == null) /* Or it could be pbspic.Image == null, depends on which is null */
{
ep.SetError(tbmonfee, "Image is missing.");
return;
}
else
{
using (MemoryStream stream = new MemoryStream())
{
Bitmap bmp = new Bitmap(pbspic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
}
if(data == null) /* Or check data length if it's never null */
{
ep.SetError(tbmonfee, "Image is missing.");
return;
}
}
try creating a metthod of your stream and then call it for picture like this
private byte[] GetPic(Image img)
{
using (MemoryStream stream = new MemoryStream())
{
Bitmap bmp = new Bitmap(pbspic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
byte[] data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
}
USAGE:
if (pbspic.Image == null)
{
cmd.Parameters.Add("#Photo", SqlDbType.VarChar).Value = "NULL";
}
else
{
cmd.Parameters.Add("#Photo", SqlDbType.Image).Value = GetPic(pbspic.Image);
}
dm2.ExecActQuery("StudentsInsert", cmd);

Categories