C# Reading Bitmap from Stream - c#

I've a network stream which sends a name and a picture. Name and picture start and end with a specific word
Example:
BeginNameXXXXXXXEndNameBeginPicYYYYYYYYYEndPic
I'll collect the stream in blocks and check if the last block contains the stop word of the picture.
byte[] data = new byte[2048];
int numBytesRead = stream.Read(data, 0, 2048);
if (numBytesRead > 0)
{
code += Encoding.ASCII.GetString(data, 0, numBytesRead);
}
If yes I'll stop collecting and divide the String into the name part and the picture part.
In principle I should have now a string only containing the picture.
Afterwards I try to save it as image but I only get an exception on the last code step
byte[] toEncodeAsBytes = ASCIIEncoding.ASCII.GetBytes(code);
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
ms.Position = 0;
var image = Image.FromStream(ms, true);
Exception thrown: 'System.ArgumentException' in System.Drawing.dll
Any ideas what could be wrong?

Related

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();

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.

IP camera streaming error

I have a Samsung IP camera and I want to stream it in to my c# program, but when I run the program I got 'invalid parameter' error.
private void button1_Click(object sender, EventArgs e) { while (true) {
string sourceURL = url; byte[] buffer = new byte[100000];
int read, total = 0;
// create HTTP request
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(sourceURL);
req.Credentials = new NetworkCredential("admin", "4321");
// get response
WebResponse resp = req.GetResponse();
// get response stream
Stream stream = resp.GetResponseStream();
// read data from stream
while ((read = stream.Read(buffer, total, 1000)) != 0)
{
total += read;
}
Bitmap bmp = (Bitmap)Bitmap.FromStream(new MemoryStream(buffer, 0, total));
pictureBox1.Image = bmp;
}
}
What might be the problem?
You are not building the correct buffer, you are overriding the old buffer with new buffer each time while there is new data, idea to fix it:
List<byte> fullData = new List<Byte>();
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)//also > 0 not == 0 because of it can be -1
{
fullData.AddRange(new List<Byte>(buffer).GetRange(0, read));//only add the actual data read
}
byte[] dataRead = fullData.ToArray();
Bitmap bmp = (Bitmap)Bitmap.FromStream(new MemoryStream(dataRead , 0, dataRead.Lenght));
My guess (since you don't indicate the error) is that the image has gone over 100,000 bytes, which your code doesn't handle at all. I would, instead:
byte[] buffer = new byte[10 * 1024];
...
using(var ms = new MemoryStream())
{
// read everything in the stream into ms
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
// rewind and load the bitmap
ms.Position = 0;
Bitmap bmp = (Bitmap)Bitmap.FromStream(ms);
pictureBox1.Image = bmp;
}
kinda late answer relative to the time of the question; however, since I'm hunting down similar issues and this has apparently not been answered, I'm adding my two cents...
There are two issues here as I see it:
First:
You don't wanna put the event handler of a button-click into an endless loop. This should probably be a thread of some type so that the event handler can return.
Second:
As mentioned in another comment, your code is expecting the response to be a raw image of some type, and most likely it is not. Your camera may eventually send MJPG, but that doesn't mean it comes raw. Sometimes you have to send other commands to the camera and then when you actually start getting the MJPG stream you have to parse it and extract headers prior to sending the portion of the image to some picturebox. You're probably getting some kind of html response from the camera (as I am) and when you try to pass that data to a method that is expecting the data to be some image format (likely JPEG), then you get the invalid parameter error.
Can't say I know how to solve the problem cause it depends on the camera. If there is some kind of standard interface for these cameras I'd sure like to know what it is! Anyway, HTH...

WPF download image bytes from Blob Storage

I want to preload a lot of images when my app starts up, sort of a once off thing.
I have an Image class that contains the Url of its image stored in the cloud as blob storage (this address is a https address BTW)
I want to download the image bytes from the cloud, store them on the object, then when it comes time to show the image, load the image from its bytes.
I have all the code for this, but I keep getting the exception:
No imaging component suitable to complete this operation was found.
Here is my code: EDIT UPDATED WITH A FIX
//Loaded on start-up
private static void LoadImageBytes(Image img)
{
var urlUri = new Uri(img.Url);
var request = (HttpWebRequest)WebRequest.CreateDefault(urlUri);
MemoryStream memStream = new MemoryStream();
using (var response = request.GetResponse())
{
var buffer = new byte[4096];
using (var stream = response.GetResponseStream())
{
int bytesRead = stream.Read(buffer, 0, buffer.Length);
while (bytesRead > 0)
{
memStream.Write(buffer, 0, bytesRead);
bytesRead = stream.Read(buffer, 0, buffer.Length);
}
img.ImageBytes = memStream.ToArray();
}
}
}
Then when I want to get the image on the screen I call this:
public BitmapImage ImageFromBuffer(Byte[] bytes)
{
MemoryStream stream = new MemoryStream(bytes);
stream.Seek(0, SeekOrigin.Begin);
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = stream;
image.EndInit();
return image;
}
But in the EndInit() call I get the exception.
I have done some testing and if I load the file from my local filesystem, I get a different set of bytes to that of the image in the cloud. I assume its something to do with blob storage or https?
And yes I can browse to that image and its not corrupted.
EDIT, fixed now all good
Are you sure this line is correct?
while (stream.Read(buffer, 0, buffer.Length) > 0)
img.ImageBytes = buffer;
img.ImageBytes will hold the last read buffer.

Image Retrieve using c#

byte[] imageData = null;
long byteSize = 0;
byteSize = _reader.GetBytes(_reader.GetOrdinal(sFieldName), 0, null, 0, 0);
imageData = new byte[byteSize];
long bytesread = 0;
int curpos = 0, chunkSize = 500;
while (bytesread < byteSize)
{
// chunkSize is an arbitrary application defined value
bytesread += _reader.GetBytes(_reader.GetOrdinal(sFieldName), curpos, imageData, curpos, chunkSize);
curpos += chunkSize;
}
byte[] imgData = imageData;
MemoryStream ms = new MemoryStream(imgData);
Image oImage = Image.FromStream((Stream)ms);
return oImage;
Code creates problem when "Image oImage = Image.FromStream((Stream)ms);" line executes.....This line shows "Parameter is not valid" message .......Why it occurs? Help me. I want to retrieve image from database ....I work on C# window vs05 .....Can any one help me? byte[] contain value. All works well, just problem occurs when this line executes.
A simple if statement should solve your problem before creating the memory stream
if (imageData.Length != 0)
{
MemoryStream ms = new MemoryStream(imageData);
Image oImage = Image.FromStream((Stream)ms);
return oImage;
}
return null;
I can't really spot any errors in this code (other than the MemoryStream not being disposed, and that it's not necessary to cast it to Stream when passing it to the Image.FromStream method; but those should not cause your error). I would do the following in order to try to find the error:
Write the byte data to a file and try to open the image in a graphics program (to verify that the byte data does indeed represent a valid image). My guess is that this would fail.
Check the code that writes the data to the database (perhaps perform the same trick as in the previous point; write it to a file and try to open the file)

Categories

Resources