How to upgrade from Lumia Imaging SDK 2.0 to 3.0

Conceptual changes

Image Providers

In version 3.0 of the Lumia Imaging SDK, the image provider model has been extended and improved.

A new IImageProvider2 interface has been added, extending IImageProvider.

Note that only image providers that implement IImageProvider2 can be used with this version of the SDK.


Under the previous model, image providers were locked during the entire rendering operation. This required the application to track which objects were being used at any given time. Accessing an image provider that was locked for rendering caused an exception to be thrown.

This is no longer the case.

When rendering begins, the entire graph of image providers is now cloned. Each image provider is asked to clone itself and its sources, recursively. This operation produces a snapshot copy of the graph topology and the settings of each image provider. While the cloning operation itself needs to be thread safe, it is very quick.

After cloning completes, the original image providers are decoupled from rendering and the application can freely modify them, rearrange the graph, or even start a new rendering operation.

Concurrently, as the render operation continues, it only deals with the clone of the graph as it was when rendering started.

Image Workers

Because the SDK in this version now supports Direct2D GPU accelerated rendering, an image provider needs a way to support one or more types of rendering - CPU based, GPU based, or both.

Thus, in the next step of rendering, each image provider (in the cloned graph) is asked about SupportedRenderOptions. This allows the SDK to schedule the work to be performed in the graph on the appropriate hardware.

CreateImageWorker is then called, which returns the selected implementation. (implementing the base interface IImageWorker), suiting the type of backend that's needed, which is a separate object that performs the actual image processing. The worker uses the cloned image provider, which holds the configuration it needs.

Less fine grained async

The previous model forced the notion of an asynchronous load phase on to every image provider in the graph.
But in practice, only certain image sources were truly asynchronous (due to file or network I/O).

To reduce complexity and improve performance, the method IImageProvider::PreloadAsync has been deprecated.

As a replacement concept, certain image sources now implement IAsyncImageResource if they represent asynchronous backing resources. A "preload" can be started prior to rendering using the method IAsyncImageResource::LoadAsync.

Image Consumers

In version 3.0 of the Lumia Imaging SDK, the image consumer model is extended.

A new interface IImageConsumer2 has been added.
This interface allows an object to keep multiple source references. The source with index 0 corresponds to IImageConsumer::Source.

Note that only image consumers that implement IImageConsumer2 can be used with this version of the SDK.

How to migrate

Image Providers

All image providers must implement the new interface IImageProvider2 in addition to IImageProvider; otherwise, an InvalidCastException may be thrown.

Any version of the interface can be used for parameter, local, and member variables, but new code should use IImageProvider2.

Also note that the methods of IImageProvider are deprecated, and allowed to throw NotImplementedException when called.

Therefore, DO replace the following calls in existing app code.

Instead of calling GetInfoAsync:

  • If the object implements IImageResource, use the properties directly (ImageSize).
  • If the object implements IAsyncImageResource, first call LoadAsync to get the IImageResource.
  • Otherwise, it's probably an effect which does not report a size. Pass the image size of the original source along in the app code.

Instead of calling PreloadAsync:

  • If the object implements IAsyncImageResource, call LoadAsync to do I/O early.
  • Otherwise, the concrete class of the object may have a method that does the equivalent of preloading.

Instead of calling GetBitmapAsync:

  • Create a temporary BitmapRenderer, pass the parameters to set it up and call RenderAsync.

Image Consumers

All image consumers must implement the new interface IImageConsumer2 in addition to IImageConsumer; otherwise, an InvalidCastException may be thrown.

Any version of the interface can be used for parameter, local, and member variables, but new code should use IImageConsumer2.

Changing filters to effects

Lumia Imaging SDK 3.0 contains an architectural breaking change: Filters and the FilterEffect class have been removed. Instead, every filter has been converted to an Effect. This is a major simplification, but being a breaking change, it will impact application code. The necessary changes should be trivial or straight-forward in most cases.

The classes have similar names. In most cases, just the postfix has changed from "Filter" to "Effect".

Table 1. Effects in the Lumia Imaging SDK
Class name in 2.0Class name in 3.0

The classes are contained within the same namespaces as before, so finding them should be easy.

A bigger change is that there is no longer a FilterEffect object and this will affect how you set up your rendering chain. The Source property is now the main chaining mechanism for all classes. It means that if you had a FilterEffect object with three filters in its Filters array, you will need to chain them manually now. See the following example.

SDK 2.0 code

using (var filterEffect = new FilterEffect(source))
   var scale = new ScaleFilter(2);
   var rotation = new RotationFilter(45);
   var blur = new BlurFilter(20);

   filterEffect.Filters = new IFilter[] { scale, rotation, blur };

   var renderer = new JpegRenderer(filterEffect);

SDK 3.0 code with EffectList

using (var scale = new ScaleEffect(2))
using (var rotation = new RotationEffect(45))
using (var blur = new BlurEffect(20))               
using (var renderer = new JpegRenderer())
    renderer.Source = new EffectList() { source, scale, rotation, blur };                     

SDK 3.0 code

using (var scale = new ScaleEffect(source, 2))
using (var rotation = new RotationEffect(scale, 45))
using (var blur = new BlurEffect(rotation, 20))
using (var renderer = new JpegRenderer(blur))

Replacing ImageFusionFilter

The ImageFusionFilter has been removed. The users are required to use BlendEffect instead. All the functionality of the ImageFusionFilter can still be achieved, and for most cases the change is trivial. The only functionality that existed in ImageFusionFilter that isn't part of the BlendEffect is the invert mask option.

If the invert mask functionality is required, the user needs to use one of the existing building blocks to achieve the desired effect. The most obvious choice is to use CurvesEffect and invert the mask that way.


var invertedCurve = new Curve(CurveInterpolation.Linear, new[] {
    new Point(0, 255),
    new Point(255, 0)
var invertingEffect = new CurvesEffect(invertedCurve);

Implementing a custom image source

Custom image sources are no longer a separate concept. ICustomImageSource and CustomImageSourceAdapter have been removed.

Implementing a custom filter

Custom filters are no longer a separate concept. ICustomFilter and CustomFilterAdapter have been removed.
Furthermore, "filters" have been replaced with "effects".

Implementing a custom effect

Custom effects are no longer a separate concept. ICustomEffect and CustomEffectAdapter have been removed.

Implementing an effect group

Effect groups are no longer a separate concept. IEffectGroup and EffectGroupAdapter have been removed.
The group pattern can be implemented as an effect with specific behavior.

For information about how to create an image source, an effect, or effect group, see Custom image sources, effects and effect groups.