1
0
mirror of https://github.com/ciromattia/kcc synced 2026-01-01 19:09:30 +00:00

Merge pull request #143 from ciromattia/dev

4.6
This commit is contained in:
Paweł Jastrzębski
2015-06-21 08:44:37 +02:00
12 changed files with 346 additions and 297 deletions

View File

@@ -1,7 +1,7 @@
# KCC
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
It was initially developed for Kindle but since version 4.0 it outputs valid EPUB 3.0 so _**despite its name, KCC is
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
actually a comic/manga to EPUB converter that every e-reader owner can happily use**_.
It can also optionally optimize images by applying a number of transformations.
@@ -33,10 +33,10 @@ You can find the latest released binary at the following links:
Following software is required to run Linux version of **KCC** and/or bare sources:
- Python 3.3+
- [PyQt](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.7.0+
- [psutil](https://pypi.python.org/pypi/psutil) 2.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify) 0.1.0+
- [scandir](https://pypi.python.org/pypi/scandir) 0.9+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.8.2+
- [psutil](https://pypi.python.org/pypi/psutil) 3.0.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify) 1.1.2+
- [scandir](https://pypi.python.org/pypi/scandir) 1.1.0+
On Debian based distributions these two commands should install all needed dependencies:
```
@@ -75,8 +75,7 @@ Options:
MAIN:
-p PROFILE, --profile=PROFILE
Device profile (Available options: K1, K2, K345, KDX,
KPW, KV, KFHD, KFHDX, KFHDX8, KFA, KoMT, KoG, KoGHD, KoA,
KoAHD, KoAH2O) [Default=KV]
KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O) [Default=KV]
-q QUALITY, --quality=QUALITY
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
-m, --manga-style Manga style (Right-to-left reading and splitting)
@@ -145,18 +144,25 @@ The app relies and includes the following scripts:
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
## SAMPLE FILES CREATED BY KCC
* [Kindle Voyage](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
* [Kindle Paperwhite](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle Paperwhite 3 / Voyage](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.cbz)
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu!-KoMT.cbz)
* [Kobo Glo](http://kcc.iosphe.re/Samples/Ubunchu!-KoG.cbz)
* [Kobo Glo HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoGHD.cbz)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu!-KoA.cbz)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoAHD.cbz)
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu!-KoAH2O.cbz)
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu-KoMT.kepub.epub)
* [Kobo Glo](http://kcc.iosphe.re/Samples/Ubunchu-KoG.kepub.epub)
* [Kobo Glo HD](http://kcc.iosphe.re/Samples/Ubunchu-KoGHD.kepub.epub)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
## CHANGELOG
####4.6:
* KEPUB is now default output for all Kobo profiles
* EPUB output now produce fully valid EPUB 3.0.1
* Added profile for Kindle Paperwhite 3
* Dropped official support of all Kindle Fire models and Kindle for Android
* Other minor tweaks
####4.5.1:
* Added Kobo Glo HD profile
* Fixed RAR/CBR parsing anomalies

View File

@@ -34,4 +34,4 @@ if __name__ == "__main__":
freeze_support()
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
main(sys.argv[1:])
sys.exit(0)
sys.exit(0)

View File

@@ -34,4 +34,4 @@ if __name__ == "__main__":
freeze_support()
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
main(sys.argv[1:])
sys.exit(0)
sys.exit(0)

View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter"
#define MyAppVersion "4.5.1"
#define MyAppVersion "4.6"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.iosphe.re/"
#define MyAppExeName "KCC.exe"

View File

@@ -375,9 +375,6 @@ class WorkerThread(QtCore.QThread):
elif GUI.QualityBox.checkState() == 2:
options.quality = 2
options.format = str(GUI.FormatBox.currentText())
if GUI.currentMode == 1:
if 'KFH' in profile:
options.upscale = True
# Advanced mode settings
if GUI.currentMode > 1:
@@ -557,6 +554,7 @@ class WorkerThread(QtCore.QThread):
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
def __init__(self):
super().__init__()
if self.isSystemTrayAvailable():
QtWidgets.QSystemTrayIcon.__init__(self, GUI.icons.programIcon, MW)
# noinspection PyUnresolvedReferences
@@ -1161,50 +1159,38 @@ class KCCGUI(KCC_ui.Ui_KCC):
self.p.ionice(1)
self.profiles = {
"Kindle Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KV'},
"Kindle Paperwhite": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KPW'},
"K. PW 3/Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KV'},
"Kindle PW 1/2": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KPW'},
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K345'},
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
'DefaultUpscale': False, 'Label': 'KDX'},
"K. Fire HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHD'},
"K. Fire HDX": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHDX'},
"K. Fire HDX 8.9": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KFHDX8'},
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Mini/Touch": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoMT'},
"Kobo Glo": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Glo": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoG'},
"Kobo Glo HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Glo HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoGHD'},
"Kobo Aura": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Aura": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoA'},
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Aura HD": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoAHD'},
"Kobo Aura H2O": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 2,
"Kobo Aura H2O": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'KoAH2O'},
"Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'OTHER'},
"Kindle for Android": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'KFA'},
"Kindle 1": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K1'},
"Kindle 2": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K2'}
}
profilesGUI = [
"Kindle Voyage",
"Kindle Paperwhite",
"K. PW 3/Voyage",
"Kindle PW 1/2",
"Kindle",
"Separator",
"K. Fire HD",
"K. Fire HDX",
"K. Fire HDX 8.9",
"Separator",
"Kobo Mini/Touch",
"Kobo Glo",
"Kobo Glo HD",
@@ -1214,7 +1200,6 @@ class KCCGUI(KCC_ui.Ui_KCC):
"Separator",
"Other",
"Separator",
"Kindle for Android",
"Kindle 1",
"Kindle 2",
"Kindle DX/DXG",

View File

@@ -1,4 +1,4 @@
__version__ = '4.5.1'
__version__ = '4.6'
__license__ = 'ISC'
__copyright__ = '2012-2015, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
__docformat__ = 'restructuredtext en'

View File

@@ -20,6 +20,7 @@
import os
import sys
from time import strftime, gmtime
from copy import copy
from glob import glob
from json import loads
@@ -119,83 +120,98 @@ def buildHTML(path, imgfile, imgfilepath, forcePV=False):
os.makedirs(htmlpath)
htmlfile = os.path.join(htmlpath, filename[0] + '.html')
f = open(htmlfile, "w", encoding='UTF-8')
f.writelines(["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" ",
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n",
"<head>\n",
"<title>", filename[0], "</title>\n",
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n",
"<link href=\"", "../" * (backref - 1),
"style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
"</head>\n",
"<body" + additionalStyle + ">\n",
"<div class=\"fs\">\n",
"<div><img src=\"", "../" * backref, "Images/", postfix, imgfile, "\" alt=\"",
imgfile, "\" class=\"singlePage\"/></div>\n"
])
if (options.panelview or forcePV) and not noPV:
options.panelviewused = True
if not noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [1, 3, 2, 4]
if options.iskindle:
f.writelines(["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
"<!DOCTYPE html>\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
"<head>\n",
"<title>", filename[0], "</title>\n",
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
"<meta charset=\"utf-8\"/>\n",
"</head>\n",
"<body" + additionalStyle + ">\n",
"<div class=\"fs\">\n",
"<div><img src=\"", "../" * backref, "Images/", postfix, imgfile, "\" alt=\"",
imgfile, "\" class=\"singlePage\"/></div>\n"
])
if (options.panelview or forcePV) and not noPV:
options.panelviewused = True
if not noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [1, 3, 2, 4]
else:
order = [2, 4, 1, 3]
else:
order = [2, 4, 1, 3]
else:
if options.righttoleft:
order = [2, 1, 4, 3]
else:
order = [1, 2, 3, 4]
boxes = ["BoxTL", "BoxTR", "BoxBL", "BoxBR"]
elif noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [1, 2]
else:
order = [2, 1]
else:
order = [1, 2]
boxes = ["BoxT", "BoxB"]
elif not noHorizontalPV and noVerticalPV:
if rotatedPage:
order = [1, 2]
else:
if options.righttoleft:
order = [2, 1]
if options.righttoleft:
order = [2, 1, 4, 3]
else:
order = [1, 2, 3, 4]
boxes = ["BoxTL", "BoxTR", "BoxBL", "BoxBR"]
elif noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [1, 2]
else:
order = [2, 1]
else:
order = [1, 2]
boxes = ["BoxL", "BoxR"]
else:
order = [1]
boxes = ["BoxC"]
for i in range(0, len(boxes)):
f.writelines(["<div id=\"" + boxes[i] + "\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"" + boxes[i] + "-Panel-Parent\", \"ordinal\":" + str(order[i]),
"}'></a></div>\n"])
if options.quality == 2 and not forcePV:
imgfilepv = imgfile.split(".")
imgfilepv[0] += "-hq"
imgfilepv = ".".join(imgfilepv)
else:
imgfilepv = imgfile
xl, yu, xr, yd = detectMargins(imgfilepath)
boxStyles = {"BoxTL": "left:" + xl + ";top:" + yu + ";",
"BoxTR": "right:" + xr + ";top:" + yu + ";",
"BoxBL": "left:" + xl + ";bottom:" + yd + ";",
"BoxBR": "right:" + xr + ";bottom:" + yd + ";",
"BoxT": "left:-25%;top:" + yu + ";",
"BoxB": "left:-25%;bottom:" + yd + ";",
"BoxL": "left:" + xl + ";top:-25%;",
"BoxR": "right:" + xr + ";top:-25%;",
"BoxC": "left:-25%;top:-25%;"
}
for box in boxes:
f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"",
"Generic-Panel\" class=\"target-mag\"><img style=\"" + boxStyles[box] + "\" src=\"",
"../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"" + imgfilepv,
"\"/></div></div>\n",
])
f.writelines(["</div>\n</body>\n</html>"])
boxes = ["BoxT", "BoxB"]
elif not noHorizontalPV and noVerticalPV:
if rotatedPage:
order = [1, 2]
else:
if options.righttoleft:
order = [2, 1]
else:
order = [1, 2]
boxes = ["BoxL", "BoxR"]
else:
order = [1]
boxes = ["BoxC"]
for i in range(0, len(boxes)):
f.writelines(["<div id=\"" + boxes[i] + "\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"" + boxes[i] + "-Panel-Parent\", \"ordinal\":" + str(order[i]),
"}'></a></div>\n"])
if options.quality == 2 and not forcePV:
imgfilepv = imgfile.split(".")
imgfilepv[0] += "-hq"
imgfilepv = ".".join(imgfilepv)
else:
imgfilepv = imgfile
xl, yu, xr, yd = detectMargins(imgfilepath)
boxStyles = {"BoxTL": "left:" + xl + ";top:" + yu + ";",
"BoxTR": "right:" + xr + ";top:" + yu + ";",
"BoxBL": "left:" + xl + ";bottom:" + yd + ";",
"BoxBR": "right:" + xr + ";bottom:" + yd + ";",
"BoxT": "left:-25%;top:" + yu + ";",
"BoxB": "left:-25%;bottom:" + yd + ";",
"BoxL": "left:" + xl + ";top:-25%;",
"BoxR": "right:" + xr + ";top:-25%;",
"BoxC": "left:-25%;top:-25%;"
}
for box in boxes:
f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"",
"Generic-Panel\" class=\"target-mag\"><img style=\"" + boxStyles[box] + "\" src=\"",
"../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"" + imgfilepv,
"\"/></div></div>\n",
])
f.writelines(["</div>\n</body>\n</html>"])
else:
f.writelines(["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
"<!DOCTYPE html>\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
"<head>\n",
"<title>", filename[0], "</title>\n",
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
"<meta charset=\"utf-8\"/>\n",
"</head>\n",
"<body" + additionalStyle + ">\n",
"<div class=\"epub:type=bodymatter\">\n",
"<img src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n",
"</div>\n",
"</body>\n</html>"
])
f.close()
return path, imgfile
@@ -205,11 +221,9 @@ def buildNCX(dstdir, title, chapters, chapterNames):
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
f = open(ncxfile, "w", encoding='UTF-8')
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\" ",
"\"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n",
"<ncx version=\"2005-1\" xml:lang=\"en-US\" xmlns=\"http://www.daisy.org/z3986/2005/ncx/\">\n",
"<head>\n",
"<meta name=\"dtb:uid\" content=\"", options.uuid, "\"/>\n",
"<meta name=\"dtb:uid\" content=\"urn:uuid:", options.uuid, "\"/>\n",
"<meta name=\"dtb:depth\" content=\"1\"/>\n",
"<meta name=\"dtb:totalPageCount\" content=\"0\"/>\n",
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
@@ -234,6 +248,35 @@ def buildNCX(dstdir, title, chapters, chapterNames):
f.close()
def buildNAV(dstdir, title, chapters, chapterNames):
navfile = os.path.join(dstdir, 'OEBPS', 'nav.xhtml')
f = open(navfile, "w", encoding='UTF-8')
f.writelines(["<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
"<!DOCTYPE html>\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xmlns:epub=\"http://www.idpf.org/2007/ops\">\n",
"<head>\n",
"<title>" + title + "</title>\n",
"<meta charset=\"utf-8\"/>\n",
"</head>\n",
"<body>\n",
"<nav xmlns:epub=\"http://www.idpf.org/2007/ops\" epub:type=\"toc\" id=\"toc\">\n",
"<ol></ol>\n",
"</nav>\n",
"<nav epub:type=\"page-list\">\n",
"<ol>\n"
])
for chapter in chapters:
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
filename = getImageFileName(os.path.join(folder, chapter[1]))
if options.chapters:
title = chapterNames[chapter[1]]
elif os.path.basename(folder) != "Text":
title = chapterNames[os.path.basename(folder)]
f.write("<li><a href=\"" + filename[0].replace("\\", "/") + ".html\">" + title + "</a></li>\n")
f.write("</ol>\n</nav>\n</body>\n</html>")
f.close()
def buildOPF(dstdir, title, filelist, cover=None):
opffile = os.path.join(dstdir, 'OEBPS', 'content.opf')
profilelabel, deviceres, palette, gamma, panelviewsize = options.profileData
@@ -243,40 +286,47 @@ def buildOPF(dstdir, title, filelist, cover=None):
writingmode = "horizontal-lr"
f = open(opffile, "w", encoding='UTF-8')
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<package version=\"2.0\" unique-identifier=\"BookID\" ",
"<package version=\"3.0\" unique-identifier=\"BookID\" ",
"prefix=\"rendition: http://www.idpf.org/vocab/rendition/#\" ",
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
"<dc:title>", title, "</dc:title>\n",
"<dc:language>en-US</dc:language>\n",
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
"<dc:identifier id=\"BookID\">urn:uuid:", options.uuid, "</dc:identifier>\n",
"<dc:contributor id=\"contributor\">KindleComicConverter-" + __version__ + "</dc:contributor>\n"])
for author in options.authors:
f.writelines(["<dc:creator>", author, "</dc:creator>\n"])
f.writelines(["<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
"<meta name=\"region-mag\" content=\"true\"/>\n",
f.writelines(["<meta property=\"dcterms:modified\">" + strftime("%Y-%m-%dT%H:%M:%SZ", gmtime()) + "</meta>\n",
"<meta name=\"cover\" content=\"cover\"/>\n",
"<meta name=\"book-type\" content=\"comic\"/>\n",
"<meta name=\"rendition:layout\" content=\"pre-paginated\"/>\n",
"<meta name=\"zero-gutter\" content=\"true\"/>\n",
"<meta name=\"zero-margin\" content=\"true\"/>\n",
"<meta name=\"fixed-layout\" content=\"true\"/>\n"
"<meta name=\"rendition:orientation\" content=\"portrait\"/>\n",
"<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
"<meta name=\"original-resolution\" content=\"",
str(deviceres[0]) + "x" + str(deviceres[1]), "\"/>\n",
"<meta name=\"primary-writing-mode\" content=\"", writingmode, "\"/>\n",
"<meta name=\"ke-border-color\" content=\"#ffffff\"/>\n",
"<meta name=\"ke-border-width\" content=\"0\"/>\n",
"</metadata>\n<manifest>\n<item id=\"ncx\" href=\"toc.ncx\" ",
"media-type=\"application/x-dtbncx+xml\"/>\n"])
"<meta property=\"rendition:orientation\">portrait</meta>\n",
"<meta property=\"rendition:spread\">portrait</meta>\n",
"<meta property=\"rendition:layout\">pre-paginated</meta>\n"])
if options.iskindle and options.profile != 'Custom':
f.writelines(["<meta property=\"RegionMagnification\">true</meta>\n",
"<meta property=\"region-mag\">true</meta>\n",
"<meta property=\"book-type\">comic</meta>\n",
"<meta property=\"zero-gutter\">true</meta>\n",
"<meta property=\"zero-margin\">true</meta>\n",
"<meta property=\"fixed-layout\">true</meta>\n",
"<meta property=\"orientation-lock\">portrait</meta>\n",
"<meta property=\"original-resolution\">",
str(deviceres[0]) + "x" + str(deviceres[1]) + "</meta>\n",
"<meta property=\"primary-writing-mode\">" + writingmode + "</meta>\n",
"<meta property=\"ke-border-color\">#ffffff</meta>\n",
"<meta property=\"ke-border-width\">0</meta>\n"])
f.writelines(["</metadata>\n<manifest>\n<item id=\"ncx\" href=\"toc.ncx\" ",
"media-type=\"application/x-dtbncx+xml\"/>\n",
"<item id=\"nav\" href=\"nav.xhtml\" ",
"properties=\"nav\" media-type=\"application/xhtml+xml\"/>\n"])
if cover is not None:
filename = getImageFileName(cover.replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\'))
if '.png' == filename[1]:
mt = 'image/png'
else:
mt = 'image/jpeg'
f.write("<item id=\"cover\" href=\"Images/cover" + filename[1] + "\" media-type=\"" + mt + "\"/>\n")
f.write("<item id=\"cover\" href=\"Images/cover" + filename[1] + "\" media-type=\"" + mt +
"\" properties=\"cover-image\"/>\n")
reflist = []
for path in filelist:
folder = path[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\').replace("\\", "/")
@@ -299,7 +349,7 @@ def buildOPF(dstdir, title, filelist, cover=None):
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
for entry in reflist:
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
f.write("</spine>\n<guide>\n</guide>\n</package>\n")
f.write("</spine>\n</package>\n")
f.close()
os.mkdir(os.path.join(dstdir, 'META-INF'))
f = open(os.path.join(dstdir, 'META-INF', 'container.xml'), 'w', encoding='UTF-8')
@@ -320,114 +370,126 @@ def buildEPUB(path, chapterNames, tomeNumber):
_, deviceres, _, _, panelviewsize = options.profileData
os.mkdir(os.path.join(path, 'OEBPS', 'Text'))
f = open(os.path.join(path, 'OEBPS', 'Text', 'style.css'), 'w', encoding='UTF-8')
# DON'T COMPRESS CSS. KINDLE WILL FAIL TO PARSE IT.
# Generic Panel View support + Margins fix for Non-Kindle devices.
f.writelines(["@page {\n",
"margin-bottom: 0;\n",
"margin-top: 0\n",
"}\n",
"body {\n",
"display: block;\n",
"margin-bottom: 0;\n",
"margin-left: 0;\n",
"margin-right: 0;\n",
"margin-top: 0;\n",
"padding-bottom: 0;\n",
"padding-left: 0;\n",
"padding-right: 0;\n",
"padding-top: 0;\n",
"text-align: left\n",
"}\n",
"div.fs {\n",
"height: ", str(deviceres[1]), "px;\n",
"width: ", str(deviceres[0]), "px;\n",
"position: relative;\n",
"display: block;\n",
"text-align: center\n",
"}\n",
"div.fs a {\n",
"display: block;\n",
"width : 100%;\n",
"height: 100%;\n",
"}\n",
"div.fs div {\n",
"position: absolute;\n",
"}\n",
"img.singlePage {\n",
"position: absolute;\n",
"height: ", str(deviceres[1]), "px;\n",
"width: ", str(deviceres[0]), "px;\n",
"}\n",
"div.target-mag-parent {\n",
"width:100%;\n",
"height:100%;\n",
"display:none;\n",
"}\n",
"div.target-mag {\n",
"position: absolute;\n",
"display: block;\n",
"overflow: hidden;\n",
"}\n",
"div.target-mag img {\n",
"position: absolute;\n",
"height: ", str(panelviewsize[1]), "px;\n",
"width: ", str(panelviewsize[0]), "px;\n",
"}\n",
"#Generic-Panel {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxC {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxT {\n",
"top: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxB {\n",
"bottom: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxL {\n",
"left: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxR {\n",
"right: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxTL {\n",
"top: 0;\n",
"left: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxTR {\n",
"top: 0;\n",
"right: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxBL {\n",
"bottom: 0;\n",
"left: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxBR {\n",
"bottom: 0;\n",
"right: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}",
])
if options.iskindle:
f.writelines(["@page {\n",
"margin-bottom: 0;\n",
"margin-top: 0\n",
"}\n",
"body {\n",
"display: block;\n",
"margin-bottom: 0;\n",
"margin-left: 0;\n",
"margin-right: 0;\n",
"margin-top: 0;\n",
"padding-bottom: 0;\n",
"padding-left: 0;\n",
"padding-right: 0;\n",
"padding-top: 0;\n",
"text-align: left\n",
"}\n",
"div.fs {\n",
"height: ", str(deviceres[1]), "px;\n",
"width: ", str(deviceres[0]), "px;\n",
"position: relative;\n",
"display: block;\n",
"text-align: center\n",
"}\n",
"div.fs a {\n",
"display: block;\n",
"width : 100%;\n",
"height: 100%;\n",
"}\n",
"div.fs div {\n",
"position: absolute;\n",
"}\n",
"img.singlePage {\n",
"position: absolute;\n",
"height: ", str(deviceres[1]), "px;\n",
"width: ", str(deviceres[0]), "px;\n",
"}\n",
"div.target-mag-parent {\n",
"width:100%;\n",
"height:100%;\n",
"display:none;\n",
"}\n",
"div.target-mag {\n",
"position: absolute;\n",
"display: block;\n",
"overflow: hidden;\n",
"}\n",
"div.target-mag img {\n",
"position: absolute;\n",
"height: ", str(panelviewsize[1]), "px;\n",
"width: ", str(panelviewsize[0]), "px;\n",
"}\n",
"#Generic-Panel {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxC {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxT {\n",
"top: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxB {\n",
"bottom: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxL {\n",
"left: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxR {\n",
"right: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxTL {\n",
"top: 0;\n",
"left: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxTR {\n",
"top: 0;\n",
"right: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxBL {\n",
"bottom: 0;\n",
"left: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxBR {\n",
"bottom: 0;\n",
"right: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}",
])
else:
f.writelines([
"@namespace epub \"http://www.idpf.org/2007/ops\";\n",
"@charset \"UTF-8\";\n",
"body {\n",
"margin: 0;\n",
"}\n",
"img {\n",
"position: absolute;\n",
"margin: 0;\n",
"z-index: 0;\n",
"height: 100%;\n",
"}"])
f.close()
for (dirpath, dirnames, filenames) in walk(os.path.join(path, 'OEBPS', 'Images')):
chapter = False
@@ -446,7 +508,7 @@ def buildEPUB(path, chapterNames, tomeNumber):
image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options, tomeNumber)
# Hack that force Panel View on at last one page
if lastfile and not options.panelviewused and 'Ko' not in options.profile \
and options.profile not in ['K1', 'K2', 'KDX', 'OTHER']:
and options.profile not in ['K1', 'K2', 'KDX', 'Custom']:
filelist[-1] = buildHTML(lastfile[0], lastfile[1], lastfile[2], True)
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
if not chapterNames and options.chapters:
@@ -464,6 +526,7 @@ def buildEPUB(path, chapterNames, tomeNumber):
chapterNames[filename] = aChapter[1]
globaldiff = pageid - (aChapter[0] + globaldiff)
buildNCX(path, options.title, chapterlist, chapterNames)
buildNAV(path, options.title, chapterlist, chapterNames)
buildOPF(path, options.title, filelist, cover)
@@ -608,7 +671,7 @@ def getWorkFolder(afile):
raise UserWarning("Failed to extract file.")
else:
rmtree(workdir, True)
raise TypeError
raise TypeError("Failed to detect archive format.")
if len(os.path.join(path, 'OEBPS', 'Images')) > 240:
raise UserWarning("Path is too long.")
move(path, path + "_temp")
@@ -976,8 +1039,8 @@ def makeParser():
otherOptions = OptionGroup(psr, "OTHER")
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
help="Device profile (Available options: K1, K2, K345, KDX, KPW, KV, KFHD, KFHDX, KFHDX8,"
" KFA, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O) [Default=KV]")
help="Device profile (Available options: K1, K2, K345, KDX, KPW, KV, KoMT, KoG, KoGHD,"
" KoA, KoAHD, KoAH2O) [Default=KV]")
mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0",
help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]")
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
@@ -1037,14 +1100,17 @@ def checkOptions():
global options
options.panelview = True
options.panelviewused = False
options.iskindle = False
options.bordersColor = None
if options.format == 'Auto':
if options.profile in ['K1', 'K2', 'K345', 'KPW', 'KV', 'KFHD', 'KFHDX', 'KFHDX8', 'KFA']:
if options.profile in ['K1', 'K2', 'K345', 'KPW', 'KV']:
options.format = 'MOBI'
elif options.profile in ['Other']:
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O']:
options.format = 'EPUB'
elif options.profile in ['KDX', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O']:
elif options.profile in ['KDX']:
options.format = 'CBZ'
if options.profile in ['K1', 'K2', 'K345', 'KPW', 'KV', 'OTHER']:
options.iskindle = True
if options.white_borders:
options.bordersColor = 'white'
if options.black_borders:
@@ -1052,11 +1118,6 @@ def checkOptions():
# Splitting MOBI is not optional
if options.format == 'MOBI':
options.batchsplit = True
# Disabling grayscale conversion for Kindle Fire family.
if 'KFH' in options.profile or options.forcecolor:
options.forcecolor = True
else:
options.forcecolor = False
# Older Kindle don't need higher resolution files due lack of Panel View.
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
options.quality = 0
@@ -1075,10 +1136,6 @@ def checkOptions():
# Kobo models can't use ultra quality mode
if options.quality == 2:
options.quality = 1
# Kindle for Android profile require target resolution.
if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0):
print("ERROR: Kindle for Android profile require --customwidth and --customheight options!")
sys.exit(1)
# CBZ files on Kindle DX/DXG support higher resolution
if options.profile == 'KDX' and options.format == 'CBZ':
options.customheight = 1200
@@ -1182,6 +1239,11 @@ def makeBook(source, qtGUI=None):
filepath.append(getOutputFilename(source, options.output, '.epub', ''))
makeZIP(tome + '_comic', tome, True)
move(tome + '_comic.zip', filepath[-1])
if 'Ko' in options.profile:
filename = filepath[-1].split(os.path.sep)
filename[-1] = ''.join(e for e in filename[-1].split('.')[0] if e.isalnum()) + '.kepub.epub'
filename = os.path.sep.join(filename)
move(filepath[-1], filename)
rmtree(tome, True)
if GUI:
GUI.progressBarTick.emit('tick')
@@ -1211,7 +1273,7 @@ def makeMOBIFix(item):
mobiPath = item.replace('.epub', '.mobi')
move(mobiPath, mobiPath + '_toclean')
try:
dualmetafix.DualMobiMetaFix(mobiPath + '_toclean', mobiPath, bytes(str(uuid4()), 'UTF-8'))
dualmetafix.DualMobiMetaFix(mobiPath + '_toclean', mobiPath, bytes(options.uuid, 'UTF-8'))
return [True]
except Exception as err:
return [False, format(err)]

View File

@@ -297,4 +297,4 @@ def main(argv=None, qtGUI=None):
else:
raise UserWarning("Provided path is not a directory.")
else:
raise UserWarning("Target height is not set.")
raise UserWarning("Target height is not set.")

View File

@@ -181,4 +181,4 @@ class DualMobiMetaFix:
replacesection(self.datain, datain_kf8, rec0)
self.datain.flush()
self.datain.close()
self.datain.close()

View File

@@ -82,12 +82,8 @@ class ProfileData:
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
'KPW': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KV': ("Kindle Voyage", (1072, 1448), Palette16, 1.8, (1608, 2172)),
'KFHD': ("K. Fire HD", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
'KFHDX': ("K. Fire HDX", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
'KFHDX8': ("K. Fire HDX 8.9", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KV': ("Kindle Paperwhite 3/Voyage", (1072, 1448), Palette16, 1.8, (1608, 2172)),
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)),
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)),

View File

@@ -130,28 +130,28 @@ def dependencyCheck(level):
if level > 1:
try:
from psutil import __version__ as psutilVersion
if StrictVersion('2.0.0') > StrictVersion(psutilVersion):
missing.append('psutil 2.0.0+')
if StrictVersion('3.0.0') > StrictVersion(psutilVersion):
missing.append('psutil 3.0.0+')
except ImportError:
missing.append('psutil 2.0.0+')
missing.append('psutil 3.0.0+')
try:
from slugify import __version__ as slugifyVersion
if StrictVersion('0.1.0') > StrictVersion(slugifyVersion):
missing.append('python-slugify 0.1.0+')
if StrictVersion('1.1.2') > StrictVersion(slugifyVersion):
missing.append('python-slugify 1.1.2+')
except ImportError:
missing.append('python-slugify 0.1.0+')
missing.append('python-slugify 1.1.2+')
try:
from PIL import PILLOW_VERSION as pillowVersion
if StrictVersion('2.7.0') > StrictVersion(pillowVersion):
missing.append('Pillow 2.7.0+')
if StrictVersion('2.8.2') > StrictVersion(pillowVersion):
missing.append('Pillow 2.8.2+')
except ImportError:
missing.append('Pillow 2.7.0+')
missing.append('Pillow 2.8.2+')
try:
from scandir import __version__ as scandirVersion
if StrictVersion('0.9') > StrictVersion(scandirVersion):
missing.append('scandir 0.9+')
if StrictVersion('1.1') > StrictVersion(scandirVersion):
missing.append('scandir 1.1+')
except ImportError:
missing.append('scandir 0.9+')
missing.append('scandir 1.1+')
if len(missing) > 0:
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
exit(1)
exit(1)

View File

@@ -135,10 +135,10 @@ else:
scripts=['build/_scripts/kcc', 'build/_scripts/kcc-c2e', 'build/_scripts/kcc-c2p'],
packages=['kcc'],
install_requires=[
'Pillow>=2.7.0',
'psutil>=2.0',
'python-slugify>=0.1.0',
'scandir>=0.9',
'Pillow>=2.8.2',
'psutil>=3.0.0',
'python-slugify>=1.1.2',
'scandir>=1.1.0',
],
zip_safe=False,
)
@@ -159,4 +159,4 @@ if platform == 'darwin':
makedirs('dist/' + NAME + '.app/Contents/PlugIns/platforms', exist_ok=True)
copyfile('other/libqcocoa.dylib', 'dist/' + NAME + '.app/Contents/PlugIns/platforms/libqcocoa.dylib')
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)