Skip to content

Commit cc6bed1

Browse files
Merge pull request #199 from AnEnglishmanInNorway/backgroundindouble
Correct backgrounds in "keepDoublePages" output
2 parents df46d6d + 6485186 commit cc6bed1

11 files changed

Lines changed: 362 additions & 40 deletions

File tree

cewe2pdf.py

Lines changed: 67 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@
105105
from otf import getTtfsFromOtfs
106106
from enum import Enum
107107

108+
class PageType(Enum):
109+
Unknown = 0 # this must be an error
110+
Normal = 1
111+
SingleSide = 2 # don't quite know what this is yet
112+
Cover = 3 # front / back cover
113+
EmptyPage = 4 # the intentional blanks inside the front and back covers
114+
115+
def __str__(self):
116+
return self.name # to print the enum name without the class
117+
108118
class ProductStyle(Enum):
109119
AlbumSingleSide = 1 # normal for albums, we divide the cewe 2 page bundle to single pages
110120
AlbumDoubleSide = 2 # any album when --keepdoublepages is set
@@ -188,6 +198,7 @@ def isAlbumDoubleSide(ps: ProductStyle):
188198
"ALB82": reportlab.lib.pagesizes.A4,
189199
"ALB98": reportlab.lib.pagesizes.A4, # unittest, L 20.5cm x 27.0cm
190200
"ALB32": (300 * reportlab.lib.pagesizes.mm, 300 * reportlab.lib.pagesizes.mm), # album XL, 30 x 30 cm
201+
"ALB17": (205 * reportlab.lib.pagesizes.mm, 205 * reportlab.lib.pagesizes.mm), # album kvadratisk, 20.5 x 20.5 cm
191202
"ALB69": (5400/100/2*reportlab.lib.units.cm, 3560/100*reportlab.lib.units.cm),
192203
# add other page sizes here
193204
"MEM3": (300 * reportlab.lib.pagesizes.mm, 300 * reportlab.lib.pagesizes.mm) # memory game cards 6x6cm
@@ -303,7 +314,7 @@ def getPageElementForPageNumber(fotobook, pageNumber):
303314
# This is only used for the <background .../> tags. The stock backgrounds use this element.
304315
def processBackground(backgroundTags, bg_notFoundDirList, cewe_folder, backgroundLocations,
305316
productstyle, pagetype, pdf, ph, pw):
306-
if pagetype == "emptypage": # don't draw background for the empty pages. That is page nr. 1 and pageCount-1.
317+
if pagetype == PageType.EmptyPage: # don't draw background for the empty pages. That is page nr. 1 and pageCount-1.
307318
return
308319
if backgroundTags is not None and len(backgroundTags) > 0:
309320
# look for a tag that has an alignment attribute
@@ -336,15 +347,19 @@ def processBackground(backgroundTags, bg_notFoundDirList, cewe_folder, backgroun
336347
try:
337348
bgPath = ""
338349
bgPath = findFileInDirs([bg + '.bmp', bg + '.webp', bg + '.jpg'], backgroundLocations)
339-
areaWidth = pw
340-
if isAlbumDoubleSide(productstyle):
341-
areaWidth = pw/2.
350+
351+
# Feb 2025, removed single/double side differentiation here, which basically cured
352+
# issue https://github.com/bash0/cewe2pdf/issues/198. I can only imagine that we have
353+
# tried to cure single/double page problems with "partial fixes" through the years
354+
# without understanding or testing all the cases. It is true that this solution does
355+
# not show the "forced empty pages" on the inside of the covers as white, a la CEWE,
356+
# but rather uses the background colour of the cover page. This whiteness is what
357+
# issue 198 is really complaining about, and I agree with it. Cover page colour is
358+
# a better choice when we are creating a pdf.
342359
areaHeight = ph
360+
areaWidth = pw
361+
areaXOffset = 0
343362

344-
if isAlbumDoubleSide(productstyle) and backgroundTag.get('alignment') == "3":
345-
ax = areaWidth
346-
else:
347-
ax = 0
348363
logging.debug(f"Reading background file: {bgPath}")
349364
# webp doesn't work with PIL.Image.open in Anaconda 5.3.0 on Win10
350365
imObj = PIL.Image.open(bgPath)
@@ -356,7 +371,7 @@ def processBackground(backgroundTags, bg_notFoundDirList, cewe_folder, backgroun
356371
memFileHandle.seek(0)
357372
# im = imread(bgpath) #does not work with 1-bit images
358373
pdf.drawImage(ImageReader(
359-
memFileHandle), f * ax, 0, width=f * areaWidth, height=f * areaHeight)
374+
memFileHandle), f * areaXOffset, 0, width=f * areaWidth, height=f * areaHeight)
360375
# pdf.drawImage(ImageReader(bgpath), f * ax, 0, width=f * aw, height=f * ah)
361376
except Exception:
362377
if bgPath not in bg_notFoundDirList:
@@ -1070,19 +1085,19 @@ def insertClipartFile(fileName:str, colorreplacements, transx, areaWidth, areaHe
10701085

10711086
def processElements(additional_fonts, fotobook, imagedir,
10721087
productstyle, mcfBaseFolder, oddpage, page, pageNumber, pagetype, pdf, ph, pw, lastpage):
1073-
if isAlbumDoubleSide(productstyle) and oddpage == 0 and pagetype == 'normal' and not lastpage:
1088+
if isAlbumDoubleSide(productstyle) and pagetype == PageType.Normal and not oddpage and not lastpage:
10741089
# if we are in double-page mode, all the images are drawn by the odd pages.
10751090
return
10761091

1077-
# switch pack to the page element for the even page to get the elements
1078-
if isAlbumProduct(productstyle) and pagetype == 'normal' and oddpage == 1:
1092+
# the mcf file really comes in "bundles" of two pages, so for odd pages we switch back to
1093+
# the page element for the preceding even page to get the elements
1094+
if isAlbumProduct(productstyle) and pagetype == PageType.Normal and oddpage:
10791095
page = getPageElementForPageNumber(fotobook, 2*floor(pageNumber/2))
10801096

10811097
for area in page.findall('area'):
10821098
areaPos = area.find('position')
10831099
areaLeft = float(areaPos.get('left').replace(',', '.'))
1084-
# old python 2 code: aleft = float(area.get('left').replace(',', '.'))
1085-
if pagetype != 'singleside' or len(area.findall('imagebackground')) == 0:
1100+
if pagetype != PageType.SingleSide or len(area.findall('imagebackground')) == 0:
10861101
if oddpage and isAlbumSingleSide(productstyle):
10871102
# shift double-page content from other page
10881103
areaLeft -= pw
@@ -1092,7 +1107,7 @@ def processElements(additional_fonts, fotobook, imagedir,
10921107
areaRot = float(areaPos.get('rotation'))
10931108

10941109
# check if the image is on current page at all
1095-
if pagetype == 'normal' and isAlbumSingleSide(productstyle):
1110+
if pagetype == PageType.Normal and isAlbumSingleSide(productstyle):
10961111
if oddpage:
10971112
# the right edge of image is beyond the left page border
10981113
if (areaLeft+areaWidth) < 0:
@@ -1130,17 +1145,14 @@ def processElements(additional_fonts, fotobook, imagedir,
11301145
def parseInputPage(fotobook, cewe_folder, mcfBaseFolder, backgroundLocations, imagedir, pdf,
11311146
page, pageNumber, pageCount, pagetype, productstyle, oddpage,
11321147
bg_notFoundDirList, additional_fonts, lastpage):
1133-
logging.info(f"parsing page {page.get('pagenr')} of {pageCount}")
1148+
logging.info(f"Pdf page {pageNumber} ({pagetype}): parsing pagenr {page.get('pagenr')} of {pageCount}")
11341149

11351150
bundlesize = page.find("./bundlesize")
11361151
if bundlesize is not None:
11371152
pw = float(bundlesize.get('width'))
11381153
ph = float(bundlesize.get('height'))
1139-
1140-
# reduce the page width to a single page width,
1141-
# if we want to have single pages.
11421154
if isAlbumSingleSide(productstyle):
1143-
pw = pw / 2
1155+
pw = pw / 2 # reduce the page width to a single page width for single sided
11441156
else:
11451157
# Assume A4 page size
11461158
pw = 2100
@@ -1149,7 +1161,7 @@ def parseInputPage(fotobook, cewe_folder, mcfBaseFolder, backgroundLocations, im
11491161

11501162
# process background
11511163
# look for all "<background...> tags.
1152-
# the preceeding designElementIDs tag only match the same
1164+
# the preceding designElementIDs tag only match the same
11531165
# number for the background attribute if it is a original
11541166
# stock image, without filters.
11551167
backgroundTags = page.findall('background')
@@ -1158,6 +1170,7 @@ def parseInputPage(fotobook, cewe_folder, mcfBaseFolder, backgroundLocations, im
11581170
# all elements (images, text,..) for even and odd pages are defined on the even page element!
11591171
processElements(additional_fonts, fotobook, imagedir, productstyle, mcfBaseFolder, oddpage, page, pageNumber, pagetype, pdf, ph, pw, lastpage)
11601172

1173+
11611174
def getBaseClipartLocations(baseFolder):
11621175
# create a tuple of places (folders) where background resources would be found by default
11631176
baseClipartLocations = (
@@ -1167,6 +1180,7 @@ def getBaseClipartLocations(baseFolder):
11671180
)
11681181
return baseClipartLocations
11691182

1183+
11701184
def readClipArtConfigXML(baseFolder, keyaccountFolder):
11711185
"""Parse the configuration XML file and generate a dictionary of designElementId to fileName
11721186
currently only cliparts_default.xml is supported !"""
@@ -1673,7 +1687,12 @@ def convertMcf(albumname, keepDoublePages: bool, pageNumbers=None, mcfxTmpDir=No
16731687
if articleConfigElement is None:
16741688
logging.error(f'{albumname} is an old version. Open it in the album editor and save before retrying the pdf conversion. Exiting.')
16751689
sys.exit(1)
1676-
pageCount = int(articleConfigElement.get('normalpages')) + 2 # maximum number of pages
1690+
pageCount = int(articleConfigElement.get('normalpages')) + 2
1691+
# The normalpages attribute in the mcf is the number of "usable" inside pages, excluding the front and back covers and the blank inside
1692+
# cover pages. Add 2 so that pagecount represents the actual number of printed pdf pages we expect in the normal single sided
1693+
# pdf print (a basic album is 26 inside pages, plus front and back cover, i.e. 28). If we use keepDoublePages, then we'll
1694+
# actually be producing 2 more (the inside covers) but halving the number of final output pdf pages, making 15 double pages.
1695+
# There is also a totalpages attribute in the mcf, but oddly in my files it is 3 more than the normalpages value. Why not 4 more?
16771696
imagedir = fotobook.get('imagedir')
16781697

16791698
# generate a list of available clip-arts
@@ -1696,20 +1715,29 @@ def convertMcf(albumname, keepDoublePages: bool, pageNumbers=None, mcfxTmpDir=No
16961715
pdf = canvas.Canvas(outputFileName, pagesize=pagesize)
16971716
pdf.setTitle(albumTitle)
16981717

1699-
for n in range(pageCount):
1718+
def IsBackCover(n):
1719+
return n == (pageCount - 1)
1720+
1721+
for n in range(pageCount): # starting at 0
17001722
try:
1701-
if isAlbumProduct(productstyle) and ((n == 0) or (n == pageCount - 1)): # clearest like this so pylint: disable=consider-using-in
1702-
pageNumber = 0
1723+
pagetype = PageType.Unknown
1724+
# The <page> sections all have a pagenr attribute. The normal pages run from pagenr 1 to pagenr 26 while there are
1725+
# actually FIVE page elements with pagenr 0 in an album file, 4 coming before pagenr 1 and 1 after pagenr 26
1726+
if isAlbumProduct(productstyle) and ((n == 0) or IsBackCover(n)): # clearest like this so pylint: disable=consider-using-in
17031727
fullcoverpages = [i for i in
17041728
fotobook.findall("./page[@pagenr='0'][@type='FULLCOVER']")
17051729
+ fotobook.findall("./page[@pagenr='0'][@type='fullcover']")
17061730
if i.find("./area") is not None]
1707-
if len(fullcoverpages) == 1: # in a well-formed album there are two fullcover pages, but only one with an area
1731+
if len(fullcoverpages) == 1:
1732+
# in a well-formed album there are two fullcover pages, but only one with an area, which we
1733+
# have just found. That fullcover "page 0" (bundle) contains all the stuff for the back cover
1734+
# on the left side, and the front cover on the right sight (and the spine, as it happens)
17081735
page = fullcoverpages[0]
17091736
oddpage = (n == 0) # bool assign is clearer with parens so pylint: disable=superfluous-parens
1710-
pagetype = 'cover'
1737+
pagetype = PageType.Cover
1738+
pageNumber = n
17111739
# for double-page-layout: the last page is already the left side of the book cover. So skip rendering the last page
1712-
if (isAlbumDoubleSide(productstyle) and (n == (pageCount - 1))):
1740+
if (isAlbumDoubleSide(productstyle) and IsBackCover(n)):
17131741
page = None
17141742
else:
17151743
logging.warning("Cannot locate a cover page, is this really an album?")
@@ -1733,24 +1761,27 @@ def convertMcf(albumname, keepDoublePages: bool, pageNumbers=None, mcfxTmpDir=No
17331761
# Look for the the first page and set it up for processing
17341762
realFirstPageList = fotobook.findall("./page[@pagenr='1'][@type='normalpage']")
17351763
if len(realFirstPageList) > 0 and (pageNumbers is None or 0 in pageNumbers):
1736-
# we need to do run parseInputPage twico for one output page in the PDF.
1764+
# for this special page we need to do run parseInputPage twice for one output page in the PDF.
17371765
# The background needs to be drawn first, or it would obscure any other other elements.
1738-
pagetype = 'singleside'
1766+
pagetype = PageType.SingleSide
17391767
lastpage = False
17401768
parseInputPage(fotobook, cewe_folder, mcfBaseFolder, backgroundLocations, imagedir, pdf,
17411769
realFirstPageList[0], pageNumber, pageCount, pagetype, productstyle, oddpage,
17421770
bg_notFoundDirList, additional_fonts, lastpage)
1743-
pagetype = 'emptypage'
1771+
pagetype = PageType.EmptyPage
17441772
else:
17451773
pageNumber = n
17461774
oddpage = (pageNumber % 2) == 1
17471775
page = getPageElementForPageNumber(fotobook, n)
1748-
pagetype = 'normal'
1776+
pagetype = PageType.Normal
17491777

17501778
if pageNumbers is not None and pageNumber not in pageNumbers:
17511779
continue
17521780

17531781
if page is not None:
1782+
if pagetype == PageType.Unknown:
1783+
logging.error(f'Unable to deduce page type for page {pageNumber}')
1784+
continue
17541785
lastpage = (n == pageCount - 2) # bool assign is clearer with parens so pylint: disable=superfluous-parens
17551786
parseInputPage(fotobook, cewe_folder, mcfBaseFolder, backgroundLocations, imagedir, pdf,
17561787
page, pageNumber, pageCount, pagetype, productstyle, oddpage,
@@ -1761,11 +1792,10 @@ def convertMcf(albumname, keepDoublePages: bool, pageNumbers=None, mcfxTmpDir=No
17611792
# it would be neat to duplicate the page for MemoryCard products but showPage
17621793
# empties the canvas so the user must just print the pdf file twice!
17631794
pdf.showPage()
1764-
elif (isAlbumSingleSide(productstyle)
1765-
or ((not (oddpage is False and pagetype == 'normal'))
1766-
and (not (n == (pageCount - 1) and pagetype == 'cover'))
1767-
)):
1768-
# If we're creating a AlbumDoubleSide then we only output after the odd pages
1795+
elif isAlbumSingleSide(productstyle):
1796+
pdf.showPage()
1797+
elif oddpage or (pagetype == PageType.Cover and not IsBackCover(n)):
1798+
# We're creating a AlbumDoubleSide so we only output after the odd pages
17691799
pdf.showPage()
17701800

17711801
except Exception as pageex:

cewe2pdf.pyproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<SchemaVersion>2.0</SchemaVersion>
66
<ProjectGuid>{261b8fb1-634c-480e-b162-8b5b56d18330}</ProjectGuid>
77
<ProjectHome />
8-
<StartupFile>tests\testClipartColorReplacement\test_clipartColorReplacement.py</StartupFile>
8+
<StartupFile>runAllTests.py</StartupFile>
99
<SearchPath />
1010
<WorkingDirectory>.</WorkingDirectory>
1111
<OutputPath>.</OutputPath>
@@ -28,7 +28,7 @@
2828
<Content Include=".github\workflows\pythonapp.yml" />
2929
<Content Include=".gitignore" />
3030
<Content Include=".pylintrc" />
31-
<Content Include="additional_fonts.txt" />
31+
<Content Include="tests\testbackgrounds\additional_fonts.txt" />
3232
<Content Include="build_a_compiled_version.md" />
3333
<Content Include="cewe2pdf.ini" />
3434
<Content Include="CLP file format.txt" />
@@ -111,7 +111,7 @@
111111
<Compile Include="processManyMcfs.py" />
112112
<Compile Include="runAllTests.py" />
113113
<Compile Include="tests\testClipartColorReplacement\test_clipartColorReplacement.py" />
114-
<Compile Include="tests\testClipart\test_drawClipart.py" />
114+
<Compile Include="tests\testbackgrounds\test_backgrounds.py" />
115115
<Compile Include="tests\testFontDoesNotExist\test_fontDoesNotExist.py" />
116116
<Compile Include="tests\testMcfxExtraction\test_McfxExtraction.py" />
117117
<Compile Include="tests\test_simpleBook.py" />
@@ -141,6 +141,7 @@
141141
<Folder Include="tests\Resources\photofun\" />
142142
<Folder Include="tests\Resources\photofun\backgrounds\" />
143143
<Folder Include="tests\Resources\photofun\decorations\" />
144+
<Folder Include="tests\testbackgrounds\" />
144145
<Folder Include="tests\testClipartColorReplacement\" />
145146
<Folder Include="tests\testClipartColorReplacement\test_clipart_colorreplacement_mcf-Dateien\" />
146147
<Folder Include="tests\testClipart\" />
631 Bytes
Loading
Binary file not shown.

tests/testbackgrounds/additional_fonts.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)