×

Custom sources, filters and effects

The Nokia Imaging SDK can be extended with user defined image sources and effects. This page describes how to accomplish that.

Custom Image Sources

User-defined custom image sources can be created and used in the image processing graph.

In C++/CX, the DelegatingImageSource must be used, and the user provides an implementation of the ICustomImageSource interface. This is not further covered by this document.

In managed code such as C#, an easier and highly recommended option is to inherit CustomImageSourceBase. This base class handles most of the plumbing, so that the user class only has to supply the actual pixel data. The resulting class can be used directly.

class SimpleImageSource : CustomImageSourceBase 
{
     private uint[] m_colors;

     public SimpleImageSource(Windows.Foundation.Size size, Windows.UI.Color[] colors) :
         base(size)
     {
         // Convert colors to array of uint for faster processing inside OnProcess()
         m_colors = colors.Select( color => FromColor(color) ).ToArray();
     }
 
     protected override void OnProcess(PixelRegion pixelRegion)
     {
         pixelRegion.ForEachRow((index, width, pos) =>
         {
             for (int x = 0; x < width; ++x, ++index)
             {
                 // Pick one of the configured colors based on the x-coordinate.
                 var color = m_colors[x % m_colors.Length];

                 pixelRegion.ImagePixels[index] = color;
             }
         });
     }
 }  

This example custom image source shows the basic requirements of a custom image source:

  • It inherits CustomImageSourceBase.
  • It passes a Windows.Foundation.Size to the base class constructor. This is the “inherent” size of the image that is generated. In the example, it makes sense to let this be specified by the caller.
  • It overrides OnProcess and writes to the PixelRegion.ImagePixels array. This is required.

It also shows the principles of:

  • Using PixelRegion.ForEachRow to ease iteration over the pixels to write.
  • The FromColor method easily converts a Windows.UI.Color to the colour format expected in the PixelRegion.ImagePixels array. Note that this method should not be used in a tight pixel processing loop, as it can introduce an unnecessary overhead.

The resulting SimpleImageSource can now be used as any other IImageProvider.

(Please note that the example source code is written to be explanatory rather than optimized for performance.)

Custom Filters

Note: Available since version 1.2.

User-defined filters can be created and used in the FilterEffect. A filter processes an image in blocks, which makes it very memory efficient. It also means that the implementation only has access to a small part of the image at any given time. If you want to implement a filter that can access all the source image pixels at once, see Custom Effects.

In C++/CX, a DelegatingFilter must be used, and the user provides an implementation of the ICustomFilter interface.

In managed code such as C#, an easier and highly recommended option is to inherit from CustomFilterBase. This handles most of the plumbing, so that the user class only has to read and write the actual pixel data. The resulting class can be used directly.

    class GrayscaleCustomFilter : CustomFilterBase
    { 
        public GrayscaleCustomFilter() 
            : base(new Margins(), false, new[] { ColorMode.Ayuv4444 }) 
        { 
        } 
 
        protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion) 
        { 
            targetPixelRegion.ForEachRow((index, width, position) => 
            { 
                for (int i = 0; i < width; ++i) 
                { 
                    var c = sourcePixelRegion.ImagePixels[index + i]; 
                    
                    c &= 0x0000FFFF; 
                    c |= 0x80800000; 
 
                    targetPixelRegion.ImagePixels[index + i] = c; 
                } 
             }); 
        } 
    } 

This example shows the basic requirements of a custom effect:

  • It inherits CustomFilterBase.
  • It passes a Margins object, a wrapBorders setting, and a list of supported color modes to the base class constructor. In this case, margins are not used, and the supported colormode is Ayuv4444.
  • It overrides OnProcess, reads pixels from the sourcePixelRegion.ImagePixels array and writes pixels to the targetPixelRegion array.

Custom Effects

User-defined effects can be created and used in the image processing graph. An effect process the entire image at once, which makes it memory inefficient, but lets you access all pixels at once which can be useful for some effects. For a more memory efficient way of implementing custom effects, see Custom Filters above.

In C++/CX, DelegatingEffect must be used, and the user provides an implementation of the ICustomEffect interface. This is not further covered by this document.

In managed code such as C#, an easier and highly recommended option is to inherit from CustomEffectBase. This handles most of the plumbing, so that the user class only has to read and write the actual pixel data. The resulting class can be used directly.

public class DoubleEffect : CustomEffectBase 
{ 
    public DoubleEffect(IImageProvider source) : base(source) 
    { 
    } 
 
    protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion) 
    { 
        sourcePixelRegion.ForEachRow((index, width, pos) => 
        { 
            for (int x = 0; x < width; ++x, ++index) 
            { 
                uint color = sourcePixelRegion.ImagePixels[index];
 
                // Extract color channel values 
                var a = (byte)((color >> 24) & 255); 
                var r = (byte)((color >> 16) & 255);  
                var g = (byte)((color >> 8) & 255);  
                var b = (byte)((color) & 255); 
  
                r = (byte)Math.Min(255, r * 2); 
                g = (byte)Math.Min(255, g * 2); 
                b = (byte)Math.Min(255, b * 2); 
 
                // Combine modified color channels 
                var newColor = (uint)(b | (g << 8) | (r << 16) | (a << 24)); 
 
                targetPixelRegion.ImagePixels[index] = newColor; 
            } 
        }); 
    } 
}

This example shows the basic requirements of a custom effect:

  • It inherits CustomEffectBase.
  • It passes an IImageProvider to the base class constructor. Most often the correct thing to do is to declare and pass through a constructor parameter, as shown.
  • It overrides OnProcess, reads pixels from the sourcePixelRegion.ImagePixels array, and writes pixels to the targetPixelRegion array.

It also shows the principles of:

  • Using PixelRegion.ForEachRow to ease iteration over the pixels to write.
  • Using bit shifting rather than the ToColor and FromColor methods in a tight loop, since calling these methods can introduce an unnecessary overhead.

(Please note that the example source code is written to be explanatory rather than optimized for performance.)


Last updated 9 June 2014

Back to top

×