From c05b7103a2ffa0fd42244215c319dd073e66648b Mon Sep 17 00:00:00 2001
From: Cyklon_3000 <67823272+Cyklon3000@users.noreply.github.com>
Date: Fri, 23 Aug 2024 22:53:44 +0200
Subject: [PATCH 1/4] ci: add python script for batch svg to .ico conversion
---
batch_convert_to_ico.py | 99 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 99 insertions(+)
create mode 100644 batch_convert_to_ico.py
diff --git a/batch_convert_to_ico.py b/batch_convert_to_ico.py
new file mode 100644
index 00000000..562593b6
--- /dev/null
+++ b/batch_convert_to_ico.py
@@ -0,0 +1,99 @@
+import os
+import subprocess
+from pathlib import Path
+from typing import Tuple, List, Dict
+
+def convert_svg_to_ico(input_folder:str, output_folder:str, sizes:Tuple[int, ...]=(16,32,48,64,256)):
+ """
+ Converts a folder of .svg icons to a folder of .ico icons of various sizes.
+ Icons can be swapped based on a maximum size attributed to .svg icons, if their name ends with '-{size}px.svg'.
+ This function requires Imagemagick to be installed.
+
+ Args:
+ input_folder (str): The path to the folder containing the .svg icons.
+ output_folder (str): The path to the folder where the .ico icons will be saved.
+ sizes (Tuple[int, ...], optional): The sizes of the .ico icons. Defaults to (16, 32, 48, 64, 256).
+ """
+
+ def ends_with_px(string:str) -> bool:
+ if not string.endswith('px'): return False
+ parts:Tuple[str, ...] = string.rsplit('-', 1)
+ if len(parts) != 2: return False
+ return parts[1][:-2].isdigit()
+
+ sizes = sorted(sizes)
+
+ base_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
+ and not any([ends_with_px(filename[:-4].lower()) for s in sizes])]
+ alt_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
+ and any([ends_with_px(filename[:-4].lower()) for s in sizes[:-1]])]
+
+ # Iterate through all base .svg files in the input folder
+ for base_filename in base_filenames:
+ # print(base_filename)
+ inputs:List[Dict[str, int | str]] = []
+
+ for size in sizes:
+ assumed_filename:str = base_filename[:-4] + f'-{size}px.svg'
+ if assumed_filename not in alt_filenames: continue
+
+ alt_input_path:str = os.path.join(input_folder, assumed_filename)
+
+ inputs.append({'path': alt_input_path, 'maximum_size': size})
+
+ # Add version that comes for sizes above alt max sizes
+ inputs.append({'path': os.path.join(input_folder, base_filename), 'maximum_size': sizes[-1]})
+
+ # Step 1: Convert input.svg's to throughput.png's using Imagemagick
+ throughput_paths:List[str] = [os.path.join(output_folder, f'{base_filename[:-4]}-{size_index}.png') for size_index in range(len(sizes))]
+ size_index:int = 0
+ # print(inputs)
+ input:Dict[str, int | str] = inputs.pop(0)
+ for size_index in range(len(sizes)):
+ # Go to next input if the current needed size is greater than input's maximum
+ if sizes[size_index] > input['maximum_size']:
+ input:Dict[str, int | str] = inputs.pop(0)
+ # print(input)
+ current_size:int = sizes[size_index]
+ throughput_path:str = throughput_paths[size_index]
+ try:
+ # magick convert -background transparent -resize x
+ subprocess.run([
+ 'magick',
+ 'convert',
+ '-background', 'transparent',
+ input['path'],
+ '-resize', f'{current_size}x{current_size}',
+ throughput_path
+ ], check=True)
+ # print(f"Converted {base_filename} to {throughput_path}")
+ except subprocess.CalledProcessError as e:
+ print(f"SVG2PNG: Error converting {base_filename}: {e}")
+ size_index += 1
+
+ # Step 2: Combine throughput.png's to final output.ico using Imagemagick
+ output_filename:str = os.path.splitext(base_filename)[0] + '.ico'
+ output_path:str = os.path.join(output_folder, output_filename)
+ try:
+ # magick convert input-1.png input-2.png ... input-n.png output.ico
+ subprocess.run([
+ 'magick',
+ 'convert',
+ '-background', 'transparent',]
+ + throughput_paths
+ + [output_path],
+ check=True)
+ print(f"Converted {base_filename} to {output_filename}")
+ except subprocess.CalledProcessError as e:
+ print(f"PNG2ICO: Error converting {base_filename}: {e}")
+
+ # Create output folder if it doesn't exist
+ Path(output_folder).mkdir(parents=True, exist_ok=True)
+ for throughput_path in throughput_paths:
+ os.remove(throughput_path)
+
+if __name__ == "__main__":
+ input_folder:str = "test_svg/" # Input folder containing .svg files
+ output_folder:str = "test_ico/" # Output folder for converted .ico files (sizes 16, 32, 48, 64, 256)
+
+ convert_svg_to_ico(input_folder, output_folder)
\ No newline at end of file
From 5cf61d6bc37daf3724bc0c0b0d790a225127e3af Mon Sep 17 00:00:00 2001
From: Cyklon_3000 <67823272+Cyklon3000@users.noreply.github.com>
Date: Fri, 23 Aug 2024 23:00:22 +0200
Subject: [PATCH 2/4] Revert "ci: add python script for batch svg to .ico
conversion"
This reverts commit c05b7103a2ffa0fd42244215c319dd073e66648b.
---
batch_convert_to_ico.py | 99 -----------------------------------------
1 file changed, 99 deletions(-)
delete mode 100644 batch_convert_to_ico.py
diff --git a/batch_convert_to_ico.py b/batch_convert_to_ico.py
deleted file mode 100644
index 562593b6..00000000
--- a/batch_convert_to_ico.py
+++ /dev/null
@@ -1,99 +0,0 @@
-import os
-import subprocess
-from pathlib import Path
-from typing import Tuple, List, Dict
-
-def convert_svg_to_ico(input_folder:str, output_folder:str, sizes:Tuple[int, ...]=(16,32,48,64,256)):
- """
- Converts a folder of .svg icons to a folder of .ico icons of various sizes.
- Icons can be swapped based on a maximum size attributed to .svg icons, if their name ends with '-{size}px.svg'.
- This function requires Imagemagick to be installed.
-
- Args:
- input_folder (str): The path to the folder containing the .svg icons.
- output_folder (str): The path to the folder where the .ico icons will be saved.
- sizes (Tuple[int, ...], optional): The sizes of the .ico icons. Defaults to (16, 32, 48, 64, 256).
- """
-
- def ends_with_px(string:str) -> bool:
- if not string.endswith('px'): return False
- parts:Tuple[str, ...] = string.rsplit('-', 1)
- if len(parts) != 2: return False
- return parts[1][:-2].isdigit()
-
- sizes = sorted(sizes)
-
- base_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
- and not any([ends_with_px(filename[:-4].lower()) for s in sizes])]
- alt_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
- and any([ends_with_px(filename[:-4].lower()) for s in sizes[:-1]])]
-
- # Iterate through all base .svg files in the input folder
- for base_filename in base_filenames:
- # print(base_filename)
- inputs:List[Dict[str, int | str]] = []
-
- for size in sizes:
- assumed_filename:str = base_filename[:-4] + f'-{size}px.svg'
- if assumed_filename not in alt_filenames: continue
-
- alt_input_path:str = os.path.join(input_folder, assumed_filename)
-
- inputs.append({'path': alt_input_path, 'maximum_size': size})
-
- # Add version that comes for sizes above alt max sizes
- inputs.append({'path': os.path.join(input_folder, base_filename), 'maximum_size': sizes[-1]})
-
- # Step 1: Convert input.svg's to throughput.png's using Imagemagick
- throughput_paths:List[str] = [os.path.join(output_folder, f'{base_filename[:-4]}-{size_index}.png') for size_index in range(len(sizes))]
- size_index:int = 0
- # print(inputs)
- input:Dict[str, int | str] = inputs.pop(0)
- for size_index in range(len(sizes)):
- # Go to next input if the current needed size is greater than input's maximum
- if sizes[size_index] > input['maximum_size']:
- input:Dict[str, int | str] = inputs.pop(0)
- # print(input)
- current_size:int = sizes[size_index]
- throughput_path:str = throughput_paths[size_index]
- try:
- # magick convert -background transparent -resize x
- subprocess.run([
- 'magick',
- 'convert',
- '-background', 'transparent',
- input['path'],
- '-resize', f'{current_size}x{current_size}',
- throughput_path
- ], check=True)
- # print(f"Converted {base_filename} to {throughput_path}")
- except subprocess.CalledProcessError as e:
- print(f"SVG2PNG: Error converting {base_filename}: {e}")
- size_index += 1
-
- # Step 2: Combine throughput.png's to final output.ico using Imagemagick
- output_filename:str = os.path.splitext(base_filename)[0] + '.ico'
- output_path:str = os.path.join(output_folder, output_filename)
- try:
- # magick convert input-1.png input-2.png ... input-n.png output.ico
- subprocess.run([
- 'magick',
- 'convert',
- '-background', 'transparent',]
- + throughput_paths
- + [output_path],
- check=True)
- print(f"Converted {base_filename} to {output_filename}")
- except subprocess.CalledProcessError as e:
- print(f"PNG2ICO: Error converting {base_filename}: {e}")
-
- # Create output folder if it doesn't exist
- Path(output_folder).mkdir(parents=True, exist_ok=True)
- for throughput_path in throughput_paths:
- os.remove(throughput_path)
-
-if __name__ == "__main__":
- input_folder:str = "test_svg/" # Input folder containing .svg files
- output_folder:str = "test_ico/" # Output folder for converted .ico files (sizes 16, 32, 48, 64, 256)
-
- convert_svg_to_ico(input_folder, output_folder)
\ No newline at end of file
From c152e24887e96850cd1791881a5fd7c067f96cf2 Mon Sep 17 00:00:00 2001
From: Cyklon_3000 <67823272+Cyklon3000@users.noreply.github.com>
Date: Fri, 23 Aug 2024 23:09:01 +0200
Subject: [PATCH 3/4] feat: add python script for batch svg to .ico conversion
---
batch_convert_to_ico.py | 107 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
create mode 100644 batch_convert_to_ico.py
diff --git a/batch_convert_to_ico.py b/batch_convert_to_ico.py
new file mode 100644
index 00000000..2a05b6b2
--- /dev/null
+++ b/batch_convert_to_ico.py
@@ -0,0 +1,107 @@
+import os
+from typing import Tuple, List, Dict
+import subprocess
+from pathlib import Path
+
+def convert_svg_to_ico(input_folder:str, output_folder:str, sizes:Tuple[int, ...]=(16,32,48,64,256)):
+ """
+ Converts a folder of .svg icons to a folder of .ico icons of various sizes.
+ Icons can be swapped based on a maximum size attributed to .svg icons, if their name ends with '-{size}px.svg'.
+ This function requires Imagemagick to be installed.
+
+ Args:
+ input_folder (str): The path to the folder containing the .svg icons.
+ output_folder (str): The path to the folder where the .ico icons will be saved.
+ sizes (Tuple[int, ...], optional): The sizes of the .ico icons. Defaults to (16, 32, 48, 64, 256).
+ """
+
+ def ends_with_px(string:str) -> bool:
+ if not string.endswith('px'): return False
+ parts:Tuple[str, ...] = string.rsplit('-', 1)
+ if len(parts) != 2: return False
+ return parts[1][:-2].isdigit()
+
+ sizes = sorted(sizes)
+
+ base_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
+ and not any([ends_with_px(filename[:-4].lower()) for s in sizes])]
+ alt_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
+ and any([ends_with_px(filename[:-4].lower()) for s in sizes[:-1]])]
+
+ # Iterate through all base .svg files in the input folder
+ for base_filename in base_filenames:
+ # print(base_filename)
+ inputs:List[Dict[str, int | str]] = []
+
+ for size in sizes:
+ assumed_filename:str = base_filename[:-4] + f'-{size}px.svg'
+ if assumed_filename not in alt_filenames: continue
+
+ alt_input_path:str = os.path.join(input_folder, assumed_filename)
+
+ inputs.append({'path': alt_input_path, 'maximum_size': size})
+
+ # Add version that comes for sizes above alt max sizes
+ inputs.append({'path': os.path.join(input_folder, base_filename), 'maximum_size': sizes[-1]})
+
+ # Step 1: Convert input.svg's to throughput.png's using Imagemagick
+ throughput_paths:List[str] = [os.path.join(output_folder, f'{base_filename[:-4]}-{size_index}.png') for size_index in range(len(sizes))]
+ size_index:int = 0
+ # print(inputs)
+ input:Dict[str, int | str] = inputs.pop(0)
+ for size_index in range(len(sizes)):
+ # Go to next input if the current needed size is greater than input's maximum
+ if sizes[size_index] > input['maximum_size']:
+ input:Dict[str, int | str] = inputs.pop(0)
+ # print(input)
+ current_size:int = sizes[size_index]
+ throughput_path:str = throughput_paths[size_index]
+ try:
+ # magick convert -background transparent -resize x
+ subprocess.run([
+ 'magick',
+ 'convert',
+ '-background', 'transparent',
+ input['path'],
+ '-resize', f'{current_size}x{current_size}',
+ throughput_path
+ ], check=True)
+ # print(f"Converted {base_filename} to {throughput_path}")
+ except subprocess.CalledProcessError as e:
+ print(f"SVG2PNG: Error converting {base_filename}: {e}")
+ size_index += 1
+
+ # Step 2: Combine throughput.png's to final output.ico using Imagemagick
+ output_filename:str = os.path.splitext(base_filename)[0] + '.ico'
+ output_path:str = os.path.join(output_folder, output_filename)
+ try:
+ # magick convert input-1.png input-2.png ... input-n.png output.ico
+ subprocess.run([
+ 'magick',
+ 'convert',
+ '-background', 'transparent',]
+ + throughput_paths
+ + [output_path],
+ check=True)
+ print(f"Converted {base_filename} to {output_filename}")
+ except subprocess.CalledProcessError as e:
+ print(f"PNG2ICO: Error converting {base_filename}: {e}")
+
+ # Create output folder if it doesn't exist
+ Path(output_folder).mkdir(parents=True, exist_ok=True)
+ for throughput_path in throughput_paths:
+ os.remove(throughput_path)
+
+if __name__ == "__main__":
+ # Input folder containing .svg files
+ input_folder:str = input("Input folder (leave blank for default): ")
+ # Output folder for converted .ico files
+ output_folder:str = input("Output folder (leave blank for default): ")
+ # List of icon sizes
+ sizes:List[int] = [s for s in map(int, input("Icon sizes (leave blank for default): ").split()) if s > 0]
+
+ input_folder = "svg/" if not input_folder else input_folder
+ output_folder = "ico/" if not output_folder else output_folder
+ sizes = [16, 32, 48, 64, 256] if not sizes else sizes
+
+ convert_svg_to_ico(input_folder, output_folder)
\ No newline at end of file
From 5e116ab52668a881e328477914370f2d05ef7d77 Mon Sep 17 00:00:00 2001
From: Cyklon_3000 <67823272+Cyklon3000@users.noreply.github.com>
Date: Fri, 23 Aug 2024 23:52:57 +0200
Subject: [PATCH 4/4] docs: updated readme with relevant formatting information
---
README.md | 2 ++
batch_convert_to_ico.py | 17 ++++++++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index dac03353..9d0c7de5 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,7 @@ We provided svg, ai, and fig template to make it easier. The specifications incl
- Name of the icon must be written in snake case.
- Because of we should not replace existing icon, new icon must be numbered that starts with 1.
- First icon must be not numbered.
+- If an icon variant for an existing icon is created it's maximum size in pixel - seperated with a dash, after potential numbering - is appended. The size must be followed by the unit shorthand 'px'.
```
Folder11
@@ -56,6 +57,7 @@ Folder11
├──📄 my_folder.svg
├──📄 my_folder-1.svg
└──📄 my_folder-2.svg
+ └──📄 my_folder-2-32px.svg
```
### Commit Naming
diff --git a/batch_convert_to_ico.py b/batch_convert_to_ico.py
index 2a05b6b2..5b0df76d 100644
--- a/batch_convert_to_ico.py
+++ b/batch_convert_to_ico.py
@@ -21,6 +21,14 @@ def ends_with_px(string:str) -> bool:
if len(parts) != 2: return False
return parts[1][:-2].isdigit()
+ def delete_folder(folder_path):
+ folder = Path(folder_path)
+ if folder.exists() and folder.is_dir():
+ for item in folder.iterdir():
+ if item.is_file():
+ item.unlink()
+ folder.rmdir()
+
sizes = sorted(sizes)
base_filenames:List[str] = [filename for filename in os.listdir(input_folder) if filename.lower().endswith('.svg')
@@ -45,7 +53,8 @@ def ends_with_px(string:str) -> bool:
inputs.append({'path': os.path.join(input_folder, base_filename), 'maximum_size': sizes[-1]})
# Step 1: Convert input.svg's to throughput.png's using Imagemagick
- throughput_paths:List[str] = [os.path.join(output_folder, f'{base_filename[:-4]}-{size_index}.png') for size_index in range(len(sizes))]
+ Path("temp_pngs").mkdir(parents=True, exist_ok=True)
+ throughput_paths:List[str] = [os.path.join("temp_pngs", f'{base_filename[:-4]}-{size_index}.png') for size_index in range(len(sizes))]
size_index:int = 0
# print(inputs)
input:Dict[str, int | str] = inputs.pop(0)
@@ -72,6 +81,7 @@ def ends_with_px(string:str) -> bool:
size_index += 1
# Step 2: Combine throughput.png's to final output.ico using Imagemagick
+ Path(output_folder).mkdir(parents=True, exist_ok=True)
output_filename:str = os.path.splitext(base_filename)[0] + '.ico'
output_path:str = os.path.join(output_folder, output_filename)
try:
@@ -87,10 +97,7 @@ def ends_with_px(string:str) -> bool:
except subprocess.CalledProcessError as e:
print(f"PNG2ICO: Error converting {base_filename}: {e}")
- # Create output folder if it doesn't exist
- Path(output_folder).mkdir(parents=True, exist_ok=True)
- for throughput_path in throughput_paths:
- os.remove(throughput_path)
+ delete_folder("temp_pngs")
if __name__ == "__main__":
# Input folder containing .svg files