×
Namespaces

Variants
Actions

Filter Parameter Harmonization: Dynamic UI for Nokia Imaging SDK 1.0 Filters

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to harmonize the Nokia Imaging SDK 1.0 filter parameters and provide a single control which would allow the user to change the filter parameters.

Note.pngNote: This is an entry in the Nokia Imaging and Big UI Wiki Competition 2013Q4.

SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 8.0
Compatibility
Platform(s):
Windows Phone 8
Article
Created: RatishPhilip (14 Dec 2013)
Last edited: chintandave_er (16 Dec 2013)

Contents

Prerequisites

This article contains the update to my previous article which was based on the beta version of Nokia Imaging SDK. There are some important changes in the latest version when compared to the beta version. I would recommend going through the following links first to get a good grasp of the changes incorporated in the latest version:

Introduction

In the FilterEffects sample, there is a FilterPropertiesControl class which acts as a place holder for custom controls used for manipulating the Filter parameters. This control made me wonder if it was possible to generate the UI for each Filter's parameters dynamically. Since each filter has a different set of parameters, this task seemed a bit difficult at first. However, I went through each of the filters available in the SDK and found out that out of the 53 filters:

  • 10 Filters do not require any parameters during creation
  • 29 Filters require either a numeric range, bool, Enum or a combination of these to create the filter. These values can be represented by a Slider control or a ToggleSwitch control.
  • The remaining 14 filters required more complex parameters such as Point, EditingSession, Color to name a few.

As the first step, I decided to harmonize the 29 filters that required either a numeric range, bool, Enum or a combination of these during instantiation. The following is the architecture of the FilterHarmonization sample app which I created for this purpose:

Architecture

The main libraries required for this application are:

  • Nokia Image SDK: For Imaging related features.
  • Reactive Extensions: For efficient subscription to UI events. (Already included in the Windows Phone SDK)
  • Windows Phone Toolkit: For the ToggleSwitch control to represent the bool parameter of the Filter.

All these libraries are available through NuGet.

The classes which mainly cater to the purpose of Filter Harmonization are depicted below

Class Diagram


IFiterParam


IFilterParam is the interface which is implemented by all the classes representing the Filter parameters. It defines three read-only properties:

  • Name : Represents the name of the property in the Filter which represents the Filter parameter.
  • DisplayName : Represents the name to be displayed along with the control describing the Filter parameter.
  • ParamType: The type of the Filter parameter that it represents. This is used to find the appropriate method in FilterFactory via Reflection.


public interface IFilterParam
{
string Name { get; }
string DisplayName { get; }
Type ParamType { get; }
}

FilterParam<T>

FilterParam<T> is a generic and abstract class which implements the IFilterParam interface. It usually represents those Filter parameters which are a numeric range or an Enum type. The control used to represent this class is the Slider. FilterParam<T> defines the following additional read-only properties:

  • Min: the minimum value for the slider.
  • Max: the maximum value for the slider.
  • Step: the small change value for the slider.
  • Default: the default value for the slider.
public abstract class FilterParam<T> : IFilterParam where T : struct, IComparable
{
public string Name
{
get;
protected set;
}
 
public string DisplayName
{
get;
protected set;
}
 
public Type ParamType
{
get;
protected set;
}
 
public T Min
{
get;
protected set;
}
 
public T Max
{
get;
protected set;
}
 
public T Step
{
get;
protected set;
}
 
public T Default
{
get;
protected set;
}
}

BoolParam

This class represents Filter parameters of type bool. The ToggleSwitch control is used to represent this class in the UI. It defines the following additional read-only properties:

  • OffText: The content of the ToggleSwitch when it is in Unchecked state.
  • OnText: The content of the ToggleSwitch when it is in Checked state.
public class BoolParam : IFilterParam
{
public string Name
{
get;
private set;
}
 
public string DisplayName
{
get;
protected set;
}
 
public Type ParamType
{
get;
private set;
}
 
public string OffText
{
get;
private set;
}
 
public string OnText
{
get;
private set;
}
 
public BoolParam(string name, string displayName, string offText, string onText)
{
ParamType = typeof(bool);
DisplayName = displayName;
Name = name;
OffText = offText;
OnText = onText;
}
}

EnumParam

This class derives from FilterParam<int> and it represents the Filter parameters which are of type enum. One constraint is that it expects the enum to be of type int. The control used to represent this class is the Slider with each value representing one of the enum values.

public class EnumParam : FilterParam<int>
{
public EnumParam(string name, string displayName, Type enumType, int defaultValue)
{
if ((enumType != null) && (enumType.IsEnum))
{
Name = name;
DisplayName = displayName;
ParamType = enumType;
var enumValues = Enum.GetValues(enumType).Cast<int>();
Min = enumValues.First();
Max = enumValues.Last();
Step = 1;
Default = defaultValue;
}
else
{
throw new ArgumentException("Argument must be of type Enum");
}
}
}

RangeParam<T>

This is a generic class which implements FilterParam<T> and represents the Filter parameters whose values should fall within a numeric range. The Slider control represents this class and provides values in the specified numeric range.

public class RangeParam<T> : FilterParam<T> where T : struct, IComparable
{
public RangeParam(string name, string displayName, T min, T max, T step, T defaultValue)
{
ParamType = typeof(T);
Name = name;
DisplayName = displayName;
Min = min;
Max = max;
Step = step;
Default = defaultValue;
}
}

ParamEntry

This class encapsulates the name of the property of the filter whose value has been changed by the user and the new value for this property.

public class ParamEntry
{
public string Name { get; set; }
public object Value { get; set; }
}

FilterEngine

FilterEngine is a static class which is responsible for providing a list of IFilterParam for a particular filter. This list is used by the FilterSettingsControl to generate the UI for the Filter settings.

public static class FilterEngine
{
public static List<IFilterParam> GetFilterParams(string filterName)
{
List<IFilterParam> result = null;
 
switch (filterName)
{
case "Blur":
result = CreateBlurFilterParams();
break;
 
case "Brightness":
result = CreateBrightnessFilterParams();
break;
 
case "Cartoon":
result = CreateCartoonFilterParams();
break;
 
case "ColorAdjust":
result = CreatColorAdjustFilterParams();
break;
 
...
 
default:
break;
}
 
return result;
}
 
/// <summary>
/// Blur Filter
/// </summary>
/// <returns>List of IFilterParam</returns>
private static List<IFilterParam> CreateBlurFilterParams()
{
List<IFilterParam> filterParams = new List<IFilterParam>();
 
filterParams.Add(new EnumParam("Blur", typeof(BlurLevel), 0));
 
return filterParams;
}
 
/// <summary>
/// Brightness Filter
/// </summary>
/// <returns>List of IFilterParam</returns>
private static List<IFilterParam> CreateBrightnessFilterParams()
{
List<IFilterParam> filterParams = new List<IFilterParam>();
 
filterParams.Add(new RangeParam<double>("Brightness", -1.0, 1.0, 0.05, 0.0));
 
return filterParams;
}
 
/// <summary>
/// Cartoon Filter
/// </summary>
/// <returns>List of IFilterParam</returns>
private static List<IFilterParam> CreateCartoonFilterParams()
{
List<IFilterParam> filterParams = new List<IFilterParam>();
 
filterParams.Add(new BoolParam("Distinct Edges", "No", "Yes"));
 
return filterParams;
}
 
/// <summary>
/// ColorAdjust Filter
/// </summary>
/// <returns>List of IFilterParam</returns>
private static List<IFilterParam> CreatColorAdjustFilterParams()
{
List<IFilterParam> filterParams = new List<IFilterParam>();
 
filterParams.Add(new RangeParam<double>("Red", -1.0, 1.0, 0.05, 0.0));
filterParams.Add(new RangeParam<double>("Green", -1.0, 1.0, 0.05, 0.0));
filterParams.Add(new RangeParam<double>("Blue", -1.0, 1.0, 0.05, 0.0));
 
return filterParams;
}
 
...
}


FilterSettingsControl

FilterSettingsControl is a UserControl which is responsible for two features:

  1. Creating the initial IFilter for applying the user selected filter to the displayed image. The newly created filter is provided to the parent page by the FilterChanged event.
  2. Dynamically generating the UI encapsulating the parameters for a particular filter and is displayed to the user. By using Reactive Extension library, any changes made to the parameters by the user is encapsulated in a ParamEntry object and is notified to the parent control or page via the FilterParamChanged event. In the beta version of the SDK, the EditingSession did not allow the filter properties to be modified once added. However, the current release of the SDK, the filter properties can be updated as long as the rendering of the image is not in progress. The parent page upon receiving the new ParamEntry updates the values of the filter by using the Interactive State machine. This Interactive State machine which was initially defined by yan_ and is now included in the FilterEffects sample. More detail on this in the later section.

This control also employs the use of the Reactive Extensions Library. Reactive Extensions (Rx) is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators. It provides an easy way of subscribing to UI events and also perform LINQ operations on them. It provides disposable handles to the event subscription which are easy to dispose when you are cleaning up resources.

The RX libraries required for this project are already included in the Windows Phone SDK under the namespace {{Icode}Microsoft.Phone.Reactive}} therefore it need not be installed separately via NuGet.

public partial class FilterSettingsControl : UserControl
{
#region Delegates and Events
 
public delegate void FilterUpdatedHandler(IFilter filter);
public event FilterUpdatedHandler FilterChanged = delegate { };
 
public delegate void FilterParamUpdatedHandler(ParamEntry entry);
public event FilterParamUpdatedHandler FilterParamChanged = delegate { };
 
#endregion
 
#region Fields
 
Dictionary<FrameworkElement, IFilterParam> _filterControls = null;
List<IDisposable> _subscribers = null;
List<Type> _types = null;
 
string _filterName;
List<IFilterParam> _filterParams;
 
#endregion
 
#region Construction / Initialization
 
public FilterSettingsControl()
{
InitializeComponent();
}
 
#endregion
 
#region APIs
 
public void Create(string name, List<IFilterParam> filterParams)
{
_filterName = name;
_filterParams = filterParams;
 
CreateUI();
}
 
#endregion
 
#region Helpers
 
private void CreateUI()
{
// Clear all previous content
CleanUp();
 
// The container for all settings controls
StackPanel panel = new StackPanel()
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
 
LayoutRoot.Children.Add(panel);
 
_filterControls = new Dictionary<FrameworkElement, IFilterParam>();
_subscribers = new List<IDisposable>();
_types = new List<Type>();
 
foreach (IFilterParam param in _filterParams)
{
if (param.ParamType == typeof(bool))
{
// Add a ToggleSwitch for boolean parameters
CreateControlsForBoolParam(panel, param);
}
else
{
// Add a slider for the rest of the parameter types
CreateControls(panel, param);
}
 
// Add the param Type to the types list so that it can be used
// to obtain the correct method in the CreateFilter method
_types.Add(param.ParamType);
}
 
// Apply the filter with current values
UpdateFilterChange();
}
 
/// <summary>
/// Creates controls for the BoolParam.
/// </summary>
/// <param name="panel">Container</param>
/// <param name="param">IFilterParam</param>
private void CreateControlsForBoolParam(StackPanel panel, IFilterParam param)
{
BoolParam bParam = param as BoolParam;
ToggleSwitch togSwitch = new ToggleSwitch()
{
Header = param.DisplayName
};
togSwitch.Content = bParam.OffText;
togSwitch.IsChecked = false;
 
// Subscription for the Checked event
var checkedSubscriber = Observable.FromEvent<RoutedEventArgs>(togSwitch, "Checked")
.Subscribe(x =>
{
Dispatcher.BeginInvoke(new Action(() =>
{
togSwitch.Content = bParam.OnText;
OnValueChanged(togSwitch);
}));
});
 
// Subscription for the Unchecked event
var uncheckedSubscriber = Observable.FromEvent<RoutedEventArgs>(togSwitch, "Unchecked")
.Subscribe(x =>
{
Dispatcher.BeginInvoke(new Action(() =>
{
togSwitch.Content = bParam.OffText;
OnValueChanged(togSwitch);
}));
});
 
panel.Children.Add(togSwitch);
_subscribers.Add(checkedSubscriber);
_subscribers.Add(uncheckedSubscriber);
_filterControls[togSwitch] = param;
}
 
/// <summary>
/// Creates controls for all IFilterParams except BoolParam.
/// </summary>
/// <param name="panel">Container</param>
/// <param name="param">IFilterParam</param>
private void CreateControls(StackPanel panel, IFilterParam param)
{
Grid grid = new Grid()
{
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
 
// Shows the name of the parameter
TextBlock tb = new TextBlock()
{
Text = param.DisplayName,
Margin = new Thickness(15, 2, 15, 0),
HorizontalAlignment = HorizontalAlignment.Left
};
 
// Displays the current value of the parameter in case of Enum parameter
TextBlock valueTB = new TextBlock
{
Margin = new Thickness(15, 2, 15, 0),
HorizontalAlignment = HorizontalAlignment.Right
};
grid.Children.Add(tb);
grid.Children.Add(valueTB);
 
panel.Children.Add(grid);
 
Type paramType = param.GetType();
double min = (double)Convert.ChangeType(paramType.GetProperty("Min").GetValue(param), typeof(double));
double max = (double)Convert.ChangeType(paramType.GetProperty("Max").GetValue(param), typeof(double));
double step = (double)Convert.ChangeType(paramType.GetProperty("Step").GetValue(param), typeof(double));
double defaultValue = (double)Convert.ChangeType(paramType.GetProperty("Default").GetValue(param), typeof(double));
 
Slider slider = new Slider
{
Margin = new Thickness(10, 2, 10, 0),
Minimum = min,
Maximum = max,
SmallChange = step,
Value = defaultValue,
};
 
// Update the current value of the enum (in case of Enum Param) in the textblock
if (param.ParamType.IsEnum)
{
Dispatcher.BeginInvoke(new Action(() =>
{
valueTB.Text = Enum.ToObject(param.ParamType, (int)(slider.Value)).ToString();
}));
}
 
// Subscribe to the Value Changed event using RX
var subscriber = Observable.FromEvent<RoutedPropertyChangedEventArgs<double>>(slider, "ValueChanged")
.Subscribe(x =>
{
Dispatcher.BeginInvoke(new Action(() =>
{
// Update the enum value shown in the ValueTB textblock
if (param.ParamType.IsEnum)
{
valueTB.Text = Enum.ToObject(param.ParamType, (int)(slider.Value)).ToString();
}
 
// Update the filter
OnValueChanged(slider);
}));
});
 
// Add the slider to the panel
panel.Children.Add(slider);
_subscribers.Add(subscriber);
_filterControls[slider] = param;
}
 
/// <summary>
/// Cleans up the resources utilized
/// </summary>
private void CleanUp()
{
if (_filterControls != null)
{
_filterControls.Clear();
}
 
if (_subscribers != null)
{
foreach (var sub in _subscribers)
{
sub.Dispose();
}
}
 
if (_types != null)
{
_types.Clear();
}
 
LayoutRoot.Children.Clear();
}
 
/// <summary>
/// Handler for the value changed in any of the Filter
/// Settings controls.
/// </summary>
private void UpdateFilterChange()
{
List<object> filterParamList = new List<object>();
 
foreach (FrameworkElement ctrl in _filterControls.Keys)
{
if (ctrl is ToggleSwitch)
{
filterParamList.Add((ctrl as ToggleSwitch).IsChecked == true);
}
else if (ctrl is Slider)
{
if (_filterControls[ctrl].ParamType.IsEnum)
{
filterParamList.Add(Enum.ToObject(_filterControls[ctrl].ParamType, (int)((ctrl as Slider).Value)));
}
else
{
filterParamList.Add(Convert.ChangeType((ctrl as Slider).Value, _filterControls[ctrl].ParamType));
}
}
}
 
IFilter filter = CreateFilter(filterParamList);
 
// Raise the event
FilterChanged(filter);
}
 
private void OnValueChanged(FrameworkElement ctrl)
{
IFilterParam param = _filterControls[ctrl];
ParamEntry entry = new ParamEntry { Name = param.Name };
 
if (ctrl is ToggleSwitch)
{
entry.Value = ((ctrl as ToggleSwitch).IsChecked == true);
}
else if (ctrl is Slider)
{
if (_filterControls[ctrl].ParamType.IsEnum)
{
entry.Value = (Enum.ToObject(_filterControls[ctrl].ParamType, (int)((ctrl as Slider).Value)));
}
else
{
entry.Value = (Convert.ChangeType((ctrl as Slider).Value, _filterControls[ctrl].ParamType));
}
}
 
// Raise the event
FilterParamChanged(entry);
}
 
/// <summary>
/// User reflection to create an instance of the IFilter
/// </summary>
/// <param name="filterParamList"></param>
/// <returns></returns>
private IFilter CreateFilter(List<object> filterParamList)
{
var nokiAsm = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name == "Nokia.Graphics.Imaging").FirstOrDefault();
if (nokiAsm != null)
{
string filterQualifiedName = String.Format("Nokia.Graphics.Imaging.{0}Filter", _filterName);
Type filterType = nokiAsm.GetType(filterQualifiedName);
if (filterType != null)
{
return (IFilter)Activator.CreateInstance(filterType, filterParamList.ToArray());
}
}
 
return null;
}
 
#endregion
}

PhotoPage

The PhotoPage is a PhoneApplicationPage which includes the Interactive state machine described by yan_ here and used in the FilterEffects sample here.

I have used a Dictionary to keep track of the latest values of the changed filter parameters and when the state machine changes its state to WAIT, then this Dictionary is used by the Render method to apply the latest values to the filter parameters and render the latest image.

public partial class PhotoPage : PhoneApplicationPage
{
/// <summary>
/// The states of the state machine.
/// </summary>
protected enum States
{
Wait = 0,
Apply,
Schedule
};
 
#region Fields
 
protected BufferImageSource _source = null;
private IFilter _filter = null;
private FilterEffect _effect = null;
private WriteableBitmap _tmpBitmap = null;
Dictionary<string, object> _latestParams;
private States _state = States.Wait;
 
#endregion
 
#region Properties
 
protected States State
{
get
{
return _state;
}
set
{
if (_state != value)
{
_state = value;
}
}
}
 
#endregion
 
#region DisplayPhoto
 
/// <summary>
/// DisplayPhoto Dependency Property
/// </summary>
public static readonly DependencyProperty DisplayPhotoProperty =
DependencyProperty.Register("DisplayPhoto", typeof(WriteableBitmap), typeof(PhotoPage), new PropertyMetadata(null));
 
/// <summary>
/// Gets or sets the DisplayPhoto property. This dependency property
/// indicates the photo to be displayed.
/// </summary>
public WriteableBitmap DisplayPhoto
{
get { return (WriteableBitmap)GetValue(DisplayPhotoProperty); }
set { SetValue(DisplayPhotoProperty, value); }
}
 
#endregion
 
public IBuffer Buffer
{
set
{
if (value != null)
{
_source = new BufferImageSource(value);
 
if (_effect != null)
{
_effect.Dispose();
_effect = null;
}
 
// Construct the FilterEffect instance and set the
// filters.
_effect = new FilterEffect(_source);
// TODO SetFilters(_effect);
}
}
}
 
#region Construction / Initialization
 
public PhotoPage()
{
InitializeComponent();
 
_latestParams = new Dictionary<string, object>();
 
this.Loaded += PhotoPage_Loaded;
 
SettingsControl.FilterChanged += OnFilterChanged;
SettingsControl.FilterParamChanged += OnFilterParamChanged;
 
this.DataContext = this;
}
 
void PhotoPage_Loaded(object sender, RoutedEventArgs e)
{
PhotoChooserTask task = new PhotoChooserTask();
EventHandler<PhotoResult> handler = null;
handler = (s, ea) =>
{
task.Completed -= handler;
if (ea.TaskResult == TaskResult.OK)
{
BitmapImage imgBmp = new BitmapImage();
imgBmp.SetSource(ea.ChosenPhoto);
DisplayPhoto = new WriteableBitmap(imgBmp.PixelWidth, imgBmp.PixelHeight);
_tmpBitmap = new WriteableBitmap(imgBmp.PixelWidth, imgBmp.PixelHeight);
 
DisplayPhoto.SetSource(ea.ChosenPhoto);
 
MemoryStream stream = new MemoryStream();
ea.ChosenPhoto.Position = 0;
ea.ChosenPhoto.CopyTo(stream);
 
this.Buffer = stream.GetWindowsRuntimeBuffer();
 
SettingsControl.Create(App.SelectedFilter, FilterEngine.GetFilterParams(App.SelectedFilter));
}
};
 
task.Completed += handler;
task.ShowCamera = false;
task.Show();
}
 
#endregion
 
#region Event Handlers
 
/// <summary>
/// Initializes the Filter for the photo
/// </summary>
/// <param name="filter"></param>
void OnFilterChanged(IFilter filter)
{
_filter = filter;
_effect.Filters = new List<IFilter> { filter };
 
Apply();
}
 
void OnFilterParamChanged(ParamEntry entry)
{
lock (_latestParams)
{
_latestParams[entry.Name] = entry.Value;
}
 
Apply();
}
 
/// <summary>
/// Creates a filtered preview image from the given buffer.
/// </summary>
public void Apply()
{
switch (State)
{
case States.Wait: // State machine transition: Wait -> Apply
State = States.Apply;
Render(); // Apply the filter
break;
case States.Apply: // State machine transition: Apply -> Schedule
State = States.Schedule;
break;
default:
// Do nothing
break;
}
}
 
/// <summary>
/// Applies the filter. If another processing request was scheduled
/// while processing the buffer, the method will recursively call
/// itself.
/// </summary>
protected async void Render()
{
try
{
if ((_source != null) && (_effect.Filters != null))
{
// Apply the new values to the filter properties
if (_filter != null)
{
lock (_latestParams)
{
 
foreach (string key in _latestParams.Keys)
{
// Get the property
PropertyInfo pInfo = _filter.GetType().GetProperty(key);
if (pInfo != null)
{
// Apply the new value
pInfo.SetValue(_filter, _latestParams[key]);
}
}
 
// Clear all values that have been applied
_latestParams.Clear();
}
}
 
// Render to a temporary WriteableBitmap to prevent concurrent access between Nokia Imaging SDK and GUI
WriteableBitmapRenderer renderer = new WriteableBitmapRenderer(_effect, _tmpBitmap);
await renderer.RenderAsync();
// copy the changes then to the preview bitmap
_tmpBitmap.Pixels.CopyTo(DisplayPhoto.Pixels, 0);
DisplayPhoto.Invalidate(); // Force a redraw
}
}
catch (Exception)
{
}
finally
{
switch (State)
{
case States.Apply: // State machine transition : Apply -> Wait
State = States.Wait;
break;
case States.Schedule: // State machine transition: Schedule -> Apply
State = States.Apply;
Render(); // Apply the filter
break;
default:
// Do nothing
break;
}
}
}
 
/// <summary>
/// Renders current image with applied filters to a buffer and returns it.
/// Meant to be used where the filtered image is for example going to be
/// saved to a file.
/// </summary>
/// <param name="buffer">The buffer containing the original image data.</param>
/// <returns>Buffer containing the filtered image data.</returns>
public async Task<IBuffer> RenderJpegAsync(IBuffer buffer)
{
using (BufferImageSource source = new BufferImageSource(buffer))
using (JpegRenderer renderer = new JpegRenderer(_effect))
{
return await renderer.RenderAsync();
}
}
 
private void OnShowSettings(object sender, RoutedEventArgs e)
{
SettingsGrid.Visibility = Visibility.Visible;
}
 
private void OnHideSettings(object sender, RoutedEventArgs e)
{
SettingsGrid.Visibility = Visibility.Collapsed;
 
}
 
#endregion
}

The FilterHarmonization sample app contains a list of the 29 filters whose settings control is generated dynamically. The user can select any filter and image and upon clicking on Show Settings, the parameters for the filter will be displayed. The user can modify the parameters and see the effect of the modified filter on the image simultaneously. Here are a few screenshots of the app.

Source Code

Download Source Code

Summary

With the release of the first version of the Nokia Imaging SDK, the Nokia team has done a great job in improving upon the feature made available in the beta version of the SDK. Here I have provided a simple technique for harmonizing the Filters provided by Nokia Imaging SDK. However, it cannot cover all the filters as some filters require more complex arguments. My next step would be to create custom controls which can represent the complex data types like Color or Rect and modify the filter params based on their values.

References

How to Upgrade to Nokia Imaging SDK 1.0
Quick Start
Core Concepts
Adding SDK Libraries to the project
Reactive Extensions (Rx)
Filter Effects sample
Optimizing Imaging SDK use for rapidly changing filter parameters

Version Hint

Windows Phone: [[Category:Windows Phone]]
[[Category:Windows Phone 7.5]]
[[Category:Windows Phone 8]]

Nokia Asha: [[Category:Nokia Asha]]
[[Category:Nokia Asha Platform 1.0]]

Series 40: [[Category:Series 40]]
[[Category:Series 40 1st Edition]] [[Category:Series 40 2nd Edition]]
[[Category:Series 40 3rd Edition (initial release)]] [[Category:Series 40 3rd Edition FP1]] [[Category:Series 40 3rd Edition FP2]]
[[Category:Series 40 5th Edition (initial release)]] [[Category:Series 40 5th Edition FP1]]
[[Category:Series 40 6th Edition (initial release)]] [[Category:Series 40 6th Edition FP1]] [[Category:Series 40 Developer Platform 1.0]] [[Category:Series 40 Developer Platform 1.1]] [[Category:Series 40 Developer Platform 2.0]]

Symbian: [[Category:Symbian]]
[[Category:S60 1st Edition]] [[Category:S60 2nd Edition (initial release)]] [[Category:S60 2nd Edition FP1]] [[Category:S60 2nd Edition FP2]] [[Category:S60 2nd Edition FP3]]
[[Category:S60 3rd Edition (initial release)]] [[Category:S60 3rd Edition FP1]] [[Category:S60 3rd Edition FP2]]
[[Category:S60 5th Edition]]
[[Category:Symbian^3]] [[Category:Symbian Anna]] [[Category:Nokia Belle]]

This page was last modified on 16 December 2013, at 13:40.
194 page views in the last 30 days.
×