Xamarin Forms Image to Stream - c#

My goal is to take an embedded image which is saved in each project's image folder, stream it, convert it to a byte array and save it to the device's local storage file system using PCLStorage. The part which I cannot figure out is how to stream from the embedded image.
var embeddedImage = new Image { Aspect = Aspect.AspectFit };
embeddedImage.Source = ImageSource.FromResource("applicationIcon.png");
then I could stream it if I had the path, or I could convert it to a byte [] if I had a stream. The code below does not work because the file source is not found (obviously).
string localFileUri = string.Empty;
// Get hold of the file system.
IFolder localFolder = FileSystem.Current.LocalStorage;
IFile file = await FileSystem.Current.GetFileFromPathAsync("applicationIcon.png");
using (Stream stream = await file.OpenAsync(FileAccess.Read))
{
using (var ms = new MemoryStream())
{
var byteArray = ms.ToArray();
var storeragePath = await iStorageService.SaveBinaryObjectToStorageAsync(string.Format(FileNames.ApplicationIcon, app.ApplicationId), byteArray);
app.IconURLLocal = storeragePath;
}
}
The only option seems to be to use some kind of resource locator, and then maintain that code for each type of project you add. Not very elegant. Is there another way?

First off, thank you to deckertron_9000 for putting me on the right path to figuring it out, and secondly these two links:
http://www.itgo.me/a/3956119637998661919/xamarin-forms-how-to-load-an-image-from-resources-into-a-byte-array
Xamarin Forms: How to use Embedded Resources in PCL Project for Image
In the end, this is what worked for me:
Firstly I added the image to a folder in my PCL. Then I made sure to change the image's Build Action to Embedded Resource.
Secondly, I added using System.Reflection;
Thirdly, this code worked for me:
string imagePath = "NameOfProject.Assets.applicationIcon.png";
Assembly assembly = typeof(NameOfClass).GetTypeInfo().Assembly;
byte[] buffer;
using (Stream stream = assembly.GetManifestResourceStream(imagePath))
{
long length = stream.Length;
buffer = new byte[length];
stream.Read(buffer, 0, (int)length);
var storeragePath = await iStorageService.SaveBinaryObjectToStorageAsync(string.Format(FileNames.ApplicationIcon, app.ApplicationId), buffer);
app.IconURLLocal = storeragePath;
}

if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await App.CurrentApp.MainPage.DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
_mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "Sample",
Name = "test.jpg"
});
if (_mediaFile == null)
return;
//ViewModel.StoreImageUrl(file.Path);
await App.CurrentApp.MainPage.DisplayAlert("Snap", "Your photo have been added to your Items collection.", "OK");
ImageSource = ImageSource.FromStream(() =>
{
var stream = _mediaFile.GetStream();
_mediaFile.Dispose();
return stream;
});

Related

Xamarin Forms: File was not saved on the android storage

private async Task DoDownloadFile(ChatMessageListRefDataModel chatMessage)
{
var status = await Permissions.RequestAsync<Permissions.StorageWrite>();
if(status == PermissionStatus.Granted)
{
await HttpRequestHelper.DownloadFile(chatMessage.FileUrl, chatMessage.FileName);
}
}
public static async Task DownloadFile(string url, string fileName) {
var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), fileName);
using (var downloadStream = await client.GetStreamAsync(url))
{
using (var memoryStream = new MemoryStream())
{
await downloadStream.CopyToAsync(memoryStream);
using(FileStream file = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
byte[] bytes = new byte[memoryStream.Length];
memoryStream.Read(bytes, 0, (int)memoryStream.Length);
file.Write(bytes, 0, bytes.Length);
memoryStream.Close();
}
}
}
The code produces no error it is just the file was not found on the phone's directory. What could have gone wrong. Thanks.
I have created a new sample to test your code. And meet the same problem as yours. But the problem just appeared on the physical device. When I run it on the andorid emulator, I can find the file by the Android Studio's emulator device file explorer.
The path Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), fileName); seems be hidden. I can't find it by the device's file manager.
So you can try to use the following code to get the path, such as:
var filename1 = Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath;
var filename = System.IO.Path.Combine(filename1, "xxx.txt");
using (System.IO.FileStream os = new System.IO.FileStream(filename, System.IO.FileMode.OpenOrCreate))
{
}
This file path can be found by the device's file manager. You can have a try.
Turns Out the Launcher.OpenAsync(fileUrl) is just okay to me.

How to save photos from gallery to shared folder on a windows server in xamarin

I am trying to save an image from the Android gallery to a shared folder on a windows server. With the NuGet SharpCifs.Std package installed, I try to use the CopyTo method to save the image but it gives an error when the path is correct to my knowledge.
This is the error
Piece of code ...
using SharpCifs.Smb;
...
...
var windowsAuth = new NtlmPasswordAuthentication("mydomain.local", "user", "password");
var source = new SmbFile(photoFile);
var dest = new SmbFile(photosPath, windowsAuth);
source.CopyTo(dest);
In debug mode, the value of variables are:
source = file:///storage/emulated/0/Android/data/com.salicru/files/Pictures/temp/IMG_20190828_101004_88.jpg
dest = file://srvdoc/compartit/fotos equips/M3/6A0BW000001/
What am I doing wrong?
I had to create a method that I called ConvertMediaFileToByteArray for the conversion of the photo stream to a byte[].
private byte[] ConvertMediaFileToByteArray(MediaFile file)
{
using (var memoryStream = new MemoryStream())
{
file.GetStream().CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
Converting call.
file = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
{
PhotoSize = PhotoSize.Small
});
if (file != null)
{
imageSource = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
//Convert ImatgeStream to BYTE[]
var imageToByte = ConvertMediaFileToByteArray(file);
}
Then, instead of using CopyTo method i used CreateNewFile method.
var windowsAuth = new NtlmPasswordAuthentication("domain", "admin", "password");
var dest = new SmbFile(photosPath + imageName, windowsAuth);
dest.CreateNewFile();
var writeStream = dest.GetOutputStream();
writeStream.Write(imageToByte);
writeStream.Dispose();

Get Thumbnail from mp3 file in c# xaml for windows phone 8.1

I need to get Thumbnail from mp3 files. I Implemented this but it never catch thumbnails. I checked the existence of the images opening them with windows media player and from xbox music (on the phone) but i can't retrieve them in my app. Please Help
async private void ThumbnailFetcher(StorageFile file)
{
if (file != null)
{
const ThumbnailMode thumbnailMode = ThumbnailMode.MusicView;
const uint size = 100;
using (StorageItemThumbnail thumbnail = await file.GetThumbnailAsync(thumbnailMode, size))
{
if (thumbnail != null && thumbnail.Type == ThumbnailType.Image)
{
this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
BitmapImage thumbnailImage = new BitmapImage();//image used for display
thumbnailImage.SetSource(thumbnail);
CurrentAlbumArt.Source = thumbnailImage;
Debug.WriteLine("true");
});
}
else
{
Debug.WriteLine("False");
}
}
}
}
P.s It gives always false.
It seems there is a bug on windows phone 8.1, I searched all the night and the only method I could implemented is this
var fileStream = await file.OpenStreamForReadAsync();
var TagFile = File.Create(new StreamFileAbstraction(file.Name, fileStream, fileStream));
// Load you image data in MemoryStream
var tags = TagFile.GetTag(TagTypes.Id3v2);
IPicture pic = TagFile.Tag.Pictures[0];
MemoryStream ms = new MemoryStream(pic.Data.Data);
ms.Seek(0, SeekOrigin.Begin);
bitmap.SetSource(ms.AsRandomAccessStream());
AlbumArt.Source = bitmap;
but it doesn't work too..
var filestream = await receivedFile.OpenStreamForReadAsync();
var tagFile = File.Create(new StreamFileAbstraction(receivedFile.Name, filestream, filestream));
var tags = tagFile.GetTag(TagLib.TagTypes.Id3v2);
var bin = (byte[])(tags.Pictures[0].Data.Data);
MemoryStream ms = new MemoryStream(bin);
await bitmapImage.SetSourceAsync(ms.AsRandomAccessStream());
AlbumArt.Source=bitmapImage;
use this and taglib portable. (Sorry for take so much time)

Windows 8 - Save Image in XAML as local file ( inside Application folder )

In my Windows store application, i am displaying a picture using Image control in XAML. Source of the Image control is set, code wise using WriteableBitmap. I am trying to send this image as attachment in email. Is there any easy way for that? I am trying to save that image locally( within application ) and attach that saved image to email. But not able to save locally. Any help is appreciated.
Here is the code.
bitmap = await WriteableBitmapRenderExtensions.Render(dataCanvas);
image.Source = bitmap;
dataCanvas is a Canvas control consists of two images, one place above another. Actually i have to place a sunglass top of users face and display it as another image in xaml. Also email that image.
Check out the WriteableBitmapSaveExtensions class in WinRT XAML Toolkit for all the SaveToFile() extension methods you can use to save your WriteableBitmap.
The core one is this:
public static async Task SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFile outputFile,
Guid encoderId)
{
Stream stream = writeableBitmap.PixelBuffer.AsStream();
byte[] pixels = new byte[(uint)stream.Length];
await stream.ReadAsync(pixels, 0, pixels.Length);
using (var writeStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite))
{
var encoder = await BitmapEncoder.CreateAsync(encoderId, writeStream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)writeableBitmap.PixelWidth,
(uint)writeableBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
using (var outputStream = writeStream.GetOutputStreamAt(0))
{
await outputStream.FlushAsync();
}
}
}
You can get the encoder ID using an overload of the method:
public static async Task<StorageFile> SaveToFile(
this WriteableBitmap writeableBitmap,
StorageFolder storageFolder,
string fileName,
CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
{
StorageFile outputFile =
await storageFolder.CreateFileAsync(
fileName,
options);
Guid encoderId;
var ext = Path.GetExtension(fileName);
if (new[] { ".bmp", ".dib" }.Contains(ext))
{
encoderId = BitmapEncoder.BmpEncoderId;
}
else if (new[] { ".tiff", ".tif" }.Contains(ext))
{
encoderId = BitmapEncoder.TiffEncoderId;
}
else if (new[] { ".gif" }.Contains(ext))
{
encoderId = BitmapEncoder.GifEncoderId;
}
else if (new[] { ".jpg", ".jpeg", ".jpe", ".jfif", ".jif" }.Contains(ext))
{
encoderId = BitmapEncoder.JpegEncoderId;
}
else if (new[] { ".hdp", ".jxr", ".wdp" }.Contains(ext))
{
encoderId = BitmapEncoder.JpegXREncoderId;
}
else //if (new [] {".png"}.Contains(ext))
{
encoderId = BitmapEncoder.PngEncoderId;
}
await writeableBitmap.SaveToFile(outputFile, encoderId);
return outputFile;
}
Any subclass of BitmapSource (including WritableBitmap) can be passed to a BitmapEncoder. A BitmapEncoder takes a Stream to which the encoded JPEG, PNG or other image is written.
You can then use a mailer library to reference the stream used by the encoder, or use the Share contract, and pass the stream directly.
Example:
var bitmap = new WritableBitmap();
// ... draw your bitmap
var tempPath = // path to where you want to save (probably in your appx temp);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(bitmap);
using (var fs = new FileStream(tempPath))
{
encoder.Save(fs);
}
// use the image saved to tempPath
// http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh871370.aspx

How to clear a file before writing into it

I am using this code to write into my file:
private async void play_Click(object sender, RoutedEventArgs e)
{
String MyScore;
Double previousScore = 0;
StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
var dataFolder1 = await local.CreateFolderAsync("MyFolder", CreationCollisionOption.OpenIfExists);
var file1 = await dataFolder1.CreateFileAsync("MyFile.txt", CreationCollisionOption.OpenIfExists);
var file = await dataFolder1.OpenStreamForReadAsync("MyFile.txt");
using (StreamReader streamReader = new StreamReader(file))
{
MyScore = streamReader.ReadToEnd();
}
if (MyScore != null && !MyScore.Equals(""))
{
previousScore = Convert.ToDouble(MyScore);
}
Double CurerentScore = 0;
Double Total = 0;
String scoreText = this.ScoreTB.Text;
CurerentScore = Convert.ToDouble(scoreText);
Total = previousScore - CurerentScore;
using (var s = await file1.OpenStreamForWriteAsync())
{
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(Convert.ToString(Total));
s.Write(fileBytes, 0, fileBytes.Length);
}
}
But before writing into it, I want that my file should get cleared. What should I do?
This is what i have tried so far but the problem is that it writes the file up to the filebytes.length and due to that if the new information to be writed in file is less in terms of length in comparison to the privous length then some garbage value or unnecessay thing comes after the end of the new file
You can use this snippet :
var folder = ApplicationData.Current.LocalFolder;
// You are going to replace the file
var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
using (var stream = await file.OpenStreamForWriteAsync())
{
var content = System.Text.Encoding.UTF8.GetBytes(Convert.ToString(Total));
await stream.WriteAsync(content, 0, content.Length);
}
To quote the documentation :
ReplaceExisting : Create the new file or folder with the desired name,
and replaces any file or folder that already exists with that name.
I have clear the file by writing a empty string to it and then i have written what i wanted in my file This solved my issue as nothing was there in the file so whatever i wanted to write to it came up successfully.
Simply use Stream.SetLength like this:
using (var s = await file1.OpenStreamForWriteAsync())
{
// Add this line
s.SetLength(0);
// Then write new bytes. use 's.SetLength(fileBytes.Length)' if needed.
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(Convert.ToString(Total));
s.Write(fileBytes, 0, fileBytes.Length);
}

Categories

Resources