locked
Create a BitmapImage from a Uri RRS feed

  • Question

  • Hi guys,

    I'm trying to create a set of BitmapImage from Uris that I have stored in a SQLite database, but for some reason is not working. here is the code.

    BitmapList.Clear();
                    foreach (var item in URIList)
                    {
                        var uri = new Uri( item);
                        BitmapImage myImage = newBitmapImage( );
                        myImage.UriSource = uri;

    //The last line of code add the image created to a list of bitmap

                        BitmapList.Add(result);
                    }

    My goal is to show images in my application with the paths I have store in the DB.  

    Thanks                                                                                              

    Tuesday, August 20, 2013 1:59 AM

Answers

  • Hi ,

    Let's say that you already now how to retrieve the images from a sqlite database so let's not focus in there.

      BitmapImage bitmapImage = new BitmapImage();
                                    IRandomAccessStream stream3 = this.ConvertToRandomAccessStream(new MemoryStream(MyTemp1.PhotoVideo));
                                    bitmapImage.SetSource(stream3);
                                    MyTemp1.BmpLogo = bitmapImage;
                                   

    the Mytemp1.photovideo is a byte array which I assume that you have a byte array field in your sqlite table.

    the BmpLogo is an image object you have in your xaml

      private IRandomAccessStream ConvertToRandomAccessStream(MemoryStream memoryStream)
            {

                var randomAccessStream = new InMemoryRandomAccessStream();
                var outputStream = randomAccessStream.GetOutputStreamAt(0);
                var wrStr = outputStream.AsStreamForWrite();
                wrStr.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
                wrStr.Flush();
                return randomAccessStream;

            }

    and this is in your XAML

                                           

    <StackPanel Orientation="Vertical"  Grid.Column="0" VerticalAlignment="Top" Width="120" Height="120">
                                            <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="100" Height="100">
                                                <Image Source="{Binding BmpLogo}"  Stretch="Fill"/>
                                            </Border>

                                        </StackPanel>

    The above is all the code you need to create from a byte array field from your sqlite database to a bitmap.

    The rest is yours . I mean the bindings or where to display them.


    Also you can use the below code to create an image from relative paths

     BitmapImage bitmapImage1 = new BitmapImage();
                                    bitmapImage1 = this.ImageFromRelativePath(this, "../Assets/videos.png");
                                    MyTemp1.BmpLogo = bitmapImage1;

    public BitmapImage ImageFromRelativePath(FrameworkElement parent, string path)
            {
                var uri = new Uri(parent.BaseUri, path);
                BitmapImage result = new BitmapImage();
                result.UriSource = uri;
                return result;
            }

    The XAML is the same.

    Tuesday, August 20, 2013 3:10 PM
  • Your app doesn't have direct access to the file system outside of its application data and install directories. It cannot read images from arbitrary file locations. See File access and permissions

    You will need to store those images somewhere the application can see them. This means either in the application data or install directories for direct access or somewhere the user has granted permission through capabilities (e.g. Pictures library) or through the file pickers.

    To read a file that requires user permission the app needs to open it with a StorageItem rather than trying to read it directly by path. See my blog entry Skip the path: stick to the StorageFile

    --Rob

    Thursday, August 22, 2013 7:42 PM
    Moderator
  • Hello Santiago,

    Or you can save your images in local folder & save path in db.

    Friday, August 23, 2013 4:13 AM

All replies

  • To display the BitmapImage you need to place it in an Image object in your visual tree. For a list of images you can use a collection control (such as a ListBox) and bind it to the BitmapList with a DataTemplate that displays the bound data in an Image.

    --Rob

    Tuesday, August 20, 2013 3:50 AM
    Moderator
  • Hi ,

    Let's say that you already now how to retrieve the images from a sqlite database so let's not focus in there.

      BitmapImage bitmapImage = new BitmapImage();
                                    IRandomAccessStream stream3 = this.ConvertToRandomAccessStream(new MemoryStream(MyTemp1.PhotoVideo));
                                    bitmapImage.SetSource(stream3);
                                    MyTemp1.BmpLogo = bitmapImage;
                                   

    the Mytemp1.photovideo is a byte array which I assume that you have a byte array field in your sqlite table.

    the BmpLogo is an image object you have in your xaml

      private IRandomAccessStream ConvertToRandomAccessStream(MemoryStream memoryStream)
            {

                var randomAccessStream = new InMemoryRandomAccessStream();
                var outputStream = randomAccessStream.GetOutputStreamAt(0);
                var wrStr = outputStream.AsStreamForWrite();
                wrStr.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
                wrStr.Flush();
                return randomAccessStream;

            }

    and this is in your XAML

                                           

    <StackPanel Orientation="Vertical"  Grid.Column="0" VerticalAlignment="Top" Width="120" Height="120">
                                            <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="100" Height="100">
                                                <Image Source="{Binding BmpLogo}"  Stretch="Fill"/>
                                            </Border>

                                        </StackPanel>

    The above is all the code you need to create from a byte array field from your sqlite database to a bitmap.

    The rest is yours . I mean the bindings or where to display them.


    Also you can use the below code to create an image from relative paths

     BitmapImage bitmapImage1 = new BitmapImage();
                                    bitmapImage1 = this.ImageFromRelativePath(this, "../Assets/videos.png");
                                    MyTemp1.BmpLogo = bitmapImage1;

    public BitmapImage ImageFromRelativePath(FrameworkElement parent, string path)
            {
                var uri = new Uri(parent.BaseUri, path);
                BitmapImage result = new BitmapImage();
                result.UriSource = uri;
                return result;
            }

    The XAML is the same.

    Tuesday, August 20, 2013 3:10 PM
  • Thanks for your response, but what I'm trying to do is show pictures in my app from  paths that I have stored in a DB. The paths point to images that are in the computer disk. I don't want to store the images as  arrays of bytes in the DB because those images might be too heavy and they might slow down the program execution.

    I'm trying to use the code in the last part where you create an image from a relative path, but the code is not working. I'm getting an error when I call the method ImageFromRelativePath. The error says I'm not supplying the correct parameters but I'm doing it.

     BitmapImage bitmapImage1 = new BitmapImage();
                                    bitmapImage1 = this.ImageFromRelativePath(this, MystringPath);
                                    MyTemp1.BmpLogo = bitmapImage1;

    public BitmapImage ImageFromRelativePath(FrameworkElement parent, string path)
            {
                var uri = new Uri(parent.BaseUri, path);
                BitmapImage result = new BitmapImage();
                result.UriSource = uri;
                return result;
            }

    Thanks anyways 

    Wednesday, August 21, 2013 1:25 AM
  • Zakkar's code is basically a repeat of the code you originally posted but expanded to read from a database.

    How are you actually displaying the images? As I mentioned previously, the code you showed looks like it should load the BitmapImages correctly, but then it doesn't do anything with them. You need to load that into an Image control displayed in your Xaml.

    For a collection of images you will want to use a collection control (ListBox, ListView, GridView, etc.) and databind it to your collection of BitmapImages

    --Rob

    Wednesday, August 21, 2013 1:40 AM
    Moderator
  • Hi  Rob,

    I didn't post the complete XAML. Just a small sample of how it will include in his listview the part of code that will be responsible to display the images.

    In my App after I retrieve the images from the database I 'm adding them in a collection and then I'm binding the collection to the listview itemssource property of the XAML.

    But I assume that he already knows how to do that so I skipped this part. 

    If he doesn't know how to do that I believe that he will tell us.

    Wednesday, August 21, 2013 8:38 AM
  • Hi Santiago. 

    Here's a complete XAML

                    

    <common:LayoutAwarePage
        x:Name="pageRoot"
        x:Class="App2.BasicPage2"
        DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App2"
        xmlns:common="using:App2.Common"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">

        <Page.Resources>
            <CollectionViewSource
                x:Name="itemsPhotosCollection"
                Source="{Binding Items}"/>
            <!-- TODO: Delete this line if the key AppName is declared in App.xaml -->
            <x:String x:Key="AppName">My Application</x:String>
        </Page.Resources>

        <!--
            This grid acts as a root panel for the page that defines two rows:
            * Row 0 contains the back button and page title
            * Row 1 contains the rest of the page layout
        -->
        <Grid Style="{StaticResource LayoutRootStyle}">
            <Grid.RowDefinitions>
                <RowDefinition Height="140"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <!-- Back button and page title -->
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
                <TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}"/>
            </Grid>

            <Grid Grid.Row="1">

                <ListView
                                  x:Name="itemPhotosListView"
                                AutomationProperties.AutomationId="itemPhotosListView"
                                AutomationProperties.Name="Items1"
                                TabIndex="1"
                                Visibility="Visible"
                                ScrollViewer.HorizontalScrollBarVisibility="Auto"
                                ScrollViewer.HorizontalScrollMode="Auto"
                                ItemsSource="{Binding Source={StaticResource itemsPhotosCollection}}" Grid.ColumnSpan="3" >
                    <ListView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="2">
                            </WrapGrid>
                        </ItemsPanelTemplate>
                    </ListView.ItemsPanel>

                    <ListView.ItemTemplate >
                        <DataTemplate >
                            <Grid   Margin="6" x:Name="DatagridPhotosTemplate" >
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="78"/>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="160"/>
                                </Grid.RowDefinitions>

                                <StackPanel Orientation="Vertical"  Grid.Column="0" VerticalAlignment="Top" Width="120" Height="120">
                                    <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}" Width="100" Height="100">
                                        <Image Source="{Binding BmpEstateLogo}"  Stretch="Fill"/>
                                    </Border>
                                    <TextBlock Text="{Binding FileName}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap"/>
                                </StackPanel>


                                <StackPanel Grid.Column="1" VerticalAlignment="Top"  Width="330" >
                                    <TextBox Text="{Binding Caption, Mode=TwoWay}" HorizontalAlignment="Left" MaxLength="80" Width="330" TextWrapping="NoWrap" />
                                    <TextBlock Text="Comments:" />
                                    <TextBox Text="{Binding Comments, Mode=TwoWay}" AcceptsReturn="True" MaxLength="4000" MaxHeight="70" Height="160" TextWrapping="Wrap" Width="330" />
                                </StackPanel>



                            </Grid>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

            </Grid>


            <VisualStateManager.VisualStateGroups>

                <!-- Visual states reflect the application's view state -->
                <VisualStateGroup x:Name="ApplicationViewStates">
                    <VisualState x:Name="FullScreenLandscape"/>
                    <VisualState x:Name="Filled"/>

                    <!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
                    <VisualState x:Name="FullScreenPortrait">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>

                    <!-- The back button and title have different styles when snapped -->
                    <VisualState x:Name="Snapped">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedBackButtonStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="pageTitle" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource SnappedPageHeaderTextStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
        </Grid>
    </common:LayoutAwarePage>

    Let's Say that you have already retrieved from the database your data and you have filled a list.

    The GalleryList will be used for the binding and the tbGallery is your table in SQLIte

     private List<GalleryList> MyCurrentPhotos;

    private List<tbGallery> MytablePhotos;

     public class tbGallery
        {
             public string Filename { get; set; }
            private string m_caption;
            [DataMember]
            public string Caption
            {
                get { return this.m_caption; }
                set { this.m_caption = value; }
            }

            private string m_comments;
            [DataMember]
            public string Comments
            {
                get { return this.m_comments; }
                set { this.m_comments = value; }

            }

             

            private byte[] m_photovideo;
            [DataMember]
            public byte[] PhotoVideo
            {
                get { return this.m_photovideo; }
                set { this.m_photovideo = value; }
            }

        }
    }

                         


     public class GalleryList
        {

            private string m_caption;
            [DataMember]
            public string Caption
            {
                get { return this.m_caption; }
                set { this.m_caption = value; }
            }
          public string Filename { get; set; }
            private string m_comments;
            [DataMember]
            public string Comments
            {
                get { return this.m_comments; }
                set { this.m_comments = value; }

            }



            private byte[] m_photovideo;
            [DataMember]
            public byte[] PhotoVideo
            {
                get { return this.m_photovideo; }
                set { this.m_photovideo = value; }
            }

            private BitmapImage m_BmpEstateLogo;
            [DataMember]
            public BitmapImage BmpEstateLogo
            {
                get { return m_BmpEstateLogo; }
                set { m_BmpEstateLogo = value; }
            }


        }

    }

    Now Let's retrieve,.I assume that you have already filled from Sqlite the MytablePhotos list.  Now we will add it to the list that will bind in our list view

     foreach (tbGalleryItem in MytablePhotos )
                        {
                            GalleryList MyTemp1 = new GalleryList();
    MyTemp1.Filename = Item.Filename;
                            MyTemp1.Caption = Item.Caption;
                              MyTemp1.PhotoVideo = Item.PhotoVideo;
                              MyTemp1.Comments = Item.Comments;

                            if (MyTemp1.PhotoVideo != null)
                            {
    //with the myextension I can understand id it is a video or a photo. If it is a video i"m displaying just a picture otherwise I'm getting the Image. Therefore perhaps you may need to keep somewhere the filename and get from there the extension with the below command

      string myextension = Path.GetExtension(MyTemp1.FileName);

                                if (myextension == ".mp4" || myextension == ".mp3" || myextension == ".avi" || myextension == ".wmv")
                                {
                                    BitmapImage bitmapImage1 = new BitmapImage();

                                   //this is the XAML page , "..Assets/Video..." is your string Path

    bitmapImage1 = this.ImageFromRelativePath(this, "../Assets/videos.png");
                                    MyTemp1.BmpEstateLogo = bitmapImage1;

                                }
                                else
                                {
                                    BitmapImage bitmapImage = new BitmapImage();
                                    IRandomAccessStream stream3 = this.ConvertToRandomAccessStream(new MemoryStream(MyTemp1.PhotoVideo));
                                    bitmapImage.SetSource(stream3);
                                    MyTemp1.BmpEstateLogo = bitmapImage;


                                }

                            }

    //adding to our list which we will bind
                            MyCurrentPhotos.Add(MyTemp1);
                        }

      this.itemPhotosListView.ItemsSource = null;
                    this.itemPhotosListView.Visibility = Windows.UI.Xaml.Visibility.Visible;
                    this.itemPhotosListView.ItemsSource = MyCurrentPhotos;

    public BitmapImage ImageFromRelativePath(FrameworkElement parent, string path)
            {
                var uri = new Uri(parent.BaseUri, path);
                BitmapImage result = new BitmapImage();
                result.UriSource = uri;
                return result;
            }

            private IRandomAccessStream ConvertToRandomAccessStream(MemoryStream memoryStream)
            {

                var randomAccessStream = new InMemoryRandomAccessStream();
                var outputStream = randomAccessStream.GetOutputStreamAt(0);
                var wrStr = outputStream.AsStreamForWrite();
                wrStr.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
                wrStr.Flush();
                return randomAccessStream;

            }

                                                                                                                                                           Let's hope that gave you a clear idea of what you are suppose to do.
    • Edited by zakkar Wednesday, August 21, 2013 9:33 AM
    Wednesday, August 21, 2013 9:31 AM
  • Hello Santiago, First thing is your bitmapimage uri is live-url or local-disl path?
    Thursday, August 22, 2013 1:07 PM
  • Hi Rob

    I'm using a listview to display the images. I set the datacontext of the stackPanel that hold the Listview to the collection of images.  here is the code.

    First, I created a Collection view source in the xaml

    <CollectionViewSource x:Name="ImgViewSource" />

    Then I hook it up in the code behind with the Collection of images

     this.ImgViewSource.Source = Imgs.BitmapList;

    This is the rest of the xaml  where I put everything together.

                     

    <StackPanel Name="ImgStack" Margin="709,0,-61,-42" VerticalAlignment="Bottom" HorizontalAlignment="Left" DataContext="{Binding Source={StaticResource ImgViewSource }}"  Width="376" Grid.Row="1">
                    <Button Name="btnPic" Height="71" Content="show pics" Width="187" FontSize="25" HorizontalAlignment="Center" Click="btnPic_Click"   />
                    <ListView x:Name="lstPic"  Height="544" ItemsSource="{Binding}" Margin="0"  >
                        <ListView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapGrid/>

                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>

                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Margin="20">

     <Image Source="{Binding image }"  Stretch="None"   Height="100" Width="200" />


                                </StackPanel>
                            </DataTemplate>
                        </ListView.ItemTemplate>

                    </ListView>
                </StackPanel>

    Thanks Rob.

    Thursday, August 22, 2013 2:15 PM
  • hi,

    They're local path like C:\Images\Fruits\apple.jpg

    Thursday, August 22, 2013 2:30 PM
  • Your app doesn't have direct access to the file system outside of its application data and install directories. It cannot read images from arbitrary file locations. See File access and permissions

    You will need to store those images somewhere the application can see them. This means either in the application data or install directories for direct access or somewhere the user has granted permission through capabilities (e.g. Pictures library) or through the file pickers.

    To read a file that requires user permission the app needs to open it with a StorageItem rather than trying to read it directly by path. See my blog entry Skip the path: stick to the StorageFile

    --Rob

    Thursday, August 22, 2013 7:42 PM
    Moderator
  • Thanks Rob. I guess I will have to save the images as arrays of bytes in the DB.

    Friday, August 23, 2013 1:08 AM
  • Hello Santiago,

    Or you can save your images in local folder & save path in db.

    Friday, August 23, 2013 4:13 AM