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();
Related
I've been searching for the past few days but did not manage to find a solution for my problem. I am currently working on a xamarin Android app. I want to display an image by using the byte array column from by database. I am using another program to find the byte array of a specific photo and after that I insert manually its value in the byte array column from my principal project.
This is my code where I am trying to reproduce the image:
Android.Graphics.Bitmap bitmap=BitmapFactory.DecodeByteArray(currentexercis.image, 0, currentexercis.image.Length);
viewHolder.exercis_photo.SetImageBitmap(bitmap);
Currentexercis.image represents the byte array from my database, and its value seems to be OK, however every time bitmap is null.
This is the code from my other program where I convert the image into bytearray:
Image img = Image.FromFile(opendlg.FileName);
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
dbpicEntities1 db = new dbpicEntities1();
db.MyPictures.Add(new MyPicture() { FileName=fileName, Data = ms.ToArray() });
db.SaveChanges();
MessageBox.Show("success");
I think you should use like this.
byte [] imageArray // is your data
MemoryStream mStream = new MemorySteram ();
mStream.write(imageArray,0,imageArray.Length);
Image img = Image.FromStream(mStream);
img.save(filelocation);
Bitmap bitmapimg = BitmapFactory.BitmapFactory.DecodeStream(mStream);
// if you want to use Bitmap
Byte Array to Image using C# in Xamarin
There are some third-party library which implements this feature quite well like Picasso or Glide.
For Glide, there is official document shows how to use it in Xamarin.Android project: Binding a .JAR.
Or you could directly use it from the nuget package:
Then you can code for example like this:
Glide.With(context)
.Load(imageBytes)
.Apply(RequestOptions.CircleCropTransform())
.Into(imageView);
convert to byteArray
byte[] imgdata = System.IO.File.ReadAllBytes(pathToImage);
convert byte array to bitmap
private void OnGetMemberAvatarCompleted(byte[] avatarBytes)
{
var avatarImageView = FindViewById<ImageView>(Resource.Id.memberProfile_avatar);
if (avatarImageView != null)
{
var imageBitmap = BitmapFactory.DecodeByteArray(avatarBytes, 0,avatarBytes.Length);
RunOnUiThread(() => avatarImageView.SetImageBitmap(imageBitmap));
}
}
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.
I am uploading jpeg images as fast as i can to a web service (it is the requirement I have been given).
I am using async call to the web service and I calling it within a timer.
I am trying to optimise as much as possible and tend to use an old laptop for testing. On a normal/reasonable build PC all is OK. On the laptop I get high RAM usage.
I know I will get a higher RAM usage using that old laptop but I want to know the lowest spec PC the app will work on.
As you can see in the code below I am converting the jpeg image into a byte array and then I upload the byte array.
If I can reduce/compress/zip the bye array then I am hoping this will be 1 of the ways of improving memory usage.
I know jpegs are already compressed but if I compare the current byte array with the previous byre array then uploading the difference between this byte arrays I could perhaps compress it even more on the basis that some of the byte values will be zero.
If I used a video encoder (which would do the trick) I would not be real time as much I would like.
Is there an optimum way of comparing 2 byte arrays and outputting to a 3rd byte array? I have looked around but could not find an answer that I liked.
This is my code on the client:
bool _uploaded = true;
private void tmrLiveFeed_Tick(object sender, EventArgs e)
{
try
{
if (_uploaded)
{
_uploaded = false;
_live.StreamerAsync(Shared.Alias, imageToByteArray((Bitmap)_frame.Clone()), Guid.NewGuid().ToString()); //web service being called here
}
}
catch (Exception _ex)
{
//do some thing but probably time out error here
}
}
//web service has finished the client invoke
void _live_StreamerCompleted(object sender, AsyncCompletedEventArgs e)
{
_uploaded = true; //we are now saying we start to upload the next byte array
}
private wsLive.Live _live = new wsLive.Live(); //web service
private byte[] imageToByteArray(Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg); //convert image to best image compression
imageIn.Dispose();
return ms.ToArray();
}
thanks...
As C.Evenhuis said - JPEG files are compressed, and changing even few pixels results in complettly differrent file. So - comparing resulting JPEG files is useless.
BUT you can compare your Image objects - quick search results in finding this:
unsafe Bitmap PixelDiff(Bitmap a, Bitmap b)
{
Bitmap output = new Bitmap(a.Width, a.Height, PixelFormat.Format32bppArgb);
Rectangle rect = new Rectangle(Point.Empty, a.Size);
using (var aData = a.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var bData = b.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
using (var outputData = output.LockBitsDisposable(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb))
{
byte* aPtr = (byte*)aData.Scan0;
byte* bPtr = (byte*)bData.Scan0;
byte* outputPtr = (byte*)outputData.Scan0;
int len = aData.Stride * aData.Height;
for (int i = 0; i < len; i++)
{
// For alpha use the average of both images (otherwise pixels with the same alpha won't be visible)
if ((i + 1) % 4 == 0)
*outputPtr = (byte)((*aPtr + *bPtr) / 2);
else
*outputPtr = (byte)~(*aPtr ^ *bPtr);
outputPtr++;
aPtr++;
bPtr++;
}
}
return output;
}
If your goal is to find out whether two byte arrays contain exactly the same data, you can create an MD5 hash and compare these as others have suggested. However in your question you mention you want to upload the difference which means the result of the comparison must be more than a simple yes/no.
As JPEGs are already compressed, the smallest change to the image could lead to a large difference in the binary data. I don't think any two JPEGs contain binary data similar enough to easily compare.
For BMP files you may find that changing a single pixel affects only one or a few bytes, and more importantly, the data for the pixel at a certain offset in the image is located at the same position in both binary files (given that both images are of equal size and color depth). So for BMPs the difference in binary data directly relates to the difference in the images.
In short, I don't think obtaining the binary difference between JPEG files will improve the size of the data to be sent.
I have a file that is created using
var recordIntent = new Intent(MediaStore.Audio.Media.RecordSoundAction);
I have no problems retrieving the URI of this file. And I can play it back using MediaPlayer without any difficulties.
However, I would like to send this as a response to my webAPI, and am looking at a way to convert the Audio File represented by this URI to a byte array that I can convert to JSON.
With an image file i can do something like
Bitmap bitmap = MediaStore.Images.Media.GetBitmap(ContentResolver, responseUri);
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
byte[] bitmapData = stream.ToArray();
Is there a similar way I can retrieve the Byte Array data from my audio URI?
edit:
formatting of Audio URI.
responseUri = {content://media/external/audio/media/21}
Taken from a ton of different SO answers, and a little bit of extra conversion for mono from Java I came up with these results.
public String GetRealPathFromUri(Uri contentUri){
String[] proj = {MediaStore.Audio.AudioColumns.Data};
ICursor cursor = ManagedQuery(contentUri, proj, null, null, null);
int column_index = cursor.GetColumnIndex(MediaStore.Audio.AudioColumns.Data);
cursor.MoveToFirst();
return cursor.GetString(column_index);
}
var responseRealPath = GetRealPathFromUri(responseUri);
var getBytes = System.IO.File.ReadAllBytes(responseRealPath);
var responseBase = Convert.ToBase64String(getBytes);
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.