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/
Related
How can I convert a BitmapImage object to byte array in UWP ? in .Net it is easy to achieve, even in previous WinRT versions, looked all over the internet but without success, one of the solutions was to use a WriteableBitmap like mentioned in this answer, but in the current version of UWP, constructing a WriteableBitmap out of a BitmapImage isn't possible, any work around ?
Since you start from image url, the only way I can figure out is to get the stream of the image. To do this, RandomAccessStreamReference.CreateFromUri() method is really useful.
Windows.Storage.Streams.IRandomAccessStream random = await Windows.Storage.Streams.RandomAccessStreamReference.CreateFromUri(new Uri("http://...")).OpenReadAsync();
Then we have to decode the stream in order to be able to read all pixels for later usage.
Windows.Graphics.Imaging.BitmapDecoder decoder = await Windows.Graphics.Imaging.BitmapDecoder.CreateAsync(random);
Windows.Graphics.Imaging.PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
Finally you can access pixel buffer in such a way.
byte[] bytes = pixelData.DetachPixelData();
Yeah, to a byte[] is not too complex, I think you can get it. I wish it were simpler, but it's not.
http://codepaste.net/ijx28i
This code actually goes a step further and converts the byte[] into a Base64 string (for serializing) but you can ignore that extra step, right?
// using System.Runtime.InteropServices.WindowsRuntime;
private async Task<string> ToBase64(Image control)
{
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(control);
return await ToBase64(bitmap);
}
private async Task<string> ToBase64(WriteableBitmap bitmap)
{
var bytes = bitmap.PixelBuffer.ToArray();
return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}
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);
}
private async Task<string> ToBase64(RenderTargetBitmap bitmap)
{
var bytes = (await bitmap.GetPixelsAsync()).ToArray();
return await ToBase64(bytes, (uint)bitmap.PixelWidth, (uint)bitmap.PixelHeight);
}
private async Task<string> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
{
// encode image
var encoded = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
await encoder.FlushAsync();
encoded.Seek(0);
// read bytes
var bytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
// create base64
return Convert.ToBase64String(bytes);
}
private async Task<ImageSource> FromBase64(string base64)
{
// read stream
var bytes = Convert.FromBase64String(base64);
var image = bytes.AsBuffer().AsStream().AsRandomAccessStream();
// decode image
var decoder = await BitmapDecoder.CreateAsync(image);
image.Seek(0);
// create bitmap
var output = new WriteableBitmap((int)decoder.PixelHeight, (int)decoder.PixelWidth);
await output.SetSourceAsync(image);
return output;
}
This was the important part:
var bytes = (await bitmap.GetPixelsAsync()).ToArray();
Thought you might enjoy seeing it context.
Best of luck.
The helper methods i use are....
private async Task<string> ToBase64(byte[] image, uint height, uint width, double dpiX = 96, double dpiY = 96)
{
var encoded = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, encoded);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, height, width, dpiX, dpiY, image);
await encoder.FlushAsync();
encoded.Seek(0);
var bytes = new byte[encoded.Size];
await encoded.AsStream().ReadAsync(bytes, 0, bytes.Length);
return Convert.ToBase64String(bytes);
}
private byte[] ImageToByteArray(WriteableBitmap wbm)
{
using (Stream stream = wbm.PixelBuffer.AsStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
The code that picks an image and converts to writable bitmap is
WriteableBitmap image;
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".jpeg");
openPicker.FileTypeFilter.Add(".png");
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var bitmp = new BitmapImage();
// Application now has read/write access to the picked file
var filePath = await file.OpenReadAsync();
bitmp.SetSource(filePath);
proPic.Source = bitmp;
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
image = new WriteableBitmap(1, 1);
image.SetSource(stream);
}
imageT = await ToBase64(ImageToByteArray(image), 100, 100, 96, 96);
pic = 1;
}
else
{
//OutputTextBlock.Text = "Operation cancelled.";
}
When i compare the base64string i get from the helper methods with http://www.dailycoding.com/utils/converter/imagetobase64.aspx
The both are not the same.
changing the file into в base64
public async Task<string> GetBase64(string name)
{
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile file = await folder.GetFileAsync(name);
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(file.Path));
byte[] fileBytes = null;
using (var stream = await file.OpenReadAsync())
{
fileBytes = new byte[stream.Size];
using (var reader = new DataReader(stream))
{
await reader.LoadAsync((uint)stream.Size);
reader.ReadBytes(fileBytes);
}
}
return Convert.ToBase64String(fileBytes);
}
I'm trying to store a BitmapImage to the filesystem using C# on UWP. The image is downloaded from Facebook using the graph api and returned as a BitmapImage. That part works, and to retrieve the image (once I can store it, tested with pictures just dropped in the local folder) I'm using the following code:
public static async Task<BitmapImage> GetProfilePicture(string userId){
BitmapImage profilePicture = new BitmapImage();
StorageFolder pictureFolder = await
ApplicationData.Current.LocalFolder.GetFolderAsync("ProfilePictures");
StorageFile pictureFile = await pictureFolder.GetFileAsync(userId + ".jpg");
IRandomAccessStream stream = await pictureFile.OpenAsync(FileAccessMode.Read);
profilePicture.SetSource(stream);
return profilePicture;
This works as well, so what I would want is to simply do the opposite. The preferred result would look like this:
public static async void SaveBitmapToFile(BitmapImage image, userId){
StorageFolder pictureFolder = await
ApplicationData.Current.LocalFolder.CreateFolderAsync(
"ProfilePictures",CreationCollisionOption.OpenIfExists);
//save bitmap to pictureFolder with name userId.jpg
}
I've searched far and wide trying to find a solution, but I can't seem to find any for the UWP platform. How would a go about saving the Bitmap to file? The extension doesn't have to be .jpg if it would be easier to use another extension.
It would be easier if you used a WriteableBitmap. For example, the first method would then be:
public static async Task<WriteableBitmap> GetProfilePictureAsync(string userId)
{
StorageFolder pictureFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync("ProfilePictures");
StorageFile pictureFile = await pictureFolder.GetFileAsync(userId + ".jpg");
using (IRandomAccessStream stream = await pictureFile .OpenAsync(FileAccessMode.Read))
{
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
WriteableBitmap bmp = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
await bmp.SetSourceAsync(stream);
return bmp;
}
}
Then you could do:
public static async Task SaveBitmapToFileAsync(WriteableBitmap image, userId)
{
StorageFolder pictureFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("ProfilePictures",CreationCollisionOption.OpenIfExists);
var file = await pictureFolder.CreateFileAsync(userId + ".jpg", CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenStreamForWriteAsync())
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream.AsRandomAccessStream());
var pixelStream = image.PixelBuffer.AsStream();
byte[] pixels = new byte[image.PixelBuffer.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)image.PixelWidth, (uint)image.PixelHeight, 96, 96, pixels);
await encoder.FlushAsync();
}
}
I am developing an universal app, in my shared code i am trying to download the image from net and save the image to LocalFolder.
I am using HttpClient to download the images from user given urls and reading the client response to save the image. I am using below code to save, but couldn't able to find Writeable SaveJpeg method.
HttpResponseMessage response = await httpClient.GetAsync(imageUri);
await Task.Run(async () =>
{
if (response.IsSuccessStatusCode)
{
// save image locally
StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Images", CreationCollisionOption.OpenIfExists);
BitmapImage bmp = new BitmapImage();
var buffer = await response.Content.ReadAsBufferAsync();
InMemoryRandomAccessStream ras = new InMemoryRandomAccessStream();
DataWriter writer = new DataWriter(ras.GetOutputStreamAt(0));
writer.WriteBuffer(buffer);
bmp.SetSource(ras);
}
});
What is the best way to save the imageresponse to localfolder with image quality % (for both WP and Windows).
You should save the stream directly instead of saving the BitmapImage.
Something like this.
var ras = new InMemoryRandomAccessStream();
var writer = new DataWriter(ras);
writer.WriteBuffer(buffer);
await writer.StoreAsync();
var inputStream = ras.GetInputStreamAt(0);
// you can still use this to display it on the UI though
//bmp.SetSource(ras);
// write the picture into this folder
var storageFile = await folder.CreateFileAsync("image1.jpg", CreationCollisionOption.GenerateUniqueName);
using (var storageStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(inputStream, storageStream.GetOutputStreamAt(0));
}
Update
You can use BitmapEncoder and when pass in property dpi values in SetPixelData.
using (var storageStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, storageStream);
var pixelStream = yourWriteableBitmap.PixelBuffer.AsStream();
var pixels = new byte[pixelStream.Length];
await pixelStream.ReadAsync(pixels, 0, pixels.Length);
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)yourWriteableBitmap.PixelWidth, (uint)yourWriteableBitmap.PixelHeight, 48, 48, pixels);
await encoder.FlushAsync();
}
I want to share the screenshot of the app on Twitter, Facebook, etc. This is my code: it saves the picture, but doesn't open the share media task. I know the problem is in the path :{
var wb = new WriteableBitmap(LayoutRoot, new TranslateTransform());
using (var mediaLibrary = new MediaLibrary()) {
using (var stream = new MemoryStream()) {
var fileName = string.Format("{0}.jpg", DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss"));
wb.SaveJpeg(stream, wb.PixelWidth, wb.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
mediaLibrary.SavePicture(fileName, stream);
shareMediaTask = new ShareMediaTask();
shareMediaTask.FilePath = fileName;
shareMediaTask.Show();
}
}
How can I get the saved picture's path?
Isn't it possible to just simply take a screenshot and share it without saving it on the phone?
To get the real path for the MediaLibrary file, you'll need to use the GetPath() extension method, something like;
using Microsoft.Xna.Framework.Media.PhoneExtensions;
...
var picture = mediaLibrary.SavePicture(fileName, stream);
shareMediaTask = new ShareMediaTask();
shareMediaTask.FilePath = picture.GetPath();
shareMediaTask.Show();
For sharing the screen shot it is not required to save the image , in windows 8.1 it is very easy.
Here is the code, enjoy!
async void dataTransferMgr_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
DataRequest request = args.Request;
request.Data.Properties.Title = "Title";
request.Data.Properties.Description = "brief description";
request.Data.SetText("detailed information");
RandomAccessStreamReference imageStreamRef = await ScreenshotToStreamReferenceAsync(yourChartControlName);
request.Data.Properties.Thumbnail = imageStreamRef;
request.Data.SetBitmap(imageStreamRef);
}
private async Task ScreenshotToStreamAsync(FrameworkElement element, IRandomAccessStream stream)
{
var renderTargetBitmap = new Windows.UI.Xaml.Media.Imaging.RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(element);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();
var dpi = Windows.Graphics.Display.DisplayInformation.GetForCurrentView().LogicalDpi;
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
dpi,
dpi,
pixelBuffer.ToArray());
await encoder.FlushAsync();
}
private async Task<RandomAccessStreamReference> ScreenshotToStreamReferenceAsync(FrameworkElement element)
{
var ms = new InMemoryRandomAccessStream();
await ScreenshotToStreamAsync(element, ms);
ms.Seek(0);
return RandomAccessStreamReference.CreateFromStream(ms);
}