Sending image with byte array convertion, from java to c# - c#

I am trying to send a .jpg file which is on my android device to my server computer.
To do this, I am converting the picture into a byte array by a java android application, and sending it as an argument to my server computer. I`m doing this by a web service call.
The first function is edited:
public static byte[] ImageConvertion(){
File inputFile = new File("/storage/emulated/0/IFSpictures/icon-si_strapclamp.jpg");
byte[] data;
try{
FileInputStream input = new FileInputStream(inputFile);
ByteArrayOutputStream output = new ByteArrayOutputStream ();
byte[] buffer = new byte[65535];
int l;
while ((l = input.read(buffer)) > 0)
output.write (buffer, 0, l);
input.close();
output.close();
data = output.toByteArray();
return data;
} catch (IOException e) {
System.err.println(e);
data=null;
}
return data;
}
My web-service is written in ASP.NET (C#) language, and there is a function that takes the byte array as an argument and converts it back into an image on server computer.
[WebMethod]
public void ByteArrayToPicture(byte[] imageData)
{
using (var ms = new MemoryStream(imageData))
{
Image image = Image.FromStream(ms);
image.Save(#"C:\newImage.jpg");
}
}
However, I couldn`t do it because of the web-service side. I have debugged it that and it seems that the problem is because of the Image.FromStream() function.
I definitely don`t have any problems with passing the arguments. I think either, the language conflict or the conversion image to byte and vice-verse may be leading the problem. Does anyone has any idea or see something wrong?
I muchly appropriate any help.
Thanks.

sorry for my incomplete question, however I want to give some tips whoever is trying to do the same thing.
If anyone is trying to send an image to a server and both side has different platforms, then do not convert the image into byte array!
The reason is, in my case the image which is converted into byte array on Java differs from the byte array on C#. Therefore according to my research it is not possible to gather the image on the server side. The byte array created on Java wont have the right format on C#.
Hence anyone wants data transferring from one language to another, use Base64 encoding. Convert the image into Base64 string on one side and send it as string to the other language. Since Base64 format is same on every language there wont be any problem to reproduce it.
I sold the problem with the following codes:
Bitmap ourbitmap = BitmapFactory.decodeStream(imageStream, null, options);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ourbitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] b = baos.toByteArray();
test = Base64.encodeToString(b, Base64.DEFAULT);
This is the code where I get the image and convert it into Base64 string on Java android application,
byte[] imageBytes = Convert.FromBase64String(Base64ImageData);
MemoryStream ms = new MemoryStream(imageBytes, 0,
imageBytes.Length);
ms.Write(imageBytes, 0, imageBytes.Length);
Image image = Image.FromStream(ms, true);
image.Save(#"D:\tmpImage.jpg");
The code above takes the Base64 type string and converts back into an image. This is written in C#.

With such an incomplete code example and such a vague problem description, it's difficult to know for sure what the problem is.
However, reviewing the code you did post, I see one bug that would be significant if this is really the code you are using. In your Java methodConvertion() method, you have this statement:
data = output.toByteArray();
The problem is that all that does is create a new byte[] object and assign the reference to your local variable named data. That object never leaves the method.
Presumably you have some other code which, after calling methodConvertion(), sends the byte[] object that is referenced by the argument you passed to that method. But that object is just going to be whatever it was before you called the method.
You should instead change your Java code so that it looks like this:
public static byte[] methodConvertion(){
File inputFile = new File("/storage/emulated/0/IFSpictures/icon-si_strapclamp.jpg");
try{
FileInputStream input = new FileInputStream(inputFile);
ByteArrayOutputStream output = new ByteArrayOutputStream ();
byte [] buffer = new byte [65536];
int l;
while ((l = input.read(buffer)) > 0)
output.write (buffer, 0, l);
input.close();
output.close();
return output.toByteArray();
} catch (IOException e) {
System.err.println(e);
return null;
}
}
And then in the caller, you should check the return value and only proceed if the value is not null, reporting the error somehow otherwise.
If that doesn't address your question, you should edit the question so that it has a better code example, and so that you are much more specific about what's wrong. What happens when you run the code, and how is that different from what you expected? Be sure to clearly state any error messages, quoting them exactly, and including any stack traces from exceptions.

Related

Rotate byte array Image and encode to Base64 string

I am having a very difficult time trying to figure this one out:
I am working with a front-end which
Reads an image taken from a mobile device to a byte array
Converts the byte array to be stored as a Base64 string
Sends the Base64 string to a database
The back-end is only slated to store images as Base64 strings, as it later embeds the image as a Base64 string to an email for the user whose email application will only show Base64-embedded images. The problem is that the images are embedding 90 degrees counter-clockwise in the email, so I am trying to rotate the image 90 degrees before encoding the base64 string which is inserted into a Sql stored procedure (executed from the application). I feel like this code should simply do the trick:
HttpPostedFile img = imageUpload.PostedFile;
Stream stream = img.InputStream;
BinaryReader binaryReader = new BinaryReader(stream);
byte[] bytes = binaryReader.ReadBytes((int)stream.Length);
// Rotate Image Code (help):
using (var memoryStream = new MemoryStream(bytes))
{
var rotateImage = System.Drawing.Image.FromStream(memoryStream); rotateImage.RotateFlip(RotateFlipType.Rotate90FlipNone);
rotateImage.Save(memoryStream, rotateImage.RawFormat);
bytes = memoryStream.ToArray();
}
// End Rotate Image Code
insert.Parameters.AddWithValue("#Image",Convert.ToBase64String(bytes));
But I am receiving an error when I try and run it:
System.ArgumentNullException: Value cannot be null.
Parameter name: encoder at the line "bytes = memoryStream.ToArray();"
When I try and save it as a jpeg the image gets chopped off at the top, but no other formats work.
I think there is a problem in the line:
rotateImage.Save(memoryStream, rotateImage.RawFormat);
Maybe you should specify the format. Try with:
rotateImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
Or even better, you can catch and force convertion only when there is an exception:
try
{
rotateImage.Save(memoryStream, rotateImage.RawFormat);
}
catch (System.ArgumentNullException)
{
rotateImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
I think the issue is related to this answer

Converting UIImage to Byte Array

I need to convert a UIImage to a byte array. I am using Xamarin's Visual Studio plugin to produce an iOS application.
The bit of code below gets the image, but I need to send it across a Service Stack as a byte array instead of a UIImage.
var signatureView = new SignaturePad.SignaturePadView(new RectangleF(10, 660, 300, 150));
signatureView.BackgroundColor = UIColor.White;
this.View.AddSubview(signatureView);
UIImage signatureImage = signatureView.GetImage();
Shamelessly stolen from ChrisNTR
using (NSData imageData = image.AsPNG()) {
Byte[] myByteArray = new Byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, myByteArray, 0, Convert.ToInt32(imageData.Length));
}
It's been a long time since I checked the ServiceStack API but, if possible, try to avoid byte[] since it will need to create another copy of the same data. It does not matter in many cases but images are often huge.
E.g. if there's an overload that accept a System.IO.Stream then use image.AsPNG ().AsStream () and avoid the overhead :-)
Stream pst = img.AsPNG().AsStream();

Invalid paramether in Image.FromStream(MemoryStream)

im trying to send an image via network stream, i have a sendData and Getdata functions
and i always get an invalid parameter when using the Image.FromStream function
this is my code :
I am Getting the pic from the screen, then converting it to a byte[]
Inserting it to a Memory stream that i send via a networkStream.
private void SendData()
{
StreamWriter swWriter = new StreamWriter(this._nsClient);
// BinaryFormatter bfFormater = new BinaryFormatter();
// this method
lock (this._secLocker)
{
while (this._bShareScreen)
{
// Check if you need to send the screen
if (this._bShareScreen)
{
MemoryStream msStream = new MemoryStream();
this._imgScreenSend = new Bitmap(this._imgScreenSend.Width, this._imgScreenSend.Height);
// Send an image code
swWriter.WriteLine(General.IMAGE);
swWriter.Flush();
// Copy image from screen
this._grGraphics.CopyFromScreen(0, 0, 0, 0, this._sizScreenSize);
this._imgScreenSend.Save(msStream, System.Drawing.Imaging.ImageFormat.Jpeg);
msStream.Seek(0, SeekOrigin.Begin);
// Create the pakage
byte[] btPackage = msStream.ToArray();
// Send its langth
swWriter.WriteLine(btPackage.Length.ToString());
swWriter.Flush();
// Send the package
_nsClient.Write(btPackage, 0, btPackage.Length);
_nsClient.Flush();
}
}
}
}
private void ReciveData()
{
StreamReader srReader = new StreamReader(this._nsClient);
string strMsgCode = String.Empty;
bool bContinue = true;
//BinaryFormatter bfFormater = new BinaryFormatter();
DataContractSerializer x = new DataContractSerializer(typeof(Image));
// Lock this method
lock (this._objLocker)
{
while (bContinue)
{
// Get the next msg
strMsgCode = srReader.ReadLine();
// Check code
switch (strMsgCode)
{
case (General.IMAGE):
{
// Read bytearray
int nSize = int.Parse(srReader.ReadLine().ToString());
byte[] btImageStream = new byte[nSize];
this._nsClient.Read(btImageStream, 0, nSize);
// Get the Stream
MemoryStream msImageStream = new MemoryStream(btImageStream, 0, btImageStream.Length);
// Set seek, so we read the image from the begining of the stream
msImageStream.Position = 0;
// Build the image from the stream
this._imgScreenImg = Image.FromStream(msImageStream); // Error Here
Part of the problem is that you're using WriteLine() which adds Environment.NewLine at the end of the write. When you just call Read() on the other end, you're not dealing with that newline properly.
What you want to do is just Write() to the stream and then read it back on the other end.
The conversion to a string is strange.
What you're doing, when transferring an image, is sending an array of bytes. All you need to do is send the length of the expected stream and then the image itself, and then read the length and the byte array on the other side.
The most basic and naive way of transferring a byte array over the wire is to first send an integer that represents the length of the array, and read that length on the receiving end.
Once you now know how much data to send/receive, you then send the array as a raw array of bytes on the wire and read the length that you previously determined on the other side.
Now that you have the raw bytes and a size, you can reconstruct the array from your buffer into a valid image object (or whatever other binary format you've just sent).
Also, I'm not sure why that DataContractSerializer is there. It's raw binary data, and you're already manually serializing it to bytes anyway, so that thing isn't useful.
One of the fundamental problems of network programming using sockets and streams is defining your protocol, because the receiving end can't otherwise know what to expect or when the stream will end. That's why every common protocol out there either has a very strictly defined packet size and layout or else does something like sending length/data pairs, so that the receiving end knows what to do.
If you implement a very simple protocol such as sending an integer which represents array length and reading an integer on the receiving end, you've accomplished half the goal. Then, both sender and receiver are in agreement as to what happens next. Then, the sender sends exactly that number of bytes on the wire and the receiver reads exactly that number of bytes on the wire and considers the read to be finished. What you now have is an exact copy of the original byte array on the receiving side and you can then do with it as you please, since you know what that data was in the first place.
If you need a code example, I can provide a simple one or else there are numerous examples available on the net.
Trying to keep it short:
the Stream.Read function (which you use) returns an int that states how many bytes were read, this is return to you so you could verify that all the bytes you need are received.
something like:
int byteCount=0;
while(byteCount < nSize)
{
int read = this._nsClient.Read(btImageStream, byteCount, nSize-byteCount);
byteCount += read;
}
this is not the best code for the job

Create Bitmap in C# from char[] buffer

I've got to interface my C++ project with a C# project and send an image to it across a named pipe. OpenCV stores matrix data in a contiguous chunk, starting at uchar* Mat::data. However, to send data across a named pipe, it must be a char*, so I just do a cast, not sure what else I'm supposed to do. It shouldn't matter, it's just data, not characters.
size_t s = frame2.elemSize() * frame2.rows * frame2.cols;
sendChars(hPipe, (char*)frame2.data, s);
On the C# side I read in the block of data to a char[] buffer. I then create a new Bitmap with the appropriate width, height, etc. and set the IntPtr to the beginning of the char[] buffer.
//in the C# forms private scope:
char[] buffer = new char[921600];
and then in a StartServer() function:
pipeServer = new NamedPipeServerStream("SamplePipe", PipeDirection.InOut);
//blah blah blah
using (StreamReader sr = new StreamReader(pipeServer))
{
sr.ReadBlock(buffer, 0, buffer.Length);
unsafe
{
fixed (char* ptr = buffer)
{
using (Bitmap image = new Bitmap(640, 480, 640*3, PixelFormat.Format24bppRgb, new IntPtr(ptr)))
{
pictureBox1.Image = image;
image.Save("test.png");
}
}
}
}
The result of this is a big red X on the C# form and the saved image looks garbled... but not just random noise. So the data's coming through and getting messed up either on the C++ end before transmission or the C# end on interpretation. I have tried to work around this by using the Bitmap constructor that reads a stream and sending an encoded image instead of the raw pixels, but that fails harder than the above method (just gives an error, no output).
How do I transfer uchar* array with pixel data from C++ to C# and then reconstruct it inside a Bitmap so that I can display it on the form?
The use of a StreamReader here seems like the wrong choice if what you're sending is actually binary data. The StreamReader is used for reading text, and will decode the data to characters with some encoding which in your case would be auto-detected (and definitely wrong).
You want to use the BinaryReader for reading binary data, or read directly from the NamedPipeServerStream using the Read() method to get a byte[] array. A char in C# is used for storing characters, and is unicode, not a single byte.
If you use stream the easiest way would be to use the SetPixel method of Bitmap to construct the image.

Problem with code converted from C++ to C#

I converted some code from a C++ application I wrote a long time ago to C#. In C++ I had a library I used that was a bit buffer, but my lack of C# knowledge has somewhat complicated the conversion.
When I query my application, and I simply use a ByteWriter without casting any values properly (just like bf.Write(-1) and bf.Write("stringhere") the query programs atleast query it, just get the wrong information. When I cast the values properly (to long, byte, short, etc) it completely breaks, and the query application doesn't even see it anymore.
C++ Code Snippet
void PlayerManager::BuildReplyInfo()
{
// Delete the old packet
g_ReplyInfo.Reset();
g_ReplyInfo.WriteLong(-1);
g_ReplyInfo.WriteByte(73);
g_ReplyInfo.WriteByte(g_ProtocolVersion.GetInt());
g_ReplyInfo.WriteString(iserver->GetName());
g_ReplyInfo.WriteString(iserver->GetMapName());
g_ReplyInfo.WriteString(gGameType);
}
C# Code
public static byte[] ConvertStringToByteArray(string str)
{
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
return encoding.GetBytes(str);
}
//-----------------------------------
while (true)
{
data = new byte[1024];
recv = socket.ReceiveFrom(data, ref Remote);
Console.WriteLine("Message length is " + recv);
// If the length is 25 and the 5th byte is 'T' it is a A2S_INFO QUERY
if (recv == 25 && data[4] == 84)
{
Console.WriteLine("Source Engine Query!");
data = BuildReplyInformation();
socket.SendTo(data, 0, data.Length, SocketFlags.None, Remote);
}
}
}
public static byte[] BuildReplyInformation()
{
MemoryStream stream = new MemoryStream();
BinaryWriter writer = new BinaryWriter(stream);
writer.Write((long)(-1));
writer.Write((byte)(73)); // Steam Version
writer.Write((byte)(15)); // Protocol
writer.Write(ConvertStringToByteArray("Minecraft Server\0")); // Hostname
writer.Write(ConvertStringToByteArray("Map Name\0")); // Map Name
writer.Write(ConvertStringToByteArray("tf\0")); // Game Directory
writer.Write(ConvertStringToByteArray("Minecraft Server\0")); // Game Description
writer.Write((short)(440));
writer.Write((byte)(15)); // Players
writer.Write((byte)(32)); // Max Players
writer.Write((byte)(0)); // Bots
writer.Write((byte)(100));
writer.Write((byte)(119)); // 108 Linux, 119 Windows
writer.Write((byte)(0)); // Password Boolean
writer.Write((byte)(01)); // Vac Secured
writer.Write(ConvertStringToByteArray("1.1.3.7\0"));
return stream.ToArray();
}
A couple of ideas that might get you on track:
Are you sure you need UTF8 as string encoding?
When you look at the array and compare it to the intended structure, are you able to find out at what point the array does not comply to the standard?
Just a few things to keep in mind:
UTF-8 strings sometimes start with a BOM (byte order mark), sometimes not.
Strings sometimes are serialized length prefixed, sometimes null-terminated.
My suggestion is to double-check the original C++ method WriteString(...) to find out how it behaves with respect to #1 and #2, and then to double-check the C# method GetBytes(...) for the same. If I recall, the .NET binary serializer writes length-prefixed strings for each string written, but the UTF8 encoder does not (and does not output a null character either). The UTF8 encoder may also (depending on how you use it?) output a BOM.
Also, I'm suspicious of how \0 might be written out when passing through the UTF8 encoder. You might (for kicks) try outputting the null marker separately from the string content, as just a 0-valued byte.
Long size in C# was different from C++, resolved the issue.

Categories

Resources