I’ve got a process I’m happy with: I can generate and export image automatically via scripting and manually tweak masks using Krita.
-
I manually created this template.kra. It’s a 1x1 pixel file with s transparent paint layer called Image with an empty transparency mask called Mask.
-
I use kritarunner to run a script that makes a directory of .kra files from a directory of images and masks (which I create with remgb).
print('-- SCRIPT BEGIN --')
from contextlib import closing, suppress
from pathlib import Path
import shutil
from typing import Final
from PIL import Image
from PyKrita.krita import Krita
ROOT_DIR: Final = Path(__file__).resolve().parent
TEMPLATE_PATH: Final = ROOT_DIR / 'template.kra'
def create_path(dir_name: str, stem: str, suffix: str) -> Path:
return (ROOT_DIR / dir_name / stem).with_suffix(suffix)
def create_kra(krita: Krita, image_path: Path):
image_stem = image_path.stem
r, g, b, a = Image.open(image_path).convert('RGBA').split()
image = Image.merge('RGBA', [b, g, r, a])
mask_path = create_path('maskes', image_stem, '.png')
mask = Image.open(mask_path).convert('L')
size = (0, 0, image.width, image.height)
with closing(krita.openDocument(str(TEMPLATE_PATH))) as document:
document.resizeImage(*size)
for name, pil_image in [('Image', image), ('Mask', mask)]:
document.nodeByName(name).setPixelData(pil_image.tobytes(), *size)
kra_path = create_path('kra', image_stem, '.kra')
document.saveAs(str(kra_path))
def main(argv: list[str]) -> None:
kra_dir = ROOT_DIR / 'kra'
with suppress(FileNotFoundError):
shutil.rmtree(kra_dir)
kra_dir.mkdir()
krita = Krita.instance()
for image_path in (ROOT_DIR / 'originals').iterdir():
print('Creating .kra for', image_path.stem)
create_kra(krita, image_path)
print()
print('-- SCRIPT END -- ')
- After manually tweaking the images and masks, I run another script that crops and resizes the images using
pillow
print('-- SCRIPT BEGIN --')
from contextlib import closing, suppress
from math import floor
from pathlib import Path
import shutil
from PIL import Image
from PyKrita.krita import Document, Krita
def clean_dir(dir_path: Path) -> Path:
with suppress(FileNotFoundError):
shutil.rmtree(dir_path)
dir_path.mkdir()
return dir_path
def create_image(document: Document) -> Image.Image:
width = document.width()
height = document.height()
data = document.rootNode().projectionPixelData(0, 0, width, height)
image = Image.frombytes('RGBA', (width, height), data, 'raw', 'BGRA', 0, 1)
return image.crop(image.getbbox())
def export_version(image: Image.Image, output_dir: Path, output_name: str,
max_width: int, max_height: int) -> None:
width = image.width
height = image.height
if (min_scale := min(max_width / width, max_height / height)) < 1:
def scale(value: int) -> int:
return floor(min_scale * value)
image = image.resize((scale(width), scale(height)),
resample=Image.Resampling.LANCZOS)
output_path = output_dir / output_name
print(output_path)
image.save(output_path)
def export_versions(krita: Krita, kra_path: Path, player_dir: Path,
stage_dir: Path) -> None:
with closing(krita.openDocument(str(kra_path))) as document:
image = create_image(document)
output_name = kra_path.with_suffix('.webp').name
export_version(image, player_dir, output_name, 128, 128)
export_version(image, stage_dir, output_name, 1280, 720)
def main(args: list[str]) -> None:
krita = Krita.instance()
root_dir = Path(__file__).resolve().parent
player_dir = clean_dir(root_dir / 'player')
stage_dir = clean_dir(root_dir / 'stage')
for kra_path in (root_dir / 'kra').glob('*.kra'):
export_versions(krita, kra_path, player_dir, stage_dir)
print('-- SCRIPT END --')
Thanks everyone for your help!