I have a function On my wcf service it returns Image as Bytes
I didnt Find any idea on how to display it in my Image Control
How can i Convert Those Bytes to an Image And thanks !
Here is my WCF Function:
public List<Data.Product> Show_P()
{
DataTable Table = new DataTable();
List<Data.Product> MyProductsLIST = new List<Data.Product>();
Table = Sp.SelectData("Show_Products", null);
if (Table.Rows.Count > 0)
for (int i = 0; i < Table.Rows.Count; i++)
{
Data.Product Log = new Data.Product();
Log._ID = Convert.ToInt32(Table.Rows[i]["ID"]);
Log._Name = Table.Rows[i]["Name"].ToString();
Log._Price = Table.Rows[i]["Price"].ToString();
Log._Qte = Table.Rows[i]["Qte"].ToString();
Log._CAT = Convert.ToInt32(Table.Rows[i]["Cat"]);
Log._Vote = Convert.ToInt32(Table.Rows[i]["Vote"]);
Log._Image = (byte[])Table.Rows[i]["Image"];
MyProductsLIST.Add(Log);
}
return MyProductsLIST;
}
And in my uwp :
public static List<Products> Get_Products()
{
MspService.Service1Client Serv = new MspService.Service1Client();
MspService.Product[] Product = Serv.Show_PAsync().Result.Show_PResult;
List<Products> Produc = new List<Design_TesTiNg.MenuBox.Products>();
for (int i = 0; i < Product.Length; i++)
{
Products Prod = new Products();
Prod._ID = Product[i]._ID;
Prod._Name = Product[i]._Name;
Prod._Price = Product[i]._Price;
Prod._Qte = Product[i]._Qte;
Prod._CAT = Product[i]._CAT;
Prod._Vote = Product[i]._Vote;
Prod._Image = Product[i]._Image;
Prod.ms = new MemoryStream(Prod._Image);
Convert(Prod.ms,Prod._Img);
Produc.Add(Prod);
}
return Produc;
}
So I tried to convert it that way :
public static async void Convert(MemoryStream mem, BitmapImage Img)
{
IRandomAccessStream a1 = await ConvertToRandomAccessStream(mem);
Img = new BitmapImage();
await Img.SetSourceAsync(a1);
}
public static async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
var dw = new DataWriter(outputStream);
var task = Task.Factory.StartNew(() => dw.WriteBytes(memoryStream.ToArray()));
await task;
await dw.StoreAsync();
await outputStream.FlushAsync();
return randomAccessStream;
}
it returns Image as Bytes I didnt Find any idea on how to display it in my Image Control
From your code Log._Image = (byte[])Table.Rows[i]["Image"];, I think your Bytes means byte array here. I think problem is you need to know how your images are converted from image to byte arrays. I assumed that your wcf is for saving data (include byte arrays of images) to table and retrieve them, your converting images to byte arrays work is still done in the UWP app, then I've tested your code, if I convert image to byte array in UWP app in this way:
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/1.jpeg"));
var b64 = await ConvertStorageFileToBase64String(file);
private async Task<byte[]> ConvertStorageFileToBase64String(StorageFile File)
{
var stream = await File.OpenReadAsync();
using (var dataReader = new DataReader(stream))
{
var bytes = new byte[stream.Size];
await dataReader.LoadAsync((uint)stream.Size);
dataReader.ReadBytes(bytes);
return bytes;
}
}
And convert back using your method like this:
MemoryStream mem = new MemoryStream(b64);
IRandomAccessStream a1 = await ConvertToRandomAccessStream(mem);
var Img = new BitmapImage();
await Img.SetSourceAsync(a1);
myimg.Source = Img; //myimg is the name of the image control.
The image can be correctly showed in image control. So if your code can't work by your side, please update your code for converting image to byte array, or maybe you can upload your sample so can we have a test.
Related
I'm trying to add an image cropper to my app and have found Xamarin.Plugin.ImageEdit, that seems to be a good way to start on it, but the problem is that I couldn't find any example of how to show the image and the square over it to cut the image, in other words, integrate it with UI. Does anyone here have used ImageEdit and can tell me how to do it?
What I have so far:
async void Init()
{
MediaFile a = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
CompressionQuality = 80,
RotateImage = true
});
byte[] imageArray = await Task.Run(()=>ImagePath2ByteArray(a));
using (var image = await CrossImageEdit.Current.CreateImageAsync(imageArray))
{
var croped = await Task.Run(() =>
image.Crop(10, 20, 250, 100)
.Rotate(180)
.Resize(100, 0)
.ToPng()
);
}
}
async Task<byte[]> ImagePath2ByteArray(MediaFile a)
{
byte[] imageArray = null;
if (a != null)
{
using (MemoryStream ms = new MemoryStream())
{
var stream = a.GetStream();
stream.CopyTo(ms);
imageArray = ms.ToArray();
}
}
return imageArray;
}
It seems to work fine but doesn't have UI.
I have a Windows 10 UWP app that will run on Windows 10 Mobile. A requirement I have is to capture a signature from the user. So far, I am simply using an InkCanvas in XAML and have it wired up to my code behind.
I then have a button that when clicked, will take the signature on the InkCanvas and send it to the server via a WCF call. The server and WCF service is already existing. It takes in the signature image as a base64 serialized string.
I know how to get the base64 once I have either an image or a byte array. However, in my many hours of reading, I am finding that articles/examples were either written for WPF or Windows 8.1 and do not work on Windows 10 UWP. Also, of the examples that I have found that will work, it seems my only option is to save the signature to file as a GIF.
I see that I can call GetStrokes() like this
var strokeCollection = cvsSignature.InkPresenter.StrokeContainer.GetStrokes();
Which will return me a read only list of InkStroke. I guess I can iterate that list and build a byte array? How would I do that? It seems this is not efficient?
Otherwise, I thought I could just change the stream from a file stream to a memory stream but I guess either this is not possible or I am missing something. I am trying this
using (var inkMemStream = new MemoryStream())
{
await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(inkMemStream);
}
But with this type of approach I get an exception that I cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream
Thanks!
I found a way, if you don't want to save your InkCanvas to a file or as a GIF, to manipulate it in memory. I actually have three options below. Note, for some of this, you will need to add a reference to Win2D.uwp, which can be found on NuGet by searching that exact name. It is provided by Microsoft.
Convert the InkCanvas to a byte array:
private byte[] ConvertInkCanvasToByteArray()
{
//First, we need to get all of the strokes in the canvas
var canvasStrokes = myCanvas.InkPresenter.StrokeContainer.GetStrokes();
//Just as a check, make sure to only do work if there are actually strokes (ie not empty)
if (canvasStrokes.Count > 0)
{
var width = (int)myCanvas.ActualWidth;
var height = (int)myCanvas.ActualHeight;
var device = CanvasDevice.GetSharedDevice();
//Create a new renderTarget with the same width and height as myCanvas at 96dpi
var renderTarget = new CanvasRenderTarget(device, width,
height, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
//This will clear the renderTarget with a clean slate of a white background.
ds.Clear(Windows.UI.Colors.White);
//Here is where we actually take the strokes from the canvas and draw them on the render target.
ds.DrawInk(myCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
//Finally, this will return the render target as a byte array.
return renderTarget.GetPixelBytes();
}
else
{
return null;
}
}
If all you need is a byte array of the pixels, you are done. However, if you now want to generate an image, you use the WriteableBitmap to do so. Here are sync and async methods that can be called to do this.
private WriteableBitmap GetSignatureBitmapFull()
{
var bytes = ConvertInkCanvasToByteArray();
if (bytes != null)
{
var width = (int)cvsSignature.ActualWidth;
var height = (int)cvsSignature.ActualHeight;
var bmp = new WriteableBitmap(width, height);
using (var stream = bmp.PixelBuffer.AsStream())
{
stream.Write(bytes, 0, bytes.Length);
return bmp;
}
}
else
return null;
}
private async Task<WriteableBitmap> GetSignatureBitmapFullAsync()
{
var bytes = ConvertInkCanvasToByteArray();
if (bytes != null)
{
var width = (int)cvsSignature.ActualWidth;
var height = (int)cvsSignature.ActualHeight;
var bmp = new WriteableBitmap(width, height);
using (var stream = bmp.PixelBuffer.AsStream())
{
await stream.WriteAsync(bytes, 0, bytes.Length);
return bmp;
}
}
else
return null;
}
Finally, here is an async method that I am using to be able to do a crop on the bitmap if you want to do that. The key thing with this method is notice how with this approach, you don't have to get the pixel bytes as an array first. You just get the strokes from the canvas and then it is saved directly into a memory stream
private async Task<WriteableBitmap> GetSignatureBitmapCropped()
{
try
{
var canvasStrokes = cvsSignature.InkPresenter.StrokeContainer.GetStrokes();
if (canvasStrokes.Count > 0)
{
var bounds = cvsSignature.InkPresenter.StrokeContainer.BoundingRect;
var xOffset = (uint)Math.Round(bounds.X);
var yOffset = (uint)Math.Round(bounds.Y);
var pixelWidth = (int)Math.Round(bounds.Width);
var pixelHeight = (int)Math.Round(bounds.Height);
using (var memStream = new InMemoryRandomAccessStream())
{
await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(memStream);
var decoder = await BitmapDecoder.CreateAsync(memStream);
var transform = new BitmapTransform();
var newBounds = new BitmapBounds();
newBounds.X = 0;
newBounds.Y = 0;
newBounds.Width = (uint)pixelWidth;
newBounds.Height = (uint)pixelHeight;
transform.Bounds = newBounds;
var pdp = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage);
var pixels = pdp.DetachPixelData();
var cropBmp = new WriteableBitmap(pixelWidth, pixelHeight);
using (var stream = cropBmp.PixelBuffer.AsStream())
{
await stream.WriteAsync(pixels, 0, pixels.Length);
}
return cropBmp;
}
}
else
{
return null;
}
}
catch (Exception ex)
{
return null;
}
}
Hope this helps provide some alternatives when using InkCanvas in Windows 10 Universal.
it seems my only option is to save the signature to file as a GIF.
GIF is not the only choice. The official sample just show GIF, but you can also save the InkStokes collection to JPG and PNG. Code as follows:
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg" ,".gif",".png"});
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
But with this type of approach I get an exception that I cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream
As you see, it cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream directly. You need to read the image file you just saved as ImageSource. As you known how to get the base64 once you have either an image or a byte array. So what we just need is to get an image or a byte array from the image file.
Read the image file as byte array and then a memory stream as follows
if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
{
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg", ".gif", ".png" });
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (null != file)
{
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
}
using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read))
{
WriteableBitmap inkimagesource = new WriteableBitmap(50, 50);
inkimagesource.SetSource(streamforread);
byte[] imageBuffer = inkimagesource.PixelBuffer.ToArray();
MemoryStream ms = new MemoryStream(imageBuffer);
}
}
}
Read the file as image source just need to change the file reading code as follows:
using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read)
{
var bitmap = new BitmapImage();
bitmap.SetSource(streamforread);
}
I guess I can iterate that list and build a byte array? How would I do that? It seems this is not efficient?
It seems like currently there is no API can build the InkStroke collections as byte array directly. SaveAsync() method has already help you save the InkStroke collection to a stream, you can use code above for using it.
I'm building a Windows Store App including a local folder of Images.
I want to protect all the Images so they can't be accessed from:
C:\Users[username]\AppData\Local\Packages\LocalState\Settings\settings.dat
I know I should encrypt and decrypt the Images using the DataProtectionProvider class, but the documentation only shows how to encrypt/decrypt strings...
How should I convert a Bitmap image into a byte array? or should I encode it with Base64? Is there any tutorial or sample using this process?
It's easiest if the images you want to encrypt are loaded from files and written back out to files. Then you can do:
async void EncryptFile(IStorageFile fileToEncrypt, IStorageFile encryptedFile)
{
IBuffer buffer = await FileIO.ReadBufferAsync(fileToEncrypt);
DataProtectionProvider dataProtectionProvider =
new DataProtectionProvider(ENCRYPTION_DESCRIPTOR);
IBuffer encryptedBuffer =
await dataProtectionProvider.ProtectAsync(buffer);
await FileIO.WriteBufferAsync(encryptedFile, encryptedBuffer);
}
DataProtectionProvider.ProtectStreamAsync is another alternative if you can get stream instances from your inputs and outputs. For example, if you have a byte[] containing your image data then you can create an in-memory input stream from it:
byte[] imageData = ...
using (var inputMemoryStream = new MemoryStream(imageData).AsInputStream())
{
...
}
Edit: Then for example to decrypt the file and display it in an Image control you could do:
var encryptedBuffer = await FileIO.ReadBufferAsync(encryptedFile);
var dataProtectionProvider = new DataProtectionProvider();
var buffer = await dataProtectionProvider.UnprotectAsync(encryptedBuffer);
var bmp = new BitmapImage();
await bmp.SetSourceAsync(buffer.AsStream().AsRandomAccessStream());
imageControl.Source = bmp;
public async void Protect()
{
for (int i = 1; i < 24; i++)
{
string imageFile = ImagePages[i];
var fileToEncrypt = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(imageFile);
var encryptedFile1 = await ApplicationData.Current.LocalFolder.CreateFileAsync("encryptedPage" + i);
var encryptedFile2 = await EncryptFile(fileToEncrypt, encryptedFile1);
IBuffer buffer = await DecryptFile(encryptedFile2);
//(2.) It goes here and throw the 'System.ArgumentException' having the encryptedFile's ContentType=""
var bmp = new BitmapImage();
await bmp.SetSourceAsync(buffer.AsStream().AsRandomAccessStream());
//Fill the List responsible for the Portrait View
MyPortrait mp = new MyPortrait();
mp.onlyImage = bmp;
PImageList.Add(mp);
}
}
public async Task<IStorageFile> EncryptFile(IStorageFile fileToEncrypt, IStorageFile encryptedFile)
{
IBuffer buffer = await FileIO.ReadBufferAsync(fileToEncrypt);
//I have no more exceptions here
DataProtectionProvider dataProtectionProvider = new DataProtectionProvider("LOCAL=user");
IBuffer encryptedBuffer = await dataProtectionProvider.ProtectAsync(buffer);
//(1.) After arriving here when deploying it goes to (2.)
await FileIO.WriteBufferAsync(encryptedFile, encryptedBuffer);
return encryptedFile;
}
public async Task<IBuffer> DecryptFile(IStorageFile encryptedFile)
{
var protectedBuffer = await FileIO.ReadBufferAsync(encryptedFile);
var dataProtectionProvider = new DataProtectionProvider();
var buffer = await dataProtectionProvider.UnprotectAsync(protectedBuffer);
return buffer;
}
I create livetiles with the following code:
// wide 310x150
var tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileWide310x150PeekImage03);
tileXml.GetElementsByTagName(textElementName).LastOrDefault().InnerText = string.Format(artist + " - " + trackname);
var image = tileXml.GetElementsByTagName(imageElementName).FirstOrDefault();
if (image != null)
{
var src = tileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_wide.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
// square 150x150
var squaredTileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150PeekImageAndText01);
squaredTileXml.GetElementsByTagName(textElementName).FirstOrDefault().InnerText = string.Format(artist + " - " + trackname);
image = squaredTileXml.GetElementsByTagName(imageElementName).LastOrDefault();
if (image != null)
{
var src = squaredTileXml.CreateAttribute("src");
if (albumart == String.Empty)
src.Value = "Assets/onemusic_logo_square.scale-240.png";
else
src.Value = albumart;
image.Attributes.SetNamedItem(src);
}
updater.Update(new TileNotification(tileXml));
updater.Update(new TileNotification(squaredTileXml));
The problem I face is that the images shown on the livetile aren't sharp (in the app they are). I think this is because of the 310x150 pixels size of the template. I looked at the templates, there aren't any higher resolution ones. Is there a way to make the images sharper?
I noticed that providing an image with a resolution of exactly 744x360 pixels solves the problem. So I wrote this function to resize my albumarts (maybe it will come in handy for someone);
private async static Task<string> CropAndSaveImage(string filePath)
{
const string croppedimage = "cropped_albumart.jpg";
// read file
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
if (file == null)
return String.Empty;
// create a stream from the file and decode the image
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// create a new stream and encoder for the new image
using (InMemoryRandomAccessStream writeStream = new InMemoryRandomAccessStream())
{
// create encoder
BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(writeStream, decoder);
enc.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Linear;
// convert the entire bitmap to a 744px by 744px bitmap
enc.BitmapTransform.ScaledHeight = 744;
enc.BitmapTransform.ScaledWidth = 744;
enc.BitmapTransform.Bounds = new BitmapBounds()
{
Height = 360,
Width = 744,
X = 0,
Y = 192
};
await enc.FlushAsync();
StorageFile albumartfile = await ApplicationData.Current.LocalFolder.CreateFileAsync(croppedimage, CreationCollisionOption.ReplaceExisting);
using (var stream = await albumartfile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(writeStream.GetInputStreamAt(0), stream.GetOutputStreamAt(0));
}
// return image path
return albumartfile.Path;
}
}
In WindowsStoreApps i want to convert an Local Image from solution explorer to byte array and then to base64 string.please guide me.The code I have tried so far is as below.
public async Task<string> ToBase64()
{
Byte[] ByteResult = null;
string bs64 = null;
if (url != null)
{
HttpClient client = new HttpClient();
ByteResult = await client.GetByteArrayAsync(url);
}
bs64 = Convert.ToBase64String(ByteResult);
return bs64;
}
Suppose you want to convert an image named MyImage.png from Assets folder then below code will return the base64 string of that image.
private async Task DoWork()
{
var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/MyImage.png"));
var b64 = await ConvertStorageFileToBase64String(file);
}
private async Task<string> ConvertStorageFileToBase64String(StorageFile File)
{
var stream = await File.OpenReadAsync();
using (var dataReader = new DataReader(stream))
{
var bytes = new byte[stream.Size];
await dataReader.LoadAsync((uint)stream.Size);
dataReader.ReadBytes(bytes);
return Convert.ToBase64String(bytes);
}
}
Try this piece of code
StorageFile file = <Your File>;
var bytes = new Byte[0];
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
var reader = new DataReader(fileStream.GetInputStreamAt(0));
bytes = new Byte[fileStream.Size];
await reader.LoadAsync((uint)fileStream.Size);
reader.ReadBytes(bytes);
}
string imageInStringFormat = Convert.ToBase64String(bytes);