×

Filter Explorer for Windows and Windows Phone 8.1

Filter Explorer application demonstrates some of the image editing capabilities and performance of the Nokia Imaging SDK by allowing the user to apply a number of filter layers to existing or newly captured photos.

Compatibility

  • Compatible with Windows and Windows Phone 8.1.
  • Tested with Nokia Lumia 2520, Windows 8.1 desktop and Windows Phone 8.1 emulator.
  • Developed with Visual Studio Express 2013 from Windows.
  • Compiling the project requires Nokia Imaging SDK.

One of the targets of this project was to create a universal app for Windows and Windows Phone 8.1, sharing most of the code between the two. Therefore most of the application business logic and image processing code was implemented in a shared code project, leaving pretty much only the UI layer to be implemented separately for the specific target platforms.

Design

Filter Explorer opens up into a grid of photos from either the device's Camera Roll (if there is content) or Pictures Library, displays the photos from there with a random filter applied on each of the photos, and randomly updates photos with new filters with a rotation animation. User can then either open some of the randomly filtered suggestions, or open a specific photo from some other folder, or go capturing a photo with the device's camera. User can also open another folder to the randomly filtered grid view, and it is also possible to refresh/re-randomize the filters by tapping on Refresh.

After selecting a photo, the application navigates to an editing view in which the selected photo is displayed fullscreen, and the application buttons/menu items provide funtionality to add and remove filters, and also to save and share the photo. Clicking on the "Add filter" button takes the user to a filter selection view, in which a quick preview of all the filters are displayed. The idea of Filter Explorer is that you can add many filters on top of each other, creating a custom combo filter stack!

Windows 8.1

Windows Phone 8.1

Architecture overview

Here's a lightweight class diagram showing the overall structure of the application implementation.

Filter Explorer for Windows has been implemented in a Model-View-ViewModel fashion, and briefly it means that the data classes and platform data source abstractions are packaged in the Models layer, the main application business logic is in the ViewModels layer, and the UI is in the Views layer. These layers have only soft dependencies on each other in pull-only fashion, meaning only in the Views -> ViewModels -> Models direction. Views are connected to ViewModels mostly with XAML bindings, and they interact with the application business logic via Commands exposed by the ViewModels. This kind of architecture makes the layers separate enough to be replaceable with quite little work, and therefore for example "porting" the app from the initially written Windows 8.1 tablet version to the Windows Phone 8.1 version was quite easy.

Application works so that photos are loaded in StreamPageViewModel and wrapped into PhotoModels (access to the data), that are again wrapped into FilteredPhotoModels (uses the PhotoModel to get the image data, and applies Filters on the images). Imaging SDK is used in the PhotoModel to resize unfiltered images from the platform, and in FilteredPhotoModel to render the filtered images.

Reading and filtering a photo

Filter Explorer for Windows wraps Nokia Imaging SDK IFilters to an abstract custom Filter base class in order to easily add them more properties like translatable names for the UI.

namespace FilterExplorer.Filters
{
    public abstract class Filter
    {
        public string Id
        {
            get
            {
                return GetType().ToString();
            }
        }

        public string Name
        {
            get
            {
                // In Filter Explorer for Windows each filter has a localizable name in resources,
                // and the key for the name is for example AntiqueFilterName
                var resourceLoader = new Windows.ApplicationModel.Resources.ResourceLoader();

                return resourceLoader.GetString(Id.Split('.').Last() + "Name");
            }
        }
    
        public abstract Nokia.Graphics.Imaging.IFilter GetFilter();
    }

    public class AntiqueFilter : Filter
    {
        public override Nokia.Graphics.Imaging.IFilter GetFilter()
        {
            return new Nokia.Graphics.Imaging.AntiqueFilter();
        }
    }

    ...
}

Each FilteredPhotoModel contains a PhotoModel, and in this partnership the PhotoModel is responsible for reading the image data from the platform, and the FilteredPhotoModel is rensponsible for applying filters on the data.

namespace FilterExplorer.Models
{
    public class PhotoModel
    {
        private Windows.Storage.StorageFile _file = null;

        ...

        public PhotoModel(Windows.Storage.StorageFile file)
        {
            _file = file;
        }

        public async Task<IRandomAccessStream> GetPhotoAsync()
        {
            ... // omitted, calls GetPhotoStreamAsync() and caches the result for sequential calls
        }

        private async Task<IRandomAccessStream> GetPhotoStreamAsync()
        {
            return await _file.OpenReadAsync();
        }

        ...
    }
}

When FilteredPhotoModel.GetFilteredPhotoAsync() is called, it causes the PhotoModel's GetPhotoAsync() to be called for getting the image data as stream from the platform, and this data is used as input for rendering the filtered photo.


namespace FilterExplorer.Models
{
    public class FilteredPhotoModel
    {
        private PhotoModel _photo = null;

        ...

        public ObservableList<Filter> Filters { get; private set; }

        public FilteredPhotoModel(Windows.Storage.StorageFile file)
        {
            _photo = new PhotoModel(file);

            Filters = new ObservableList<Filter>();

            ...
        }

        public async Task<IRandomAccessStream> GetFilteredPhotoAsync()
        {
            ... // omitted, calls GetFilteredPhotoStreamAsync() and caches the result for sequential calls
        }

        private async Task<IRandomAccessStream> GetFilteredPhotoStreamAsync()
        {
            IRandomAccessStream filteredStream = null;

            using (var stream = await _photo.GetPhotoAsync())
            {
                if (Filters.Count > 0)
                {
                    var list = new List<IFilter>();

                    foreach (var filter in Filters)
                    {
                        list.Add(filter.GetFilter());
                    }

                    filteredStream = new InMemoryRandomAccessStream();

                    using (var source = new RandomAccessStreamImageSource(stream))
                    using (var effect = new FilterEffect(source) { Filters = list })
                    using (var renderer = new JpegRenderer(effect))
                    {
                        var buffer = await renderer.RenderAsync();

                        await filteredStream.WriteAsync(buffer);
                    }
                }
                else
                {
                    filteredStream = stream.CloneStream();
                }
            }

            return filteredStream;
        }

        ...
    }
}

Downloads

Filter Explorer for Windows and Windows Phone 8.1 project v2.0 filter-explorer-2.0.zip

Get the app from Windows store › 

This example application is hosted in GitHub, where you can check the latest activities, report issues, browse source, ask questions, or even contribute to the project yourself.

Note: Due to the time required to pass the store certification process, the version in the store may not always be the latest version.

Last updated 15 April 2014

Back to top

Was this page helpful?

Your feedback about this content is important. Let us know what you think.

 

Thank you!

We appreciate your feedback.

×