Converting String to Stream - c#

So I am trying to serialize and deserialize an IReadOnlyList<InkStroke> from Windows.UI.Input.Inking for my UWP app, and I have used the following code to serialize the data:
var stream = new InMemoryRandomAccessStream();
await canvas.InkPresenter.StrokeContainer.SaveAsync(stream);
await stream.FlushAsync();
var buffer = new byte[stream.Size];
await stream.AsStream().ReadAsync(buffer, 0, buffer.Length);
return Convert.ToBase64String(buffer);
How can I deserialize this string to create an IInputStream (or IRandomAccessStream instead) which can be used in the StrokeContainer.LoadAsync() method?

You can use the following piece of code....
byte[] bytes = Convert.FromBase64String(stringinput);
MemoryStream stream = new MemoryStream(bytes);
IInputStream is=stream.AsRandomAccessStream(); //It will return an IInputStream object

Try this:
byte[] data = Convert.FromBase64String(encodedString);
InMemoryRandomAccessStream inputStream = new InMemoryRandomAccessStream();
await inputStream.WriteAsync(data.AsBuffer());
inputStream.Seek(0);
await canvas.InkPresenter.StrokeContainer.LoadAsync(inputStream);

Related

HTTP POST multipart/formdata using HttpClient

When I post the below code using httpclient
using var formContent = new MultipartFormDataContent("NKdKd9Yk");
using var stream = new MemoryStream();
file.CopyTo(stream);
var fileBytes = stream.ToArray();
formContent.Headers.ContentType.MediaType = "multipart/form-data";
formContent.Add(new StreamContent(stream), "file", fileName);
var response = await httpClient.PostAsync(GetDocumentUpdateRelativeUrl(), formContent);
here file is of type IFormfile
In API side I retrieve file as follows
var base64str= "";
using (var ms = new MemoryStream())
{
request.file.CopyTo(ms);
var fileBytes = ms.ToArray();
base64str= Convert.ToBase64String(fileBytes);
// act on the Base64 data
}
I get 0 byte. My questions is what's wrong with this approch?
But If I use below code. Then API works and I get what I post.
using var formContent = new MultipartFormDataContent("NKdKd9Yk");
using var stream = new MemoryStream();
file.CopyTo(stream);
var fileBytes = stream.ToArray();
formContent.Headers.ContentType.MediaType = "multipart/form-data";
formContent.Add(new StreamContent(new MemoryStream(fileBytes)), "file", fileName);
differece is how I add stream content
formContent.Add(new StreamContent(stream), "file", fileName);
vs
formContent.Add(new StreamContent(new MemoryStream(fileBytes)), "file", fileName);
Why the first approch didn't work but second one does?
You need to add stream.Seek(0, SeekOrigin.Begin); in order to jump back to the beginning of the MemoryStream. You should also use CopyToAsync
In the second version, you had a fresh MemoryStream from the byte[] array, which is positioned on 0 anyway.
using var formContent = new MultipartFormDataContent("NKdKd9Yk");
using var stream = new MemoryStream();
await file.CopyToAsync(stream);
stream.Seek(0, SeekOrigin.Begin);
formContent.Headers.ContentType.MediaType = "multipart/form-data";
formContent.Add(new StreamContent(stream), "file", fileName);
using var response = await httpClient.PostAsync(GetDocumentUpdateRelativeUrl(), formContent);
Although to be honest, the MemoryStream seems entirely unnecessary here. Just pass the a Stream from file directly.
using var formContent = new MultipartFormDataContent("NKdKd9Yk");
formContent.Headers.ContentType.MediaType = "multipart/form-data";
using var stream = file.OpenReadStream();
formContent.Add(new StreamContent(stream), "file", fileName);
using var response = await httpClient.PostAsync(GetDocumentUpdateRelativeUrl(), formContent);

Can't convert a Base64 to MemoryStream

I'm having some issues in converting an image from an Base63 string to image memoryStream on a WebApi. The result looks like this:
I have tried several ways ala this:
var imageBytes = Convert.FromBase64String(pagedResult.Data);
var ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
var image = await Image.LoadAsync(ms, cancellationToken);
var stream = new MemoryStream();
await image.SaveAsync(stream, new JpegEncoder(), cancellationToken);
stream.Position = 0;
ms.Position = 0;
return (stream, pagedResult.Mimetype);
Or something as simple like this:
var sapDoc = Convert.FromBase64String(pagedResult.Data);
return (new MemoryStream(sapDoc), pagedResult.Mimetype);
The controller looks like this:
[HttpGet("document")]
public async Task<ActionResult<Stream>> GetImage([FromQuery] long documentNumber, string documentId)
{
var query = new GetDocument.Query
{
DocumentId = documentId,
DocumentNumber = documentNumber
};
var (image, imageFormat) = await _mediator.Send(query);
return File(image, imageFormat);
Any idea what's going on?
I have verified the base64 string. If i take the output and use forexample this: https://codebeautify.org/base64-to-image-converter i can see the image.
I found the issue. I was the mimType that from SAP was set to JPG instead of JPEG. An simple mimType.Replace("jpg", "jpeg") fixed the issue :)
Here is a way to do it:
var data = Encoding.UTF8.GetBytes(pagedResult.Data);
MemoryStream stream = new MemoryStream();
stream.Write(data, 0, data.Length);

C# UWP Converting from System.IO.Stream to Windows.Storage.Streams.IRandomAccessStreamWithContentType

so I am trying to get IRandomAccessStreamWithContentType but cant, because I get exception:
"This IRandomAccessStream does not support the CloneStream method because it requires cloning and this stream does not support cloning."
And this happens on last line of the following code:
PixelDataProvider pix = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.ColorManageToSRgb);
byte[] pixels = pix.DetachPixelData();
Stream pixStream = cropBmp.PixelBuffer.AsStream();
pixStream.Write(pixels, 0, (int)(width * height * 4));
IRandomAccessStream iStream= pixStream.AsRandomAccessStream(); //dafaq with streams
RandomAccessStreamReference iReferenceStream= RandomAccessStreamReference.CreateFromStream(iStream);
IRandomAccessStreamWithContentType newStream = await iReferenceStream.OpenReadAsync();
Is there any workaround or something?
Edit 1
I have also tried this way, still doesn't work. (But now I get null not that Clone failed)
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
await ras.WriteAsync(pixels.AsBuffer());
RandomAccessStreamReference iReferenceStream = RandomAccessStreamReference.CreateFromStream(ras);
IRandomAccessStreamWithContentType newStream = await iReferenceStream.OpenReadAsync();
From your code, it seems you have used BitmapDecoder. The BitmapDecoder provides read access to bitmap container data as well as data from the first frame.
We should be able to create a new InMemoryRandomAccessStream for the encoder to write to and call BitmapEncoder.CreateForTranscodingAsync, passing in the in-memory stream and the decoder object.
For example:
Windows.Storage.Streams.IRandomAccessStream random = await Windows.Storage.Streams.RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/sunset.jpg")).OpenReadAsync();
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(random);
Windows.Graphics.Imaging.PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
byte[] buffer = pixelData.DetachPixelData();
InMemoryRandomAccessStream inMemoryRandomAccessStream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateForTranscodingAsync(inMemoryRandomAccessStream, decoder);
encoder.BitmapTransform.ScaledWidth = 320;
encoder.BitmapTransform.ScaledHeight = 240;
await encoder.FlushAsync();
inMemoryRandomAccessStream.Seek(0);
random.Seek(0);
BitmapImage bitmapImage = new BitmapImage();
RandomAccessStreamReference iReferenceStream = RandomAccessStreamReference.CreateFromStream(inMemoryRandomAccessStream);
IRandomAccessStreamWithContentType newStream = await iReferenceStream.OpenReadAsync();
bitmapImage.SetSource(newStream);
MyImage.Source = bitmapImage;

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;
}
}
}

WriteableBitmap to Base64 c#

First of all,I'm sorry for my poor English.
I work on this project for few days without any solution for my problem. I try to send a picture from my UWP application to a Webservice in c#. I did this thing in a android app without any problem.
I should encode a image into a base64 string that the webservice can decode it.
I have two issues , the first is that if I try ( with a online decoder) to decode my base64 string, this gave me something like this with this code.
In the image, we can see the it have not show the whole picture.:
I write it with this code to base64:
private async void ToBase64(WriteableBitmap img)
{
var encoded = new InMemoryRandomAccessStream();
// Copy buffer to pixels
byte[] pixels;
using (var stream = img.PixelBuffer.AsStream())
{
pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
}
var encoder = await BitmapEncoder
.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied, (uint)img.PixelWidth, (uint)img.PixelHeight
, 96, 96, pixels);
await encoder.FlushAsync();
encoded.Seek(0);
var array = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(array, 0, array.Length);
Base64String = Convert.ToBase64String(array);
}
My second issue is that if I try to send this Base64 to my webservices and decode it with FromBase64String, the webservice return an error "The base64 string format is not correct". I don't understand it because as we can see, online decoder can decode it and i don't have this issue with android app.
If you have any ideas about this issues.
I tried multiple things that i saw on internet
Thank you per advance.
EDIT 1
This is my decode method. This method work with Bitmap base64 send with android app.
[WebMethod]
public string uploadPhoto(string image)
{
byte[] bytes = Convert.FromBase64String(image);
using (var imageFile = new FileStream("directory+filename", FileMode.Create))
{
imageFile.Write(bytes, 0, bytes.Length);
imageFile.Flush();
}
return number;
}
EDIT 2
It works with this code :
public async Task<String> SaveToBytesAsync(ImageSource imageSource)
{
byte[] imageBuffer;
var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await localFolder.CreateFileAsync("temp.jpg", CreationCollisionOption.ReplaceExisting);
using (var ras = await file.OpenAsync(FileAccessMode.ReadWrite, StorageOpenOptions.None))
{
WriteableBitmap bitmap = imageSource as WriteableBitmap;
var stream = bitmap.PixelBuffer.AsStream();
byte[] buffer = new byte[stream.Length];
await stream.ReadAsync(buffer, 0, buffer.Length);
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, ras);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight, 96.0, 96.0, buffer);
await encoder.FlushAsync();
var imageStream = ras.AsStream();
imageStream.Seek(0, SeekOrigin.Begin);
imageBuffer = new byte[imageStream.Length];
var re = await imageStream.ReadAsync(imageBuffer, 0, imageBuffer.Length);
}
await file.DeleteAsync(StorageDeleteOption.Default);
return Convert.ToBase64String(imageBuffer);
}
the decoding on the server give a full image.
Thanks.
is there a reason to encode the image?, try this.
string base64String = await ToBase64Async(bitmap);
public async Task<string> ToBase64Async(WriteableBitmap bitmap)
{
using (Stream stream = bitmap.PixelBuffer.AsStream())
{
stream.Position = 0;
var reader = new DataReader(stream.AsInputStream());
var bytes = new byte[stream.Length];
await reader.LoadAsync((uint)stream.Length);
reader.ReadBytes(bytes);
return Convert.ToBase64String(bytes);
}
}
Try use the code to base64
private async Task<string> ToBase64(Image control)
{
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(control);
return await ToBase64(bitmap);
}
And if you have a WriteableBitmap ,try use the code:
private async Task<string> ToBase64(WriteableBitmap bitmap)
{
var bytes = bitmap.PixelBuffer.ToArray();
return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}
If your image is a SotrageFile,you can use
private async Task<string> ToBase64(StorageFile bitmap)
{
var stream = await bitmap.OpenAsync(Windows.Storage.FileAccessMode.Read);
var decoder = await BitmapDecoder.CreateAsync(stream);
var pixels = await decoder.GetPixelDataAsync();
var bytes = pixels.DetachPixelData();
return await ToBase64(bytes, (uint)decoder.PixelWidth, (uint)decoder.PixelHeight, decoder.DpiX, decoder.DpiY);
}
If your picture is RenderTargetBitmap
private async Task<string> ToBase64(RenderTargetBitmap bitmap)
{
var bytes = (await bitmap.GetPixelsAsync()).ToArray();
return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}
See https://codepaste.net/ijx28i
http://lindexi.oschina.io/lindexi/post/win10-uwp-%E8%AF%BB%E5%8F%96%E4%BF%9D%E5%AD%98WriteableBitmap-BitmapImage/

Categories