How to upgrade from 1.2 to 2.0

Major differences

The Nokia Imaging SDK has changed its name to the Lumia Imaging SDK. The name of the NuGet package has also changed, and with it the names of the DLLs and the namespaces. The changed namespaces are a breaking change.

In addition to the namespace changes, we have also introduced sub-namespaces to provide better structure to the code. Additional using statements may be needed in your source files.

The Lumia Imaging SDK types have now been split into the following namespaces:

  • Lumia.Imaging
  • Lumia.Imaging.Adjustments
  • Lumia.Imaging.Artistic
  • Lumia.Imaging.Custom
  • Lumia.Imaging.Compositing
  • Lumia.Imaging.Transforms

After installing the new version of the SDK, replace all references to the Nokia.Graphics.Imaging with Lumia.Imaging. You'll also have to add some more namespaces because of the new sub-namespaces added to version 2.0 A simple way to this is just to right-click the missing type and select Resolve (or press Alt + Shift + F10) to resolve the namespace.

There are two ways to update to the new package. The simplest way is just to right-click References in your project, select Manage NuGet Packages, and update the package in the Updates area of the left panel. This removes the old package and installs the new Lumia.Imaging package, but a reference to the Nokia.Graphics.Imaging package will still be there. To get a clean start with no references to the old package, try the second approach: just uninstall the old package (instead of updating it) and then install the new Lumia.Imaging package.

How to upgrade from Beta to 1.0

Major differences

Conceptually, all functionality is the same as before, but names of classes and their members have changed. Static factory methods have been changed in favor of objects to make changes easier - for example, from an MVVM perspective - but also to make it easier to test apps that depend on the Imaging SDK.

Session creation used to be asynchronous and resulted in the session reserving memory. Now only the rendering is asynchronous, and no memory is allocated on creation of the image source or effect.

The filters could not be modified after creation in the beta version, and the filter stack had to be redefined for any changes. Now the list of applied effects, including the properties of each effect, can be changed at any time as long as we're not rendering.

Pipeline

The overall conceptual pipeline is now ImageSource -> Effect -> ... -> Effect -> Renderer. Both ImageSources and Effects implement IImageProvider. Effects and Renderers implement IImageConsumer. IImageProviders can plug into IImageConsumers, forming an effect chain. In addition, some effects can use other inputs - perhaps secondary IImageProviders or, as with FilterEffect, lightweight IFilters.

Example

This code presents a basic scenario where a single cartoon filter is added as the only filter for the effect.

Beta code

var session = await EditingSessionFactory.CreateEditingSessionAsync(e.ChosenPhoto);

// Define the effects to apply
session.AddFilter(FilterFactory.CreateCartoonFilter(true));

// Render the image
await session. RenderToWriteableBitmapAsync(cartoonImageBitmap,
    OutputOption.PreserveAspectRatio);

Final code

var imageSource = new StreamImageSource(e.ChosenPhoto);

// Define the effects to apply
var filterEffect = new FilterEffect(imageSource);
filterEffect.Filters = new [] { new CartoonFilter() };

// Render the image using WriteableBitmapRenderer
WriteableBitmapRenderer renderer = new WriteableBitmapRenderer(
    filterEffect, cartoonImageBitmap, OutputOption.PreserveAspectRatio);
await renderer.RenderAsync();

Specifics

This section brings up some of the more specific changes related to filters, image providers, effects, and renderers.

Filters

Filters are now mutable and have properties that can be modified after instantiation. When a render operation is ongoing, properties cannot be changed; if you try to do so, an exception will be thrown.

The FreeRotationFilter and StepRotationFilter have been combined into a single RotationFilter.

ReframingFilter has been added; it combines the crop and rotate operations.

CropFilter can now crop only within the image area. Use the new ReframingFilter to compose a rectangle of any size inside or outside the current image.

FrameFilter has been removed, because it was only a specialization of the existing BlendFilter.

BlurFilter now comes in only one version, with a fine-grained level of control by way of a kernel size property. Old BlurLevel values map to the new KernelSize property as shown here.

BlurLevel KernelSize
Blur0 3
Blur1 9
Blur2 15
Blur3 23
Blur4 40
Blur5 60
Blur6 80
Blur7 100

ChromaKeyFilter is a new "green screen" filter that will make one color transparent. A new background can then be provided for rendering.

Image providers

There are now several new image providers shipped with the SDK, to provide an image source for the most common scenarios: BitmapImageSource, BufferImageSource, CameraPreviewImageSource, ColorImageSource, GradientImageSource, RandomAccessStreamImageSource, StorageFileImageSource.

It is also possible to create custom image providers using the DelegatingImageSource in C++/CX or the CustomImageSourceBase in managed code. This is called the "custom image source pattern." In the current release, the results are similar to just using a BitmapImageSource and passing in app-generated data.

By following the custom image source pattern, the user class looks and feels like any other image source, including those in the SDK. The most important benefit, looking forward, is that further improvements to the SDK (one of which is lower memory consumption) can be easily exploited by classes that follow the pattern. This is the main intent behind DelegatingImageSource/CustomImageSourceBase.

Effects

FilterEffect is one of the two currently provided effects in the SDK. It is also possible to hook into the rendering pipeline, and thus implement a custom effect, by using DelegatingEffect in C++/CX or the CustomEffectBase in managed code. This "custom effect pattern" is similar to the one used for custom image sources, described previously.

Renderers

To support different render targets, some renderers are provided out-of-the-box in the SDK, namely BitmapRenderer, JpegRenderer and WriteableBitmapRenderer.

There is no "ImageRenderer" in the new API that would have corresponded to the EditingSessionExtensions.RenderToImageAsync method in the previous version. This is because rendering to an image control has to be done on the UI thread. This is easily handled by the app, which is in control of which thread things are done on, whereas letting the Imaging SDK handle it could lead to subtle bugs. Rendering to an Image is quite straightforward. as shown here.

// MyImage is the XAML Image control where we render.

// First create a WriteableBitmap, matching the size of MyImage XAML Image control.
var writeableBitmap = new WriteableBitmap(MyImage, null);

// Render, and update the Image control.
var renderer = new WriteableBitmapRenderer(source, writeableBitmap);
MyImage.Source = await renderer.RenderAsync();

Asynchronous results

While not technically a new issue for this version, it's important to mention that we don't recommend calling Task.Wait on any IAsyncOperation or IAsyncAction returned by the SDK. The practice can lead to deadlock - a hang of the calling thread. This risk is not specific to the Imaging SDK; it exists for any asynchronous API that happens to have a dependency on the calling context (especially if this is the application UI thread).

We strongly recommend that apps use the await keyword (or ContinueWith) instead. If this seems too fine-grained, and the app has many asynchronous tasks to perform, task composition (for instance, via Task.WhenAll) is very useful to let the app await many tasks at once.

See https://msdn.microsoft.com/en-us/magazine/jj991977.aspx for more info about pitfalls in mixing synchronous and asynchronous models.