Image.FromStream Fails After Editing One Byte in the Array - c#

I'm trying to create an image from an array of bytes. As a sanity test of the underlying concept, I create a byte[] from a local BMP file:
Bitmap sample = (Bitmap)Bitmap.FromFile("C:\\frames\\Sample.bmp");
ImageConverter converter = new ImageConverter();
byte[] sampleArray = (byte[])converter.ConvertTo(sample, typeof(byte[]));
Printing the array looks like this: sampleArray[] { 66, 77, 182, 173, 3, 0, 0, 0, 0, 0, 54, 4, 0,...
Then, I re-create the BMP using a MemoryStream from the array:
var ms = new MemoryStream(sampleArray);
System.Drawing.Image bmp = Image.FromStream(ms, false, false);
This all works great. However, when I edit a single entry in the array to values >= 55, I get a "Parameter is not valid" error.
sampleArray[20] = (byte)55;
I've tried a few values to try and figure it out, but I don't see a connection. 255, 250, 100, 80, 60, 55 all fail. But, 33, 40, 50-54 work.
I've also tried copying values from the existing array to another position (in case there's a type issue or something). The low values can be copied, but not the higher ones (I didn't test this extensively).
What's going on? Is there a header or checksum or something that validates the array of bytes as a valid image?
Here's the code all put together:
private void sampleBMP(object sender, EventArgs e)
{
try
{
Bitmap img = (Bitmap)Bitmap.FromFile("C:\\frames\\Sample.bmp");
ImageConverter converter = new ImageConverter();
byte[] sampleArray = (byte[])converter.ConvertTo(img, typeof(byte[]));
outputArray("Sample", sampleArray);
try
{
var ms = new MemoryStream(sampleArray);
System.Drawing.Image bmp = Image.FromStream(ms, false, false);
bmp.Save(#"C:\\frames\\Sample_recreated.bmp");
}
catch (Exception ex)
{
Console.WriteLine("sample_recreated didn't work: " + ex);
}
sampleArray[10] = (byte)33; // doesn't work: 255, 250, 100, 80, 60, 55 Works: 33, 50, 51, 52, 53, 54
try
{
var ms = new MemoryStream(sampleArray);
System.Drawing.Image bmp = Image.FromStream(ms, false, false);
bmp.Save(#"C:\\frames\\Sample_recreated_edited.bmp");
}
catch (Exception ex)
{
Console.WriteLine("sample_recreated_edited didn't work: " + ex);
}
}
catch (Exception ex)
{
Console.WriteLine("====Exception: " + ex);
}
}
private void outputArray(string passedName, byte[] passedArray)
{
var sb = new StringBuilder(passedName + "[] { ");
foreach (var b in passedArray)
{
sb.Append(b + ", ");
}
sb.Append("}");
Console.WriteLine(sb.ToString());
}

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.

Randomly getting Argument Exception and out of memory exception when receiving images via tcp c#

I've been racking my brain over why this is happening, it'll run several times very well but it'll randomly receive the length as an odd number (-123456 for example, or it'll receive as 0).
Then when it goes to make an image out of the stream it can't because the length was wrong. Sometimes the length value will look like a normal value but I'll still get the argument exception when it goes to generate the image.
Edit: I'm also randomly receiving large numbers for the "len" object which causes an Out Of Memory Exception, yet the send side never sends anything as large as that number so I don't understand where that number is coming from.
This is the receiving code:
public void ReceiveSS()
{
bool firstTimeRun = true;
TcpListener ssTcpListener = new TcpListener(IPAddress.Any, 63000);
TcpClient tcpReceiver = new TcpClient();
ssTcpListener.Start();
tcpReceiver = new TcpClient();
if (!uPnPWorks)
{
try
{
Console.WriteLine(contactIP + " " + port);
tcpReceiver.Connect(contactIP.ToString(), port);
}
catch (Exception)
{
}
}
else
{
tcpReceiver = ssTcpListener.AcceptTcpClient();
}
while (!ssStop)
{
try
{
//Start listening for connection.
if (tcpReceiver.Connected)
{
if (firstTimeRun)
{
//TCP connected. Receive images from contact.
NetworkStream receivedNs = new NetworkStream(tcpReceiver.Client);
BinaryReader br = new BinaryReader(receivedNs);
byte[] lenOfImage = new byte[4];
br.Read(lenOfImage, 0, 4);
int len = (int)(lenOfImage[0] << 24) | (int)(lenOfImage[1] << 16) | (int)(lenOfImage[2] << 8) | lenOfImage[3];
Console.WriteLine(len);
byte[] receivedData = new byte[len];
br.Read(receivedData, 0, receivedData.Length);
MemoryStream ms = new MemoryStream(receivedData, 0, receivedData.Length);
ms.Seek(0, SeekOrigin.Begin);
receivedNs.Flush();
Bitmap image = new Bitmap(ms);
receivedImage = image;
//Put image into picturebox.
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(delegate() { pboScreenShare.Image = image; }));
}
else { pboScreenShare.Image = image; }
//br.Close();
firstTimeRun = false;
}
else if (!firstTimeRun)
{
//TCP connected. Receive images from contact.
NetworkStream receivedNs = new NetworkStream(tcpReceiver.Client);
BinaryReader br = new BinaryReader(receivedNs);
byte[] lenOfImage = new byte[4];
br.Read(lenOfImage, 0, 4);
int len = (int)(lenOfImage[0] << 24) | (int)(lenOfImage[1] << 16) | (int)(lenOfImage[2] << 8) | lenOfImage[3];
try
{
MemoryStream ms = new MemoryStream();
if (len > 0)
{
byte[] receivedData = new byte[len];
br.Read(receivedData, 0, receivedData.Length);
ms = new MemoryStream(receivedData, 0, receivedData.Length);
ms.Seek(0, SeekOrigin.Begin);
}
receivedNs.Flush();
receivedImage2 = new Bitmap(ms); //Where I get the random argument exception
receivedImage2.MakeTransparent(Color.Pink);
Bitmap overlayedImage = new Bitmap(receivedImage.Width, receivedImage.Height);
using (Graphics gr = Graphics.FromImage(overlayedImage))
{
gr.DrawImage(receivedImage, new Point(0, 0));
gr.DrawImage(receivedImage2, new Point(0, 0));
}
//Put image into picturebox.
this.Invoke(new MethodInvoker(delegate() { pboScreenShare.Image = overlayedImage; }));
receivedImage2.Dispose();
receivedImage = overlayedImage;
//br.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + " Getting image");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString() + " ReceiveSS()");
}
}
}
Send code:
private void SendSS()
{
int cursorX = 0;
int cursorY = 0;
TcpListener listener = new TcpListener(IPAddress.Any, 63001);
listener.Start();
tcpClient = new TcpClient();
if (uPnPWorks)
{
tcpClient = listener.AcceptTcpClient();
}
else
{
try
{
tcpClient.Connect(contactIP, 63000);
}
catch (Exception)
{
}
}
bool firstTimeRun = true;
while (!ssStop)
{
try
{
if (tcpClient.Connected)
{
//Connected. Capture screen image.
if (firstTimeRun)
{
MemoryStream ssmemStream = new MemoryStream();
screenShotBMP = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Bitmap cursorBMP = CaptureCursor(ref cursorX, ref cursorY);
Graphics graphics = Graphics.FromImage(screenShotBMP as Image);
graphics.CopyFromScreen(0, 0, 0, 0, screenShotBMP.Size);
if (cursorBMP != null)
{
using (Graphics g = Graphics.FromImage(screenShotBMP))
{
Rectangle r = new Rectangle(cursorX, cursorY, cursorBMP.Width, cursorBMP.Height);
g.DrawImage(cursorBMP, r);
}
}
Bitmap saveScreenShot = screenShotBMP;
saveScreenShot.Save(ssmemStream, ImageFormat.Png);
NetworkStream ns = tcpClient.GetStream();
//Convert image to data.
BinaryWriter bw = new BinaryWriter(ns);
byte[] bytesToSend = ssmemStream.ToArray();
byte[] imageLen = new byte[4];
int len = bytesToSend.Length;
imageLen[0] = (byte)((len & 0xff000000) >> 24);
imageLen[1] = (byte)((len & 0x00ff0000) >> 16);
imageLen[2] = (byte)((len & 0x0000ff00) >> 8);
imageLen[3] = (byte)(len & 0xff);
ns.Write(imageLen, 0, 4);
ns.Write(bytesToSend, 0, bytesToSend.Length);
Console.WriteLine(bytesToSend.Length);
ns.Flush();
//bw.Close();
firstTimeRun = false;
}
else if (!firstTimeRun)
{
MemoryStream ssmemStream = new MemoryStream();
screenShotBMP2 = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Bitmap cursorBMP = CaptureCursor(ref cursorX, ref cursorY);
Graphics graphics = Graphics.FromImage(screenShotBMP2 as Image);
graphics.CopyFromScreen(0, 0, 0, 0, screenShotBMP2.Size);
if (cursorBMP != null)
{
using (Graphics g = Graphics.FromImage(screenShotBMP2))
{
Rectangle r = new Rectangle(cursorX, cursorY, cursorBMP.Width, cursorBMP.Height);
g.DrawImage(cursorBMP, r);
}
}
diffImage = ImageTool.GetDifferenceImage(screenShotBMP, screenShotBMP2, Color.Pink);
diffImage.Save(ssmemStream, ImageFormat.Png);
try
{
NetworkStream ns = tcpClient.GetStream();
//Convert image to data.
BinaryWriter bw = new BinaryWriter(ns);
byte[] bytesToSend = ssmemStream.ToArray();
byte[] imageLen = new byte[4];
int len = bytesToSend.Length;
Console.WriteLine(len);
imageLen[0] = (byte)((len & 0xff000000) >> 24);
imageLen[1] = (byte)((len & 0x00ff0000) >> 16);
imageLen[2] = (byte)((len & 0x0000ff00) >> 8);
imageLen[3] = (byte)(len & 0xff);
ns.Write(imageLen, 0, 4);
ns.Write(bytesToSend, 0, bytesToSend.Length);
Console.WriteLine(bytesToSend.Length);
ns.Flush();
//bw.Close();
}
catch
{
Console.WriteLine("iox exception");
}
screenShotBMP = screenShotBMP2;
}
}
}
catch (SocketException sockEx)
{
Console.WriteLine(sockEx.Message + " SendSS()");
}
}
}
You are assuming that Read/Receive returns you exactly the amount of data you wanted. That is not the case. It returns you at most that much and at least one byte. Adapt your code to deal with that fact. For example, by using BinaryReader or reading in a loop until you have got the required number of bytes.
Better yet: Stop using sockets. Use something higher-level like HTTP or web-services. Sockets are the wrong solution most of the time.

Error at sending a picture from server to client

I have 2 Apps (server - client ) .
The server is modified version of TVsharp (Application that stream local analog tv signal using RTLSDR)
Each frame of the streamed video is a grayscale array of bytes .
I have modified it so it re sizes and sends each frame for a client over TCP socket
The client is supposed to receive the frames through the socket as Image objects and displays them in a picture box
Im getting invalid parameters error .
After i added a delay (Thread.Sleep()) it started to display one frame and then it gives invalid parameter exception (after the sleeping time)
This is the part of TVsharp that dose the sending :
Grayscale is an array that contains the brightness for each pixel
private string drive = "E:\\";
private string file = "0";
private string extension = ".bmp";
private string path2 = "E:\\test\\";
private string fullpath;
private int file_counter = 0;
Bitmap bitmap2 = new Bitmap(_pictureWidth, _pictureHeight);
var data2 = bitmap2.LockBits(new Rectangle(Point.Empty, bitmap2.Size),
ImageLockMode.WriteOnly,PixelFormat.Format24bppRgb);
Marshal.Copy(GrayScaleValues, 0, data2.Scan0, GrayScaleValues.Length);
bitmap2.UnlockBits(data2);
bitmap2.Save(fullpath, System.Drawing.Imaging.ImageFormat.Bmp);
string Npath = path2 + file + extension;
Image img = Image.FromFile(fullpath);
// Size size = new Size(982, 543);
// ResizeImage(img, size);
Rectangle cropRect = new Rectangle(80, 0, 240, 175);
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using (Graphics g = Graphics.FromImage(target))
{
g.DrawImage(img, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
}
//double scale = 203 / 96;
int width = (int)(target.Width);
int height = (int)(target.Height);
BinaryWriter brn = new BinaryWriter(s);
System.Drawing.Bitmap bmpScaled = new System.Drawing.Bitmap(target, width, height);
bmpScaled.Save(Npath);
byte[] imageArray = File.ReadAllBytes(Npath);
sw.WriteLine(imageArray.Length.ToString());
sw.Flush();
// Thread.Sleep(500);
brn.Write(imageArray);
//Thread.Sleep(500);
_detectLevel = Convert.ToInt32(_maxSignalLevel * _detectorLevelCoef);
_agcSignalLevel = agcMaxLevel;
}
This client the client segment that suppose to get the frames and display them
flag = true;
TcpClient client = new TcpClient(textBox1.Text, Convert.ToInt32(textBox2.Text));
Stream s = client.GetStream();
StreamReader sr = new StreamReader(s);
StreamWriter sw = new StreamWriter(s);
sw.Flush();
BinaryFormatter formatter = new BinaryFormatter();
string msg = sr.ReadLine();
MessageBox.Show("It's working !! the message is " + msg);
BinaryReader Brn = new BinaryReader(s);
Thread.Sleep(5000);
while (flag)
{
// Thread.Sleep(5000);
int size = Convert.ToInt32(sr.ReadLine());
label3.Text = "Size is " + size;
byte[] imagerray = Brn.ReadBytes(size);
MemoryStream ms = new MemoryStream(imagerray);
Thread.Sleep(10000);
Image image = Image.FromStream(ms);
ResizeImage(image, this.Size);
pictureBox1.Image = image;
Thread.Sleep(10);
}
}

How to transfer images from wcf ksoap2 to android

I am trying to send images from wcf ksoap2 to android.
At wcf side I have converted all images into byte array and stored them in an ArrayList.
At android side I fill the ArrayList from wcf response.
Now the problem is byte array is not receiving properly and byte array is not converting into Image/BufferedImage.
Here is my code
byt = new byte[4096];
byt = (byte[]) al.get(5);
//Image im;
BufferedImage bImageFromConvert = null;
InputStream in = new ByteArrayInputStream(byt);
try {
bImageFromConvert = ImageIO.read(in);
//ImageIO.write(bImageFromConvert, "jpg", new File(
// "c:/new-darksouls.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
al is my ArrayList.
private String prepareImage() {
if (tempPath == null ) {
return "";
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(tempPath, options);
bitmap = Bitmap.createScaledBitmap(bitmap, 50, 50, true);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//bitmap.compress(Bitmap.CompressFormat.PNG, 50, baos);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, baos);
byte[] byteArray = baos.toByteArray();
String imageString = com.size4u.utils.Base64
.encodeBytes(byteArray);
bitmap = null;
System.gc();
Runtime.getRuntime().gc();
return imageString;
}

c# shorten query string parameter

I need to pass a URL as a parameter into my querystring, since the URLs can be long I need to shorten the URL while passing and then be able to decrypt them on server side.
The URL that I am trying to pass does not contain sensitive information so string encryption techniques are not required, I am just looking to convert a long string to a short string and be able to reconstruct it back to a string.
I have tried AES encryption and it works but the resulting string is sometimes longer than the URL value itself.
Example of what I've tried so far :
private static byte[] key = { 252, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
private static byte[] vector = { 152, 64, 191, 111, 23, 3, 113, 119, 231, 121, 221, 112, 79, 32, 114, 156 };
private ICryptoTransform encryptor, decryptor;
private UTF8Encoding encoder;
public SimpleAES()
{
RijndaelManaged rm = new RijndaelManaged();
encryptor = rm.CreateEncryptor(key, vector);
decryptor = rm.CreateDecryptor(key, vector);
encoder = new UTF8Encoding();
}
public string Encrypt(string unencrypted)
{
return Convert.ToBase64String(Encrypt(encoder.GetBytes(unencrypted)));
}
public string Decrypt(string encrypted)
{
return encoder.GetString(Decrypt(Convert.FromBase64String(encrypted)));
}
public string EncryptToUrl(string unencrypted)
{
return HttpUtility.UrlEncode(Encrypt(unencrypted));
}
public string DecryptFromUrl(string encrypted)
{
return Decrypt(HttpUtility.UrlDecode(encrypted));
}
public byte[] Encrypt(byte[] buffer)
{
return Transform(buffer, encryptor);
}
public byte[] Decrypt(byte[] buffer)
{
return Transform(buffer, decryptor);
}
protected byte[] Transform(byte[] buffer, ICryptoTransform transform)
{
MemoryStream stream = new MemoryStream();
using (CryptoStream cs = new CryptoStream(stream, transform, CryptoStreamMode.Write))
{
cs.Write(buffer, 0, buffer.Length);
}
return stream.ToArray();
}
Example TEST :
string unencrypted = "/exampleurl/this_is_a_long_string_the_length_of_this_url_is_112_charachters_/this_string_needs_to_be-shortened/";
var result = EncryptToUrl(unencrypted);
"MHMyQdwbJpw8ah%2fbhAr2eJwTFa%2fyupemjuOVcBJmxTIdzcR0PZKCNSa5Fvi7kNrY3Kxlk5KWqAAEspWVtJfNjwwPs%2bCDGpC9Fn8CeGezWhXEbLT6CST2v%2fKpvptHVi3fBYSk1w3q1FYMx3C5DdKueQ%3d%3d"
The actual string is 112 charachters long and the result is 165 charahcters long.
The following code is taken verbatim from here. I duplicated this because the question is not a duplicate but the answer solves the problem this question poses. When you call Zip you will need to base64 encode the result to make it friendly for a browser if you plan to include it in a URL or something.
public static void CopyTo(Stream src, Stream dest) {
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) {
dest.Write(bytes, 0, cnt);
}
}
public static byte[] Zip(string str) {
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
using (var gs = new GZipStream(mso, CompressionMode.Compress)) {
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray();
}
}
public static string Unzip(byte[] bytes) {
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream()) {
using (var gs = new GZipStream(msi, CompressionMode.Decompress)) {
//gs.CopyTo(mso);
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
}
static void Main(string[] args) {
byte[] r1 = Zip("StringStringStringStringStringStringStringStringStringStringStringStringStringString");
string r2 = Unzip(r1);
}
This might sound strange, but can you store the querystring in a database and reference it by some primary key? That might be similar to using some third party URL shortening service.

Categories