Krita Source Code Documentation
Loading...
Searching...
No Matches
CPMT_ACBF_XML_Exporter.py
Go to the documentation of this file.
1"""
2SPDX-FileCopyrightText: 2018 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3
4This file is part of the Comics Project Management Tools(CPMT).
5
6SPDX-License-Identifier: GPL-3.0-or-later
7"""
8
9"""
10Write the Advanced Comic Book Data xml file.
11
12http://acbf.wikia.com/wiki/ACBF_Specifications
13
14"""
15
16import os
17import re
18try:
19 from PyQt6.QtCore import QDate, Qt, QPointF, QByteArray, QBuffer, QLocale
20 from PyQt6.QtGui import QImage, QColor
21 from PyQt6.QtXml import QDomDocument, QDomElement
22except:
23 from PyQt5.QtCore import QDate, Qt, QPointF, QByteArray, QBuffer, QLocale
24 from PyQt5.QtGui import QImage, QColor
25 from PyQt5.QtXml import QDomDocument, QDomElement
26from . import CPMT_po_parser as po_parser
27
28def write_xml(configDictionary = {}, pageData = [], pagesLocationList = [], locationBasic = str(), locationStandAlone = str(), projectUrl = str()):
29 acbfGenreList = ["science_fiction", "fantasy", "adventure", "horror", "mystery", "crime", "military", "real_life", "superhero", "humor", "western", "manga", "politics", "caricature", "sports", "history", "biography", "education", "computer", "religion", "romance", "children", "non-fiction", "adult", "alternative", "other", "artbook"]
30 acbfAuthorRolesList = ["Writer", "Adapter", "Artist", "Penciller", "Inker", "Colorist", "Letterer", "Cover Artist", "Photographer", "Editor", "Assistant Editor", "Translator", "Other", "Designer"]
31 document = QDomDocument()
32 root = document.createElement("ACBF")
33 root.setAttribute("xmlns", "http://www.acbf.info/xml/acbf/1.1")
34 document.appendChild(root)
35
36 emphasisStyle = {}
37 strongStyle = {}
38 if "acbfStyles" in configDictionary.keys():
39 stylesDictionary = configDictionary.get("acbfStyles", {})
40 emphasisStyle = stylesDictionary.get("emphasis", {})
41 strongStyle = stylesDictionary.get("strong", {})
42 styleString = "\n"
43 tabs = " "
44 for key in sorted(stylesDictionary.keys()):
45 style = stylesDictionary.get(key, {})
46 if key == "emphasis" or key == "strong":
47 styleClass = key+" {\n"
48 elif key == "speech":
49 styleClass = "text-area {\n"
50 elif key == "general":
51 styleClass = "* {\n"
52 elif key == "inverted":
53 styleClass = "text-area[inverted=\"true\"] {\n"
54 else:
55 styleClass = "text-area[type=\""+key+"\"] {\n"
56 styleString += tabs+styleClass
57 if "color" in style.keys():
58 styleString += tabs+tabs+"color:"+style["color"]+";\n"
59 if "font" in style.keys():
60 fonts = style["font"]
61 genericfont = style.get("genericfont", "sans-serif")
62 if isinstance(fonts, list):
63 styleString += tabs+tabs+"font-family:\""+str("\", \"").join(fonts)+"\", "+genericfont+";\n"
64 else:
65 styleString += tabs+tabs+"font-family:\""+fonts+"\", "+genericfont+";\n"
66 if "bold" in style.keys():
67 if style["bold"]:
68 styleString += tabs+tabs+"font-weight: bold;\n"
69 if "ital" in style.keys():
70 if style["ital"]:
71 styleString += tabs+tabs+"font-style: italic;\n"
72 else:
73 styleString += tabs+tabs+"font-style: normal;\n"
74 styleString += tabs+"}\n"
75 style = document.createElement("style")
76 style.setAttribute("type", "text/css")
77 style.appendChild(document.createTextNode(styleString))
78 root.appendChild(style)
79
80
81 meta = document.createElement("meta-data")
82
83 translationFolder = configDictionary.get("translationLocation", "translations")
84 fullTranslationPath = os.path.join(projectUrl, translationFolder)
85 poParser = po_parser.po_file_parser(fullTranslationPath, True)
86
87 bookInfo = document.createElement("book-info")
88 if "authorList" in configDictionary.keys():
89 for authorE in range(len(configDictionary["authorList"])):
90 author = document.createElement("author")
91 authorDict = configDictionary["authorList"][authorE]
92 if "first-name" in authorDict.keys():
93 authorN = document.createElement("first-name")
94 authorN.appendChild(document.createTextNode(str(authorDict["first-name"])))
95 author.appendChild(authorN)
96 if "last-name" in authorDict.keys():
97 authorN = document.createElement("last-name")
98 authorN.appendChild(document.createTextNode(str(authorDict["last-name"])))
99 author.appendChild(authorN)
100 if "initials" in authorDict.keys():
101 authorN = document.createElement("middle-name")
102 authorN.appendChild(document.createTextNode(str(authorDict["initials"])))
103 author.appendChild(authorN)
104 if "nickname" in authorDict.keys():
105 authorN = document.createElement("nickname")
106 authorN.appendChild(document.createTextNode(str(authorDict["nickname"])))
107 author.appendChild(authorN)
108 if "homepage" in authorDict.keys():
109 authorN = document.createElement("home-page")
110 authorN.appendChild(document.createTextNode(str(authorDict["homepage"])))
111 author.appendChild(authorN)
112 if "email" in authorDict.keys():
113 authorN = document.createElement("email")
114 authorN.appendChild(document.createTextNode(str(authorDict["email"])))
115 author.appendChild(authorN)
116 if "role" in authorDict.keys():
117 if str(authorDict["role"]).title() in acbfAuthorRolesList:
118 author.setAttribute("activity", str(authorDict["role"]))
119 if "language" in authorDict.keys():
120 author.setAttribute("lang", str(authorDict["language"]).replace("_", "-"))
121 bookInfo.appendChild(author)
122 bookTitle = document.createElement("book-title")
123 if "title" in configDictionary.keys():
124 bookTitle.appendChild(document.createTextNode(str(configDictionary["title"])))
125 else:
126 bookTitle.appendChild(document.createTextNode(str("Comic with no Name")))
127 bookInfo.appendChild(bookTitle)
128 extraGenres = []
129
130 if "genre" in configDictionary.keys():
131 genreListConf = configDictionary["genre"]
132 if isinstance(configDictionary["genre"], dict):
133 genreListConf = configDictionary["genre"].keys()
134 for genre in genreListConf:
135 genreModified = str(genre).lower()
136 genreModified.replace(" ", "_")
137 if genreModified in acbfGenreList:
138 bookGenre = document.createElement("genre")
139 bookGenre.appendChild(document.createTextNode(str(genreModified)))
140 if isinstance(configDictionary["genre"], dict):
141 genreMatch = configDictionary["genre"][genreModified]
142 if genreMatch>0:
143 bookGenre.setAttribute("match", str(genreMatch))
144 bookInfo.appendChild(bookGenre)
145 else:
146 extraGenres.append(genre)
147
148 if "characters" in configDictionary.keys():
149 character = document.createElement("characters")
150 for name in configDictionary["characters"]:
151 char = document.createElement("name")
152 char.appendChild(document.createTextNode(str(name)))
153 character.appendChild(char)
154 bookInfo.appendChild(character)
155
156 annotation = document.createElement("annotation")
157 if "summary" in configDictionary.keys():
158 paragraphList = str(configDictionary["summary"]).split("\n")
159 for para in paragraphList:
160 p = document.createElement("p")
161 p.appendChild(document.createTextNode(str(para)))
162 annotation.appendChild(p)
163 else:
164 p = document.createElement("p")
165 p.appendChild(document.createTextNode(str("There was no summary upon generation of this file.")))
166 annotation.appendChild(p)
167 bookInfo.appendChild(annotation)
168
169 keywords = document.createElement("keywords")
170 stringKeywordsList = []
171 for key in extraGenres:
172 stringKeywordsList.append(str(key))
173 if "otherKeywords" in configDictionary.keys():
174 for key in configDictionary["otherKeywords"]:
175 stringKeywordsList.append(str(key))
176 if "format" in configDictionary.keys():
177 for key in configDictionary["format"]:
178 stringKeywordsList.append(str(key))
179 keywords.appendChild(document.createTextNode(", ".join(stringKeywordsList)))
180 bookInfo.appendChild(keywords)
181
182 coverpageurl = ""
183 coverpage = document.createElement("coverpage")
184 if "pages" in configDictionary.keys():
185 if "cover" in configDictionary.keys():
186 pageList = []
187 pageList = configDictionary["pages"]
188 coverNumber = max([pageList.index(configDictionary["cover"]), 0])
189 image = document.createElement("image")
190 if len(pagesLocationList) >= coverNumber:
191 coverpageurl = pagesLocationList[coverNumber]
192 image.setAttribute("href", os.path.basename(coverpageurl))
193 coverpage.appendChild(image)
194 bookInfo.appendChild(coverpage)
195
196 if "language" in configDictionary.keys():
197 language = document.createElement("languages")
198 textlayer = document.createElement("text-layer")
199 textlayer.setAttribute("lang", str(configDictionary["language"]).replace("_", "-"))
200 textlayer.setAttribute("show", "false")
201 textlayerNative = document.createElement("text-layer")
202 textlayerNative.setAttribute("lang", str(configDictionary["language"]).replace("_", "-"))
203 textlayerNative.setAttribute("show", "true")
204 language.appendChild(textlayer)
205 language.appendChild(textlayerNative)
206 translationComments = {}
207 for lang in poParser.get_translation_list():
208 textlayer = document.createElement("text-layer")
209 textlayer.setAttribute("lang", lang)
210 textlayer.setAttribute("show", "true")
211 language.appendChild(textlayer)
212 translationComments[lang] = []
213 translation = poParser.get_entry_for_key("@meta-title "+configDictionary["title"], lang).get("trans", None)
214 if translation is not None:
215 bookTitleTr = document.createElement("book-title")
216 bookTitleTr.setAttribute("lang", lang)
217 bookTitleTr.appendChild(document.createTextNode(translation))
218 bookInfo.insertAfter(bookTitleTr, bookTitle)
219 translation = poParser.get_entry_for_key("@meta-summary "+configDictionary["summary"], lang).get("trans", None)
220 if translation is not None:
221 annotationTr = document.createElement("annotation")
222 annotationTr.setAttribute("lang", lang)
223 paragraph = document.createElement("p")
224 paragraph.appendChild(document.createTextNode(translation))
225 annotationTr.appendChild(paragraph)
226 bookInfo.insertAfter(annotationTr, annotation)
227 translation = poParser.get_entry_for_key("@meta-keywords "+", ".join(configDictionary["otherKeywords"]), lang).get("trans", None)
228 if translation is not None:
229 keywordsTr = document.createElement("keywords")
230 keywordsTr.setAttribute("lang", lang)
231 keywordsTr.appendChild(document.createTextNode(translation))
232 bookInfo.insertAfter(keywordsTr, keywords)
233 bookInfo.appendChild(language)
234
235 bookTitle.setAttribute("lang", str(configDictionary["language"]).replace("_", "-"))
236 annotation.setAttribute("lang", str(configDictionary["language"]).replace("_", "-"))
237 keywords.setAttribute("lang", str(configDictionary["language"]).replace("_", "-"))
238
239 if "databaseReference" in configDictionary.keys():
240 database = document.createElement("databaseref")
241 dbRef = configDictionary["databaseReference"]
242 database.setAttribute("dbname", dbRef.get("name", ""))
243 if "type" in dbRef.keys():
244 database.setAttribute("type", dbRef["type"])
245 database.appendChild(document.createTextNode(dbRef.get("entry", "")))
246 bookInfo.appendChild(database)
247
248 if "seriesName" in configDictionary.keys():
249 sequence = document.createElement("sequence")
250 sequence.setAttribute("title", configDictionary["seriesName"])
251 if "seriesVolume" in configDictionary.keys():
252 sequence.setAttribute("volume", str(configDictionary["seriesVolume"]))
253 if "seriesNumber" in configDictionary.keys():
254 sequence.appendChild(document.createTextNode(str(configDictionary["seriesNumber"])))
255 else:
256 sequence.appendChild(document.createTextNode(str(0)))
257 bookInfo.appendChild(sequence)
258 contentrating = document.createElement("content-rating")
259
260 if "rating" in configDictionary.keys():
261 contentrating.appendChild(document.createTextNode(str(configDictionary["rating"])))
262 else:
263 contentrating.appendChild(document.createTextNode(str("Unrated.")))
264 if "ratingSystem" in configDictionary.keys():
265 contentrating.setAttribute("type", configDictionary["ratingSystem"])
266 bookInfo.appendChild(contentrating)
267
268 if "readingDirection" in configDictionary.keys():
269 readingDirection = document.createElement("reading-direction")
270 if configDictionary["readingDirection"] == "rightToLeft":
271 readingDirection.appendChild(document.createTextNode(str("RTL")))
272 else:
273 readingDirection.appendChild(document.createTextNode(str("LTR")))
274 bookInfo.appendChild(readingDirection)
275 meta.appendChild(bookInfo)
276
277 publisherInfo = document.createElement("publish-info")
278 if "publisherName" in configDictionary.keys():
279 publisherName = document.createElement("publisher")
280 publisherName.appendChild(document.createTextNode(str(configDictionary["publisherName"])))
281 publisherInfo.appendChild(publisherName)
282 if "publishingDate" in configDictionary.keys():
283 publishingDate = document.createElement("publish-date")
284 publishingDate.setAttribute("value", configDictionary["publishingDate"])
285 publishingDate.appendChild(document.createTextNode(QDate.fromString(configDictionary["publishingDate"], Qt.DateFormat.ISODate).toString(Qt.DateFormat.SystemLocaleLongDate)))
286 publisherInfo.appendChild(publishingDate)
287 if "publisherCity" in configDictionary.keys():
288 publishCity = document.createElement("city")
289 publishCity.appendChild(document.createTextNode(str(configDictionary["publisherCity"])))
290 publisherInfo.appendChild(publishCity)
291 if "isbn-number" in configDictionary.keys():
292 publishISBN = document.createElement("isbn")
293 publishISBN.appendChild(document.createTextNode(str(configDictionary["isbn-number"])))
294 publisherInfo.appendChild(publishISBN)
295 license = str(configDictionary.get("license", ""))
296 if license.isspace() is False and len(license) > 0:
297 publishLicense = document.createElement("license")
298 publishLicense.appendChild(document.createTextNode(license))
299 publisherInfo.appendChild(publishLicense)
300
301 meta.appendChild(publisherInfo)
302
303 documentInfo = document.createElement("document-info")
304 # TODO: ACBF apparently uses first/middle/last/nick/email/homepage for the document author too...
305 # The following code compensates for me not understanding this initially.
306 if "acbfAuthor" in configDictionary.keys():
307 if isinstance(configDictionary["acbfAuthor"], list):
308 for e in configDictionary["acbfAuthor"]:
309 acbfAuthor = document.createElement("author")
310 authorDict = e
311 if "first-name" in authorDict.keys():
312 authorN = document.createElement("first-name")
313 authorN.appendChild(document.createTextNode(str(authorDict["first-name"])))
314 acbfAuthor.appendChild(authorN)
315 if "last-name" in authorDict.keys():
316 authorN = document.createElement("last-name")
317 authorN.appendChild(document.createTextNode(str(authorDict["last-name"])))
318 acbfAuthor.appendChild(authorN)
319 if "initials" in authorDict.keys():
320 authorN = document.createElement("middle-name")
321 authorN.appendChild(document.createTextNode(str(authorDict["initials"])))
322 acbfAuthor.appendChild(authorN)
323 if "nickname" in authorDict.keys():
324 authorN = document.createElement("nickname")
325 authorN.appendChild(document.createTextNode(str(authorDict["nickname"])))
326 acbfAuthor.appendChild(authorN)
327 if "homepage" in authorDict.keys():
328 authorN = document.createElement("home-page")
329 authorN.appendChild(document.createTextNode(str(authorDict["homepage"])))
330 acbfAuthor.appendChild(authorN)
331 if "email" in authorDict.keys():
332 authorN = document.createElement("email")
333 authorN.appendChild(document.createTextNode(str(authorDict["email"])))
334 acbfAuthor.appendChild(authorN)
335 if "language" in authorDict.keys():
336 acbfAuthor.setAttribute("lang", str(authorDict["language"]).replace("_", "-"))
337 documentInfo.appendChild(acbfAuthor)
338 else:
339 acbfAuthor = document.createElement("author")
340 acbfAuthorNick = document.createElement("nickname")
341 acbfAuthorNick.appendChild(document.createTextNode(str(configDictionary["acbfAuthor"])))
342 acbfAuthor.appendChild(acbfAuthorNick)
343 documentInfo.appendChild(acbfAuthor)
344 else:
345 acbfAuthor = document.createElement("author")
346 acbfAuthorNick = document.createElement("nickname")
347 acbfAuthorNick.appendChild(document.createTextNode(str("Anon")))
348 acbfAuthor.appendChild(acbfAuthorNick)
349 documentInfo.appendChild(acbfAuthor)
350
351 acbfDate = document.createElement("creation-date")
352 now = QDate.currentDate()
353 acbfDate.setAttribute("value", now.toString(Qt.DateFormat.ISODate))
354 acbfDate.appendChild(document.createTextNode(QLocale().toString(now, QLocale.FormatType.LongFormat)))
355 documentInfo.appendChild(acbfDate)
356
357 if "acbfSource" in configDictionary.keys():
358 acbfSource = document.createElement("source")
359 acbfSourceP = document.createElement("p")
360 acbfSourceP.appendChild(document.createTextNode(str(configDictionary["acbfSource"])))
361 acbfSource.appendChild(acbfSourceP)
362 documentInfo.appendChild(acbfSource)
363
364 if "acbfID" in configDictionary.keys():
365 acbfID = document.createElement("id")
366 acbfID.appendChild(document.createTextNode(str(configDictionary["acbfID"])))
367 documentInfo.appendChild(acbfID)
368
369 if "acbfVersion" in configDictionary.keys():
370 acbfVersion = document.createElement("version")
371 acbfVersion.appendChild(document.createTextNode(str(configDictionary["acbfVersion"])))
372 documentInfo.appendChild(acbfVersion)
373
374 if "acbfHistory" in configDictionary.keys():
375 if len(configDictionary["acbfHistory"])>0:
376 acbfHistory = document.createElement("history")
377 for h in configDictionary["acbfHistory"]:
378 p = document.createElement("p")
379 p.appendChild(document.createTextNode(str(h)))
380 acbfHistory.appendChild(p)
381 documentInfo.appendChild(acbfHistory)
382 meta.appendChild(documentInfo)
383
384 root.appendChild(meta)
385
386 body = document.createElement("body")
387
388 references = document.createElement("references")
389
390 def figure_out_type(svg = QDomElement()):
391 type = None
392 skipList = ["speech", "emphasis", "strong", "inverted", "general"]
393 if svg.attribute("text-anchor") == "middle" or svg.attribute("text-align") == "center":
394 if "acbfStyles" in configDictionary.keys():
395 stylesDictionary = configDictionary.get("acbfStyles", {})
396 for key in stylesDictionary.keys():
397 if key not in skipList:
398 style = stylesDictionary.get(key, {})
399 font = style.get("font", "")
400 if isinstance(fonts, list):
401 if svg.attribute("family") in font:
402 type = key
403 elif svg.attribute("family") == font:
404 type = key
405 else:
406 type = None
407 elif svg.attribute("text-align") == "justified":
408 type = "formal"
409 else:
410 type = "commentary"
411 inverted = None
412 #Figure out whether this is inverted colored text.
413 if svg.hasAttribute("fill"):
414 stylesDictionary = configDictionary.get("acbfStyles", {})
415 key = stylesDictionary.get("general", {})
416 regular = QColor(key.get("color", "#000000"))
417 key = stylesDictionary.get("inverted", {})
418 invertedColor = QColor(key.get("color", "#FFFFFF"))
419 textColor = QColor(svg.attribute("fill"))
420 # Proceed to get luma for the three colors.
421 lightnessR = (0.21 * regular.redF()) + (0.72 * regular.greenF()) + (0.07 * regular.blueF())
422 lightnessI = (0.21 * invertedColor.redF()) + (0.72 * invertedColor.greenF()) + (0.07 * invertedColor.blueF())
423 lightnessT = (0.21 * textColor.redF()) + (0.72 * textColor.greenF()) + (0.07 * textColor.blueF())
424 if lightnessI > lightnessR:
425 if lightnessT > (lightnessI+lightnessR)*0.5:
426 inverted = "true"
427 else:
428 if lightnessT < (lightnessI+lightnessR)*0.5:
429 inverted = "true"
430 return [type, inverted]
431
432 listOfPageColors = []
433
434 for p in range(0, len(pagesLocationList)):
435 page = pagesLocationList[p]
436 imageFile = QImage()
437 imageFile.load(page)
438 imageRect = imageFile.rect().adjusted(0, 0, -1, -1)
439 pageColor = findDominantColor([imageFile.pixelColor(imageRect.topLeft()), imageFile.pixelColor(imageRect.topRight()), imageFile.pixelColor(imageRect.bottomRight()), imageFile.pixelColor(imageRect.bottomLeft())])
440 listOfPageColors.append(pageColor)
441 language = "en"
442 if "language" in configDictionary.keys():
443 language = str(configDictionary["language"]).replace("_", "-")
444 textLayer = document.createElement("text-layer")
445 textLayer.setAttribute("lang", language)
446 data = pageData[p]
447 transform = data["transform"]
448 frameList = []
449 listOfTextColors = []
450 for v in data["vector"]:
451 boundingBoxText = []
452 listOfBoundaryColors = []
453 for point in v["boundingBox"]:
454 offset = QPointF(transform["offsetX"], transform["offsetY"])
455 pixelPoint = QPointF(point.x() * transform["resDiff"], point.y() * transform["resDiff"])
456 newPoint = pixelPoint - offset
457 x = max(0, min(imageRect.width(), int(newPoint.x() * transform["scaleWidth"])))
458 y = max(0, min(imageRect.height(), int(newPoint.y() * transform["scaleHeight"])))
459 listOfBoundaryColors.append(imageFile.pixelColor(x, y))
460 pointText = str(x) + "," + str(y)
461 boundingBoxText.append(pointText)
462 mainColor = findDominantColor(listOfBoundaryColors)
463
464 if "text" in v.keys():
465 textArea = document.createElement("text-area")
466 textArea.setAttribute("points", " ".join(boundingBoxText))
467 # TODO: Rotate will require proper global transform api as transform info is not written intotext. #textArea.setAttribute("text-rotation", str(v["rotate"]))
468 svg = QDomDocument()
469 svg.setContent(v["text"])
470 figureOut = figure_out_type(svg.documentElement())
471 type = figureOut[0]
472 inverted = figureOut[1]
473 paragraph = QDomDocument()
474 paragraph.appendChild(paragraph.createElement("p"))
475 parseTextChildren(paragraph, svg.documentElement(), paragraph.documentElement(), emphasisStyle, strongStyle)
476 textArea.appendChild(paragraph.documentElement())
477 textArea.setAttribute("bgcolor", mainColor.name())
478 if type is not None:
479 textArea.setAttribute("type", type)
480 if inverted is not None:
481 textArea.setAttribute("inverted", inverted)
482 textLayer.appendChild(textArea)
483 else:
484 f = {}
485 f["points"] = " ".join(boundingBoxText)
486 frameList.append(f)
487 listOfTextColors.append(mainColor)
488 textLayer.setAttribute("bgcolor", findDominantColor(listOfTextColors).name())
489 textLayerList = document.createElement("trlist")
490 for lang in poParser.get_translation_list():
491 textLayerTr = document.createElement("text-layer")
492 textLayerTr.setAttribute("lang", lang)
493 for i in range(len(data["vector"])):
494 d = data["vector"]
495 v = d[i]
496 boundingBoxText = []
497 for point in v["boundingBox"]:
498 offset = QPointF(transform["offsetX"], transform["offsetY"])
499 pixelPoint = QPointF(point.x() * transform["resDiff"], point.y() * transform["resDiff"])
500 newPoint = pixelPoint - offset
501 x = int(newPoint.x() * transform["scaleWidth"])
502 y = int(newPoint.y() * transform["scaleHeight"])
503 pointText = str(x) + "," + str(y)
504 boundingBoxText.append(pointText)
505
506 if "text" in v.keys():
507 textArea = document.createElement("text-area")
508 textArea.setAttribute("points", " ".join(boundingBoxText))
509 # TODO: Rotate will require proper global transform api as transform info is not written intotext. #textArea.setAttribute("text-rotation", str(v["rotate"]))
510 svg = QDomDocument()
511 svg.setContent(v["text"])
512 figureOut = figure_out_type(svg.documentElement())
513 type = figureOut[0]
514 inverted = figureOut[1]
515 string = re.sub(r"<\/*?text.*?>",'', str(v["text"]))
516 string = re.sub(r"\s+?", " ", string)
517 translationEntry = poParser.get_entry_for_key(string, lang)
518 string = translationEntry.get("trans", string)
519 svg.setContent("<text>"+string+"</text>")
520 paragraph = QDomDocument()
521 paragraph.appendChild(paragraph.createElement("p"))
522 parseTextChildren(paragraph, svg.documentElement(), paragraph.documentElement(), emphasisStyle, strongStyle)
523 if "translComment" in translationEntry.keys():
524 key = translationEntry["translComment"]
525 listOfComments = []
526 listOfComments = translationComments[lang]
527 index = 0
528 if key in listOfComments:
529 index = listOfComments.index(key)+1
530 else:
531 listOfComments.append(key)
532 index = len(listOfComments)
533 translationComments[lang] = listOfComments
534 refID = "-".join(["tn", lang, str(index)])
535 anchor = document.createElement("a")
536 anchor.setAttribute("href", "#"+refID)
537 anchor.appendChild(document.createTextNode("*"))
538 paragraph.documentElement().appendChild(anchor)
539 textArea.appendChild(paragraph.documentElement())
540 textLayerTr.appendChild(textArea)
541 if type is not None:
542 textArea.setAttribute("type", type)
543 if inverted is not None:
544 textArea.setAttribute("inverted", inverted)
545 textArea.setAttribute("bgcolor", listOfTextColors[i].name())
546 if textLayerTr.hasChildNodes():
547 textLayerTr.setAttribute("bgcolor", findDominantColor(listOfTextColors).name())
548 textLayerList.appendChild(textLayerTr)
549
550
551
552 if page is not coverpageurl:
553 pg = document.createElement("page")
554 image = document.createElement("image")
555 image.setAttribute("href", os.path.basename(page))
556 pg.appendChild(image)
557 if "acbf_title" in data["keys"]:
558 title = document.createElement("title")
559 title.setAttribute("lang", language)
560 title.appendChild(document.createTextNode(str(data["title"])))
561 pg.appendChild(title)
562 for lang in poParser.get_translation_list():
563 titleTrans = " "
564 titlekey = "@page-title "+str(data["title"])
565 translationEntry = poParser.get_entry_for_key(titlekey, lang)
566 titleTrans = translationEntry.get("trans", titleTrans)
567 if titleTrans.isspace() is False:
568 titleT = document.createElement("title")
569 titleT.setAttribute("lang", lang)
570 titleT.appendChild(document.createTextNode(titleTrans))
571 pg.appendChild(titleT)
572 if "acbf_none" in data["keys"]:
573 pg.setAttribute("transition", "none")
574 if "acbf_blend" in data["keys"]:
575 pg.setAttribute("transition", "blend")
576 if "acbf_fade" in data["keys"]:
577 pg.setAttribute("transition", "fade")
578 if "acbf_horizontal" in data["keys"]:
579 pg.setAttribute("transition", "scroll_right")
580 if "acbf_vertical" in data["keys"]:
581 pg.setAttribute("transition", "scroll_down")
582 if textLayer.hasChildNodes():
583 pg.appendChild(textLayer)
584 pg.setAttribute("bgcolor", pageColor.name())
585 for n in range(0, textLayerList.childNodes().size()):
586 node = textLayerList.childNodes().at(n)
587 pg.appendChild(node)
588 for f in frameList:
589 frame = document.createElement("frame")
590 frame.setAttribute("points", f["points"])
591 pg.appendChild(frame)
592 body.appendChild(pg)
593 else:
594 for f in frameList:
595 frame = document.createElement("frame")
596 frame.setAttribute("points", f["points"])
597 coverpage.appendChild(frame)
598 coverpage.appendChild(textLayer)
599 for n in range(0, textLayerList.childNodes().size()):
600 node = textLayerList.childNodes().at(n)
601 coverpage.appendChild(node)
602 bodyColor = findDominantColor(listOfPageColors)
603 body.setAttribute("bgcolor", bodyColor.name())
604
605 if configDictionary.get("includeTranslComment", False):
606 for lang in translationComments.keys():
607 for key in translationComments[lang]:
608 index = translationComments[lang].index(key)+1
609 refID = "-".join(["tn", lang, str(index)])
610 ref = document.createElement("reference")
611 ref.setAttribute("lang", lang)
612 ref.setAttribute("id", refID)
613 transHeaderStr = configDictionary.get("translatorHeader", "Translator's Notes")
614 transHeaderStr = poParser.get_entry_for_key("@meta-translator "+transHeaderStr, lang).get("trans", transHeaderStr)
615 translatorHeader = document.createElement("p")
616 translatorHeader.appendChild(document.createTextNode(transHeaderStr+":"))
617 ref.appendChild(translatorHeader)
618 refPara = document.createElement("p")
619 refPara.appendChild(document.createTextNode(key))
620 ref.appendChild(refPara)
621 references.appendChild(ref)
622
623 root.appendChild(body)
624 if references.childNodes().size():
625 root.appendChild(references)
626
627 f = open(locationBasic, 'w', newline="", encoding="utf-8")
628 f.write(document.toString(indent=2))
629 f.close()
630 success = True
631 success = createStandAloneACBF(configDictionary, document, locationStandAlone, pagesLocationList)
632 return success
633
634def createStandAloneACBF(configDictionary, document = QDomDocument(), location = str(), pagesLocationList = []):
635 title = configDictionary["projectName"]
636 if "title" in configDictionary.keys():
637 title = configDictionary["title"]
638 root = document.firstChildElement("ACBF")
639 meta = root.firstChildElement("meta-data")
640 bookInfo = meta.firstChildElement("book-info")
641 cover = bookInfo.firstChildElement("coverpage")
642
643 body = root.firstChildElement("body")
644 pages = []
645 for p in range(0, len(body.elementsByTagName("page"))):
646 pages.append(body.elementsByTagName("page").item(p).toElement())
647 if (cover):
648 pages.append(cover)
649
650 data = document.createElement("data")
651 root.appendChild(data)
652
653 # Convert pages to base64 strings.
654 for i in range(0, len(pages)):
655 image = pages[i].firstChildElement("image")
656 href = image.attribute("href")
657 for p in pagesLocationList:
658 if href in p:
659 binary = document.createElement("binary")
660 binary.setAttribute("id", href)
661 imageFile = QImage()
662 imageFile.load(p)
663 imageData = QByteArray()
664 buffer = QBuffer(imageData)
665 imageFile.save(buffer, "PNG")
666 # For now always embed as png.
667 contentType = "image/png"
668 binary.setAttribute("content-type", contentType)
669 binary.appendChild(document.createTextNode(str(bytearray(imageData.toBase64()).decode("ascii"))))
670
671 image.setAttribute("href", "#" + href)
672 data.appendChild(binary)
673
674 f = open(location, 'w', newline="", encoding="utf-8")
675 f.write(document.toString(indent=2))
676 f.close()
677 return True
678
679"""
680Function to parse svg text to acbf ready text
681"""
682
683def parseTextChildren(document = QDomDocument(), elRead = QDomElement(), elWrite = QDomElement(), emphasisStyle = {}, strongStyle = {}):
684 for n in range(0, elRead.childNodes().size()):
685 childNode = elRead.childNodes().item(n)
686 if childNode.isText():
687 if elWrite.hasChildNodes() and str(childNode.nodeValue()).startswith(" ") is False:
688 elWrite.appendChild(document.createTextNode(" "))
689 elWrite.appendChild(document.createTextNode(str(childNode.nodeValue())))
690 elif childNode.hasChildNodes():
691 childNode = childNode.toElement()
692 fontFamily = str(childNode.attribute("font-family"))
693 fontWeight = str(childNode.attribute("font-weight", "400"))
694 fontItalic = str(childNode.attribute("font-style"))
695 fontStrikeThrough = str(childNode.attribute("text-decoration"))
696 fontBaseLine = str(childNode.attribute("baseline-shift"))
697 newElementMade = False
698
699 emphasis = False
700 strong = False
701 if len(emphasisStyle.keys()) > 0:
702 emphasis = compare_styles(emphasisStyle, fontFamily, fontWeight, fontItalic)
703 else:
704 if fontItalic == "italic":
705 emphasis = True
706 if len(strongStyle.keys()) > 0:
707 strong = compare_styles(strongStyle, fontFamily, fontWeight, fontItalic)
708 else:
709 if fontWeight == "bold" or int(fontWeight) > 400:
710 strong = True
711
712 if strong:
713 newElement = document.createElement("strong")
714 newElementMade = True
715 elif emphasis:
716 newElement = document.createElement("emphasis")
717 newElementMade = True
718 elif fontStrikeThrough == "line-through":
719 newElement = document.createElement("strikethrough")
720 newElementMade = True
721 elif fontBaseLine.isalnum():
722 if (fontBaseLine == "super"):
723 newElement = document.createElement("sup")
724 newElementMade = True
725 elif (fontBaseLine == "sub"):
726 newElement = document.createElement("sub")
727 newElementMade = True
728
729 if newElementMade is True:
730 parseTextChildren(document, childNode, newElement, emphasisStyle, strongStyle)
731 elWrite.appendChild(newElement)
732 else:
733 parseTextChildren(document, childNode, elWrite, emphasisStyle, strongStyle)
734
735 # If it is not a text node, nor does it have children(which could be textnodes),
736 # we should assume it's empty and ignore it.
737 elWrite.normalize()
738 for e in range(0, elWrite.childNodes().size()):
739 el = elWrite.childNodes().item(e)
740 if el.isText():
741 eb = el.nodeValue()
742 el.setNodeValue(eb.replace(" ", " "))
743
744def compare_styles(style = {}, fontFamily = str(), fontWeight = str(), fontStyle = str()):
745 compare = []
746 if "font" in style.keys():
747 font = style.get("font")
748 if isinstance(font, list):
749 compare.append(fontFamily in font)
750 else:
751 compare.append((fontFamily == font))
752 if "bold" in style.keys():
753 compare.append(fontWeight == "bold" or int(fontWeight) > 400)
754 if "ital" in style.keys():
755 compare.append(fontStyle == "italic")
756 countTrue = 0
757 for i in compare:
758 if i is True:
759 countTrue +=1
760 if countTrue > 1:
761 return True
762 else:
763 return False
764"""
765This function tries to determine if there's a dominant color,
766and if not, it'll mix all of them.
767"""
768
769def findDominantColor(listOfColors = [QColor()]):
770 dominantColor = QColor()
771 listOfColorNames = {}
772
773 for color in listOfColors:
774 count = listOfColorNames.get(color.name(), 0)
775 listOfColorNames[color.name()] = count+1
776
777 # Check if there's a sense of dominant color:
778 clear_dominant = False
779
780 if len(listOfColorNames) == 2 and len(listOfColors) == 1:
781 clear_dominant = True
782 elif len(listOfColorNames) == 3 and len(listOfColors) == 2:
783 clear_dominant = True
784 elif len(listOfColorNames.keys()) < (len(listOfColors)*0.5):
785 clear_dominant = True
786
787 if clear_dominant:
788 namesSorted = sorted(listOfColorNames, key=listOfColorNames.get, reverse=True)
789 dominantColor = QColor(namesSorted[0])
790 else:
791 for color in listOfColors:
792 dominantColor.setRedF(0.5*(dominantColor.redF()+color.redF()))
793 dominantColor.setGreenF(0.5*(dominantColor.greenF()+color.greenF()))
794 dominantColor.setBlueF(0.5*(dominantColor.blueF()+color.blueF()))
795
796 return dominantColor
VertexDescriptor get(PredecessorMap const &m, VertexDescriptor v)
createStandAloneACBF(configDictionary, document=QDomDocument(), location=str(), pagesLocationList=[])
parseTextChildren(document=QDomDocument(), elRead=QDomElement(), elWrite=QDomElement(), emphasisStyle={}, strongStyle={})
write_xml(configDictionary={}, pageData=[], pagesLocationList=[], locationBasic=str(), locationStandAlone=str(), projectUrl=str())
compare_styles(style={}, fontFamily=str(), fontWeight=str(), fontStyle=str())