Introduction
For the App Innovation Contest, I propose to develop a Quick Retouch+ App.
This app will help users to quickly add different type of effects on a picture like sketch, oldphoto, emboss, nightvision, cartoon, oilify, etc. Users will also be able to add different types of frame just using a single touch, change EXIF information, and resize or crop an image. You can also perform red eye reduction, and there is a lens correction option. Finally, the user can directly upload his modified image to any social network using Quick Retouch+.
Background
Nowadays, retouching images is a fashion and social networks make it more popular with image sharing. Besides this, sometimes users need to change the brightness, contrast, or size to make it more fashionable. Here, I have just packed all things into one bundle and made it a fun task. Everything is possible from one place.
Note
I am developing this app for my own interest and now "Windows 8 Ultra Book App Dev Contest" has provided me a good opportunity to expose my ideas and show my strength. Some parts of this app are still under development.
Development Step
To make my development more understandable, I will discuss some code sections to represent my Details Level Design (DLD) and most of the UI activities.
Let's start the journey.
1. APP UI Code Section
I have used Expression Studio to design my primary mockup of UI. It is a great development tool for UI design. And WPF, which employs XAML, an XML-based language, to define and link various UI elements.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" x:Class="WPFGui.MainWindow"
Title="MainWindow" Height="687" Width="1010"
Background="Transparent" WindowStyle="None" KeyDown="Window_KeyDown"
BorderThickness="0" AllowsTransparency="True" BorderBrush="#FF73695C">
<Window.Resources>
<LinearGradientBrush x:Key="SelectionBrush" EndPoint="0.5,1"
MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<LinearGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform Angle="-45" CenterY="0.5" CenterX="0.5"/>
<TranslateTransform/>
</TransformGroup>
</LinearGradientBrush.RelativeTransform>
<GradientStop Color="#FFC3681E" Offset="0"/>
<GradientStop Color="#FFFBA503" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="toolbarMouseOver" Color="White" Opacity=".2"/>
<SolidColorBrush x:Key="toolbarMouseClick" Color="Black" Opacity=".7"/>
<Style x:Key="toolbarButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="buttonBorder" BorderBrush="Transparent"
Margin="0,2,2,2" BorderThickness="1" CornerRadius="1">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="buttonBorder" Property="Background"
Value="{StaticResource ResourceKey=toolbarMouseOver}" />
<Setter TargetName="buttonBorder" Property="BorderBrush"
Value="{StaticResource ResourceKey=toolbarMouseOver}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="buttonBorder" Property="Background"
Value="{StaticResource toolbarMouseClick}" />
<Setter TargetName="buttonBorder" Property="BorderBrush"
Value="{StaticResource toolbarMouseClick}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ImageBrush x:Key="Logo" ImageSource="UIRES\kies-png-small.png" />
<Style TargetType="{x:Type Control}" x:Key="baseStyle">
<Setter Property="FontFamily" Value="Tahoma"/>
<Setter Property="FontSize" Value="11"/>
</Style>
</Window.Resources>
<Grid>
<Rectangle x:Name="LeftMargin" Margin="0,0,993,16" Fill="#FFCFC7BC"/>
<Rectangle x:Name="RifghtMargin" Margin="0,0,0,16"
Fill="#FFCFC7BC" HorizontalAlignment="Right" Width="6"/>
<Rectangle x:Name="Title" Height="29"
VerticalAlignment="Top"
MouseLeftButtonDown="Title_MouseLeftButtonDown" Fill="#FFCFC7BC"/>
<Rectangle x:Name="Bottom" Height="29"
VerticalAlignment="Bottom"
MouseLeftButtonDown="Title_MouseLeftButtonDown" Fill="#FFCFC7BC"/>
<Rectangle x:Name="Logo" Height="16" VerticalAlignment="Top"
MouseLeftButtonDown="Title_MouseLeftButtonDown"
Fill="{StaticResource ResourceKey=Logo}" Margin="12,5,0,0"
HorizontalAlignment="Left" Width="16" />
<StackPanel Margin="27,0,647,657" Background="Transparent"
Orientation="Horizontal">
<Menu Name="MainMenu" Background="Transparent"
DockPanel.Dock="Left" Margin="5,5,5,-3"
Style="{StaticResource ResourceKey=baseStyle}" Height="27" Width="331.3">
<MenuItem Header="File" Margin="9,0,9,0" Style="{StaticResource StyleMenuItem}">
<MenuItem Header="Add file to Library"/>
<MenuItem Header="Add folder to Library"/>
<Separator/>
<MenuItem Header="Add file to Connected Device" IsEnabled="False"/>
<MenuItem Header="Add Folder to Connected Device" IsEnabled="False"/>
<Separator/>
<MenuItem InputGestureText="Alt+F4" Header="Exit" Click="CloseButton_Click"/>
</MenuItem>
<MenuItem Header="Edit" Margin="9,0,9,0" Style="{StaticResource StyleMenuItem}">
<MenuItem Header="Copy"/>
<MenuItem Header="Pase" IsEnabled="False"/>
<Separator/>
<MenuItem Header="Delete"/>
<Separator/>
<MenuItem Header="Select All"/>
<MenuItem Header="Deselect All"/>
</MenuItem>
<MenuItem Header="View" Margin="9,0,9,0" Style="{StaticResource StyleMenuItem}">
<MenuItem Header="List View"/>
<MenuItem Header="Thumbnail View"/>
<Separator />
<MenuItem Header="Sort Thumbnails" IsEnabled="False"/>
<MenuItem Header="Goto Current playing Music" IsEnabled="False"/>
<MenuItem Header="Goto Current playing Podcast" IsEnabled="False"/>
</MenuItem>
<MenuItem Header="Tool" Margin="9,0,9,0" Style="{StaticResource StyleMenuItem}">
<MenuItem Header="Connect Using Bluetooth"/>
<Separator/>
<MenuItem Header="Emergency Firmware Recovery"/>
<MenuItem Header="Firmware Updgrade Settings"/>
</MenuItem>
<MenuItem Header="Help"
Margin="10,0,9,0" Style="{StaticResource StyleMenuItem}">
<MenuItem Header="Kies Help"/>
<MenuItem Header="Kies Tutorial"/>
<Separator/>
<MenuItem Header="Check for updates"/>
<Separator/>
<MenuItem Header="Kies Information"/>
</MenuItem>
<MenuItem Name="webShareMenu" Header="WebShare"
Margin="10,0,9,0"
Style="{StaticResource StyleMenuItem}" Visibility="Hidden"/>
</Menu>
</StackPanel>
<Border x:Name="Body" Margin="205,29,6,29"
BorderBrush="#FF85817E" MouseUp="Body_MouseUp">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF3C3C3C" Offset="0"/>
<GradientStop Color="#FF2B2B2B" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<Border x:Name="TitleBorder" BorderBrush="#FF73695C"
BorderThickness="1" CornerRadius="0.5">
<StackPanel x:Name="stackPanel1" />
</Border>
<DockPanel LastChildFill="False" VerticalAlignment="Top"
HorizontalAlignment="Right" Margin="0,1.664,0,0">
<Button x:Name="MinimizeButton"
Visibility="Visible"
DockPanel.Dock="Left"
Style="{StaticResource LooklessButton}"
Margin="2" Click="MinimizeButton_Click">
<Image Stretch="Uniform"
Source="UIRES\min-1.png"
Height="10"
Width="10" Margin="3"/>
</Button>
<Button x:Name="MaximizeButton"
Visibility="Visible"
DockPanel.Dock="Left"
Style="{StaticResource LooklessButton}"
Margin="2" Click="MaximizeButton_Click">
<Image Stretch="Uniform"
Source="UIRES\max-1.png"
Height="10"
Width="10" Margin="3"/>
</Button>
<Button x:Name="CloseButton"
Visibility="Visible"
DockPanel.Dock="Left"
Style="{StaticResource LooklessButton}"
Margin="2" Click="CloseButton_Click">
<Image Stretch="Uniform"
Source="UIRES\close-1.png"
Height="10"
Width="10" Margin="3"/>
</Button>
</DockPanel>
<StackPanel x:Name="SideBar" Margin="7,29,766,29" >
<Image Source="UIRes\SideBar.png" Stretch="Fill"
Height="641.384" Margin="0,0,31,0"/>
</StackPanel>
<StackPanel x:Name="RightSide"
Margin="214,30,6,16" Orientation="Vertical">
<Grid>
<Rectangle Height="36"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF747067" Offset="0"/>
<GradientStop Color="#FF5A5750" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Button Content="Add Photos"
Height="28"
HorizontalAlignment="Left" x:Name="button1"
VerticalAlignment="Top" Width="89.5"
Style="{StaticResource ResourceKey=CustomButtonMainInterface}"
Foreground="White"
Margin="4,4,0,0" />
<Button Content="Delete"
Height="28" HorizontalAlignment="Left" x:Name="button1_Copy"
VerticalAlignment="Top"
Width="72.167"
Style="{StaticResource ResourceKey=CustomButtonMainInterface}"
Foreground="#FF929292"
Margin="90.836,4,0,0" IsEnabled="False" />
<Button Content="Transfer To Device"
Height="28" HorizontalAlignment="Left" x:Name="button1_Copy1"
VerticalAlignment="Top" Width="120.5"
Style="{StaticResource ResourceKey=CustomButtonMainInterface}"
Foreground="#FF929292"
Margin="175.667,4,0,0" IsEnabled="False" />
<Button Visibility="Hidden" Content="Edit"
Height="28" HorizontalAlignment="Left" Margin="311,4,0,0"
Name="editButton" Style="{StaticResource CustomButtonMainInterface}"
VerticalAlignment="Top"
Width="63" Click="editButton_Click">
<Button.Foreground>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF7492EB" Offset="1"/>
<GradientStop Color="#FF4A66BC"/>
</LinearGradientBrush>
</Button.Foreground>
</Button>
</Grid>
<Border>
<Image Source="UIRes\topBar2.png" Stretch="Uniform"/>
</Border>
<Border Height="28" BorderBrush="#FF222222"
BorderThickness="1" HorizontalAlignment="Stretch">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF474747" Offset="0"/>
<GradientStop Color="#FF444444" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Label Content="2012-2-21" Height="14" x:Name="label1"
Margin="26,0,0,0" Width="52"
Padding="0" HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="White" FontWeight="Light"/>
</Border>
<StackPanel Height="214" x:Name="imagePanel"
Width="Auto" Orientation="Horizontal">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center">
<Border x:Name="imgBorder1"
BorderThickness="1" BorderBrush="Wheat"
Height="104" Margin="20,10"
MouseUp="Border_MouseClick">
<Image Source="UIRes\image1.jpg" />
</Border>
<Border x:Name="imgToolbar1"
BorderThickness="1" BorderBrush="Black"
CornerRadius="1"
Width="102" Height="24"
d:LayoutOverrides="Width,
Height" Visibility="Hidden">
<Border.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="2"/>
</Border.Effect>
<Border.Background>
<ImageBrush ImageSource="UIRes\toolbar.png"/>
</Border.Background>
<StackPanel Width="102"
Height="22" Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button Style="{StaticResource ResourceKey=toolbarButton}"
Margin="2,0">
<Image Source="UIRes\iconStar.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes\iconTag.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes\iconUndo.png" Margin="0"/>
</Button>
<Path Data="M150,2 L150,22"
Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource
ResourceKey=toolbarButton}" Width="22">
<Image Source="UIRes\iconRedo.png"/>
</Button>
</StackPanel>
</Border>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Border x:Name="imgBorder2" BorderBrush="Wheat"
BorderThickness="1" Height="93"
Margin="20,10" MouseUp="Border_MouseClick">
<Image Source="UIRes\image2.jpg"/>
</Border>
<Border x:Name="imgToolbar2"
BorderThickness="1" BorderBrush="Black"
CornerRadius="1" Width="102" Height="24"
d:LayoutOverrides="Width, Height" Visibility="Hidden">
<Border.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="2"/>
</Border.Effect>
<Border.Background>
<ImageBrush ImageSource="UIRes/toolbar.png"/>
</Border.Background>
<StackPanel Width="102"
Height="22" Orientation="Horizontal"
HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Style="{StaticResource ResourceKey=toolbarButton}"
Margin="2,0">
<Image Source="UIRes\iconStar.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes/iconTag.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes/iconUndo.png" Margin="0"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill" Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22">
<Image Source="UIRes/iconRedo.png"/>
</Button>
</StackPanel>
</Border>
</StackPanel>
<StackPanel VerticalAlignment="Center">
<Border x:Name="imgBorder3" BorderBrush="Wheat"
BorderThickness="1" Height="128"
Margin="20,10" MouseUp="Border_MouseClick">
<Image Source="UIRes\image3.jpg"/>
</Border>
<Border x:Name="imgToolbar3" BorderThickness="1"
BorderBrush="Black" CornerRadius="1" Width="102"
Height="24" d:LayoutOverrides="Width,
Height" Visibility="Hidden">
<Border.Effect>
<DropShadowEffect BlurRadius="3" ShadowDepth="2"/>
</Border.Effect>
<Border.Background>
<ImageBrush ImageSource="UIRes/toolbar.png"/>
</Border.Background>
<StackPanel Width="102" Height="22"
Orientation="Horizontal"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<Button Style="{StaticResource ResourceKey=toolbarButton}"
Margin="2,0">
<Image Source="UIRes\iconStar.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes/iconTag.png"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill" Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22" >
<Image Source="UIRes/iconUndo.png" Margin="0"/>
</Button>
<Path Data="M150,2 L150,22" Margin="0,0.75,0,0.25"
Stretch="Fill"
Width="1" Stroke="#FFB8B8B8"/>
<Button Margin="2,0"
Style="{StaticResource ResourceKey=toolbarButton}"
Width="22">
<Image Source="UIRes/iconRedo.png"/>
</Button>
</StackPanel>
</Border>
</StackPanel>
</StackPanel>
</StackPanel>
<Frame x:Name="EditFrame" Content="Frame"
Margin="6,29,6,16" Visibility="Hidden"
NavigationUIVisibility="Hidden" />
</Grid>
</Window>
Key Features
Through screenshots, here I will describe the key features of the app.
Main UI
UI looks like this when closing the left and right dock panels.
EXIF Info
Tuning Control
Tuning control helps users to change brightness, contrast, sharpness, etc. using slider.
Resize and Crop
The user has two options to resize the image: percentage wise and pixel wise. Crop can be done manually or according to an aspect ratio.
Add Frame
Some predefined frames which can be added in a picture.
Add Effects
Currently, twelve effects are available: sketch, oilify, nightvision, cartoon, photocopy, vignating, softglow, simple makeup, poster, canvas, oldphoto. Just touch any of the effects and get the result on the original image.
Lens Correction and Red Eye Reduction
Recently used operations are shown on the leftside.
Web Share
After completing all the work, to share the image, just select any social site, provide the username and password and press Login. The image will be uploaded to your profile.
2. Code Design
All types of modules are handled by their own handler like effect handler handles effect request. So it does not interrupt others, we can add more effects as we need. I also made a DLL of effects to increase usablity.
It looks odd if I copy and paste all code in here. I put some code blocks here to understand the design and code flow. Here is the request handler code for adding an effect.
private void Effect_Button_Click(object sender, RoutedEventArgs e)
{
Button b = (Button)sender;
ImageEffects effect = new ImageEffects(ref m_unmanagedImg);
AF.UnmanagedImage newImg = null;
string s = (string)b.Name;
switch(s)
{
case "ButtonSketch":
newImg = effect.ApplyEffect(EffectID.Sketch);
break;
case "ButtonPoster":
newImg = effect.ApplyEffect(EffectID.Poster);
break;
case "ButtonNightVision":
newImg = effect.ApplyEffect(EffectID.NightVision);
break;
case "ButtonCartoon":
newImg = effect.ApplyEffect(EffectID.Cartoon);
break;
case "ButtonPhotocopy":
newImg = effect.ApplyEffect(EffectID.Photocopy);
break;
case "ButtonVignetting":
newImg = effect.ApplyEffect(EffectID.Vignetting);
break;
case "ButtonMosaic":
newImg = effect.ApplyEffect(EffectID.Mosaic);
break;
case "ButtonSoftGlow":
newImg = effect.ApplyEffect(EffectID.SoftGlow);
break;
case "ButtonOldImage":
newImg = effect.ApplyEffect(EffectID.OldImage);
break;
case "ButtonOilify":
newImg = effect.ApplyEffect(EffectID.Oilify);
break;
case "ButtonCanvas":
newImg = effect.ApplyEffect(EffectID.Canvas);
break;
case "ButtonEdgeGlow":
newImg = effect.ApplyEffect(EffectID.EdgeGlow);
break;
case "ButtonEmboss":
newImg = effect.ApplyEffect(EffectID.Emboss);
break;
case "ButtonSimpleMakeup":
newImg = effect.ApplyEffect(EffectID.SimpleMakeup);
break;
default:
break;
}
DrawThumb(newImg);
ShowBitmap(newImg);
UpdateHistogram(newImg);
}
Now the ImageEffects
class code which perform activities through a DLL call. Pass the input image data, reference the output image data and sometimes some parameters. The final effect is obtained in the output image data and displayed in the UI.
using System;
using System.Runtime.InteropServices;
namespace WPFGui
{
using AF = AForge.Imaging;
using GDI = System.Drawing;
public enum EffectID
{
Sketch,
Poster,
NightVision,
Cartoon,
Photocopy,
Vignetting,
Mosaic,
SoftGlow,
OldImage,
Oilify,
Canvas,
EdgeGlow,
Emboss,
SimpleMakeup
}
unsafe class ImageEffects : IDisposable
{
#region EffectDLLImport
protected const string dllPath = "Effects.dll";
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 SketchImage
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 ApplyEffectEmbos
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 ApplyOilify
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 OldimageEffect
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 PhotocopyFilter
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 ApplyCanvas
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 NightVision2(ImgInfo* RGBarray);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 NightVision
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 Posterize
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 VignettingFilter
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 Mosaic
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 SimpleMakeUp
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 SoftGlowFilter
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 CartoonFilter
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
[DllImport(dllPath, CallingConvention=CallingConvention.Cdecl)]
unsafe public static extern Int32 EdgeGlow
(ImgInfo* imageIn, ImgInfo* imageOut, float* parameter, int ParamNo);
#endregion
#region Necessary Structures (Unsafe)
[StructLayout(LayoutKind.Sequential)]
unsafe public struct RGBQuad
{
public byte B;
public byte G;
public byte R;
}
[StructLayout(LayoutKind.Sequential)]
unsafe public struct ImgInfo
{
public RGBQuad** rgb;
public byte** gray;
public int height;
public int width;
public int bitdepth;
}
#endregion
#region DATA MEMBERS
public unsafe RGBQuad** rgbInput;
public unsafe RGBQuad** rgbOutput;
public unsafe ImgInfo* nativeInputBitmap;
public unsafe ImgInfo* nativeOutputBitmap;
unsafe byte* inputStream;
unsafe byte* effectOutput;
readonly AF.UnmanagedImage m_inputImage;
AF.UnmanagedImage m_outputImage;
#endregion
unsafe public float* param;
public ImageEffects(ref AF.UnmanagedImage inputBitmap)
{
this.m_inputImage = inputBitmap;
m_outputImage = m_inputImage.Clone();
byte* ptr = (byte*)m_inputImage.ImageData;
int stride = m_inputImage.Stride;
int numBytes = stride * m_inputImage.Height;
inputStream = ptr;
rgbInput = (RGBQuad**)Marshal.AllocHGlobal(sizeof(RGBQuad*) * inputBitmap.Height);
rgbOutput = (RGBQuad**)Marshal.AllocHGlobal(sizeof(RGBQuad*) * inputBitmap.Height);
effectOutput = (byte*)m_outputImage.ImageData;
int nextPtr = stride;
for (int i = 0; i < inputBitmap.Height; i++)
{
*(rgbInput + i) = (RGBQuad*)inputStream;
inputStream += nextPtr;
*(rgbOutput + i) = (RGBQuad*)effectOutput;
effectOutput += nextPtr;
}
inputStream = ptr;
nativeInputBitmap = (ImgInfo*)Marshal.AllocHGlobal(sizeof(ImgInfo));
nativeOutputBitmap = (ImgInfo*)Marshal.AllocHGlobal(sizeof(ImgInfo));
nativeInputBitmap->width = nativeOutputBitmap->width = inputBitmap.Width;
nativeInputBitmap->height = nativeOutputBitmap->height = inputBitmap.Height;
nativeInputBitmap->bitdepth = nativeOutputBitmap->bitdepth = 24;
nativeInputBitmap->rgb = rgbInput;
nativeOutputBitmap->rgb = rgbOutput;
nativeInputBitmap->gray = null;
nativeOutputBitmap->gray = null;
}
~ImageEffects()
{
Dispose();
}
public void Dispose()
{
if (rgbInput != null)
{
Marshal.FreeHGlobal((IntPtr)rgbInput);
rgbInput = null;
}
if (rgbOutput != null)
{
Marshal.FreeHGlobal((IntPtr)rgbOutput);
rgbOutput = null;
}
if (nativeInputBitmap != null)
{
Marshal.FreeHGlobal((IntPtr)nativeInputBitmap);
nativeInputBitmap = null;
}
if (nativeOutputBitmap != null)
{
Marshal.FreeHGlobal((IntPtr)nativeOutputBitmap);
nativeOutputBitmap = null;
}
inputStream = null;
effectOutput = null;
}
#if !DISABLE
public AF.UnmanagedImage ApplyEffect(EffectID effectId)
{
int paramNo;
switch (effectId)
{
case EffectID.Sketch:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 16;
SketchImage(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Poster:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 128;
Posterize(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.NightVision:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 200;
NightVision(nativeInputBitmap, nativeOutputBitmap, param, 1);
break;
}
case EffectID.Cartoon:
{
paramNo = 2;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 8.0f;
param[1] = 0.3f;
CartoonFilter(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Photocopy:
{
paramNo = 2;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 25;
param[1] = 0.85f;
PhotocopyFilter(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Vignetting:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 1.2f;
VignettingFilter(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Mosaic:
{
paramNo = 3;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 15;
param[1] = 200;
param[2] = 4;
Mosaic(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.SoftGlow:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 5;
SoftGlowFilter(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.OldImage:
{
paramNo = 1;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 0.2f;
OldimageEffect(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Oilify:
{
paramNo = 2;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 10;
param[1] = 10;
ApplyOilify(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Canvas:
{
paramNo = 3;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 2;
param[1] = 1;
param[2] = 1;
ApplyCanvas(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.EdgeGlow:
{
paramNo = 3;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 11;
param[1] = 11;
param[2] = 1;
EdgeGlow(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.Emboss:
{
paramNo = 0;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
ApplyEffectEmbos(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
case EffectID.SimpleMakeup:
{
paramNo = 2;
param = (float*)Marshal.AllocHGlobal(sizeof(float) * (paramNo));
param[0] = 4;
param[1] = 45;
SimpleMakeUp(nativeInputBitmap, nativeOutputBitmap, param, paramNo);
break;
}
default:
System.Windows.MessageBox.Show("Done Nothing");
break;
}
Marshal.FreeHGlobal((IntPtr)param);
param = null;
return m_outputImage;
}
#endif
}
}
Similarly, for adding a frame, use a frame handler:
private void Frame_Button_Click(object sender, RoutedEventArgs e)
{
string buttonName = (string)((Button)sender).Name;
string fileName = @"Frames\" + buttonName + ".png";
AF.UnmanagedImage frameImage = null;
DisposableGDIBitmap frameBMP = new DisposableGDIBitmap(fileName);
try
{
frameImage = new AF.UnmanagedImage(frameBMP.GetBitmapData);
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.ToString());
}
AF.UnmanagedImage viewImg = this.m_frames.getFramedImage(frameImage, m_unmanagedImg);
DrawThumb(viewImg);
ShowBitmap(viewImg);
UpdateHistogram(viewImg);
}
This class is responsible for adding a frame to an image:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WPFGui
{
using AF = AForge.Imaging;
using GDI = System.Drawing;
class ImageFrame
{
AF.UnmanagedImage resizedFrame;
AF.UnmanagedImage originalFrame;
AF.UnmanagedImage resultImage;
AF.Filters.ResizeBilinear resizeBilinearFilter;
GDI.Color framePixelColor;
AF.Filters.RotateBilinear rotateBilinearFilter;
private int RED = 240;
private int GREEN = 240;
private int BLUE = 240;
private float frameRatio;
private float mainImageRatio;
public ImageFrame()
{
}
public AF.UnmanagedImage getFramedImage
(AF.UnmanagedImage frameUnmImg, AF.UnmanagedImage mainImageUnmImg)
{
this.resultImage = mainImageUnmImg.Clone();
this.frameRatio = (float)frameUnmImg.Width / (float)frameUnmImg.Height;
this.mainImageRatio =
(float)this.resultImage.Width / (float)this.resultImage.Height;
if (!((this.frameRatio <= 1.0 && this.mainImageRatio <= 1.0) ||
(1.0 <= this.frameRatio && 1.0 <= this.mainImageRatio)))
{
this.rotateBilinearFilter = new AF.Filters.RotateBilinear(90, false);
this.originalFrame = this.rotateBilinearFilter.Apply(frameUnmImg);
}
else
{
this.originalFrame = frameUnmImg.Clone();
}
this.resizeBilinearFilter =
new AF.Filters.ResizeBilinear(this.resultImage.Width, this.resultImage.Height);
this.resizedFrame = this.resizeBilinearFilter.Apply(originalFrame);
try
{
for (int h = 0; h < this.resultImage.Height; h++)
{
for (int w = 0; w < this.resultImage.Width; w++)
{
this.framePixelColor = this.resizedFrame.GetPixel(w, h);
if (!((0 == this.framePixelColor.A) || (this.framePixelColor.R >
this.RED && this.framePixelColor.G >
this.GREEN && this.framePixelColor.B > this.BLUE)))
{
this.resultImage.SetPixel(w, h, this.framePixelColor);
}
}
}
}
catch (Exception ex)
{
System.Windows.MessageBox.Show(ex.ToString());
}
return this.resultImage;
}
}
}
The webshare handler handles all types of image upload requests:
private void LoginToWebshare(object sender, RoutedEventArgs e)
{
string userName = UserNameBox.Text;
string userPassword = UserPasswordBox.Password;
System.Windows.MessageBox.Show(userName);
Button b = (Button)sender;
if (m_unmanagedImg == null)
return;
}
Ultrabook Features Utilized in the Application
Swipe and touch feature for controlling activities, slider, zoom in/out, and image switching.