Software-Entwicklung, Projektleitung, Web-Design
Kontakt:   +41 61 927 18 30
You are here:

Blog

Windows 8 / WinRT save an image to database and read the image again from the database

by Joerg Lang | Jan 06, 2013

I started working on a small Window 8 project to get to know WinRT.

One part of the app has to store an image to a database and later read it again to display the Image in the application.
What you think might be trivial took me hours to accomplish. Finally I had working code that is quite short.

First a little warning: I started out with the WriteableBitmapEx that has an easy to use ToByteArray method. The problem is that this bytea array is not equal to the bytes of the image file. You can of course use the FromByteArray method of the library to recreate the WritableBitmap, but to do so you have to know the width and height of the image. If you pass a width and height that does not correspond to the original height and width you get back an distorted image. But when I read back the byteArray from the database, I do not know the width and height anymore (except if I had stored them in the databas as well).

For that reason the WriteableBitmapEx library was no help for me, even though this library is very good.
So I had to go the long way and use the WinRT classes and methods to do what I wanted, but it turned out that the WinRT classes for reading files and turn them into a ByteArray are not so obvious and self explaining as you would like. Also there are several ways how you can accomplish things, but I think (hope) that I have found the one route with the fewest lines.

Turning the image into a byte array

 /// <summary> /// Reads a file from an uri and returns the byte array /// </summary> /// <param name="sourceUri">The source URI.</param> /// <returns></returns> private static async Task<Byte[]> FileToByteArray(Uri sourceUri)
{
    var file = await StorageFile.GetFileFromApplicationUriAsync(sourceUri);
    using (var inputStream = await file.OpenSequentialReadAsync())
    {
        var readStream = inputStream.AsStreamForRead();
        var buffer = new byte[readStream.Length];
        await readStream.ReadAsync(buffer, 0, buffer.Length);
        return buffer;
    }
}

The ByteArray this method returns can be saved to the database.
Then when you need to display the image you will use databinding to display the image. If you databind your image control to the ByteArray nothing will be displayed. (Actually the Image control should have the ability trying to convert the bytes you throw at it into an image.)

Displaying the image in the application

As long as the image control can't simply deal with a byte array, we need to write a converter that does it for us. The first thing is to set up databinding in the XAML. This should look something like this

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Common="using:PresenceTracker.Common"> <Common:ByteArrayImageConverter x:Key="ByteArrayImageConverter"/> <!-- Grid-appropriate 250 pixel square item template as seen in the GroupedItemsPage and ItemsPage --> <DataTemplate x:Key="App250x250CourseItemTemplate"> <Grid HorizontalAlignment="Left" Width="250" Height="250"> <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"> <Image Source="{Binding Image, Converter={StaticResource ByteArrayImageConverter}}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/> </Border> <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}"> <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/> <TextBlock Text="{Binding Description}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/> </StackPanel> </Grid> </DataTemplate>

The next thing you need is of course the actual converter. Here is the code.

using System;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media.Imaging;

namespace PresenceTracker.Common
{
    /// <summary> /// Converts a byte array to an image. The byte image needs to an image. /// </summary> public class ByteArrayImageConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            var imageBytes = (byte[]) value;
            return ConvertToImage(imageBytes).Result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }

        private static async Task<BitmapImage> ConvertToImage(byte[] imageBytes)
        {
            var image = new BitmapImage();
            using (var randomAccessStream = new InMemoryRandomAccessStream())
            {
                var dw = new DataWriter(randomAccessStream.GetOutputStreamAt(0));
                dw.WriteBytes(imageBytes);
                await dw.StoreAsync();
                image.SetSourceAsync(randomAccessStream);
            }
            return image;
        }
    }
}

With this in place we are finally done. We can read an image from a file and store the resulting bytes in a database and then read it back and convert it back into an image.

Comment

  1. RadEditor - HTML WYSIWYG Editor. MS Word-like content editing experience thanks to a rich set of formatting tools, dropdowns, dialogs, system modules and built-in spell-check.
    RadEditor's components - toolbar, content area, modes and modules
       
    Toolbar's wrapper 
     
    Content area wrapper
    RadEditor's bottom area: Design, Html and Preview modes, Statistics module and resize handle.
    It contains RadEditor's Modes/views (HTML, Design and Preview), Statistics and Resizer
    Editor Mode buttonsStatistics moduleEditor resizer
      
    RadEditor's Modules - special tools used to provide extra information such as Tag Inspector, Real Time HTML Viewer, Tag Properties and other.