This repository has been archived by the owner on Aug 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from SnowzNZ/dev
Dev
- Loading branch information
Showing
7 changed files
with
768 additions
and
153 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,20 @@ | ||
# HD2SD | ||
|
||
<img src="https://media.discordapp.net/attachments/1044134327434358847/1049529615762333716/image.png"> | ||
|
||
[![CodeFactor](https://www.codefactor.io/repository/github/snowznz/hd2sd/badge)](https://www.codefactor.io/repository/github/snowznz/hd2sd) | ||
|
||
High Definition to Standard Definition converter for osu! skins. | ||
|
||
Contact: <https://twitter.com/Snowz2k> | ||
|
||
I am not responsible for any damage caused to your skins by this program. This can be caused by overwriting files. Make sure to backup any important files before running. | ||
Easily convert @2x (HD) images to SD. | ||
|
||
## Usage | ||
- Download the latest executable from the [releases](https://github.com/SnowzNZ/HD2SD/releases/latest). | ||
- Run `HD2SD.exe`. | ||
|
||
- Download [latest release](https://github.com/SnowzNZ/HD2SD/releases/latest) | ||
|
||
- Run HD2SD.exe | ||
#### Manual Installation | ||
```sh | ||
git clone https://github.com/SnowzNZ/HD2SD | ||
cd HD2SD | ||
pip install -r requirements.txt | ||
|
||
- Building from source | ||
py main.py | ||
``` | ||
|
||
- Download ZIP and extract it or | ||
## License | ||
|
||
```sh | ||
git clone https://github.com/SnowzNZ/HD2SD | ||
cd HD2SD | ||
pip install -r requirements.txt | ||
pyinstaller --noconfirm --onefile --windowed --add-data "%localappdata%/Programs/Python/Python311/Lib/site-packages/customtkinter;customtkinter/" "main.py" | ||
``` | ||
This project is licensed under the GPL-3.0 License - see the [LICENSE.md](https://github.com/SnowzNZ/HD2SD/blob/main/LICENCE.md) file for details |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# HD2SD Planned Features | ||
|
||
|
||
### Todo | ||
|
||
- [ ] Add option to change Resampling algorithm | ||
- [ ] Add option to change downscale/upscale size | ||
- [ ] Ask if the user wishes to overwrite existing SD images | ||
- [ ] Add option to include sub-directories | ||
- [ ] Add GitHub Actions workflow for pyinstaller |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,79 @@ | ||
""" | ||
Program to convert HD images to SD | ||
Create SD images for osu! skins by downscaling HD images by 50% | ||
""" | ||
|
||
import glob | ||
import threading | ||
from tkinter import filedialog, messagebox | ||
import os | ||
import textwrap | ||
import time | ||
from tkinter import filedialog | ||
|
||
import customtkinter # type: ignore | ||
import readchar | ||
from pick import pick | ||
from PIL import Image | ||
|
||
customtkinter.set_appearance_mode("System") | ||
customtkinter.set_default_color_theme("blue") | ||
|
||
|
||
class App(customtkinter.CTk): | ||
"""GUI""" | ||
|
||
WIDTH = 350 | ||
HEIGHT = 200 | ||
|
||
def __init__(self): | ||
super().__init__() | ||
|
||
self.title("HD2SD") | ||
self.geometry(f"{App.WIDTH}x{App.HEIGHT}") | ||
self.protocol("WM_DELETE_WINDOW", self.on_closing) | ||
self.resizable(False, False) | ||
self.filename = None | ||
|
||
self.button_folder = customtkinter.CTkButton( | ||
master=self, | ||
width=250, | ||
height=30, | ||
border_width=0, | ||
corner_radius=30, | ||
text="Select Skin Folder", | ||
command=self.select_folder, | ||
text_color_disabled="#000", | ||
) | ||
self.button_folder.place( | ||
relx=0.5, rely=0.2, anchor=customtkinter.CENTER | ||
) | ||
|
||
self.entry = customtkinter.CTkEntry( | ||
master=self, placeholder_text="", state="disabled", width=250 | ||
) | ||
self.entry.place(relx=0.5, rely=0.35, anchor=customtkinter.CENTER) | ||
|
||
self.button_convert = customtkinter.CTkButton( | ||
master=self, | ||
width=250, | ||
height=30, | ||
border_width=0, | ||
corner_radius=30, | ||
text="Convert!", | ||
command=self.start_convert, | ||
) | ||
self.button_convert.place( | ||
relx=0.5, rely=0.62, anchor=customtkinter.CENTER | ||
) | ||
self.button_convert.configure(state="disabled") | ||
|
||
self.progressbar = customtkinter.CTkProgressBar(master=self, width=250) | ||
self.progressbar.place( | ||
relx=0.5, rely=0.73, anchor=customtkinter.CENTER | ||
) | ||
self.progressbar.set(0) | ||
|
||
def start_convert(self): | ||
"""Start the convert function""" | ||
threading.Thread(target=self.convert).start() | ||
self.progressbar.set(0) | ||
|
||
def convert(self): | ||
"""Convert all @2x images to SD""" | ||
images_converted = 0 | ||
confirm = messagebox.askquestion( | ||
"HD2SD", "Are you sure you want to convert your HD files to SD?" | ||
) | ||
if confirm == "yes": | ||
hd_images = glob.glob(rf"{self.filename}/*@2x.png") | ||
|
||
for i in hd_images: | ||
images_converted += 1 | ||
progress = images_converted / len(hd_images) | ||
hd_image = Image.open(i) | ||
x_pos, y_pos = hd_image.size | ||
if x_pos >= 2 and y_pos >= 2: | ||
size = (x_pos // 2, y_pos // 2) | ||
else: | ||
size = (x_pos, y_pos) | ||
hd_image = hd_image.resize(size, Image.Resampling.LANCZOS) | ||
name = i.split("@") | ||
hd_image.save(f"{name}.png") | ||
self.progressbar.set(progress) | ||
messagebox.showinfo("HD2SD", "Conversion Complete!") | ||
from tqdm import tqdm | ||
|
||
print( | ||
""" | ||
HD2SD Copyright (C) 2023 SnowzNZ | ||
This program comes with ABSOLUTELY NO WARRANTY. | ||
This is free software, and you are welcome to redistribute it | ||
under certain conditions. | ||
""" | ||
) | ||
|
||
# Default location for osu! skins | ||
default_skin_path = os.path.join(os.environ["LOCALAPPDATA"], "osu!", "Skins") | ||
|
||
# Check if the path exists | ||
if os.path.exists(default_skin_path): | ||
folder_path = filedialog.askdirectory(initialdir=default_skin_path) | ||
else: | ||
folder_path = filedialog.askdirectory() | ||
|
||
# Ask the user if they wish to continue | ||
option, _ = pick( | ||
["Yes", "No"], | ||
textwrap.fill(f"Selected Folder: {folder_path}") | ||
+ "\n\nAre you sure you wish to continue?", | ||
) | ||
|
||
if option == "Yes": | ||
# Get start time of process | ||
start_time = time.time() | ||
|
||
# Get every image in the folder | ||
for image in tqdm( | ||
glob.glob(rf"{folder_path}/*@2x.png"), | ||
desc="Converting images to SD", | ||
unit=" image", | ||
): | ||
# Open the HD image | ||
hd_image = Image.open(image) | ||
|
||
# Get the width and height of the image | ||
width, height = hd_image.size | ||
|
||
# Check if the image is more than 1x1 | ||
# If not, break out of the for loop as 1/2 != a whole number | ||
if width > 1 and height > 1: | ||
size = (width // 2, height // 2) | ||
else: | ||
pass | ||
continue | ||
|
||
# Resize the image | ||
hd_image = hd_image.resize(size, Image.Resampling.LANCZOS) | ||
# Save the image as an SD image | ||
hd_image.save(image.replace("@2x", "")) | ||
|
||
def select_folder(self): | ||
"""Choose folder to convert""" | ||
self.filename = filedialog.askdirectory() | ||
self.button_convert.configure(state="normal") | ||
self.entry.configure( | ||
state="normal", placeholder_text=self.filename.split("Skins/")[1] | ||
) | ||
self.entry.configure(state="disabled") | ||
self.button_folder.configure(text="Change Skin Folder") | ||
self.progressbar.set(0) | ||
# Get end time of process | ||
end_time = time.time() | ||
|
||
def on_closing(self): | ||
"""Destroy window on close""" | ||
self.destroy() | ||
# Calculate total time it took | ||
elapsed_time = end_time - start_time | ||
|
||
# Print total time it took to complete | ||
print(f"\nCompleted in {round(elapsed_time, 3)} seconds.") | ||
|
||
if __name__ == "__main__": | ||
app = App() | ||
app.mainloop() | ||
print("Press any key to exit...") | ||
key = readchar.readkey() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
tqdm | ||
pillow | ||
customtkinter | ||
tk | ||
types-Pillow | ||
pick | ||
readchar |