WPF C#/VB.NET
Compress Images for Free
C#
// AZUL CODING ---------------------------------------
// WPF C#/VB.NET - Compress Images for Free
// https://youtu.be/XJ7n6QTjKcY
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Text;
using TinifyAPI;
using Microsoft.Win32;
namespace CompressImages
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly string APIKey = "[replace with an API key from tinypng.com/developers]";
private readonly ObservableCollection<KeyValuePair<string, string>> ImageList = new();
private static readonly OpenFileDialog OpenDialog = new()
{
Title = "Select image files",
Filter = "Supported files (.jpg, .jpeg, .png)|*.jpg;*.jpeg;*.png",
Multiselect = true
};
public MainWindow()
{
InitializeComponent();
CompressItemsControl.ItemsSource = ImageList;
CompressBtn.Visibility = Visibility.Collapsed;
Tinify.Key = APIKey;
}
private void AddBtn_Click(object sender, RoutedEventArgs e)
{
if (OpenDialog.ShowDialog() == true)
AddFiles(OpenDialog.FileNames);
}
private void AddFiles(string[] filenames)
{
foreach (var item in filenames)
{
if (!ImageList.Any(x => x.Key == item))
ImageList.Add(new KeyValuePair<string, string>(item, Path.GetFileName(item)));
}
if (ImageList.Count > 0)
CompressBtn.Visibility = Visibility.Visible;
}
private void RemoveItemBtn_Click(object sender, RoutedEventArgs e)
{
var mi = (MenuItem)sender;
RemoveFile((string)mi.Tag);
}
private void RemoveFile(string id)
{
ImageList.Remove(ImageList.Where(x => x.Key == id).First());
if (ImageList.Count == 0)
CompressBtn.Visibility = Visibility.Collapsed;
}
private async void CompressBtn_Click(object sender, RoutedEventArgs e)
{
AddBtn.IsEnabled = false;
CompressBtn.IsEnabled = false;
TitleLbl.Content = "Compression in progress...";
try
{
StringBuilder sb = new();
sb.AppendLine("All files compressed.");
sb.AppendLine();
foreach (var item in ImageList.ToList())
{
string path = item.Key;
var source = Tinify.FromFile(path);
string pathWithoutExt = Path.Combine(Path.GetDirectoryName(path) ?? "", Path.GetFileNameWithoutExtension(path));
string ext = Path.GetExtension(path);
string newPath = string.Format("{0}-compressed{1}", pathWithoutExt, ext);
await source.ToFile(newPath);
long oldSize = new FileInfo(path).Length;
long newSize = new FileInfo(newPath).Length;
double percentage = Math.Round((oldSize - newSize) / (double)oldSize * 100);
sb.AppendLine(string.Format("{0} reduced by {1}%", item.Value, percentage));
RemoveFile(path);
}
MessageBox.Show(sb.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
AddBtn.IsEnabled = true;
CompressBtn.IsEnabled = true;
TitleLbl.Content = "Image compressor";
if (ImageList.Count == 0)
CompressBtn.Visibility = Visibility.Collapsed;
}
}
}
}
VB.NET
' AZUL CODING ---------------------------------------
' WPF C#/VB.NET - Compress Images for Free
' https://youtu.be/XJ7n6QTjKcY
Imports System.IO
Imports System.Text
Imports TinifyAPI
Imports Microsoft.Win32
Imports System.Collections.ObjectModel
Class MainWindow
Private ReadOnly APIKey As String = "[replace with an API key from tinypng.com/developers]"
Private ReadOnly ImageList As New ObservableCollection(Of KeyValuePair(Of String, String))()
Private Shared ReadOnly OpenDialog As New OpenFileDialog() With {
.Title = "Select image files",
.Filter = "Supported files (.jpg, .jpeg, .png)|*.jpg;*.jpeg;*.png",
.Multiselect = True
}
Public Sub New()
InitializeComponent()
CompressItemsControl.ItemsSource = ImageList
CompressBtn.Visibility = Visibility.Collapsed
Tinify.Key = APIKey
End Sub
Private Sub AddBtn_Click(sender As Object, e As RoutedEventArgs)
If OpenDialog.ShowDialog() = True Then AddFiles(OpenDialog.FileNames)
End Sub
Private Sub AddFiles(filenames As String())
For Each item In filenames
If Not ImageList.Any(Function(x) x.Key = item) Then
ImageList.Add(New KeyValuePair(Of String, String)(item, Path.GetFileName(item)))
End If
Next
If ImageList.Count > 0 Then CompressBtn.Visibility = Visibility.Visible
End Sub
Private Sub RemoveItemBtn_Click(sender As Object, e As RoutedEventArgs)
Dim mi = CType(sender, MenuItem)
RemoveFile(mi.Tag.ToString())
End Sub
Private Sub RemoveFile(id As String)
ImageList.Remove(ImageList.Where(Function(x) x.Key = id).First())
If ImageList.Count = 0 Then CompressBtn.Visibility = Visibility.Collapsed
End Sub
Private Async Sub CompressBtn_Click(sender As Object, e As RoutedEventArgs)
AddBtn.IsEnabled = False
CompressBtn.IsEnabled = False
TitleLbl.Content = "Compression in progress..."
Try
Dim sb As New StringBuilder()
sb.AppendLine("All files compressed.")
sb.AppendLine()
For Each item In ImageList.ToList()
Dim path As String = item.Key
Dim source = Tinify.FromFile(path)
Dim pathWithoutExt As String = IO.Path.Combine(IO.Path.GetDirectoryName(path), IO.Path.GetFileNameWithoutExtension(path))
Dim ext As String = IO.Path.GetExtension(path)
Dim newPath As String = String.Format("{0}-compressed{1}", pathWithoutExt, ext)
Await source.ToFile(newPath)
Dim oldSize As Long = New FileInfo(path).Length
Dim newSize As Long = New FileInfo(newPath).Length
Dim percentage As Double = Math.Round((oldSize - newSize) / oldSize * 100)
sb.AppendLine(String.Format("{0} reduced by {1}%", item.Value, percentage))
RemoveFile(path)
Next
MessageBox.Show(sb.ToString())
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
AddBtn.IsEnabled = True
CompressBtn.IsEnabled = True
TitleLbl.Content = "Image compressor"
If ImageList.Count = 0 Then CompressBtn.Visibility = Visibility.Collapsed
End Try
End Sub
End Class
XAML
<!-- AZUL CODING --------------------------------------- -->
<!-- WPF C#/VB.NET - Compress Images for Free -->
<!-- https://youtu.be/XJ7n6QTjKcY -->
<Window x:Class="CompressImages.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:CompressImages"
mc:Ignorable="d"
Title="Image Compressor - Azul Coding" Width="500" SizeToContent="Height" ResizeMode="CanMinimize">
<StackPanel Background="White">
<Label x:Name="TitleLbl" Content="Image compressor" Padding="5,0,5,5" Margin="20" FontWeight="SemiBold" FontSize="16" BorderBrush="DodgerBlue" BorderThickness="0,0,0,2"/>
<ScrollViewer Margin="20,0" Height="200" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<ItemsControl x:Name="CompressItemsControl" Background="#f0f0f0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button HorizontalContentAlignment="Stretch" BorderThickness="0" Background="#f0f0f0" ToolTip="{Binding Key}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Click="RemoveItemBtn_Click" Header="Remove" Tag="{Binding Key}"/>
</ContextMenu>
</Button.ContextMenu>
<StackPanel Orientation="Vertical" Margin="3,3">
<TextBlock Text="{Binding Value}" FontSize="14" TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<StackPanel Margin="20" Orientation="Horizontal">
<Button Name="AddBtn" Padding="10,5" Margin="0,0,10,0" Background="#f0f0f0" Click="AddBtn_Click">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Image Height="24" Width="24" Source="https://img.icons8.com/fluency/48/opened-folder.png"/>
<TextBlock Text="Add files" VerticalAlignment="Center" FontSize="14" Margin="10,0,5,2"/>
</StackPanel>
</Button>
<Button Name="CompressBtn" Padding="10,5" Margin="0,0,10,0" Background="#f0f0f0" Click="CompressBtn_Click">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Image Height="24" Width="24" Source="https://img.icons8.com/fluency/48/ok.png"/>
<TextBlock Text="Compress files" FontWeight="SemiBold" VerticalAlignment="Center" FontSize="14" Margin="10,0,5,2"/>
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</Window>