Skip to content

Commit

Permalink
Upgrade to use a proper screen
Browse files Browse the repository at this point in the history
This is considered a major update to the MakeIcon project. It not only adds a proper screen for previewing the selected images to be used for the icon but also changes the style of the icon of the application.

However, the biggest change in this version is the change from in license from MIT to Apache. Despite being more verbose, it clearly states that any contribution to the project goes under the same license, which could be a source of misunderstanding with the MIT. Details of the reason can be read on the NOTICE file.
  • Loading branch information
Lmpessoa committed Feb 12, 2021
1 parent 2614365 commit c331545
Show file tree
Hide file tree
Showing 27 changed files with 974 additions and 461 deletions.
6 changes: 0 additions & 6 deletions App/App.config

This file was deleted.

52 changes: 52 additions & 0 deletions App/App.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<AssemblyName>MakeIcon</AssemblyName>
<RootNamespace>Lmpessoa.MakeIcon</RootNamespace>
<Version>2.0.0</Version>
<Authors>Leonardo Pessoa</Authors>
<NeutralLanguage>en-gb</NeutralLanguage>
<PackageProjectUrl>https://www.github.com/Lmpessoa/MakeIcon/</PackageProjectUrl>
<RepositoryUrl>https://www.github.com/Lmpessoa/MakeIcon/</RepositoryUrl>
<Description>A simple application to build Windows 10 compatible ICO icon files from multiple PNG image files.</Description>
<Copyright>Copyright © 2019 Leonardo Pessoa</Copyright>
<ApplicationIcon>..\Resources\MakeIcon.ico</ApplicationIcon>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<PackageIcon>MakeIcon.ico</PackageIcon>
<PackageTags>icons windows-10 ico</PackageTags>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\Lmpessoa.pfx</AssemblyOriginatorKeyFile>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Program.cs" />
</ItemGroup>

<ItemGroup>
<None Remove="help-icon.png" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="5.0.1" />
</ItemGroup>

<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="..\Resources\MakeIcon.ico">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="Program.cs" />
</ItemGroup>

<ItemGroup>
<Resource Include="help-icon.png" />
</ItemGroup>

</Project>
14 changes: 14 additions & 0 deletions App/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Application x:Class="Lmpessoa.MakeIcon.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Lmpessoa.MakeIcon"
x:ClassModifier="internal"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Themes/Dark.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
21 changes: 21 additions & 0 deletions App/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2021 Leonardo Pessoa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Windows;

namespace Lmpessoa.MakeIcon {

internal partial class App : Application { }
}
25 changes: 25 additions & 0 deletions App/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2019 Leonardo Pessoa
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
83 changes: 39 additions & 44 deletions App/Icon.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
/*
* Copyright (c) 2019 Leonardo Pessoa
* https://lmpessoa.com
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;

namespace Lmpessoa.MakeIcon {

class Icon {
internal sealed class Icon {

private List<Bitmap> images = new List<Bitmap>();
private static readonly int[] validSizes = new int[] { 16, 32, 48, 64, 128, 256 };
private readonly Dictionary<int, Bitmap> images = new Dictionary<int, Bitmap>();

internal void Add(Bitmap image) {
if (image.Width != image.Height) {
throw new Exception("Icon images must have same width and height");
throw new BadImageFormatException("Icon images must have same width and height");
}
if (image.Width > 256) {
throw new Exception($"Image size is not supported in ICO format: {image.Width}x{image.Height}");
if (!validSizes.Contains(image.Width)) {
throw new BadImageFormatException($"Image size is not supported in ICO format: {image.Width}x{image.Height}");
}
if (image.PixelFormat != PixelFormat.Format32bppArgb) {
throw new Exception($"Unsupported format for icon: {image.PixelFormat.ToString()}");
throw new BadImageFormatException($"Unsupported format for icon: {image.PixelFormat}");
}
foreach (Bitmap bmp in images) {
if (bmp.Width == image.Width) {
throw new Exception($"This icon already has an image {image.Width}x{image.Height}");
}
images[image.Width] = image;
}

internal void Remove(int size) {
if (images.ContainsKey(size)) {
images.Remove(size);
}
images.Add(image);
}

internal int Count => images.Count;

internal Bitmap this[int size] => images[size];

internal void SaveTo(string filename) {
Bitmap[] images = GetSortedImages();
byte[][] data = GetImageBytes(images);
FileStream file = File.OpenWrite(filename);
file.SetLength(0);
using (BinaryWriter icon = new BinaryWriter(file)) {
icon.Write((UInt32) 0x00010000);
icon.Write((UInt16) images.Length);
icon.Write((uint) 0x00010000);
icon.Write((ushort) images.Length);
int offset = (images.Length * 16) + 6;
for (int i = 0; i < images.Length; ++i) {
Bitmap image = images[i];
Expand All @@ -77,7 +77,7 @@ class Icon {
}

private Bitmap[] GetSortedImages() {
List<Bitmap> images = new List<Bitmap>(this.images);
List<Bitmap> images = new List<Bitmap>(this.images.Values);
images.Sort((b1, b2) => b2.Width - b1.Width);
return images.ToArray();
}
Expand Down Expand Up @@ -136,19 +136,14 @@ class Icon {
}

private byte BitsPerPixel(PixelFormat format) {
switch (format) {
case PixelFormat.Format1bppIndexed:
return 1;
case PixelFormat.Format4bppIndexed:
return 4;
case PixelFormat.Format8bppIndexed:
return 8;
case PixelFormat.Format24bppRgb:
return 24;
case PixelFormat.Format32bppArgb:
return 32;
}
return 0;
return format switch {
PixelFormat.Format1bppIndexed => 1,
PixelFormat.Format4bppIndexed => 4,
PixelFormat.Format8bppIndexed => 8,
PixelFormat.Format24bppRgb => 24,
PixelFormat.Format32bppArgb => 32,
_ => 0,
};
}
}
}
85 changes: 85 additions & 0 deletions App/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<Window x:Class="Lmpessoa.MakeIcon.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:Lmpessoa.MakeIcon"
mc:Ignorable="d"
x:ClassModifier="internal"
Title="MainWindow" Height="400" Width="470"
WindowStyle="None"
WindowStartupLocation="CenterScreen"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
AllowDrop="True" ResizeMode="CanMinimize"
Background="{DynamicResource WindowBorder}" Drop="Window_DropFiles" DragOver="Window_DragOver">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/SystemButtonStyles.xaml"/>
<ResourceDictionary Source="Resources/MainWindowStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.InputBindings>
<KeyBinding Modifiers="Ctrl" Key="S" Command="{x:Static local:MainWindow.SaveAsCommand}"/>
<KeyBinding Key="Delete" Command="{x:Static local:MainWindow.RemoveImageCommand}"/>
<KeyBinding Key="Esc" Command="{x:Static local:MainWindow.ClearSelectionCommand}"/>
<KeyBinding Key="Tab" Command="{x:Static local:MainWindow.SelectNextCommand}"/>
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:MainWindow.ClearSelectionCommand}" Executed="ClearSelection"/>
<CommandBinding Command="{x:Static local:MainWindow.RemoveImageCommand}" Executed="RemoveSelection"/>
<CommandBinding Command="{x:Static local:MainWindow.SelectNextCommand}" Executed="SelectNext"/>
<CommandBinding Command="{x:Static local:MainWindow.SaveAsCommand}" Executed="SaveAs_Click"/>
</Window.CommandBindings>
<DockPanel Margin="1" Background="{DynamicResource WindowBackground}">
<DockPanel DockPanel.Dock="Top" Height="34">
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
<Button Style="{StaticResource SystemButton}" Content="&#xEF3C;" ToolTip="Change Theme" Click="ChangeTheme_Click"/>
<Button Style="{StaticResource SystemButton}" Content="&#xE921;" FontSize="9" ToolTip="Minimize" Click="Minimize_Click"/>
<Button Style="{StaticResource CloseSystemButton}" Content="&#xE711;" FontSize="12" ToolTip="Close" Click="Close_Click"/>
</StackPanel>
<Label MouseLeftButtonDown="TitlePanel_MouseLeftButtonDown"/>
</DockPanel>
<Button Style="{StaticResource SaveAsButton}" DockPanel.Dock="Bottom" Content="Save as..." HorizontalAlignment="Stretch" Height="24" Click="SaveAs_Click"/>
<Grid ScrollViewer.VerticalScrollBarVisibility="Disabled">
<Label Content="256 x 256" HorizontalAlignment="Left" Margin="118,256,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon256}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon256" Style="{StaticResource Icon}" Margin="10,0,0,0" Height="256" Width="256"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<Label Content="128 x 128" HorizontalAlignment="Left" Margin="364,145,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon128}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon128" Style="{StaticResource Icon}" Margin="330,17,0,0" Height="128" Width="128"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<Label Content="64 x 64" HorizontalAlignment="Left" Margin="298,230,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon64}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon64" Style="{StaticResource Icon}" Margin="290,167,0,0" Height="64" Width="64"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<Label Content="48 x 48" HorizontalAlignment="Left" Margin="384,230,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon48}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon48" Style="{StaticResource Icon}" Margin="384,182,0,0" Height="48" Width="48"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<Label Content="32 x 32" HorizontalAlignment="Left" Margin="363,292,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon32}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon32" Style="{StaticResource Icon}" Margin="371,260,0,0" Height="32" Width="32"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<Label Content="16 x 16" HorizontalAlignment="Left" Margin="309,310,0,0" VerticalAlignment="Top"
Tag="{x:Reference Icon16}" MouseLeftButtonDown="Label_Click"/>
<Button x:Name="Icon16" Style="{StaticResource Icon}" Margin="325,294,0,0" Height="16" Width="16"
BorderBrush="{DynamicResource IconBorder}" Click="ImageSelect" IsTabStop="False" Focusable="False"/>

<TextBlock x:Name="HelpTip" FontSize="11" TextWrapping="Wrap" Margin="0,0,178,33" Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}"
VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="272" Padding="10,5" ScrollViewer.VerticalScrollBarVisibility="Disabled" Visibility="Hidden">
Drag the desired PNG images files onto this window to add them to your icon and press the "Save as..." button below to save it to as an ICO file.
<LineBreak/><LineBreak/>
You can also remove an image previously included from the icon by clicking on a desired image and pressing the DELETE key.
</TextBlock>
<Image Margin="10,310,433,5" Stretch="Uniform" Source="help-icon.png" Width="25" Height="25" MouseLeave="Help_MouseLeave" MouseEnter="Help_MouseEnter"/>
</Grid>
</DockPanel>
</Window>

0 comments on commit c331545

Please sign in to comment.