×
Namespaces

Variants
Actions
Revision as of 08:56, 21 July 2014 by venu238 (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Clip Image Filter Effect

From Nokia Developer Wiki
Jump to: navigation, search
Featured Article
14 Jul
2014

Note.pngNote: This was a winning entry in the Nokia Original Imaging Effect Wiki Challenge 2014Q2

This article explains how to create ClipImage filter effect and also provides a sample which can be used as a template for applying filters.

WP Metro Icon WP8.png
Article Metadata
Code Example
Source file: Media:ClipImage.zip
Tested with
SDK: Windows Phone 8.0 SDK
Devices(s): Nokia Lumia 920
Compatibility
Platform(s):
Windows Phone 8
Article
Created: venu238 (28 Jun 2014)
Last edited: venu238 (21 Jul 2014)

Contents

Introduction

ClipImage Effect is a cool filter effect that clips an image into any clip-art shape. In easy words, you can use ClipImage effect like an image brush to produce visually stunning effects.

ClipImage Effect

Understanding ClipImage Effect is so simple, it has two core parts

  1. Clipping
  2. Cropping

Clipping

The basic concept here is to compare pixels of two equally sized images[Clip-Art Image(Apple) and Background Image(Leaves)] and then converting the pixels of background image to transparent where the same pixel is transparent in Clip-Art image.
It can be better explained with code,

  • To compare both background and clip-art image pixels, we need to pass both of them into the Custom Effect
public IImageProvider ClipArt { get; set; }
 
public ClipnCrop(IImageProvider source, IImageProvider clipArt) :
base(source, false)
{
ClipArt= clipArt;
}
  • Now the next part is Creating ClipArt Buffer which is done in Custom Effect OnProcess method
//create buffer
uint[] buffer = new uint[(int)(sourcePixelRegion.Bounds.Width * sourcePixelRegion.Bounds.Height)];
 
//interface buffer
var bitmap = new Bitmap(
new Windows.Foundation.Size(sourcePixelRegion.Bounds.Width, sourcePixelRegion.Bounds.Height),
ColorMode.Bgra8888,
4*(uint)sourcePixelRegion.Bounds.Width,
buffer.AsBuffer());
 
//load buffer
ClipArt.GetBitmapAsync(bitmap, OutputOption.Stretch).AsTask().Wait();
  • Finally converting the background image pixels to transparent where clip-art image pixel is transparent.
sourcePixelRegion.ForEachRow((index, width, pos) =>
{
for (int x = 0; x < width; ++x, ++index)
{
if (buffer[index] > 128)
{
targetPixelRegion.ImagePixels[index] = sourcePixelRegion.ImagePixels[index];
}
else
{
targetPixelRegion.ImagePixels[index] = 0;
}
}
});


Cropping

The main aim of doing this is removing the unnecessary transparent part from the final image. We can achieve this by detecting the maximum height and width of colored pixels as shown in the figure

Cropping Filter Explanation

  • We can obtain the Crop Size and Corner Point from the cropping Custom Effect by detecting the color pixels extreme points like this
class Crop : CustomEffectBase
{
 
public Windows.Foundation.Size CropSize { get; set; }
public Windows.Foundation.Point Corner { get; set; }
 
int cropMinWidth = int.MaxValue, cropMinHeight = int.MaxValue, cropMaxWidth = int.MinValue, cropMaxHeight = int.MinValue;
 
 
public Crop(IImageProvider source) :
base(source, false)
{
}
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
for (int i = 0; i < sourcePixelRegion.ImageSize.Height; ++i)
for (int j = 0; j < sourcePixelRegion.ImageSize.Width; ++j)
{
int index = i * (int)sourcePixelRegion.ImageSize.Width + j;
if (sourcePixelRegion.ImagePixels[index] > 128)
{
if (cropMinWidth > j) cropMinWidth = j;
if (cropMaxWidth < j) cropMaxWidth = j;
if (cropMinHeight > i) cropMinHeight = i;
if (cropMaxHeight < i) cropMaxHeight = i;
}
}
 
CropSize = new Windows.Foundation.Size(cropMaxWidth - cropMinWidth, cropMaxHeight - cropMinHeight);
Corner = new Windows.Foundation.Point(cropMinWidth, cropMinHeight);
}
}
  • Applying reframing filter by using the above obtained values. For convenience I've included both Clipping and Cropping effects in one custom effect and we can apply both effects easily in few steps like this
            var clipArt = new WriteableBitmap(First, null);
var image = new WriteableBitmap(Second, null);
 
var bmp = new Bitmap(new Windows.Foundation.Size((int)Second.ActualWidth, (int)Second.ActualHeight), ColorMode.Ayuv4444);
 
Windows.Foundation.Size outputSize;
Windows.Foundation.Point corner;
 
 
using (BitmapImageSource imageSource = new BitmapImageSource(image.AsBitmap()))
using (BitmapImageSource clipArtSource = new BitmapImageSource(clipArt.AsBitmap()))
using (var effect = new ClipnCrop(imageSource, clipArtSource))
using (var renderer = new BitmapRenderer(effect, bmp, OutputOption.PreserveAspectRatio))
{
await renderer.RenderAsync();
 
outputSize = effect.CropSize;
corner = effect.Corner;
 
// cropping image
 
var reframeFilter = new ReframingFilter(new Windows.Foundation.Rect(corner, outputSize), 0.0);
var cropdWbm = new WriteableBitmap((int)outputSize.Width, (int)outputSize.Height);
 
using (var source1 = new BitmapImageSource(bmp))
using (var cropFilter = new FilterEffect(source1))
using (var renderer1 = new WriteableBitmapRenderer(cropFilter, cropdWbm))
{
cropFilter.Filters = new IFilter[] { reframeFilter };
await renderer1.RenderAsync();
 
Final.Source = cropdWbm;
}
}


  • Total Clipping and Cropping Custom Effect Code
class ClipnCrop : CustomEffectBase
{
public Windows.Foundation.Size CropSize { get; set; }
public Windows.Foundation.Point Corner { get; set; }
 
public IImageProvider ClipArt { get; set; }
 
int cropMinWidth = int.MaxValue, cropMinHeight = int.MaxValue, cropMaxWidth = int.MinValue, cropMaxHeight = int.MinValue;
 
public ClipnCrop(IImageProvider source, IImageProvider clipArt) :
base(source, false)
{
ClipArt = clipArt;
}
 
protected override void OnProcess(PixelRegion sourcePixelRegion, PixelRegion targetPixelRegion)
{
if (ClipArt == null)
{
//copy all pixel
Array.Copy(sourcePixelRegion.ImagePixels, targetPixelRegion.ImagePixels, sourcePixelRegion.ImagePixels.Length);
return;
}
 
//create buffer
uint[] buffer = new uint[(int)(sourcePixelRegion.Bounds.Width * sourcePixelRegion.Bounds.Height)];
 
var bitmap = new Bitmap(
new Windows.Foundation.Size(sourcePixelRegion.Bounds.Width, sourcePixelRegion.Bounds.Height),
ColorMode.Bgra8888,
4*(uint)sourcePixelRegion.Bounds.Width,
buffer.AsBuffer());
 
//load buffer
ClipArt.GetBitmapAsync(bitmap, OutputOption.Stretch).AsTask().Wait();
 
//Process
sourcePixelRegion.ForEachRow((index, width, pos) =>
{
for (int x = 0; x < width; ++x, ++index)
{
if (buffer[index] > 128)
{
targetPixelRegion.ImagePixels[index] = sourcePixelRegion.ImagePixels[index];
}
else
{
targetPixelRegion.ImagePixels[index] = 0;
}
}
});
 
for (int i = 0; i < sourcePixelRegion.ImageSize.Height; ++i)
for (int j = 0; j < sourcePixelRegion.ImageSize.Width; ++j)
{
int index = i * (int)sourcePixelRegion.ImageSize.Width + j;
if (buffer[index] > 128)
{
if (cropMinWidth > j) cropMinWidth = j;
if (cropMaxWidth < j) cropMaxWidth = j;
if (cropMinHeight > i) cropMinHeight = i;
if (cropMaxHeight < i) cropMaxHeight = i;
}
}
 
CropSize = new Windows.Foundation.Size(cropMaxWidth - cropMinWidth, cropMaxHeight - cropMinHeight);
Corner = new Windows.Foundation.Point(cropMinWidth, cropMinHeight);
}
 
}


Summary

This is how we create visually stunning effects with ClipImage effect. Here is a picture sample created with ClipImage effect

ClipImage.png

This page was last modified on 21 July 2014, at 08:56.
269 page views in the last 30 days.

Was this page helpful?

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

 

Thank you!

We appreciate your feedback.

×