How to overcome writing over a file C# - c#

EDIT: Add method where error actually occurs...
I am opening an image and I want to be able to overwrite the original file as modification happens. I tryed both of the methods here
public ImgPro(String Path)
{
Bitmap bt1 = new Bitmap(Path);
Bitmap bt2 = new Bitmap(bt1.Width, bt1.Height, PixelFormat.Format24bppRgb);
var imgRec = new Rectangle(0, 0, bt1.Width, bt1.Height);
Graphics bt2G = Graphics.FromImage(bt2);
bt2G.DrawImage(bt1, imgRec);
bt1.Dispose();
this.bitmap = bt2;
}
And
public ImgPro(String Path)
{
Bitmap bt1 = new Bitmap(Path);
Bitmap bt2 = new Bitmap(bt1.Width, bt1.Height, PixelFormat.Format24bppRgb);
var imgRec = new Rectangle(0, 0, bt1.Width, bt1.Height);
BitmapData bt1Data = bt1.LockBits(imgRec, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData bt2Data = bt2.LockBits(imgRec, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
// Create data array to hold bmpSource pixel data
int numBytes = bt1Data.Stride * (int)bt1.Height;
var srcData = new byte[numBytes];
var destData = new byte[numBytes];
Marshal.Copy(bt1Data.Scan0, srcData, 0, numBytes);
Array.Copy(srcData, destData, srcData.Length);
Marshal.Copy(destData, 0, bt2Data.Scan0, numBytes);
bt1.UnlockBits(bt1Data); bt2.UnlockBits(bt2Data);
bt1.Dispose();
this.bitmap = bt2;
}
But both options failed when I went to save the file I got this error.
An unhandled exception of type 'System.Runtime.InteropServices.ExternalException' occurred in System.Drawing.dll
For this method:
public void Save(string filename)
{
bitmap.Save(filename, ImageFormat.Jpeg);
}

Since Bitmap locks the underlying stream, you could copy the file contents to a MemoryStream and base the Bitmap on that instead. This should prevent the file from being locked:
var bytes = File.ReadAllBytes(Path);
using (var stream = new MemoryStream(bytes)) // Don't dispose this until you're done with your Bitmap
{
Bitmap bt1 = new Bitmap(stream);
// ...
}

Related

How to convert byte[] to bitmap

I want to share bitmap between server and client. I've tried a lot, but I've had problems with all the way the bottom part of the image missing.
First way:
Bitmap bmp = new Bitmap(800, 450);
using (var ms = new MemoryStream(readBuffer))
{
bmp = new Bitmap(ms);
}
Second way:
using (var ms = new MemoryStream(readBuffer))
{
bmp = new Bitmap(ms);
//bmp = Image.FromStream(ms) as Bitmap;
}
This way, the image wasn't converted properly.
Bitmap bmp = new Bitmap(800, 450, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(readBuffer, 0, bmpData.Scan0, readBuffer.Length);
bmp.UnlockBits(bmpData);
How can I properly convert to a bitmap where the bottom part has not disappeared?
This is the code I used to convert the bitmap to byte.
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, panel1.Width, panel1.Height));
using (var stream = new MemoryStream())
{
bmp.Save(stream, ImageFormat.Png);
sendBuffer = stream.ToArray();
}
Array.Resize(ref sendBuffer, 1024*4);

How to cretae a bitmap image from a byte arrayin androidwith java?

I have a c# tcp server and i send a image byte array to my android client. But i have no success to convert array to bitmap.
This is my c# code:
new Thread(() =>{
//İmage converter
ImageConverter imConv = new ImageConverter();
//memory streaö
MemoryStream ms = new MemoryStream();
//bitmap
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format16bppRgb555);
Graphics g = Graphics.FromImage(bitmap);
g.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
Cursors.Default.Draw(g, new Rectangle(new Point(Cursor.Position.X, Cursor.Position.Y), new Size(Cursors.Default.Size.Width, Cursors.Default.Size.Height)));
bitmap.Save(ms, ImageFormat.Png);
Image img = Image.FromStream(ms);
byte[] imgArry = (byte[])imConv.ConvertTo(img,typeof(byte[]));
tcpManager.SendTo(socket,imgArry);
bitmap.Dispose();
ms.Close();
ms.Dispose();
Thread.Sleep(41);
}).Start();
And this is my android client code, i get successfully the byte array but the function returns me a null bitmap
#Override
public void OnReceived(byte[] byteData) {
try{
final Bitmap bitmap = BitmapFactory.decodeByteArray(byteData, 0, byteData.length);
runOnUiThread(new Runnable() {
#Override
public void run() {
screenView.setImageBitmap(bitmap);
}
});
}catch (Exception ex){
}
}

convert gdcm_image to .NET bitmap fail

Hi am trying to get bitmap to display from DICOM file , but when try to create bitmap from the buffer I get Parameter is not valid for the Bitmap constructor call. I use the following code
gdcm.ImageReader reader = new gdcm.ImageReader();
reader.SetFileName(_dicomFilePath);
if (reader.Read())
{
var image = reader.GetImage();
if (image != null)
{
byte[] imageByteArray = new byte[image.GetBufferLength()];
if (image.GetBuffer(imageByteArray))
{
MemoryStream stream = new MemoryStream();
stream.Write(imageByteArray, 0, imageByteArray.Length);
stream.Seek(0, SeekOrigin.Begin);
Bitmap bmp = new Bitmap(stream);
CurrentFrameDataGDCM = Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight((int)image.GetRows(), (int)image.GetColumns()));
}
}
}

Kinect Byte Stream Too Large

I'm trying to stream Kinect video data (just the image, not depth/infared) but I find the default buffer size on the image is very large (1228800) and incapable of sending over a network. I was wondering if there was any way of getting access to a smaller array without having to go down the route of codec compression. Here's is how I declare the Kinect which I took from a Microsoft sample;
// Turn on the color stream to receive color frames
this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
// Allocate space to put the pixels we'll receive
this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
// This is the bitmap we'll display on-screen
this.colorBitmap = new WriteableBitmap(this.sensor.ColorStream.FrameWidth,
this.sensor.ColorStream.FrameHeight, 96.0, 96.0, PixelFormats.Bgr32, null);
// Set the image we display to point to the bitmap where we'll put the image data
this.kinectVideo.Source = this.colorBitmap;
// Add an event handler to be called whenever there is new color frame data
this.sensor.ColorFrameReady += this.SensorColorFrameReady;
// Start the sensor!
this.sensor.Start();
And here is the New Frame event which I then try to send each frame;
private void SensorColorFrameReady(object sender,
ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame != null)
{
// Copy the pixel data from the image to a temporary array
colorFrame.CopyPixelDataTo(this.colorPixels);
// Write the pixel data into our bitmap
this.colorBitmap.WritePixels(
new Int32Rect(0, 0, this.colorBitmap.PixelWidth,
this.colorBitmap.PixelHeight),
this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int),
0);
if (NetworkStreamEnabled)
{
networkStream.Write(this.colorPixels, 0,
this.colorPixels.GetLength(0));
}
}
}
}
UPDATE
I'm using the following two methods to convert the ImageFrame to a Bitmap and then the Bitmap to a Byte[]. This has brought the buffer size down to ~730600. Still not enough but progress. (Source: Convert Kinect ColorImageFrame to Bitmap)
public static byte[] ImageToByte(Image img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
Bitmap ImageToBitmap(ColorImageFrame Image)
{
byte[] pixeldata = new byte[Image.PixelDataLength];
Image.CopyPixelDataTo(pixeldata);
Bitmap bmap = new Bitmap(Image.Width, Image.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
BitmapData bmapdata = bmap.LockBits(
new Rectangle(0, 0, Image.Width, Image.Height),
ImageLockMode.WriteOnly,
bmap.PixelFormat);
IntPtr ptr = bmapdata.Scan0;
Marshal.Copy(pixeldata, 0, ptr, Image.PixelDataLength);
bmap.UnlockBits(bmapdata);
return bmap;
}
My recommendation would be to store the colorframe in a bitmap, then send those files over the network and reassemble them in a video program. A project I've been doing with the Kinect does this:
//Save to file
if (skeletonFrame != null)
{
RenderTargetBitmap bmp = new RenderTargetBitmap(800, 600, 96, 96, PixelFormats.Pbgra32);
bmp.Render(window.image);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
// create frame from the writable bitmap and add to encoder
if (skeletonFrame.Timestamp - lastTime > 90)
{
encoder.Frames.Add(BitmapFrame.Create(bmp));
string myPhotos = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string path = "C:your\\directory\\here" + skeletonFrame.Timestamp + ".jpg";
using (FileStream fs = new FileStream(path, FileMode.Create))
{
encoder.Save(fs);
}
lastTime = skeletonFrame.Timestamp;
}
}
Of course, if you need this to be in real time, you're not going to like this solution, and I think my "comment" button is gone after the bounty.

Comparing Images as Byte Arrays for Unit Tests

I have a class that creates an Image from a Byte[], along with some other logic, and I am trying to write a unit test that asserts that the Image instance returned from my class is the same as some fake Image I have in my unit test.
I cannot find a reliable way to:
Start with a fake Image \ Byte[] \ Resource \ something.
Pass a Byte[] representing the fake thing to my class.
Assert the Image returned from my class is the same as my fake thing.
Here's the code I have come up with so far:
Bitmap fakeBitmap = new Bitmap(1, 1);
Byte[] expectedBytes;
using (var ms = new MemoryStream())
{
fakeBitmap.Save(ms, ImageFormat.Png);
expectedBytes = ms.ToArray();
}
//This is where the call to class goes
Image actualImage;
using (var ms = new MemoryStream(expectedBytes))
actualImage = Image.FromStream(ms);
Byte[] actualBytes;
using (var ms = new MemoryStream())
{
actualImage.Save(ms, ImageFormat.Png);
actualBytes = ms.ToArray();
}
var areEqual =
Enumerable.SequenceEqual(expectedBytes, actualBytes);
Console.WriteLine(areEqual);
var desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
using(StreamWriter sw = new StreamWriter(Path.Combine(desktop, "expectedBytes.txt")))
sw.Write(String.Join(Environment.NewLine, expectedBytes));
using(StreamWriter sw = new StreamWriter(Path.Combine(desktop, "actualBytes.txt")))
sw.Write(String.Join(Environment.NewLine, actualBytes));
This always returns false.
Try this:
public static class Ext
{
public static byte[] GetBytes(this Bitmap bitmap)
{
var bytes = new byte[bitmap.Height * bitmap.Width * 3];
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
Marshal.Copy(bitmapData.Scan0, bytes, 0, bytes.Length);
bitmap.UnlockBits(bitmapData);
return bytes;
}
}
var bitmap = new Bitmap(#"C:\myimg.jpg");
var bitmap1 = new Bitmap(#"C:\myimg.jpg");
var bytes = bitmap.GetBytes();
var bytes1 = bitmap1.GetBytes();
//true
var sequenceEqual = bytes.SequenceEqual(bytes1);
I can imagine that Image.Save also updates the metadata inside the image, modifying the date/time of that picture which will change your byte-array.

Categories