Added a simple arranger, which arranges the sections on pages

Output2Img now simply writes all of the sections on a page below each other
This commit is contained in:
Marco van Dijk 2021-07-09 01:40:07 +02:00
parent db9633a855
commit 0767b7c2eb
4 changed files with 131 additions and 68 deletions

View File

@ -36,7 +36,7 @@ def initConfig():
'metaFontWeight': 8, 'metaFontWeight': 8,
'lyricfontfamily': 'fonts/CourierPrime-Regular.ttf', 'lyricfontfamily': 'fonts/CourierPrime-Regular.ttf',
'tablaturefontfamliy': 'fonts/CourierPrime-Bold.ttf', 'tablaturefontfamliy': 'fonts/CourierPrime-Bold.ttf',
'songFontWeight': 18, 'songFontWeight': 14,
'imageWidth': 595, 'imageHeight': 842, # A4 at 72dpi 'imageWidth': 595, 'imageHeight': 842, # A4 at 72dpi
'backgroundColour': '255,255,255', 'backgroundColour': '255,255,255',
'fontColour': '0,0,0', 'fontColour': '0,0,0',

View File

@ -89,9 +89,6 @@ class Section:
self.expectedHeight = -1 self.expectedHeight = -1
"""!@brief Calculates dimensions of rendered text """!@brief Calculates dimensions of rendered text
This function calculates the dimensions of each line of text
the section contains and sets the internal variables
@param section lib.dataStructures.Section object
@return None @return None
""" """
def calculateSectionDimensions(self, fontTablature, fontLyrics): def calculateSectionDimensions(self, fontTablature, fontLyrics):
@ -165,6 +162,13 @@ class Section:
self.lyrics.append("") self.lyrics.append("")
self.isParsed = True self.isParsed = True
"""!@brief Class containing Sections which fit on 1 page
"""
class Page:
def __init__(self):
self.sections = []
self.totalHeight = -1
"""!@brief Class containing Song specific data """!@brief Class containing Song specific data
""" """
class Song: class Song:
@ -179,8 +183,12 @@ class Song:
self.sections = [] self.sections = []
# Meta info: the text before the first section # Meta info: the text before the first section
self.metadata = "" self.metadata = ""
self.metadataWidth = -1
self.metadataHeight = -1
# String of entire input # String of entire input
self.rawData = "" self.rawData = ""
# List of pages, which contain sections which fit on a page
self.pages = []
# Flag for succesfully parsed # Flag for succesfully parsed
self.isParsed = False self.isParsed = False
configObj = lib.config.config['output'] configObj = lib.config.config['output']
@ -197,21 +205,25 @@ class Song:
self.fontTablature = ImageFont.truetype(configObj['tablaturefontfamliy'], self.fontSize) self.fontTablature = ImageFont.truetype(configObj['tablaturefontfamliy'], self.fontSize)
self.configObj = configObj self.configObj = configObj
"""!@brief Calculates the expected dimensions of all sections
"""!@brief Calculates dimensions of metadata
@param section lib.dataStructures.Section object
@return None @return None
""" """
def prerenderSections(self): def calculateMetadataDimensions(self):
for section in self.sections: # metadata starts topMargin removed from top
section.calculateSectionDimensions(self.fontTablature, self.fontLyrics) currentHeight = self.topMargin
maxWidth = 0
"""!@brief Checks whether we are overflowing on the width of the page for line in self.metadata.split('\n'):
@return True if everything OK, False if overflowing line = line.rstrip()
""" if not line:
def checkOverflowX(self): continue
for section in self.sections: metadataTextWidth, metadataTextHeight = self.fontMetadata.getsize(line)
if section.expectedWidth > self.imageWidth: if metadataTextWidth > maxWidth:
return False maxWidth = metadataTextWidth
return True currentHeight += metadataTextHeight
self.metadataWidth = maxWidth
self.metadataHeight = currentHeight
"""!@brief Resizes all sections by a specified amount """!@brief Resizes all sections by a specified amount
Also recalculates all section sizes afterwards Also recalculates all section sizes afterwards
@ -224,6 +236,63 @@ class Song:
self.fontTablature = ImageFont.truetype(self.configObj['tablaturefontfamliy'], self.fontSize) self.fontTablature = ImageFont.truetype(self.configObj['tablaturefontfamliy'], self.fontSize)
self.prerenderSections() self.prerenderSections()
"""!@brief Calculates the expected dimensions of all sections
@return None
"""
def prerenderSections(self):
self.calculateMetadataDimensions()
for section in self.sections:
section.calculateSectionDimensions(self.fontTablature, self.fontLyrics)
"""!@brief Calculates the expected dimensions of all sections
@return None
"""
def fitSectionsByWidth(self):
self.prerenderSections()
while not self.checkOverflowX():
#print("Overflowing on width of the page. Decreasing font size by 2...")
self.resizeAllSections(-2)
"""!@brief Checks whether we are overflowing on the width of the page
@return True if everything OK, False if overflowing
"""
def checkOverflowX(self):
for section in self.sections:
if section.expectedWidth > self.imageWidth:
return False
return True
"""!@brief Fits current sections into pages
@return None
"""
def sectionsToPages(self):
self.prerenderSections()
# First page contains metadata
currentHeight = self.topMargin
currentHeight += self.metadataHeight
currentHeight += self.topMargin
curPage = Page()
# Now fit all sections
for section in self.sections:
if (section.expectedHeight == -1 or section.expectedWidth == -1):
print("Warning: this file was not processed correctly. The expected dimensions are not set")
# See if the section would fit on the current page - if it does not, we have a filled page
if currentHeight + section.expectedHeight > self.imageHeight:
curPage.totalHeight = currentHeight
self.pages.append(curPage)
currentHeight = self.topMargin
curPage = Page()
# Add setion header size and size of lines of data
headerWidth, headerHeight = self.fontTablature.getsize(section.header)
currentHeight += headerHeight
currentHeight += section.expectedHeight
curPage.sections.append(section)
# Margin between each section
currentHeight += self.topMargin
# No more sections left, so the current buffered image is ready to be written to file
curPage.totalHeight = currentHeight
self.pages.append(curPage)
"""!@brief Parses self.rawData into Section objects and metadata """!@brief Parses self.rawData into Section objects and metadata
@return None @return None
""" """

14
main.py
View File

@ -37,17 +37,17 @@ def main():
print("Start parsing of file '{}'...".format(song.inputFile)) print("Start parsing of file '{}'...".format(song.inputFile))
# Initialise internal data structures # Initialise internal data structures
song.initSections() song.initSections()
# Prerender: calculate the expected dimensions for each section # Fit all sections on each page, resizes down if it does not fit on width
song.prerenderSections() song.fitSectionsByWidth()
# While we overflow on X: resize all sections down and recalculate # Prerender: calculate Pages, and move sections into Pages
while not song.checkOverflowX(): song.sectionsToPages()
#print("Overflowing on width of the page. Decreasing font size by 2...") # Optimalisation: check for whitespace, check verhouding of whitespace&first section on next page
song.resizeAllSections(-2) # TODO
# Parse as PNG a4 # Parse as PNG a4
if song.isParsed: if song.isParsed:
# Create subdirectory where we will output our images # Create subdirectory where we will output our images
targetDirectory = song.outputLocation + "-a4-png" targetDirectory = song.outputLocation + "-a4-png"
print("Successfully parsed file. Writing output to '{}'".format(song.inputFile, targetDirectory)) print("Successfully parsed file. Writing output to '{}'".format(targetDirectory))
# Write out metadata and sections, as many as can fit on one page # Write out metadata and sections, as many as can fit on one page
output2img.outputToImage(targetDirectory, song) output2img.outputToImage(targetDirectory, song)

View File

@ -54,10 +54,9 @@ def outputToImage(folderLocation, songObj):
currentHeight += metadataTextHeight currentHeight += metadataTextHeight
# Margin between metadata and the first section # Margin between metadata and the first section
currentHeight += songObj.topMargin currentHeight += songObj.topMargin
# Iterate over each section # Draw all pages
# NOTE: sections might be split into lists of pages containing a list of sections for page in songObj.pages:
# This change will occur when we add an arranger which resizes sections to fit pages better for section in page.sections:
for section in songObj.sections:
# Reset section specific variables # Reset section specific variables
lineIterator = 0 lineIterator = 0
amountOfLines = len(section.lyrics) amountOfLines = len(section.lyrics)
@ -67,15 +66,6 @@ def outputToImage(folderLocation, songObj):
if (section.expectedHeight == -1 or section.expectedWidth == -1): if (section.expectedHeight == -1 or section.expectedWidth == -1):
print("Cannot write this section to file, since it was not processed correctly. The expected dimensions are not set. Aborting...") print("Cannot write this section to file, since it was not processed correctly. The expected dimensions are not set. Aborting...")
return return
# See if the section would fit on the current page - if it does not, write current buffered image & make the next image ready
if currentHeight + section.expectedHeight > songObj.imageHeight:
#print("overflow! starting with a new image")
outputLocation = folderLocation + "/" + str(imageNumber) + ".png"
imageNumber += 1
a4image.save(outputLocation)
currentHeight = songObj.topMargin
a4image = Image.new('RGB',(songObj.imageWidth, songObj.imageHeight),(songObj.backgroundColour))
draw = ImageDraw.Draw(a4image)
# write section title # write section title
headerWidth, headerHeight = songObj.fontTablature.getsize(section.header) headerWidth, headerHeight = songObj.fontTablature.getsize(section.header)
draw.text((songObj.leftMargin,currentHeight), section.header, fill=songObj.fontColour, font=songObj.fontTablature) draw.text((songObj.leftMargin,currentHeight), section.header, fill=songObj.fontColour, font=songObj.fontTablature)
@ -95,9 +85,13 @@ def outputToImage(folderLocation, songObj):
#print("currentheight={}".format(currentHeight)) #print("currentheight={}".format(currentHeight))
# Margin between each section # Margin between each section
currentHeight += songObj.topMargin currentHeight += songObj.topMargin
# No more sections left, so the current buffered image is ready to be written to file # Got all sections in the page, so write it
outputLocation = folderLocation + "/" + str(imageNumber) + ".png" outputLocation = folderLocation + "/" + str(imageNumber) + ".png"
a4image.save(outputLocation) a4image.save(outputLocation)
a4image = Image.new('RGB',(songObj.imageWidth, songObj.imageHeight),(songObj.backgroundColour))
draw = ImageDraw.Draw(a4image)
currentHeight = songObj.topMargin
imageNumber += 1