×
Namespaces

Variants
Actions

如何使用Nokia Imaging SDK的卡通和裁剪滤镜

From Nokia Developer Wiki
Jump to: navigation, search

本篇文章讲解如何使用Nokia Imaging SDK创建图片的卡通和裁剪滤镜,以及使用WriteableBitmapEx拼接图片。

WP Metro Icon Multimedia.png
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
Article Metadata

代码示例
测试基于
SDK: Windows Phone 8.0 SDK
设备:: Nokia Lumia 920

兼容于
Dependencies: Nokia Imaging SDK

文章
翻译:
highcedar
最后由 hamishwillee 在 02 Sep 2013 编辑

Contents

Introduction

使用Nokia Imaging SDK可高效的创建令人惊奇的图片滤镜效果。将自己的肖像照片增加卡通的滤镜效果是很有趣的事,至少我喜欢这么做。本文提供使用FilterFactory.CreateCartoonFilter的方法可将图像转换为卡通样式,本文也介绍如何在应用中使用FilterFactory.CreateCropFilter方法裁剪图片,文章的最后一个内容就是创建如下面右侧图片的宽图块的磁贴图像。下面的宽图块的图片其实由五张图片拼接而成。 本篇文档的英文版Using Nokia Imaging SDK Create Cartoon Photo参加了Nokia Imaging Wiki Competition 2013Q3

Pre-requisites

安装Nokia Imaging SDK请参考以下的文档:

使用 Nokia Imaging SDK 请特别注意编译的条件:ARM编译模式可使程序在手机中运行,X86的编译模式可使程序在模拟器中运行。 因此“All CPU”的编译配置必需在配置管理器中删除,只保留“ARM”和“X86”。打开配置管理器的方法:BUILD – Configuration Manager…

在配置管理器中,打开“Active Solution platform:”列表,选择“<Edit…>”。在解决方案平台的窗体中,选中“Any CPU”然后将其删除,最后确保“ARM”和“X86”仍在列表中。

安装WriteableBitmapEx库

启动 NuGet 库管理:Tools 菜单 > Library Package Manager > Manage NuGet Packages for Solution...

在搜索栏中键入“WriteableBitmap”并搜索,则WriteableBitmapEX的SDK会在搜索结果中显示,点击安装按钮即可。

"Cartoon Me" 应用

“Cartoon Me”应用是如何使用Nokia Imaging SDK的示例,在此示例中使用拍照取景器获取照片,然后使用Imaging SDK为照片增加卡通的滤镜效果,并可将滤镜处理的图片保存至相机的camera roll相册;最近浏览的列表则保存您在应用中最近处理的原始图片。

Cartoon Me 应用还是用 Imaging SDK 的 FilterFactory.CreateCropFilter 方法裁剪图片,并将裁剪后的图片与另外四个图片拼接为宽图块的图像,最后生成动态磁贴显示在手机的开始屏幕中。

捕获照片

在 MainPage 类中捕获照片,使用 UIFramework 库实现增加照片的 UI 。当点击增加按钮,则执行以下的代码。如果 PhotoChooserTask 返回为OK,则应用加图片流,并且应用导航至EditPage。

private void AddButton_Click(object sender, RoutedEventArgs e)
{
if (isChoosing)
{
return;
}
 
isChoosing = true;
 
PhotoChooserTask photoChoose = new PhotoChooserTask();
photoChoose.ShowCamera = true;
photoChoose.Completed += (s, res) =>
{
isChoosing = false;
 
if (res.TaskResult == TaskResult.Cancel && res.Error is InvalidOperationException)
{
MessageBox.Show(CartoonMe.Resources.AppResources.message_duplicate_add);
return;
}
 
if (res.TaskResult == TaskResult.OK)
{
chosenPhoto = res.ChosenPhoto;
 
if (null != res.ChosenPhoto)
{
DataContext dataContext = CartoonMe.DataContext.Singleton;
 
// Reset the streams
dataContext.CreateStreams();
 
// Use the largest possible dimensions
WriteableBitmap bitmap = new WriteableBitmap(3552, 2448);
try
{
// Jpeg images can be used as such.
bitmap.LoadJpeg(chosenPhoto);
chosenPhoto.Position = 0;
chosenPhoto.CopyTo(dataContext.ImageStream);
}
catch (Exception /*ex*/)
{
// Image format is not jpeg. Can be anything, so first
// load it into a bitmap image and then write as jpeg.
BitmapImage image = new BitmapImage();
image.SetSource(chosenPhoto);
 
bitmap = new WriteableBitmap(image);
bitmap.SaveJpeg(dataContext.ImageStream, image.PixelWidth, image.PixelHeight, 0, 100);
}
}
 
// Since PhotoChooserTask is not completed yet to front, NavigationService.Navigate is not allowed here.
// This is a workaround by one time navigation event subscribed, and deplayed the navigation to another page.
NavigationService.Navigated += new NavigatedEventHandler(NavigationService_Navigated);
}
};
photoChoose.Show();
}

请注意应声明程序具有 ID_CAP_ISV_CAMERA 的能力。

卡通滤镜处理图片

在 EditPage 类中创建卡通图像:

/// <summary>
/// Takes the captured image and applies filters to it.
/// </summary>
private async void CreateCartoonImage()
{
DataContext dataContext = CartoonMe.DataContext.Singleton;
 
if (dataContext.ThumbStream == null)
{
// No captured image available!
NavigationService.GoBack();
return;
}
 
// Create a session that we will use with all the filters
IBuffer buffer = dataContext.ImageStream.GetWindowsRuntimeBuffer();
EditingSession session = new EditingSession(buffer);
 
// Perform the filtering
using (session)
{
foreach (AbstractFilter filter in _filters)
{
filter.SetBuffer(buffer);
filter.DefineFilter(session);
 
await filter.RenderToBitmapAsync(session);
//session.UndoAll();
}
}
}

卡通滤镜的实现:在 CartoonFilter.cs 中实现虚函数 DefineFilter()。

public override void DefineFilter(EditingSession session)
{
session.AddFilter(FilterFactory.CreateCartoonFilter(_distinctEdges));
}

RenderToBitmapAsync()在CartoonFilter 的父类 AbstractFilter 中实现(AbstractFilter.cs):

public async Task RenderToBitmapAsync(EditingSession session)
{
await session.RenderToBitmapAsync(_filteredBitmap, OutputOption.PreserveAspectRatio);
_previewBitmap.Invalidate(); // Force a redraw
}

保存滤镜处理后的图片至媒体库:

private async void OnSaveButtonClicked(object sender, RoutedEventArgs e)
{
_progressIndicator.Text = AppResources.SavingText;
_progressIndicator.IsVisible = true;
SystemTray.SetProgressIndicator(this, _progressIndicator);
 
MediaLibrary library = new MediaLibrary();
 
DataContext dataContext = CartoonMe.DataContext.Singleton;
 
try
{
AbstractFilter filter = _filters[0]; // cartoon filter
EditingSession session = new EditingSession(dataContext.ImageStream.GetWindowsRuntimeBuffer());
 
using (session)
{
filter.DefineFilter(session);
IBuffer data = await session.RenderToJpegAsync();
 
// Save the rendered image into a file
library.SavePictureToCameraRoll(FileNamePrefix
+ DateTime.UtcNow.ToString(Constant.DateTimeFormat) + Constant.ImageFileSuffix, data.AsStream());
 
}
 
}
catch (Exception ex)
{
Debug.WriteLine("EditPage::SaveButton_Click(): Failed to save the image to camera roll: "
+ ex.ToString());
}
 
_progressIndicator.IsVisible = false;
SystemTray.SetProgressIndicator(this, _progressIndicator);
 
NavigationService.GoBack();
}

请注意应声明程序具有 ID_CAP_MEDIALIB_PHOTO 的能力。

裁剪滤镜

我们将使用 FilterFactory.CreateCropFilter 方法裁剪图片,裁剪后的图片将作为动态磁贴的背景图片。 为了实现裁剪的滤镜效果,在 AbstractFilter 类中增加 CreateCropImage 方法,在EditPage中裁剪图片:

DataContext dataContext = CartoonMe.DataContext.Singleton;
// Create a session that we will use with all the filters
IBuffer buffer = dataContext.ImageStream.GetWindowsRuntimeBuffer();
EditingSession session = new EditingSession(buffer);
 
// Perform the filtering
using (session)
{
foreach (AbstractFilter filter in _filters)
{
filter.SetBuffer(buffer);
filter.CropFilter(session);
 
await filter.CropRenderToBitmapAsync(session);
session.UndoAll();
}
}

在 AbstractFilter 类中实现 CreateCropImage 方法:

public abstract void CropFilter(EditingSession session);
/// <summary>
/// Creates a filtered crip image from the given buffer.
/// </summary>
public async void CreateCropImage()
{
if (_buffer == null)
{
return;
}
 
EditingSession session = new EditingSession(_buffer);
 
// Perform the filtering
using (session)
{
CropFilter(session);
await CropRenderToBitmapAsync(session);
}
}
 
/// <summary>
/// Creates the preview buffers or resize them if needed.
/// </summary>
/// <param name="session">The session initialized with the desired jpeg.</param>
public async Task CropRenderToBitmapAsync(EditingSession session)
{
await session.RenderToBitmapAsync(_cropFilteredBitmap, OutputOption.PreserveAspectRatio);
_cropBitmap.Invalidate(); // Force a redraw
}

在 AbstractFilter 类中输出裁剪滤镜的图片流:

private WriteableBitmap _cropBitmap;
 
private Bitmap _cropFilteredBitmap;
 
/// <summary>
/// Creates the PreviewBuffers or resize them if needed.
/// </summary>
/// <param name="session">The session initialized with the desired jpeg.</param>
public void SetOutputResolution(int width, int height)
{
......
 
_cropBitmap = new WriteableBitmap(355, 355);
_cropFilteredBitmap = _cropBitmap.AsBitmap();
CropImage.Source = _cropBitmap; // Force a redraw
}

在 CartoonFilter 类中冲在虚函数 CropFilter ,设置裁剪图片的矩形区域。

public override void CropFilter(EditingSession session)
{
Windows.Foundation.Rect cropArea = new Windows.Foundation.Rect(0, 0, 355, 355);
session.AddFilter(FilterFactory.CreateCropFilter(cropArea));
}

拼接图片

曾在一个项目中遇到过拼接图片是由服务器端完成,还是有Windows Phone客户端完成的问题。抛开这个问题不谈,我很感兴趣于在Windows Phone中实现拼接图片的方法,最终图片拼接完成的效果如下图所示。您也在此方法之上将其改进,应用于您自己的项目。书的目标为读者提供有用内容,Wiki也是这样。

WriteableBitmapEx 是 WriteableBitmap 的扩展,这里所讲的是其组合图片的功能。 691X336的宽图块的图片尺寸和拼接点坐标如下图所示,左侧为一张大图,右侧由四张小图组成。如果微软以后更新图块的尺寸和样式,那么这个图片拼接的处理方法也要相应改变。

在 EditPage 类中我们使用 Blit 方法组成图片:

WriteableBitmap wbmp = new WriteableBitmap(_filters[0].CropImage.Source as BitmapSource);
 
using (var stream = store.OpenFile(backgoundImagePath, System.IO.FileMode.OpenOrCreate))
{
System.Windows.Media.Imaging.Extensions.SaveJpeg(wbmp, stream, MediumTilePixelWidth, MediumTilePixelHeight, 0, 100);
//wbmp.SaveJpeg(stream, bitmap.PixelWidth, bitmap.PixelHeight, 0, 100);
}
 
WriteableBitmap wideBitmap = new WriteableBitmap(WideTilePixelWidth, WideTilePixelHeight);
 
System.IO.Stream stream1 = Application.GetResourceStream(new Uri(@"Assets/Images/01_imaging_sdk_text.png", UriKind.Relative)).Stream;
BitmapImage image1 = new BitmapImage();
image1.SetSource(stream1);
 
System.IO.Stream stream2 = Application.GetResourceStream(new Uri(@"Assets/Images/02_imaging_sdk_icon.png", UriKind.Relative)).Stream;
BitmapImage image2 = new BitmapImage();
image2.SetSource(stream2);
 
System.IO.Stream stream3 = Application.GetResourceStream(new Uri(@"Assets/Images/03_nokia_future_icon.png", UriKind.Relative)).Stream;
BitmapImage image3 = new BitmapImage();
image3.SetSource(stream3);
 
System.IO.Stream stream4 = Application.GetResourceStream(new Uri(@"Assets/Images/04_nokia_future_text.png", UriKind.Relative)).Stream;
BitmapImage image4 = new BitmapImage();
image4.SetSource(stream4);
 
int leftImageWidth = (wbmp.PixelWidth > 355) ? 355 : wbmp.PixelWidth;
int leftImageHeight = (wbmp.PixelHeight > 336) ? 336 : wbmp.PixelHeight;
 
wideBitmap.Blit(new Rect(0, 0, 355, 336), new WriteableBitmap(wbmp), new Rect(0, 0, wbmp.PixelWidth, wbmp.PixelHeight), WriteableBitmapExtensions.BlendMode.Additive);
wideBitmap.Blit(new Rect(355, 0, 168, 168), new WriteableBitmap(image1), new Rect(0, 0, image1.PixelWidth, image1.PixelHeight), WriteableBitmapExtensions.BlendMode.Additive);
wideBitmap.Blit(new Rect(523, 0, 168, 168), new WriteableBitmap(image2), new Rect(0, 0, image4.PixelWidth, image4.PixelHeight), WriteableBitmapExtensions.BlendMode.Additive);
wideBitmap.Blit(new Rect(355, 168, 168, 168), new WriteableBitmap(image3), new Rect(0, 0, image3.PixelWidth, image3.PixelHeight), WriteableBitmapExtensions.BlendMode.Additive);
wideBitmap.Blit(new Rect(523, 168, 168, 168), new WriteableBitmap(image4), new Rect(0, 0, image4.PixelWidth, image4.PixelHeight), WriteableBitmapExtensions.BlendMode.Additive);

参考

This page was last modified on 2 September 2013, at 08:25.
163 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.

×