WPF C#/VB
Making a Simple Photo Editor
C#
// AZUL CODING ---------------------------------------
// WPF C#/VB - Making a Simple Photo Editor
// https://youtu.be/9Gc8BgZl75I
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Drawing;
using System.Drawing.Imaging;
namespace AzulPhotoEditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly Bitmap OriginalImage;
private Bitmap EditedImage;
private int CurrentRotation = 0;
public MainWindow()
{
InitializeComponent();
OriginalImage = new Bitmap(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + "\\sample.jpg");
EditedImage = new Bitmap(OriginalImage);
EditImage.Source = BitmapToSource(new Bitmap(OriginalImage));
}
private static BitmapImage BitmapToSource(Bitmap src)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
src.Save(ms, ImageFormat.Jpeg);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, System.IO.SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
private void UpdateImage(object sender, EventArgs e)
{
if (IsLoaded)
{
float brightness = (float)BrightnessSlider.Value;
float contrast = (float)ContrastSlider.Value;
if (ContrastSlider.Value < 1)
{
contrast = (float)(ContrastSlider.Value / 2) + 0.5f;
}
if (sender is Button btn)
{
if (btn.Name == "RotateAnticlockwiseBtn")
{
if (CurrentRotation <= 0)
{
CurrentRotation = 270;
}
else
{
CurrentRotation -= 90;
}
}
else if (btn.Name == "RotateClockwiseBtn")
{
if (CurrentRotation >= 270)
{
CurrentRotation = 0;
}
else
{
CurrentRotation += 90;
}
}
}
float[][] greyscale = new float[][] {
new float[] { 0.299f, 0.299f, 0.299f, 0, 0},
new float[] { 0.587f, 0.587f, 0.587f, 0, 0},
new float[] { 0.114f, 0.114f, 0.114f, 0, 0},
new float[] { 0, 0, 0, 1, 0},
new float[] { 0, 0, 0, 0, 1}
};
float[][] light = new float[][] {
new float[] {contrast, 0, 0, 0, 0},
new float[] {0, contrast, 0, 0, 0},
new float[] {0, 0, contrast, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {brightness, brightness, brightness, 0, 1}
};
Bitmap bmp = new Bitmap(OriginalImage);
ImageAttributes imgattr = new ImageAttributes();
Rectangle rc = new Rectangle(0, 0, bmp.Width, bmp.Height);
if (NoFilterRadio.IsChecked == true)
{
imgattr.SetColorMatrix(new ColorMatrix(light));
}
else
{
imgattr.SetColorMatrix(new ColorMatrix(Multiply(greyscale, light)));
}
using (var g = Graphics.FromImage(bmp))
{
g.DrawImage(bmp, rc, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, imgattr);
if (RedRadio.IsChecked == true)
{
g.FillRectangle(new SolidBrush(Color.FromArgb(100, 235, 58, 52)), rc);
}
else if (GreenRadio.IsChecked == true)
{
g.FillRectangle(new SolidBrush(Color.FromArgb(100, 52, 235, 73)), rc);
}
else if (BlueRadio.IsChecked == true)
{
g.FillRectangle(new SolidBrush(Color.FromArgb(100, 52, 122, 235)), rc);
}
}
switch (CurrentRotation)
{
case 90:
bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);
break;
case 180:
bmp.RotateFlip(RotateFlipType.Rotate180FlipNone);
break;
case 270:
bmp.RotateFlip(RotateFlipType.Rotate270FlipNone);
break;
default:
break;
}
EditedImage = bmp;
EditImage.Source = BitmapToSource(EditedImage);
}
}
private float[][] Multiply(float[][] f1, float[][] f2)
{
float[][] X = new float[5][];
for (int d = 0; d < 5; d++)
X[d] = new float[5];
int size = 5;
float[] column = new float[5];
for (int j = 0; j < 5; j++)
{
for (int k = 0; k < 5; k++)
{
column[k] = f1[k][j];
}
for (int i = 0; i < 5; i++)
{
float[] row = f2[i];
float s = 0;
for (int k = 0; k < size; k++)
{
s += row[k] * column[k];
}
X[i][j] = s;
}
}
return X;
}
private void ExportBtn_Click(object sender, RoutedEventArgs e)
{
EditedImage.Save(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) + "\\sample-edited.jpg");
MessageBox.Show("Image saved.");
}
}
}
VB.NET
' AZUL CODING ---------------------------------------
' WPF C#/VB - Making a Simple Photo Editor
' https://youtu.be/9Gc8BgZl75I
Imports System.Drawing
Imports System.Drawing.Imaging
Class MainWindow
Private ReadOnly OriginalImage As Bitmap
Private EditedImage As Bitmap
Private CurrentRotation As Integer = 0
Public Sub New()
InitializeComponent()
OriginalImage = New Bitmap(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) & "\sample.jpg")
EditedImage = New Bitmap(OriginalImage)
EditImage.Source = BitmapToSource(New Bitmap(OriginalImage))
End Sub
Private Shared Function BitmapToSource(ByVal src As Bitmap) As BitmapImage
Dim ms As System.IO.MemoryStream = New System.IO.MemoryStream()
src.Save(ms, ImageFormat.Jpeg)
Dim image As BitmapImage = New BitmapImage()
image.BeginInit()
ms.Seek(0, System.IO.SeekOrigin.Begin)
image.StreamSource = ms
image.EndInit()
Return image
End Function
Private Sub UpdateImage(ByVal sender As Object, ByVal e As EventArgs)
If IsLoaded Then
Dim brightness As Single = BrightnessSlider.Value
Dim contrast As Single = ContrastSlider.Value
If ContrastSlider.Value < 1 Then
contrast = (ContrastSlider.Value / 2) + 0.5F
End If
If TryCast(sender, Button) IsNot Nothing Then
Dim btn = TryCast(sender, Button)
If btn.Name = "RotateAnticlockwiseBtn" Then
If CurrentRotation <= 0 Then
CurrentRotation = 270
Else
CurrentRotation -= 90
End If
ElseIf btn.Name = "RotateClockwiseBtn" Then
If CurrentRotation >= 270 Then
CurrentRotation = 0
Else
CurrentRotation += 90
End If
End If
End If
Dim greyscale As Single()() = New Single()() {
New Single() {0.299F, 0.299F, 0.299F, 0, 0},
New Single() {0.587F, 0.587F, 0.587F, 0, 0},
New Single() {0.114F, 0.114F, 0.114F, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {0, 0, 0, 0, 1}}
Dim light As Single()() = New Single()() {
New Single() {contrast, 0, 0, 0, 0},
New Single() {0, contrast, 0, 0, 0},
New Single() {0, 0, contrast, 0, 0},
New Single() {0, 0, 0, 1, 0},
New Single() {brightness, brightness, brightness, 0, 1}}
Dim bmp As Bitmap = New Bitmap(OriginalImage)
Dim imgattr As ImageAttributes = New ImageAttributes()
Dim rc As Rectangle = New Rectangle(0, 0, bmp.Width, bmp.Height)
If NoFilterRadio.IsChecked = True Then
imgattr.SetColorMatrix(New ColorMatrix(light))
Else
imgattr.SetColorMatrix(New ColorMatrix(Multiply(greyscale, light)))
End If
Using g = Graphics.FromImage(bmp)
g.DrawImage(bmp, rc, 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, imgattr)
If RedRadio.IsChecked = True Then
g.FillRectangle(New SolidBrush(Color.FromArgb(100, 235, 58, 52)), rc)
ElseIf GreenRadio.IsChecked = True Then
g.FillRectangle(New SolidBrush(Color.FromArgb(100, 52, 235, 73)), rc)
ElseIf BlueRadio.IsChecked = True Then
g.FillRectangle(New SolidBrush(Color.FromArgb(100, 52, 122, 235)), rc)
End If
End Using
Select Case CurrentRotation
Case 90
bmp.RotateFlip(RotateFlipType.Rotate90FlipNone)
Case 180
bmp.RotateFlip(RotateFlipType.Rotate180FlipNone)
Case 270
bmp.RotateFlip(RotateFlipType.Rotate270FlipNone)
Case Else
End Select
EditedImage = bmp
EditImage.Source = BitmapToSource(EditedImage)
End If
End Sub
Private Function Multiply(ByVal f1 As Single()(), ByVal f2 As Single()()) As Single()()
Dim X As Single()() = New Single(4)() {}
For d As Integer = 0 To 5 - 1
X(d) = New Single(4) {}
Next
Dim size As Integer = 5
Dim column As Single() = New Single(4) {}
For j As Integer = 0 To 5 - 1
For k As Integer = 0 To 5 - 1
column(k) = f1(k)(j)
Next
For i As Integer = 0 To 5 - 1
Dim row As Single() = f2(i)
Dim s As Single = 0
For k As Integer = 0 To size - 1
s += row(k) * column(k)
Next
X(i)(j) = s
Next
Next
Return X
End Function
Private Sub ExportBtn_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
EditedImage.Save(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures) & "\sample-edited.jpg")
MessageBox.Show("Image saved.")
End Sub
End Class
XAML
<!-- AZUL CODING --------------------------------------- -->
<!-- WPF C#/VB - Making a Simple Photo Editor -->
<!-- https://youtu.be/9Gc8BgZl75I -->
<Window x:Class="AzulPhotoEditor.MainWindow"
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"
xmlns:local="clr-namespace:AzulPhotoEditor"
mc:Ignorable="d"
Title="Photo Editor - Azul Coding" Height="475" Width="825" ResizeMode="CanMinimize">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="450"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Margin="20,20,0,20" Grid.Column="0">
<Image x:Name="EditImage"/>
</Grid>
<StackPanel Grid.Column="1" Margin="20">
<Label Content="Brightness" FontSize="14"/>
<Slider x:Name="BrightnessSlider" ValueChanged="UpdateImage" VerticalAlignment="Center" Value="0" IsSnapToTickEnabled="True" Minimum="-0.5" Maximum="0.5" LargeChange="0.1" SmallChange="0.01" TickFrequency="0.01" Margin="0,5,0,0"/>
<Label Content="Contrast" FontSize="14" Margin="0,20,0,0"/>
<Slider x:Name="ContrastSlider" ValueChanged="UpdateImage" VerticalAlignment="Center" Value="1" IsSnapToTickEnabled="True" Minimum="0" Maximum="2" LargeChange="0.2" TickFrequency="0.02" SmallChange="0.02" Margin="0,5,0,0"/>
<Label Content="Colour filter" FontSize="14" Margin="0,20,0,0"/>
<StackPanel Orientation="Horizontal" Margin="10,0,0,0">
<Grid Margin="0,0,5,0">
<RadioButton Name="NoFilterRadio" Content="None" GroupName="FilterRadios" Margin="5" IsChecked="True" Click="UpdateImage"/>
</Grid>
<Grid Background="#64999999" Margin="0,0,5,0">
<RadioButton Name="GrayscaleRadio" Content="Gray" GroupName="FilterRadios" Margin="5" Click="UpdateImage"/>
</Grid>
<Grid Background="#64eb3a34" Margin="0,0,5,0">
<RadioButton Name="RedRadio" Content="Red" GroupName="FilterRadios" Margin="5" Click="UpdateImage"/>
</Grid>
<Grid Background="#6434eb49" Margin="0,0,5,0">
<RadioButton Name="GreenRadio" Content="Green" GroupName="FilterRadios" Margin="5" Click="UpdateImage"/>
</Grid>
<Grid Background="#64347aeb">
<RadioButton Name="BlueRadio" Content="Blue" GroupName="FilterRadios" Margin="5" Click="UpdateImage"/>
</Grid>
</StackPanel>
<Label Content="Rotation" FontSize="14" Margin="0,20,0,0"/>
<Button Name="RotateAnticlockwiseBtn" Content="Rotate 90° anticlockwise" HorizontalAlignment="Left" Padding="20,5" Margin="10,5,0,0" Click="UpdateImage"/>
<Button Name="RotateClockwiseBtn" Content="Rotate 90° clockwise" HorizontalAlignment="Left" Padding="20,5" Margin="10,5,0,0" Click="UpdateImage"/>
<Label Content="Export edited image" FontSize="14" Margin="0,20,0,0"/>
<Button Name="ExportBtn" Content="Export" HorizontalAlignment="Left" Padding="20,5" Margin="10,5,0,0" Click="ExportBtn_Click"/>
</StackPanel>
</Grid>
</Window>