Compare commits
No commits in common. "a2f3fb084800c6bf5044bd23509de5d6a371a455" and "2d8cd7fd79a0f6c792427dd163d898558f652391" have entirely different histories.
a2f3fb0848
...
2d8cd7fd79
@ -1,158 +0,0 @@
|
|||||||
from xml.etree import ElementTree
|
|
||||||
import subprocess
|
|
||||||
import tempfile
|
|
||||||
import zipfile
|
|
||||||
import shutil
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
from PIL import Image, ImageOps
|
|
||||||
from modules import logger
|
|
||||||
|
|
||||||
RATIO = 16/9 # 16:9
|
|
||||||
|
|
||||||
|
|
||||||
def get_elements(root, attribute):
|
|
||||||
return [i for i in root if i.tag == attribute]
|
|
||||||
|
|
||||||
def get_element(root, attribute):
|
|
||||||
elems = get_elements(root, attribute)
|
|
||||||
|
|
||||||
if len(elems) > 1:
|
|
||||||
print(f"More than one '{attribute}' found", file=sys.stderr)
|
|
||||||
if len(elems) == 0:
|
|
||||||
raise IndexError(f"No '{attribute}' found !")
|
|
||||||
|
|
||||||
return elems[0]
|
|
||||||
|
|
||||||
def create_pagebreaks(data):
|
|
||||||
"""
|
|
||||||
Replaces all manual linebreaks by pagebreaks in a .mscx file (xml)
|
|
||||||
"""
|
|
||||||
root = ElementTree.fromstring(data)
|
|
||||||
|
|
||||||
score = get_element(root, "Score")
|
|
||||||
parts = get_elements(score, "Part")
|
|
||||||
staffs = get_elements(score, "Staff")
|
|
||||||
for part in parts:
|
|
||||||
staffs += get_elements(part, "Staff")
|
|
||||||
|
|
||||||
changes = 0
|
|
||||||
for staff in staffs:
|
|
||||||
measures = get_elements(staff, "Measure")
|
|
||||||
for measure in measures:
|
|
||||||
layoutbreaks = get_elements(measure, "LayoutBreak")
|
|
||||||
for layoutbreak in layoutbreaks:
|
|
||||||
subtype = get_element(layoutbreak, "subtype")
|
|
||||||
if subtype.text == "line":
|
|
||||||
subtype.text = "page"
|
|
||||||
changes += 1
|
|
||||||
|
|
||||||
|
|
||||||
return ElementTree.tostring(root), changes
|
|
||||||
|
|
||||||
def remove_footer(data):
|
|
||||||
"""
|
|
||||||
Disable page footer in .mss (xml)
|
|
||||||
"""
|
|
||||||
root = ElementTree.fromstring(data)
|
|
||||||
|
|
||||||
style = get_element(root, "Style")
|
|
||||||
show_footer = get_element(style, "showFooter")
|
|
||||||
show_footer.text = 0
|
|
||||||
|
|
||||||
return ElementTree.tostring(root)
|
|
||||||
|
|
||||||
def prepare_mscz(source, dest):
|
|
||||||
shutil.copy(source, dest)
|
|
||||||
with zipfile.ZipFile(source) as inzip, zipfile.ZipFile(dest, "w") as outzip:
|
|
||||||
for inzipinfo in inzip.infolist():
|
|
||||||
with inzip.open(inzipinfo) as infile:
|
|
||||||
if inzipinfo.filename.endswith(".mscx"):
|
|
||||||
new_data, changes = create_pagebreaks(infile.read())
|
|
||||||
outzip.writestr(inzipinfo.filename, new_data)
|
|
||||||
elif inzipinfo.filename.endswith(".mss"):
|
|
||||||
new_data = remove_footer(infile.read())
|
|
||||||
outzip.writestr(inzipinfo.filename, new_data)
|
|
||||||
else:
|
|
||||||
outzip.writestr(inzipinfo.filename, infile.read())
|
|
||||||
|
|
||||||
def generate_images(mscz_file, base_dest):
|
|
||||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
|
||||||
tmp_mscz = os.path.join(tmpdirname, "score.mscz")
|
|
||||||
prepare_mscz(mscz_file, tmp_mscz)
|
|
||||||
logger.log(".mscz file patched")
|
|
||||||
|
|
||||||
subprocess.call(["mscore", tmp_mscz, "-o", base_dest+".png"])
|
|
||||||
subprocess.call(["mscore", mscz_file, "-o", base_dest+"-short.png"])
|
|
||||||
logger.log("Images generated")
|
|
||||||
|
|
||||||
def crop_image(file):
|
|
||||||
"""
|
|
||||||
Crop white bottom and top of an image
|
|
||||||
"""
|
|
||||||
def pixel_diff(px0, px1):
|
|
||||||
return abs(px0[0]-px1[0])+abs(px0[1]-px1[1])+abs(px0[2]-px1[2])
|
|
||||||
|
|
||||||
img = Image.open(file).convert("RGB")
|
|
||||||
|
|
||||||
min_non_white, max_non_white = 0, img.height
|
|
||||||
for y in range(img.height):
|
|
||||||
non_white = False
|
|
||||||
for x in range(img.width):
|
|
||||||
if img.getpixel((x, y)) != (255, 255, 255):
|
|
||||||
non_white = True
|
|
||||||
break
|
|
||||||
if non_white:
|
|
||||||
break
|
|
||||||
min_non_white += 1
|
|
||||||
|
|
||||||
for y in range(img.height-1, -1, -1):
|
|
||||||
non_white = False
|
|
||||||
for x in range(img.width):
|
|
||||||
if img.getpixel((x, y)) != (255, 255, 255):
|
|
||||||
non_white = True
|
|
||||||
break
|
|
||||||
if non_white:
|
|
||||||
break
|
|
||||||
max_non_white -= 1
|
|
||||||
|
|
||||||
img.crop((0, min_non_white, img.width-1, max_non_white)).save(file)
|
|
||||||
return img.width, max_non_white - min_non_white
|
|
||||||
|
|
||||||
|
|
||||||
def adjust_images(images):
|
|
||||||
width, height = -1, -1
|
|
||||||
for img_file in images:
|
|
||||||
logger.log(f"Cropping {img_file}")
|
|
||||||
w, h = crop_image(img_file)
|
|
||||||
width = width if w < width else w
|
|
||||||
height = height if h < height else h
|
|
||||||
|
|
||||||
logger.log("Images cropped")
|
|
||||||
|
|
||||||
width += 50 # Add some padding
|
|
||||||
height += 50
|
|
||||||
if width / height < RATIO:
|
|
||||||
width = int(height*RATIO)
|
|
||||||
else:
|
|
||||||
height = int(width/RATIO)
|
|
||||||
|
|
||||||
for img_file in images:
|
|
||||||
img = Image.open(img_file).convert("RGB")
|
|
||||||
ImageOps.pad(img, size=(width, height), color="white").save(img_file)
|
|
||||||
|
|
||||||
logger.log("Padding added")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
if len(sys.argv) < 3:
|
|
||||||
print(f"Usage: {sys.argv[0]} <score.mscz> <out_basename>", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
generate_images(sys.argv[1], sys.argv[2])
|
|
||||||
adjust_images([
|
|
||||||
img for img in os.listdir(os.path.dirname(sys.argv[2])) if
|
|
||||||
img.startswith(os.path.basename(sys.argv[2])) and img.endswith(".png") and "short" not in img
|
|
||||||
])
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
|||||||
import time
|
|
||||||
|
|
||||||
starting_time = time.time()
|
|
||||||
|
|
||||||
def log(*args, **kwargs):
|
|
||||||
print(f"[{round(time.time()-starting_time, 3):>8}] ", *args, **kwargs)
|
|
Loading…
Reference in New Issue
Block a user