Created
June 28, 2018 20:48
-
-
Save Victorious3/34b4720b3ad948722b27a6b9114e700c to your computer and use it in GitHub Desktop.
SAI File Converter
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
# sai_converter.py by VicNightfall - https://twitter.com/VicNightfall | |
# | |
# ---------------------------------- README: -------------------------------------------- | |
# First you need to install python, if you haven't done that already. | |
# You can get it from here: https://www.python.org/downloads/ (Just get the newest release) | |
# | |
# You also need to install pywinauto: | |
# pip install pywinauto | |
# | |
# (inside a command prompt, see steps below) | |
# | |
# It needs to be run as Administrator for some reason or | |
# else the import on pywinauto fails, so make sure you create | |
# an elevated prompt and run it from there: | |
# | |
# type <Win> powershell <Ctrl+Shift+Enter> | |
# | |
# From here you first have to navigate to wherever you saved this file, | |
# this might be your Downloads folder. I recommend moving it to where your pictures are, | |
# that makes specifying the other arguments a lot easier. | |
# | |
# In my case: | |
# | |
# cd C:\Users\Vic\Downloads | |
# | |
# Once you are inside here you can run the script with | |
# | |
# py sai_converter.py -h | |
# | |
# This will show all the options for it. | |
# | |
# You can contact me on twitter if you have any questions. | |
# Tested with SAI 1.2.5, other versions might not work. | |
import ctypes, sys | |
if not ctypes.windll.shell32.IsUserAnAdmin(): # Requires elevated priviliges | |
print("You have to run this script with Administrator privileges!") | |
exit(-1) | |
import time, os, argparse | |
from pywinauto import application, keyboard, findwindows | |
from glob import glob | |
extensions = ["psd", "bmp", "jpg", "png", "tga"] | |
scales = ["6.25%", "12.5%", "25%", "50%", "100%", "200%", "400%", "800%", "1600%"] | |
parser = argparse.ArgumentParser(description = "Convert .sai files into another program") | |
parser.add_argument("file", type = str, nargs = '+', help = "List of files to convert") | |
parser.add_argument("-e", "--extension", choices = extensions, help = "File extension to convert to", required = True) | |
parser.add_argument("-o", "--out", type = str, help = "Output directory", default = os.getcwd()) | |
parser.add_argument("--overwrite", action = "store_true", help = "Overwrite already existing files") | |
parser.add_argument("--sai", help = "Path to sai executable") | |
png_opt = parser.add_argument_group("png") | |
png_opt.add_argument("--no-opacity", action = "store_true", help = "Export png files without opacity") | |
jpg_opt = parser.add_argument_group("jpg") | |
jpg_opt.add_argument("--scale", type = str, choices = scales, help = "Output image scaling", default = "100%") | |
jpg_opt.add_argument("--compressed", action = "store_true", help = "Enable jpg compression (Lower file size and lower quality)") | |
jpg_opt.add_argument("--quality", type = int, choices = range(0, 101), metavar="[0-100]", help = "Quality, in percent", default = 100) | |
args = parser.parse_args() | |
if args.sai is None: | |
sai_exec = "C:\\Program Files (x86)\\PaintToolSAI\\sai.exe" | |
if not os.path.isfile(sai_exec): | |
sai_exec = "C:\\PaintToolSAI\\sai.exe" | |
if not os.path.isfile(sai_exec): | |
print("Can't find the sai executable, please specify it with --sai") | |
exit(-1) | |
else: | |
sai_exec = args.sai | |
if not os.path.isfile(sai_exec): | |
print("--sai: Not a valid file") | |
exit(-1) | |
extension = extensions.index(args.extension) + 1 # This is how often we need to press down | |
extension = "{VK_DOWN}" * extension # So make a string from it | |
if not os.path.isdir(args.out): | |
print("--out: Not a valid path name") | |
exit(-1) | |
args.out = os.path.abspath(args.out) | |
files = [] | |
for fstr in args.file: | |
for filename in glob(fstr): | |
if not (filename.endswith(".sai") or filename.endswith(".sai2")): continue # Skip all non sai files | |
files.append(os.path.abspath(filename)) | |
if not files: | |
print("No files specified!") | |
app = application.Application() | |
try: | |
app.connect(path = sai_exec, timeout = 0) | |
print("SAI is already running! Please close it before you run the converter.") | |
exit(-1) | |
except application.ProcessNotFoundError: | |
pass | |
for file in files: | |
if not os.path.exists(file): | |
print("Skipping: " + file + " - Files does not exist") | |
continue | |
app.start(sai_exec + " " + file) | |
time.sleep(0.5) | |
sai = app.window(title_re="SAI") | |
time.sleep(0.5) | |
sai.type_keys("%F%E" + extension + "{ENTER}") | |
time.sleep(0.5) | |
save_dialog = app["Save Canvas"] # Save Canvas Dialog | |
save_dialog[2].click() | |
save_dialog[2].type_keys(args.out, with_spaces = True, pause = 0) | |
save_dialog[2].type_keys("{ENTER}") | |
# save_dialog[15] - File name | |
save_dialog.Save.click() | |
if save_dialog.exists(): # Popup | |
if args.overwrite: app.top_window()["&Yes"].click() | |
else: | |
app.top_window()["&No"].click() | |
app.kill() | |
print("Skipping: " + file + " - File already exists") | |
continue | |
# Additional arguments here | |
if args.extension == "png": | |
png_options = app.top_window() | |
if args.no_opacity: | |
png_options.child_window(title_re="24").click() | |
else: | |
png_options.child_window(title_re="32").click() | |
png_options["OK"].click() | |
elif args.extension == "jpg": | |
jpg_options = app.top_window() | |
# Compression switch | |
button_height = (jpg_options[1].Rectangle().height() - 2) // 2 | |
if args.compressed: | |
jpg_options[1].click(button = 'left', coords = (0, button_height + button_height // 2)) | |
else: | |
jpg_options[1].click(button = 'left', coords = (0, button_height - button_height // 2)) | |
# Scale switch | |
scale = scales.index(args.scale) | |
button_height = (jpg_options[2].Rectangle().height() - 2) // 9 | |
jpg_options[2].click(button = 'left', coords = (0, button_height * scale + button_height // 2)) | |
# Quality switch | |
width = jpg_options[6].Rectangle().width() - 2 | |
print(args.quality / 100 * width, width) | |
jpg_options[6].click(button = 'left', coords = (int(args.quality / 100 * width), 0)) | |
jpg_options["OK"].click() | |
sai.wait("enabled", timeout = 30) # Wait for save to finish | |
print("Converted: " + file + " -> " + args.out + "\\" + os.path.splitext(os.path.basename(file))[0] + "." + args.extension) | |
app.kill() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment