Xamarin IOS Encoding/Decoding Images from and to Base64 - c#

I am working on an application for IOS in Xamarin. I have a menu in which I request something called "Doublechecks". These doublechecks have a field with the name "Medication". In a previous working copy of the app, I simply used a string to fill this field, but now we had the idea to, instead of filling this medication field with a string, to fill it with an image. One of the tips I got was to convert a taken or chosen image to base64.
In the menu where I make a new doublecheck I have a button that pops up an actionsheet, where you can choose weather you want to pick an image from your PhotoLibrary, or take a new picture with your camera. When you've taken or chosen a picture, I use the following method to encode it to Base64:
var imageToSend = originalImage.AsJPEG (0.23f).GetBase64EncodedString (NSDataBase64EncodingOptions.None);
Where the originalImage is the image I took/chose. Now, when requesting all doublechecks, I use the following to decode it:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
string decoded = System.Text.Encoding.ASCII.GetString (encodedDataAsBytes);
NSData data = NSData.FromString (decoded, NSStringEncoding.ASCIIStringEncoding);
return UIImage.LoadFromData (data);
The method works up until the return. Somehow, the UIImage is not being constructed, and has its value null, even though the 'data' contains the decoded string.
I have searched several threads and fora, but without much avail. Any help would be much appreciated.

Why are you converting the base64 decoded data into a string ?
Since you already have the byte array you should be able to simply do:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
NSData data = NSData.FromArray (encodedDataAsBytes);
return UIImage.LoadFromData (data);

NSData method not always a good solution. You can also try following
var rawData = pixelMap.ToByteArray();
using (var provider = new CGDataProvider(rawData, 0, rawData.Length))
{
using (var colorSpace = CGColorSpace.CreateDeviceRGB())
{
var cgImage = new CGImage(
pixelMap.Width,
pixelMap.Height,
pixelMap.BitsPerComponent,
pixelMap.BytesPerPixel * ByteToBit,
pixelMap.BytesPerPixel * pixelMap.Width,
colorSpace,
CGBitmapFlags.ByteOrderDefault,
provider,
null,
true,
CGColorRenderingIntent.Default
);
return ImageSource.FromStream(() => UIImage.FromImage(cgImage).AsPNG().AsStream());
}
}
Check out my library and samples for more info about both Android and iOS bitmap from/to 2d pixel map.
https://github.com/enginkirmaci/Imaging-Library

Related

How to convert ImageSourse to NSUrl or CGImage in xamarin ios

I want to convert the ImageSource or image byte array to Xamarin.ios NSUrl or CGImage. How to implement this. I am generating the byte Array from LayoutView like below. So after getting the the byte array I need to convert it to NSUrl or CGImage for printing that layout. From the below code I will get the bytearray.
public byte[] LayoutToImage()
{
var view = UIApplication.SharedApplication.KeyWindow;
UIGraphics.BeginImageContext(view.Frame.Size);
view.DrawViewHierarchy(view.Frame, true);
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
using (var imageData = image.AsPNG())
{
var bytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, bytes, 0, Convert.ToInt32(imageData.Length));
return bytes;
}
}
I am able to print the image on the iOS project resource file, like that I need to print the layout view also.
string fileName = "SampleImg.png";
string localDocUrl = Path.Combine(NSBundle.MainBundle.BundlePath, fileName);var Error = Driver.PrintImageWithURL(new NSUrl(localDocUrl), pSettings);
As Jason said GetImageFromCurrentImageContext returns a UIImage. If you want to convert to CGImage, you can directly use UIImage.CGImage to get CGImage. Converting a byte array to a CGImage also needs to be converted to a UIImage first.

Convert byte[] image to string

MediaFile ficheiro;
byte[] image = File.ReadAllBytes(ficheiro.Path);
var file = image.ByteArrayImageToBase64();
string[] x = new string[] { file };
MediaFile is a plugin to get image in gallery
Visually the code does not give me error. But I want to see another way that I can convert the bytes of the image to string.
What would be the most efficient way to convert an array of bytes from an image to a string. I intend to send this image later with a post method. But my difficulty is in conversion because trying to send says that the request is too long. due to ByteArrayImageToBase64

Error converting byte array to Image

I've read images in and saved them in a database in byte[] format. Later I want to retrieve the images and convert them into Image format. I've written the following method:
private List<Image> ConvertByteArraysToImages(List<byte[]> byteDataList)
{
List<Image> retVal = new List<Image>();
int counter = 0;
foreach (byte[] byteData in byteDataList)
{
// Something is wrong here
MemoryStream memstr = new MemoryStream(byteData);
Image img = Image.FromStream(memstr);
retVal.Add(img);
memstr.Dispose();// Just added this
// This works fine, the images appear in the folder
System.IO.File.WriteAllBytes(String.Format(#"C:\dev\test{0}.png", counter), byteData);
counter++;
}
return retVal;
}
I'm calling this method from an action which adds the images to the ViewBag to use in the view.
public ActionResult ViewTicket(Incident ticket)
{
//Read the ticket via the web API
string serialisedJSON = JsonConvert.SerializeObject(ticket.ID);
string response = TicketUtilities.JSONRequestToAPI(serialisedJSON, "GetSingleIncident");
Incident retVal = JsonConvert.DeserializeObject<Incident>(response);
//Convert byte[] to Image and add to ViewBag
List<Image> ScreenshotImagesFullsize = ConvertByteArraysToImages(retVal.Screenshots);
ViewBag.Add(ScreenshotImagesFullsize); //Error here
return View(retVal);
}
When I try to add the images to the ViewBag I get the following error in the browser:
Cannot perform runtime binding on a null reference
Writing the byte arrays to file produces the correct output but I'm not getting a list of Images in my return value. Hovering over retVal in debug mode shows the following:
I passed in two byte arrays and I see 2 objects in retVal, but I also I see the error: "Cannot evaluate expression because the code of the current method is optimized". Why does this occur?
Update: I disabled JIT optimization and now I can see the following:
I can see that the object has correctly acquired properties such as the height and width but the actual data is null.
Do not dispose the stream and do keep at least one reference to it as long as you need the image.
"You must keep the stream open for the lifetime of the Image."
https://msdn.microsoft.com/de-de/library/1kcb3wy4(v=vs.110).aspx
Note that there is no need to manually call dispose on a MemoryStream because it does not have unmanaged resources
So I solved this, the problem turned out not to be the conversion but rather adding Image objects to the view. For some reason adding Image objects to the view does not work, to overcome this I converted the image to a Base64 string
using (MemoryStream m = new MemoryStream())
{
retVal.Img.Save(m, retVal.Img.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string imreBase64Data = Convert.ToBase64String(imageBytes);
retVal.ImgB64 = string.Format("data:image/png;base64,{0}", imreBase64Data);
}

Deserialization .json to Bitmap image c#

I have a bitmap image, which I converted to a JSON file using:
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Bitmap image);
Content of .json file:
{
"Tag":null,
"PhysicalDimension":{
"IsEmpty":false,
"Width":376,
"Height":221
},
"Size":{
"IsEmpty":false,
"Width":376,
"Height":221
},
"Width":376,
"Height":221,
"HorizontalResolution":96,
"VerticalResolution":96,
"Flags":2,
"RawFormat":{
"Guid":"b96b3caa-0728-11d3-9d7b-0000f81ef32e"
},
"PixelFormat":2498570,
"Palette":{
"Flags":62,
"Entries":[
]
},
"FrameDimensionsList":[
"7462dc86-6180-4c7e-8e3f-ee7333a7a483"
],
"PropertyIdList":[
],
"PropertyItems":[
]
}
Now I tried to deserialize the file in this way:
Bitmap bm = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Bitmap>(json);
But got the error:
System.MissingMethodException: "For the" System.Bitmap "type, the
constructor without parameters is not defined."
Is there another way to deserialize the file or how can I fix this code?
Thanks!
The error of the message is... quite clear on this. If you look at the MSDN documentation for Bitmap, you'll find that it has no empty constructors defined. The JSON deserializer basically creates an new instance of a specified type (using the empty constructor) then fills out the properties. The Bitmap is a bit too complex for that to work. So... you need to work around that.
Bernard Vander Beken already showed you how to read a base64 string containin bitmap data. Here's how you can CREATE it from an existing bitmap:
ImageConverter converter = new ImageConverter();
var bitmapData = Convert.ToBase64String((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
Note that bitmapData, in the example above, is a string which can easily be sent, stored, etc. (so no need to serialize this into JSON).
EDIT:
Please note that given the above, you need to update BOTH your serialization and deserialization code. I.e. to use the deserialization samples provided, you need to send / store a completely different JSON from the one you're currently working with... which won't be a JSON any more.
In fact, your current JSON file doesn't really contain an actual image; it only has some metadata about the image you originally used. So you definitely need to change the code responsible for serialization.
I would also modify the code for deserializing a bitmap ever so slightly (MemoryStream should, in theory, be disposed of properly and setting the position isn't required).
var bytes = Convert.FromBase64String(bitmapData);
Bitmap bitmap;
using (var ms = new MemoryStream(bytes))
bitmap = new Bitmap(Bitmap.FromStream(ms));
Since Bitmap has no default constructor, it cannot be used out of the box for deserialization.
You can try to deserialize the JSON payload to a byte array, then pass it to Bitmap.FromStream via a MemoryStream.
string image = json;
byte[] byteBuffer = Convert.FromBase64String(image);
MemoryStream memoryStream = new MemoryStream(byteBuffer);
memoryStream.Position = 0;
return (Bitmap)Bitmap.FromStream(memoryStream);
Credits to http://ingsharksoft.blogspot.be/2013/07/solution-problem-serializedeserialize.html

get screenshot image data plain [duplicate]

I would need to take a screenshot, if easy to without saving it. I would sent the image data directly to a PHP script. Because I don't have this PHP script at the moment, so I search for the easiest way of format in which I should convert the screenshot data. For debugging reasons until I've got my PHP script I would like to convert a picture of these data on my client side using C#.
My code at the moment for taking a screenshot and convert it (I'm not sure if I can convert the output in my logfile back into a picture):
internal static byte[] ImageToByteArray(Image img)
{
byte[] byteArray = new byte[0];
MemoryStream stream = new MemoryStream();
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Close();
byteArray = stream.ToArray();
return byteArray;
}
public static string TakeScreenshot()
{
String filepath = #"C:\log2.txt";
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
graphics.Dispose();
bitmap.Save("C:\\temp.png");
Image img = (Image)bitmap;
string str = System.Text.Encoding.Default.GetString(ImageToByteArray(img));
System.IO.File.AppendAllText(filepath, str);
//just for debugging
return "OH";
}
Main question at the moment, is there any way to get a picture back from my converted code (log2.txt).
This line of code:
string str = System.Text.Encoding.Default.GetString(ImageToByteArray(img));
Will almost certainly not do what you want it to do. It will try to interpret your byte array as a string in whatever is the default character encoding on your machine. If the default is something like UTF-8 or any multibyte character set, then it's quite likely to fail. Even if the default encoding is a single-byte character set, it could create a string that can't be reliably turned back into the original byte array.
If you really want to store the byte array as text, you can call Convert.ToBase64String:
string str = Convert.ToBase64String(ImageToByteArray(img));
If you read that string back from the file into str, you can rebuild the byte array with:
byte[] imageBytes = Convert.FromBase64String(str);
Another advantage in your particular case is that there are PHP functions for dealing with base 64 strings.

Categories