Convert Xamarin bitmap to byte[] not work or throw exception - c#

I tried to convert my image from camera to byte[] and then make request to my server but it is not working so my image from camera is
var image = textureView.Bitmap;
image = Android.Graphics.Bitmap.CreateBitmap
(image,
(int)OCR_Rectangle.GetX(),
(int)OCR_Rectangle.GetY(),
OCR_Rectangle.Width,
OCR_Rectangle.Height);
My web request is
public async static Task<string> ParseAsync(byte[] image)
{
string id = "my id ";
string apiKey = "my api key ";
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("app_id", id);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("app_key", apiKey);
var base64 = Convert.ToBase64String(image);
var imageUri = "data:image/jpg;base64," + base64;
var json = JsonConvert.SerializeObject(new { src = imageUri });
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("my website", content);
var dynObj = JsonConvert.DeserializeObject<RootObjectLatex>(await response.Content.ReadAsStringAsync());
return dynObj.latex;
}
}
Here is my attempt to convert bitmap to byte[]
byte[] bitmapData;
using (var stream = new MemoryStream())
{
image.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
And then i want to use bitmapData in my request.But no luck.

So, I found error this works
byte[] bitmapData;
using (var stream = new MemoryStream())
{
image.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
but i type wrong api key in my request

Related

sending binary file byte array to web api method

I have a requirement to post binary file of size 100MB data in the format of either JSON or byte array to Web API 1.1.
My client application is C# winforms application with x32 bit architecture. Where as I want to perform reading binary file from this client application and send this binary file byte array to Web API.
Current implementation in my winforms application is as below
var sFile = #"C"\binary.zip";
var mybytearray = File.ReadAllBytes(sFile);
var webRequest =
(HttpWebRequest)WebRequest.Create("http://localhost/filewriter");
webRequest.ContentType = "text/plain";
webRequest.Method = WebRequestMethods.Http.Post;
webRequest.AllowWriteStreamBuffering = true;
webRequest.Timeout = 100000;
webRequest.Headers.Add("fileName", Path.GetFileName(sFile));
webRequest.ContentLength = mybytearray.Length;
using (var dataStream = new StreamWriter(webRequest.GetRequestStream()))
dataStream.Write(mybytearray);
using (var response = webRequest.GetResponse())
{
if(response.StatusCode = HttpStatusCode.Ok;
return true;
}
below is written at my Web api method
[HttpPost]
public HttpResponseMessage filewriter(byte[] binaryData)
{
using (FileStream binaryFileStream = new FileStream("C:\\myNewFile.zip", FileMode.Create, FileAccess.ReadWrite))
{
binaryFileStream.Write(binaryData, 0, binaryData.Length);
}
}
As you can see, in above code I was not able to send byte array to web api method filewriter. Am I missing something that should work in this case.
Other way as I said I was tried same but instead of byte array with Json one as below
var sFile = #"C"\binary.zip";
var mybytearray = File.ReadAllBytes(sFile);
var mymodel = new model
{
fileName = sFile,
binaryData = mybytearray
};
var jsonResendObjects = JsonConvert.SerializeObject(mymodel);
var webRequest = (HttpWebRequest)WebRequest.Create("http://localhost/filewriter");
webRequest.ContentType = "application/json";
webRequest.Method = WebRequestMethods.Http.Post;
webRequest.AllowWriteStreamBuffering = true;
webRequest.Timeout = 100000;
webRequest.Headers.Add("fileName", Path.GetFileName(sFile));
webRequest.ContentLength = jsonResendObjects.Length;
byte[] responseData = null;
webRequest.AllowWriteStreamBuffering = true;
using (var dataStream = new StreamWriter(webRequest.GetRequestStream()))
dataStream.Write(jsonResendObjects);
On web api side
[HttpPost]
public HttpResponseMessage filewriter([FromBody]model mymodel)
{
using (FileStream binaryFileStream = new FileStream("C:\\myNewFile.zip", FileMode.Create, FileAccess.ReadWrite))
{
binaryFileStream.Write(mymodel.binarydata, 0, binaryDatabinarydat.Length);
}
}
According to me, it would be easy to use base64 encoding for
communication.
If you want to do so
First, convert your file to byte[] and then to base64 string
Like this:
byte[] bytes = File.ReadAllBytes("path");
string file = Convert.ToBase64String(bytes);
// You have base64 Data in "file" variable
On your WebAPI Endpoint accept string
[HttpPost]
public HttpResponseMessage filewriter(string fileData)
{
}
Then convert your base64 string back to byte[] and write it to file or whatever you want to do with that.
Like This:
// put your base64 string in b64str
Byte[] bytes = Convert.FromBase64String(b64Str);
File.WriteAllBytes(path, bytes);
And you can Compress your string Using GZIP Like this
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());
}
}
Reference:-
Convert file to base64 and back
GZip Compression

JSON parsing issue when using filepath as image url

I am having an issue getting my image to upload to the microsoft face api.
I have a function that posts to the server, which implements another function that turns a user selected image into a base64 encoded stream.
public async Task getImageID(){
//filedialogs, etc...
HttpResponseMessage response;
string responseBodyAsText;
byte[] byteData = Encoding.UTF8.GetBytes("{ \"url\":\""+baseEncodeImage(getPhoto.FileName)+" \"}");
using (var content = new ByteArrayContent(byteData)){
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
response = await client.PostAsync(uri, content);
responseBodyAsText = await response.Content.ReadAsStringAsync();
//debug prints
Console.Write(responseBodyAsText+"\n"+ getPhoto.FileName+"\n"+byteData);
}
}
public string baseEncodeImage(string filePath){
//This function will take the filepath selected from the filedialog
//and turn it into a base64 encoded stream to be used by the face api
using (Image image = Image.FromFile(filePath))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
}
It posts to the server, and returns the following in the command line:
What do I need to manipulate so that it works with the base64 encoding? It was posting with an image url off the internet prior to the modifications.
I have found the solution. I converted the type returned from the encode function to a byte[] and simplified the process by making the byte[] the size of the image, and simply writing the binary data to memory. The calling function was further simplified by placing the call in the using statement and removing the original url formatting which wasnt needed.
// Request body
HttpResponseMessage response;
string responseBodyAsText;
using (var content = new ByteArrayContent((baseEncodeImage(getPhoto.FileName))))
{
content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
response = await client.PostAsync(uri, content);
responseBodyAsText = await response.Content.ReadAsStringAsync();
//debug prints
Console.Write(responseBodyAsText + "\n" + getPhoto.FileName + "\n");
}
}
public byte[] baseEncodeImage(string filePath){
//This function will take the filepath selected from the filedialog
//and turn it into a base64 encoded stream to be used by the face api
using (Image image = Image.FromFile(filePath))
{
using (MemoryStream m = new MemoryStream())
{
FileStream imgStream = File.OpenRead(filePath);
byte[] blob = new byte[imgStream.Length];
imgStream.Read(blob, 0, (int)imgStream.Length);
return blob;
}
}
}

Load an image from URL as base64 string

I am trying to load an image as a base 64 string so that i can show it in a html like this:
<html><body><img src="data:image/jpeg;base64,/></img></body></html>
Heres my code so far, but it does not really work:
public async static Task<string> getImage(string url)
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "data:image/jpg;charset=base64";
request.Credentials = new NetworkCredential(user, pw);
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse, null)))
{
StreamReader sr = new StreamReader(response.GetResponseStream());
return sr.ReadToEnd();
}
I tried using this method i found elsewhere to encode the return-String as base64, but when placing it in a html the image just shows the typical placeholder.
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
EDIT:
Here is how the html looks:
It seems to me that you need to separate the base64 part, which is only needed in your HTML, from fetching the data from the response. Just fetch the data from the URL as binary data and convert that to base64. Using HttpClient makes this simple:
public async static Task<string> GetImageAsBase64Url(string url)
{
var credentials = new NetworkCredential(user, pw);
using (var handler = new HttpClientHandler { Credentials = credentials })
using (var client = new HttpClient(handler))
{
var bytes = await client.GetByteArrayAsync(url);
return "image/jpeg;base64," + Convert.ToBase64String(bytes);
}
}
This assumes the image always will be a JPEG. If it could sometimes be a different content type, you may well want to fetch the response as an HttpResponse and use that to propagate the content type.
I suspect you may want to add caching here as well :)
using (HttpClient client = new HttpClient())
{
try
{
using (Stream stream = await client.GetStreamAsync(uri))
{
if (stream == null)
return (Picture)null;
byte[] buffer = new byte[16384];
using (MemoryStream ms = new MemoryStream())
{
while (true)
{
int num = await stream.ReadAsync(buffer, 0, buffer.Length, cancellation);
int read;
if ((read = num) > 0)
ms.Write(buffer, 0, read);
else
break;
}
imageData = Convert.ToBase64String(ms.ToArray());
}
buffer = (byte[])null;
}
}
catch (Exception ex)
{
}
}
You must first get the image from disk, then convert it to byte[] and then again to base64.
public string ImageToBase64(Image image, System.Drawing.Imaging.ImageFormat format)
{
using (MemoryStream ms = new MemoryStream())
{
// Convert Image to byte[]
image.Save(ms, format);
byte[] imageBytes = ms.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}

How can I get the bytes of a GetObjectResponse from S3?

I'm retrieving a file from Amazon S3. I want to convert the file to bytes so that I can download it as follows:
var download = new FileContentResult(bytes, "application/pdf");
download.FileDownloadName = filename;
return download;
I have the file here:
var client = Amazon.AWSClientFactory.CreateAmazonS3Client(
accessKey,
secretKey,
config
);
GetObjectRequest request = new GetObjectRequest();
GetObjectResponse response = client.GetObject(request);
I know about response.WriteResponseStreamToFile() but I want to download the file to the regular downloads folder. If I convert the GetObjectResponse to bytes, I can return the file. How can I do this?
Here's the solution I found for anyone else who needs it:
GetObjectResponse response = client.GetObject(request);
using (Stream responseStream = response.ResponseStream)
{
var bytes = ReadStream(responseStream);
var download = new FileContentResult(bytes, "application/pdf");
download.FileDownloadName = filename;
return download;
}
public static byte[] ReadStream(Stream responseStream)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Just another option:
Stream rs;
using (IAmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client())
{
GetObjectRequest getObjectRequest = new GetObjectRequest();
getObjectRequest.BucketName = "mybucketname";
getObjectRequest.Key = "mykey";
using (var getObjectResponse = client.GetObject(getObjectRequest))
{
getObjectResponse.ResponseStream.CopyTo(rs);
}
}
I struggled to get the cleaner method offered by Alex to work (not sure what I'm missing), but I wanted to do it w/o the extra ReadStream method offered by Erica (although it worked)... here is what I wound up doing:
var s3Client = new AmazonS3Client(AccessKeyId, SecretKey, Amazon.RegionEndpoint.USEast1);
using (s3Client)
{
MemoryStream ms = new MemoryStream();
GetObjectRequest getObjectRequest = new GetObjectRequest();
getObjectRequest.BucketName = BucketName;
getObjectRequest.Key = awsFileKey;
using (var getObjectResponse = s3Client.GetObject(getObjectRequest))
{
getObjectResponse.ResponseStream.CopyTo(ms);
}
var download = new FileContentResult(ms.ToArray(), "image/png"); //"application/pdf"
download.FileDownloadName = ToFilePath;
return download;
}
Stream now has asynchronous methods. In C# 8, you can do this:
public async Task<byte[]> GetAttachmentAsync(string objectPointer)
{
var objReq = new GetObjectRequest
{
BucketName = "bucket-name",
Key = objectPointer, // the file name
};
using var objResp = await _s3Client.GetObjectAsync(objReq);
using var ms = new MemoryStream();
await objResp.ResponseStream.CopyToAsync(ms, _ct); // _ct is a CancellationToken
return ms.ToArray();
}
This won't block any threads while the IO occurs.

Windows 8 How to open a BitmapImage as a stream?

In a Windows 8 app, how do I convert a BitmapImage to a Stream? I have a List of BitmapImages and I'm going to use that List to upload each image to a server and I need to use a Stream to do that. So is there a way to convert each individual BitmapImage into a Stream?
No, there isn't. You need to track the original sources or use a WriteableBitmap instead.
Retrieve the bitmap image:
public async void ContinueFileOpenPicker(FileOpenPickerContinuationEventArgs args)
{
if (args.Files.Count > 0)
{
var imageFile = args.Files[0] as StorageFile;
// Ensure the stream is disposed once the image is loaded
using (IRandomAccessStream fileStream = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// Set the image source to the selected bitmap
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
ImageControl.Source = bitmapImage;
await _viewModel.Upload(imageFile);
}
}
}
Create the file stream:
internal async Task Upload(Windows.Storage.StorageFile file)
{
var fileStream = await file.OpenAsync(FileAccessMode.Read);
fileStream.Seek(0);
var reader = new Windows.Storage.Streams.DataReader(fileStream.GetInputStreamAt(0));
await reader.LoadAsync((uint)fileStream.Size);
Globals.MemberId = ApplicationData.Current.LocalSettings.Values[Globals.PROFILE_KEY];
var userName = "Rico";
var sex = 1;
var url = string.Format("{0}{1}?memberid={2}&name={3}&sex={4}", Globals.URL_PREFIX, "api/Images", Globals.MemberId, userName,sex);
byte[] image = new byte[fileStream.Size];
await UploadImage(image, url);
}
Create a memory stream from the image:
public async Task UploadImage(byte[] image, string url)
{
Stream stream = new System.IO.MemoryStream(image);
HttpStreamContent streamContent = new HttpStreamContent(stream.AsInputStream());
Uri resourceAddress = null;
Uri.TryCreate(url.Trim(), UriKind.Absolute, out resourceAddress);
Windows.Web.Http.HttpRequestMessage request = new Windows.Web.Http.HttpRequestMessage(Windows.Web.Http.HttpMethod.Post, resourceAddress);
request.Content = streamContent;
var httpClient = new Windows.Web.Http.HttpClient();
var cts = new CancellationTokenSource();
Windows.Web.Http.HttpResponseMessage response = await httpClient.SendRequestAsync(request).AsTask(cts.Token);
}

Categories