Use a Byte[] in Image.Source in xamarin forms - xamarin

I have a viewModel returning a byte[] image from database and I want to use it on my image.Source
My .XAML
<Image x:Name="imgPerfil" Aspect="AspectFill" WidthRequest="200" HeightRequest="200" HorizontalOptions="Center"></Image>
My .XAML.CS
public InformacoesUsuario ()
{
InitializeComponent();
viewModel = new InformacoesUsuarioVM(Login.seq_cliente);
viewModel.LoadItemsCommand.Execute(null);
imgPerfil.Source = ImageSource.FromStream(() => new MemoryStream(viewModel.Item.foto));
}
I thought that it will work, but not success

imgPerfil.Source = ImageSource.FromStream(() => new MemoryStream(viewModel.Item.foto));
This will work, but could you do the following:
Debug the byte array as a base64 image:
Debug.WriteLine(Convert.ToBase64String(viewModel.Item.foto));
Then you could use the output to check if the base64 image is really there by pasting the string in this site:
Base64 to image

Related

Best way to retrieve multiple images from .net Web API and populate in Xamarin Form

This is the code I am using to fetch single image. This code runs in loop to populate the image and is working. But sometimes if there is a delay in fetching the image. The application gets stuck in populating data
var resp = await Client.GetAsync(imageUrl);
if (resp.IsSuccessStatusCode)
{
imageData = await resp.Content.ReadAsByteArrayAsync();
}
This is the loop which is calling the download of individual products images:
List<Task> tasks = new List<Task>();
foreach (var product in productsList)
{
var task = DownloadImage(eImageType.Brand, product);
tasks.Add(task);
}
code to build the image object dynamically
foreach(var brand in brands)
{
brand.ImageSource = ImageSource.FromStream(() =>
{
if (brand.ImageData != null)
return new MemoryStream(brand.ImageData);
else
return null;
});
}
Code to show image view in XAMLS
<AbsoluteLayout>
<ffimage:CachedImage Source="blugegb" HorizontalOptions="Fill"
DownsampleWidth="180"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFill"/>
<ffimage:CachedImage Source="{Binding ImageSource}" HorizontalOptions="Fill"
DownsampleWidth="100"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds=".5,.5,.8,.8" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFit"/>
</AbsoluteLayout>
In my opinion the best way is to return the Files as URLs and not as a stream.
Example:
Upload your images to let's say azure blob storage
Create a table with the information about the files (or save metadata with the file)
In your .NET web api build and action that queries all your files.
Make sure that the query returns a JSON that has a result at least like this:
{ name: 'test', url: 'http://yourpathtoyourimage.com/test.png' }
In your Xamarin Application use a plugin or custom logic to show the images by using their URL:
<Image Height="100" Width="100" Margin="12,0,9,0">
<Image.Source>
<BitmapImage UriSource="{Binding Url}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
if you are using FFImageLoading then its very simple all you have to do is :
<ffimage:CachedImage Source="{Binding ImageSource}" HorizontalOptions="Fill"
DownsampleWidth="100"
DownsampleUseDipUnits="True"
AbsoluteLayout.LayoutBounds=".5,.5,.8,.8" AbsoluteLayout.LayoutFlags="All"
VerticalOptions="Fill"
Aspect="AspectFit"/>
Provide a binding to CachedImage in its source, then directly pass the URL as the binding to the source eg:
public string ImageSource {get; set;}
//SomeWhere in your code
ImageSource="https://images.pexels.com/photos/807598/pexels-photo-807598.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940/abcd.jpg";

How to show image files from a directory in a flipview?

I found many samples of displaying images from a resource in a Windows Store app and got it to display images within a sample, but I would require the flipview to show images in a directory, or at least to show image file names I provide by code. With everything I tried so far the flipview remains empty. I maybe missing something obvious, this is the relevant part of the XAML:
<FlipView x:Name="flipView1" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="809,350,9,7" Width="548" Height="411" >
<FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=Image }" Stretch="Uniform"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
this works, but it requires me to add the images a resource first....
ImageBrush brush1 = new ImageBrush();
brush1.ImageSource = new BitmapImage(new Uri("ms-appx:///Assets/P1000171.jpg"));
FlipViewItem flipvw1 = new FlipViewItem();
flipvw1.Background = brush1;
flipView1.Items.Add(flipvw1);
but (for example) this doesn't:
string name = String.Format(#"c:\temp\P1000171.JPG");
Uri uri = new Uri(name);
BitmapImage img = new BitmapImage(uri);
flipView1.Items.Add(img);
What do I miss?
In the meantime I've found the answer myself which I now add for future readers. The above example won't work because a Windows 8 app isn't allowed to access most of the PC's directories without the user having selected one using a FolderPicker. The program can re-use that directory later with:
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
I've changed the above XAML here:
<Image Source="{Binding}" Stretch="UniformToFill"/>
The Task below will show all .JPG files in the Pictures library in a Flipview, if, in the Package.appxmanifest, Capabilities, "Pictures library" has been checked:
public async Task flipviewload()
{
IReadOnlyList<StorageFile> fileList = await picturesFolder.GetFilesAsync();
var images = new List<BitmapImage>();
if (fileList != null)
{
foreach (StorageFile file in fileList)
{
string cExt = file.FileType;
if (cExt.ToUpper()==".JPG")
{
Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
using (Windows.Storage.Streams.IRandomAccessStream filestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
images.Add(bitmapImage);
}
}
}
}
flpView.ItemsSource = images;
}

System.OutOfMemoryException while reading and binding image from isolated storage

This is the code I am using for binding image in XAML
<Border toolkit:TiltEffect.IsTiltEnabled="true" Height="350" Width="400" Grid.ColumnSpan="3">
<Grid Height="350" Width="400" Margin="70,0,70,0" x:Name="Container1">
<Grid.Background>
<ImageBrush ImageSource="{Binding ImageCollection[0]}" Stretch="Uniform" AlignmentX="Left" AlignmentY="Center"/>
</Grid.Background>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ImageTapCommand}" CommandParameter="CONTAINER0"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
</Border>
Likewise I am using 4 border for displaying my recent images.
In my ViewModel I am using the below method for reading image from isolated storage.
public Stream GetFileStream(string filename, ImageLocation location)
{
try
{
lock (SyncLock)
{
if (location == ImageLocation.RecentImage)
{
filename = Constants.IsoRecentImage + #"\" + filename;
}
using (var iSf = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!iSf.FileExists(filename)) return null;
var fs = iSf.OpenFile(filename, FileMode.Open, FileAccess.Read);
return fs;
}
}
}
catch (Exception ex)
{
return null;
}
}
And after getting the stream I will use this below written method four building the WritableBitmap for UI binding
private WriteableBitmap BuildImage(Stream imageStream)
{
using (imageStream)
{
var image = new BitmapImage();
image.SetSource(imageStream);
return new WriteableBitmap(image);
}
}
In this case my issue is after navigating to and from my page for two - three times. The app crashes on BuildImage() method where I am using " image.SetSource(imageStream);" method. I tried many alternatives but failed. The exception I am getting is "System.OutOfMemoryException "
I tried Image control instead of Image brush.
I tried Bitmap instead of WritableBitmap etc. but the result is same.
The app crashing rate will reduce if I use small images. But the crash rate is high with the images taken through camera.
I am trying for a solution to this issue for last one week, But didn't find any alternative to fix the issue.
I found a link that talks about similar issue But didn't get many to solve the issue
Try this,
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
bitmapImage.CreateOptions = BitmapCreateOptions.None;
var bmp = new WriteableBitmap((BitmapSource) bitmapImage);
bitmapImage.UriSource = (Uri) null;
return bmp;
Silverlight caches images by default to improve performance. You should call
image.UriSource = null after using the BitmapImage to dispose of the resources.
Are you reseting/disposing the IsolatedStorageFileStream and the IsolatedStorageFile after you use them?
Have you tried forcing the garbage collector to run to see if that makes any difference.
GC.Collect();
This is not intended as a solution - you should never have to call GC.Collect, but it might help determine whether your problem is a memory leak or just a delay in the memory being reclaimed.

Loading image from projects files

I'm trying to get png image which is my Resource folder. I tested solution that was written here :Add images to ListBox (c#, windows phone 7). For start I wanted to get the same image for every item in my ListBox. But I can't achive that. The picture doesn't show.
It's how my list in xaml look like:
<ListBox x:Name="ProductList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<Image Source="{Binding ImagePath}" Stretch="None"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This is how I populate Items:
List<ImageData1> productsList = new List<ImageData1>();
foreach (ProductItem item in ProductsTable)
{
if (item.Category == chosenCategory.TrId)
{
ImageData1 img = new ImageData1();
img.Name = item.Name;
img.ImagePath = new Uri("Resources/img.png", UriKind.RelativeOrAbsolute);
productsList.Add(img);
}
}
ProductList.ItemsSource = productsList;
Here is my class to hold image data:
public class ImageData1
{
public Uri ImagePath
{
get;
set;
}
public string Name
{
get;
set;
}
}
Try putting / before your image path. Like /Resources/img.png. And try to change UriKind.RelativeOrAbsolute to UriKind.Relative. And make sure your images are added as Content (Build Action property of image). That way it works for me.
Probably, You can also use the following assembled code to read the image from the current application.
StreamResourceInfo info =Application.GetResourceStream(new Uri("Resources/img.png", UriKind.RelativeOrAbsolute));
var bitmap = new BitmapImage();
bitmap.SetSource(info.Stream);
img.Soure = bitmap;

pass data from viewmodel to code behind windows phone

I was trying to use the MVVM pattern on my first (very simple) WP7 app but I got seriously stuck and now I am just trying to get it working without caring about MVVM.
I have a MainViewModel for my MainPage, which works fine. I have a button that passes some data and navigates to a "details page." I had setup a navigation service to navigate to the details page and pass parameters, which works fine. I just couldn't get the databinding to the view working. Since it is a simple app, I decided I would pass the data from the DetailsPageVieModel.cs to the DetailsPage.xaml.cs code behind and do the work there. Here is what that veiw model portion looks like.
public override void Initialize(IDictionary<string, string> parameters)
{
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
base.Initialize(parameters);
parameters.TryGetValue("url", out vidUrl);
dp.LoadVideoData(vidUrl);
}
In my DetailsPage.xaml.cs I have the following:
public void LoadVideoData(string url)
{
HtmlWeb doc = new HtmlWeb();
doc.LoadAsync("http://mydomain.com/video.php?url=" + url);
doc.LoadCompleted += doc_LoadCompleted;
}
private void doc_LoadCompleted(object sender, HtmlDocumentLoadCompleted e)
{
this.vidTitle.Text = e.Document.GetElementbyId("title").InnerText;
vidId = e.Document.GetElementbyId("youtubeId").InnerText;
this.vidUrl.Source = new Uri("http://mydomain.com/video.php?url=" + vidUrl, UriKind.Absolute);
BitmapImage bi = new BitmapImage();
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileStream = myIsolatedStorage.OpenFile("temp.jpg", FileMode.Open, FileAccess.Read))
{
bi.SetSource(fileStream);
this.vidImg.Height = bi.PixelHeight;
this.vidImg.Width = bi.PixelWidth;
}
}
this.vidImg.Source = bi;
}
And here is the relevant DetailsPage.xaml code
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<TextBlock x:Name="vidTitle" Canvas.ZIndex="99" />
<TextBlock Canvas.ZIndex="99" Text="Tap on the image to view the video." FontSize="14" Margin="0"/>
<Button Margin="0 -50" Padding="0" BorderThickness="0">
<Image x:Name="vidImg" Height="225" />
</Button>
<StackPanel Canvas.ZIndex="99" Height="516">
<phone:WebBrowser x:Name="vidUrl" IsScriptEnabled="True" Height="516" Margin="0"/>
</StackPanel>
</StackPanel>
</Grid>
I am guessing the problem lies with the following
DetailsPage dp = new DetailsPage();
//DetailsPage dp = Application.Current.RootVisual as DetailsPage;
Neither of these lines of code works. The first line executes properly but the page doesn't get updated with the proper data. And the second line gives me a runtime error message when it gets to the dp.LoadVideoData(vidUrl); line.
This is my first Windows Phone app and I would appreciate any help anyone can provide.
Kamal
After digging around some more, I found the following solution.
DetailsPage currentPage = (App.Current as App).RootFrame.Content as DetailsPage;
I put this code in DetailsPageViewModel.cs. But for other newbies like me, there is nothing special about the name of the file. It could have very well been Monkey.cs. The above code just gives you access to the code behind of the current page being displayed.

Resources