mirror of
https://github.com/ciromattia/kcc
synced 2025-12-19 20:51:45 +00:00
10
README.md
10
README.md
@@ -1,6 +1,6 @@
|
|||||||
# KCC
|
# KCC
|
||||||
|
|
||||||
[]() []() []()
|
[](https://github.com/ciromattia/kcc/releases) [](https://pypi.python.org/pypi/KindleComicConverter) [](https://aur.archlinux.org/packages/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.
|
**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.6 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
|
||||||
@@ -72,7 +72,7 @@ After completed conversion you should find ready file alongside the original inp
|
|||||||
|
|
||||||
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
||||||
|
|
||||||
CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-)
|
CLI version of **KCC** is intended for power users. It allow to use options that might not be compatible and decrease quality of output.
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
@@ -86,6 +86,7 @@ Options:
|
|||||||
KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
||||||
KoAO) [Default=KV]
|
KoAO) [Default=KV]
|
||||||
-m, --manga-style Manga style (right-to-left reading and splitting)
|
-m, --manga-style Manga style (right-to-left reading and splitting)
|
||||||
|
-q, --hq Try to increase the quality of magnification
|
||||||
-2, --two-panel Display two not four panels in Panel View mode
|
-2, --two-panel Display two not four panels in Panel View mode
|
||||||
-w, --webtoon Webtoon processing mode
|
-w, --webtoon Webtoon processing mode
|
||||||
|
|
||||||
@@ -170,6 +171,11 @@ The app relies and includes the following scripts:
|
|||||||
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
|
#### 5.4:
|
||||||
|
* Reimplemented high quality Panel View option
|
||||||
|
* Improved webtoon splitter
|
||||||
|
* Fixed page splitter
|
||||||
|
|
||||||
#### 5.3.1:
|
#### 5.3.1:
|
||||||
* Small increase of output quality
|
* Small increase of output quality
|
||||||
* Improved error reporting
|
* Improved error reporting
|
||||||
|
|||||||
62
gui/KCC.ui
62
gui/KCC.ui
@@ -66,7 +66,16 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
@@ -127,7 +136,16 @@
|
|||||||
<item row="4" column="0" colspan="2">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="optionWidget" native="true">
|
<widget class="QWidget" name="optionWidget" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
@@ -156,10 +174,13 @@
|
|||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 4 high quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Panel View 4/2</string>
|
<string>Panel View 4/2/HQ</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -238,7 +259,16 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@@ -267,7 +297,16 @@
|
|||||||
<item row="0" column="0" colspan="2">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="toolWidget" native="true">
|
<widget class="QWidget" name="toolWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item>
|
<item>
|
||||||
@@ -316,7 +355,16 @@
|
|||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
<property name="margin">
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
|
|||||||
2
kcc.iss
2
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "5.3.1"
|
#define MyAppVersion "5.4"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
|
|||||||
2
kcc.py
2
kcc.py
@@ -39,7 +39,7 @@ elif sys.platform.startswith('win'):
|
|||||||
class _Popen(forking.Popen):
|
class _Popen(forking.Popen):
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
if hasattr(sys, 'frozen'):
|
if hasattr(sys, 'frozen'):
|
||||||
# noinspection PyProtectedMember
|
# noinspection PyUnresolvedReferences,PyProtectedMember
|
||||||
os.putenv('_MEIPASS2', sys._MEIPASS)
|
os.putenv('_MEIPASS2', sys._MEIPASS)
|
||||||
try:
|
try:
|
||||||
super(_Popen, self).__init__(*args, **kw)
|
super(_Popen, self).__init__(*args, **kw)
|
||||||
|
|||||||
@@ -254,8 +254,10 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.splitter = 2
|
options.splitter = 2
|
||||||
elif GUI.rotateBox.checkState() == 2:
|
elif GUI.rotateBox.checkState() == 2:
|
||||||
options.splitter = 1
|
options.splitter = 1
|
||||||
if GUI.qualityBox.isChecked():
|
if GUI.qualityBox.checkState() == 1:
|
||||||
options.autoscale = True
|
options.autoscale = True
|
||||||
|
elif GUI.qualityBox.checkState() == 2:
|
||||||
|
options.hq = True
|
||||||
if GUI.webtoonBox.isChecked():
|
if GUI.webtoonBox.isChecked():
|
||||||
options.webtoon = True
|
options.webtoon = True
|
||||||
if GUI.upscaleBox.checkState() == 1:
|
if GUI.upscaleBox.checkState() == 1:
|
||||||
@@ -531,8 +533,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
def clearJobs(self):
|
def clearJobs(self):
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
|
|
||||||
# noinspection PyCallByClass,PyTypeChecker
|
|
||||||
def openWiki(self):
|
def openWiki(self):
|
||||||
|
# noinspection PyCallByClass
|
||||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki'))
|
QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki'))
|
||||||
|
|
||||||
def modeChange(self, mode):
|
def modeChange(self, mode):
|
||||||
@@ -613,6 +615,18 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.rotateBox.setEnabled(True)
|
GUI.rotateBox.setEnabled(True)
|
||||||
GUI.upscaleBox.setEnabled(True)
|
GUI.upscaleBox.setEnabled(True)
|
||||||
|
|
||||||
|
def togglequalityBox(self, value):
|
||||||
|
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
||||||
|
if value == 2:
|
||||||
|
if profile['Label'] in ['KV']:
|
||||||
|
self.addMessage('This option is intended for older Kindle models.', 'warning')
|
||||||
|
self.addMessage('It might not provide any quality increase in this case.', 'warning')
|
||||||
|
GUI.upscaleBox.setEnabled(False)
|
||||||
|
GUI.upscaleBox.setChecked(True)
|
||||||
|
else:
|
||||||
|
GUI.upscaleBox.setEnabled(True)
|
||||||
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
|
|
||||||
def changeGamma(self, value):
|
def changeGamma(self, value):
|
||||||
valueRaw = int(5 * round(float(value) / 5))
|
valueRaw = int(5 * round(float(value) / 5))
|
||||||
value = '%.2f' % (float(valueRaw) / 100)
|
value = '%.2f' % (float(valueRaw) / 100)
|
||||||
@@ -634,6 +648,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.changeFormat()
|
self.changeFormat()
|
||||||
GUI.gammaSlider.setValue(0)
|
GUI.gammaSlider.setValue(0)
|
||||||
self.changeGamma(0)
|
self.changeGamma(0)
|
||||||
|
if not GUI.webtoonBox.isChecked():
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
if not profile['PVOptions']:
|
if not profile['PVOptions']:
|
||||||
@@ -648,6 +663,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.formatBox.setCurrentIndex(outputFormat)
|
GUI.formatBox.setCurrentIndex(outputFormat)
|
||||||
else:
|
else:
|
||||||
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
||||||
|
if not GUI.webtoonBox.isChecked():
|
||||||
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
|
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
|
||||||
GUI.outputSplit.setEnabled(True)
|
GUI.outputSplit.setEnabled(True)
|
||||||
@@ -1002,6 +1018,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
||||||
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
||||||
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
|
||||||
|
GUI.qualityBox.stateChanged.connect(self.togglequalityBox)
|
||||||
GUI.deviceBox.activated.connect(self.changeDevice)
|
GUI.deviceBox.activated.connect(self.changeDevice)
|
||||||
GUI.formatBox.activated.connect(self.changeFormat)
|
GUI.formatBox.activated.connect(self.changeFormat)
|
||||||
MW.progressBarTick.connect(self.updateProgressbar)
|
MW.progressBarTick.connect(self.updateProgressbar)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'gui\KCC.ui'
|
# Form implementation generated from reading ui file 'gui\KCC.ui'
|
||||||
#
|
#
|
||||||
# Created by: PyQt5 UI code generator 5.6
|
# Created by: PyQt5 UI code generator 5.8.1
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
@@ -81,6 +81,7 @@ class Ui_mainWindow(object):
|
|||||||
self.rotateBox.setObjectName("rotateBox")
|
self.rotateBox.setObjectName("rotateBox")
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||||
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.qualityBox.setTristate(True)
|
||||||
self.qualityBox.setObjectName("qualityBox")
|
self.qualityBox.setObjectName("qualityBox")
|
||||||
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
||||||
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.webtoonBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
@@ -241,8 +242,8 @@ class Ui_mainWindow(object):
|
|||||||
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
||||||
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
||||||
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
||||||
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html>"))
|
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>"))
|
||||||
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2"))
|
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ"))
|
||||||
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
||||||
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
||||||
self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
|
self.upscaleBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>"))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.3.1'
|
__version__ = '5.4'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2017, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2017, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -16,12 +16,11 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
import os
|
||||||
from zipfile import is_zipfile, ZipFile
|
from zipfile import is_zipfile, ZipFile
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen
|
from psutil import Popen
|
||||||
from shutil import move, copy
|
from shutil import move
|
||||||
from . import rarfile
|
from . import rarfile
|
||||||
from .shared import check7ZFile as is_7zfile
|
from .shared import check7ZFile as is_7zfile
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
os.makedirs(htmlpath)
|
os.makedirs(htmlpath)
|
||||||
htmlfile = os.path.join(htmlpath, filename[0] + '.xhtml')
|
htmlfile = os.path.join(htmlpath, filename[0] + '.xhtml')
|
||||||
imgsize = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
|
imgsize = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
|
||||||
|
if options.hq:
|
||||||
|
imgsizeframe = deviceres
|
||||||
|
else:
|
||||||
|
imgsizeframe = imgsize
|
||||||
f = open(htmlfile, "w", encoding='UTF-8')
|
f = open(htmlfile, "w", encoding='UTF-8')
|
||||||
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
|
||||||
"<!DOCTYPE html>\n",
|
"<!DOCTYPE html>\n",
|
||||||
@@ -111,15 +115,18 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
"<title>", escape(filename[0]), "</title>\n",
|
"<title>", escape(filename[0]), "</title>\n",
|
||||||
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
"<link href=\"", "../" * (backref - 1), "style.css\" type=\"text/css\" rel=\"stylesheet\"/>\n",
|
||||||
"<meta name=\"viewport\" "
|
"<meta name=\"viewport\" "
|
||||||
"content=\"width=" + str(deviceres[0]) + ", height=" + str(deviceres[1]) + "\"/>\n"
|
"content=\"width=" + str(imgsize[0]) + ", height=" + str(imgsize[1]) + "\"/>\n"
|
||||||
"</head>\n",
|
"</head>\n",
|
||||||
"<body style=\"" + additionalStyle + "\">\n",
|
"<body style=\"" + additionalStyle + "\">\n",
|
||||||
"<div style=\"text-align:center;top:" + getTopMargin(deviceres, imgsize) + "%;\">\n",
|
"<div style=\"text-align:center;top:" + getTopMargin(deviceres, imgsize) + "%;\">\n",
|
||||||
"<img width=\"" + str(imgsize[0]) + "\" height=\"" + str(imgsize[1]) + "\" ",
|
"<img width=\"" + str(imgsizeframe[0]) + "\" height=\"" + str(imgsizeframe[1]) + "\" ",
|
||||||
"src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n</div>\n"])
|
"src=\"", "../" * backref, "Images/", postfix, imgfile, "\"/>\n</div>\n"])
|
||||||
if options.iskindle and options.panelview:
|
if options.iskindle and options.panelview:
|
||||||
if options.autoscale:
|
if options.autoscale:
|
||||||
size = (getPanelViewResolution(imgsize, deviceres))
|
size = (getPanelViewResolution(imgsize, deviceres))
|
||||||
|
else:
|
||||||
|
if options.hq:
|
||||||
|
size = imgsize
|
||||||
else:
|
else:
|
||||||
size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5))
|
size = (int(imgsize[0] * 1.5), int(imgsize[1] * 1.5))
|
||||||
if size[0] - deviceres[0] < deviceres[0] * 0.01:
|
if size[0] - deviceres[0] < deviceres[0] * 0.01:
|
||||||
@@ -455,7 +462,7 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
|||||||
|
|
||||||
def imgDirectoryProcessing(path):
|
def imgDirectoryProcessing(path):
|
||||||
global workerPool, workerOutput
|
global workerPool, workerOutput
|
||||||
workerPool = Pool()
|
workerPool = Pool(maxtasksperchild=100)
|
||||||
workerOutput = []
|
workerOutput = []
|
||||||
options.imgMetadata = {}
|
options.imgMetadata = {}
|
||||||
options.imgOld = []
|
options.imgOld = []
|
||||||
@@ -884,6 +891,8 @@ def makeParser():
|
|||||||
" KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
" KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
||||||
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Manga style (right-to-left reading and splitting)")
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
|
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
|
||||||
|
help="Try to increase the quality of magnification")
|
||||||
mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
||||||
help="Display two not four panels in Panel View mode")
|
help="Display two not four panels in Panel View mode")
|
||||||
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
||||||
@@ -960,16 +969,20 @@ def checkOptions():
|
|||||||
# Older Kindle models don't support Panel View.
|
# Older Kindle models don't support Panel View.
|
||||||
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
|
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
# Webtoon mode mandatory options
|
# Webtoon mode mandatory options
|
||||||
if options.webtoon:
|
if options.webtoon:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.righttoleft = False
|
options.righttoleft = False
|
||||||
options.upscale = True
|
options.upscale = True
|
||||||
|
options.hq = False
|
||||||
# Disable all Kindle features for other e-readers
|
# Disable all Kindle features for other e-readers
|
||||||
if options.profile == 'OTHER':
|
if options.profile == 'OTHER':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
if 'Ko' in options.profile:
|
if 'Ko' in options.profile:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
|
options.hq = False
|
||||||
# CBZ files on Kindle DX/DXG support higher resolution
|
# CBZ files on Kindle DX/DXG support higher resolution
|
||||||
if options.profile == 'KDX' and options.format == 'CBZ':
|
if options.profile == 'KDX' and options.format == 'CBZ':
|
||||||
options.customheight = 1200
|
options.customheight = 1200
|
||||||
@@ -1185,9 +1198,11 @@ def makeMOBI(work, qtGUI=None):
|
|||||||
threadNumber = 1
|
threadNumber = 1
|
||||||
elif 2 < availableMemory <= 4:
|
elif 2 < availableMemory <= 4:
|
||||||
threadNumber = 2
|
threadNumber = 2
|
||||||
else:
|
elif 4 < availableMemory <= 8:
|
||||||
threadNumber = 4
|
threadNumber = 4
|
||||||
makeMOBIWorkerPool = Pool(threadNumber)
|
else:
|
||||||
|
threadNumber = None
|
||||||
|
makeMOBIWorkerPool = Pool(threadNumber, maxtasksperchild=10)
|
||||||
for i in work:
|
for i in work:
|
||||||
makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick)
|
makeMOBIWorkerPool.apply_async(func=makeMOBIWorker, args=(i, ), callback=makeMOBIWorkerTick)
|
||||||
makeMOBIWorkerPool.close()
|
makeMOBIWorkerPool.close()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import sys
|
|||||||
from shutil import rmtree, copytree, move
|
from shutil import rmtree, copytree, move
|
||||||
from optparse import OptionParser, OptionGroup
|
from optparse import OptionParser, OptionGroup
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from PIL import Image, ImageStat, ImageOps
|
from PIL import Image, ImageChops, ImageOps, ImageDraw
|
||||||
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
from .shared import getImageFileName, walkLevel, walkSort, sanitizeTrace
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
@@ -67,8 +67,7 @@ def mergeDirectory(work):
|
|||||||
result = Image.new('RGB', (targetWidth, targetHeight))
|
result = Image.new('RGB', (targetWidth, targetHeight))
|
||||||
y = 0
|
y = 0
|
||||||
for i in imagesValid:
|
for i in imagesValid:
|
||||||
img = Image.open(i)
|
img = Image.open(i).convert('RGB')
|
||||||
img = img.convert('RGB')
|
|
||||||
if img.size[0] < targetWidth:
|
if img.size[0] < targetWidth:
|
||||||
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
result.paste(img, (0, y))
|
result.paste(img, (0, y))
|
||||||
@@ -80,30 +79,8 @@ def mergeDirectory(work):
|
|||||||
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
return str(sys.exc_info()[1]), sanitizeTrace(sys.exc_info()[2])
|
||||||
|
|
||||||
|
|
||||||
def sanitizePanelSize(panel, opt):
|
def detectSolid(img):
|
||||||
newPanels = []
|
return not ImageChops.invert(img).getbbox() or not img.getbbox()
|
||||||
if panel[2] > 6 * opt.height:
|
|
||||||
diff = int(panel[2] / 8)
|
|
||||||
newPanels.append([panel[0], panel[1] - diff * 7, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 7, panel[1] - diff * 6, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 6, panel[1] - diff * 5, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 5, panel[1] - diff * 4, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 4, panel[1] - diff * 3, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff])
|
|
||||||
newPanels.append([panel[1] - diff, panel[1], diff])
|
|
||||||
elif panel[2] > 3 * opt.height:
|
|
||||||
diff = int(panel[2] / 4)
|
|
||||||
newPanels.append([panel[0], panel[1] - diff * 3, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff])
|
|
||||||
newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff])
|
|
||||||
newPanels.append([panel[1] - diff, panel[1], diff])
|
|
||||||
elif panel[2] > 1.5 * opt.height:
|
|
||||||
newPanels.append([panel[0], panel[1] - int(panel[2] / 2), int(panel[2] / 2)])
|
|
||||||
newPanels.append([panel[1] - int(panel[2] / 2), panel[1], int(panel[2] / 2)])
|
|
||||||
else:
|
|
||||||
newPanels = [panel]
|
|
||||||
return newPanels
|
|
||||||
|
|
||||||
|
|
||||||
def splitImageTick(output):
|
def splitImageTick(output):
|
||||||
@@ -121,56 +98,60 @@ def splitImage(work):
|
|||||||
path = work[0]
|
path = work[0]
|
||||||
name = work[1]
|
name = work[1]
|
||||||
opt = work[2]
|
opt = work[2]
|
||||||
# Hardcoded options
|
|
||||||
threshold = 1.0
|
|
||||||
delta = 15
|
|
||||||
fileExpanded = os.path.splitext(name)
|
|
||||||
filePath = os.path.join(path, name)
|
filePath = os.path.join(path, name)
|
||||||
image = Image.open(filePath)
|
imgOrg = Image.open(filePath).convert('RGB')
|
||||||
image = image.convert('RGB')
|
imgProcess = Image.open(filePath).convert('1')
|
||||||
widthImg, heightImg = image.size
|
widthImg, heightImg = imgOrg.size
|
||||||
if heightImg > opt.height:
|
if heightImg > opt.height:
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
from PIL import ImageDraw
|
drawImg = Image.open(filePath).convert(mode='RGBA')
|
||||||
debugImage = Image.open(filePath)
|
draw = ImageDraw.Draw(drawImg)
|
||||||
draw = ImageDraw.Draw(debugImage)
|
|
||||||
|
|
||||||
# Find panels
|
# Find panels
|
||||||
y1 = 0
|
yWork = 0
|
||||||
y2 = 15
|
panelDetected = False
|
||||||
panels = []
|
panels = []
|
||||||
while y2 < heightImg:
|
while yWork < heightImg:
|
||||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg:
|
tmpImg = imgProcess.crop([0, yWork, widthImg, yWork + 4])
|
||||||
y2 += delta
|
solid = detectSolid(tmpImg)
|
||||||
y2 -= delta
|
if not solid and not panelDetected:
|
||||||
y1Temp = y2
|
panelDetected = True
|
||||||
y1 = y2 + delta
|
panelY1 = yWork - 2
|
||||||
y2 = y1 + delta
|
if solid and panelDetected:
|
||||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg:
|
panelDetected = False
|
||||||
y1 += delta
|
panelY2 = yWork + 6
|
||||||
y2 += delta
|
panels.append((panelY1, panelY2, panelY2 - panelY1))
|
||||||
if y1 + delta >= heightImg:
|
yWork += 5
|
||||||
y1 = heightImg - 1
|
|
||||||
y2Temp = y1
|
# Split too big panels
|
||||||
if opt.debug:
|
panelsProcessed = []
|
||||||
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0))
|
for panel in panels:
|
||||||
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0))
|
if panel[2] <= opt.height * 1.5:
|
||||||
panelHeight = y2Temp - y1Temp
|
panelsProcessed.append(panel)
|
||||||
if panelHeight > delta:
|
elif panel[2] < opt.height * 2:
|
||||||
# Panels that can't be cut nicely will be forcefully splitted
|
diff = panel[2] - opt.height
|
||||||
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
|
panelsProcessed.append((panel[0], panel[1] - diff, opt.height))
|
||||||
for panel in panelsCleaned:
|
panelsProcessed.append((panel[1] - opt.height, panel[1], opt.height))
|
||||||
panels.append(panel)
|
else:
|
||||||
|
parts = round(panel[2] / opt.height)
|
||||||
|
diff = panel[2] // parts
|
||||||
|
for x in range(0, parts):
|
||||||
|
panelsProcessed.append((panel[0] + (x * diff), panel[1] - ((parts - x - 1) * diff), diff))
|
||||||
|
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
|
for panel in panelsProcessed:
|
||||||
# noinspection PyUnboundLocalVariable
|
# noinspection PyUnboundLocalVariable
|
||||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
draw.rectangle([(0, panel[0]), (widthImg, panel[1])], (0, 255, 0, 128), (0, 0, 255, 255))
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
|
debugImage = Image.alpha_composite(imgOrg.convert(mode='RGBA'), drawImg)
|
||||||
|
debugImage.save(os.path.join(path, os.path.splitext(name)[0] + '-debug.png'), 'PNG')
|
||||||
|
|
||||||
# Create virtual pages
|
# Create virtual pages
|
||||||
pages = []
|
pages = []
|
||||||
currentPage = []
|
currentPage = []
|
||||||
pageLeft = opt.height
|
pageLeft = opt.height
|
||||||
panelNumber = 0
|
panelNumber = 0
|
||||||
for panel in panels:
|
for panel in panelsProcessed:
|
||||||
if pageLeft - panel[2] > 0:
|
if pageLeft - panel[2] > 0:
|
||||||
pageLeft -= panel[2]
|
pageLeft -= panel[2]
|
||||||
currentPage.append(panelNumber)
|
currentPage.append(panelNumber)
|
||||||
@@ -190,14 +171,14 @@ def splitImage(work):
|
|||||||
pageHeight = 0
|
pageHeight = 0
|
||||||
targetHeight = 0
|
targetHeight = 0
|
||||||
for panel in page:
|
for panel in page:
|
||||||
pageHeight += panels[panel][2]
|
pageHeight += panelsProcessed[panel][2]
|
||||||
if pageHeight > delta:
|
if pageHeight > 15:
|
||||||
newPage = Image.new('RGB', (widthImg, pageHeight))
|
newPage = Image.new('RGB', (widthImg, pageHeight))
|
||||||
for panel in page:
|
for panel in page:
|
||||||
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
panelImg = imgOrg.crop([0, panelsProcessed[panel][0], widthImg, panelsProcessed[panel][1]])
|
||||||
newPage.paste(panelImg, (0, targetHeight))
|
newPage.paste(panelImg, (0, targetHeight))
|
||||||
targetHeight += panels[panel][2]
|
targetHeight += panelsProcessed[panel][2]
|
||||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
newPage.save(os.path.join(path, os.path.splitext(name)[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||||
pageNumber += 1
|
pageNumber += 1
|
||||||
os.remove(filePath)
|
os.remove(filePath)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -238,13 +219,13 @@ def main(argv=None, qtGUI=None):
|
|||||||
work = []
|
work = []
|
||||||
pagenumber = 1
|
pagenumber = 1
|
||||||
splitWorkerOutput = []
|
splitWorkerOutput = []
|
||||||
splitWorkerPool = Pool()
|
splitWorkerPool = Pool(maxtasksperchild=10)
|
||||||
if options.merge:
|
if options.merge:
|
||||||
print("Merging images...")
|
print("Merging images...")
|
||||||
directoryNumer = 1
|
directoryNumer = 1
|
||||||
mergeWork = []
|
mergeWork = []
|
||||||
mergeWorkerOutput = []
|
mergeWorkerOutput = []
|
||||||
mergeWorkerPool = Pool()
|
mergeWorkerPool = Pool(maxtasksperchild=10)
|
||||||
mergeWork.append([options.targetDir])
|
mergeWork.append([options.targetDir])
|
||||||
for root, dirs, files in os.walk(options.targetDir, False):
|
for root, dirs, files in os.walk(options.targetDir, False):
|
||||||
dirs, files = walkSort(dirs, files)
|
dirs, files = walkSort(dirs, files)
|
||||||
@@ -263,7 +244,8 @@ def main(argv=None, qtGUI=None):
|
|||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
if len(mergeWorkerOutput) > 0:
|
if len(mergeWorkerOutput) > 0:
|
||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0], mergeWorkerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0][0],
|
||||||
|
mergeWorkerOutput[0][1])
|
||||||
print("Splitting images...")
|
print("Splitting images...")
|
||||||
for root, _, files in os.walk(options.targetDir, False):
|
for root, _, files in os.walk(options.targetDir, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
@@ -286,7 +268,8 @@ def main(argv=None, qtGUI=None):
|
|||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
if len(splitWorkerOutput) > 0:
|
if len(splitWorkerOutput) > 0:
|
||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0], splitWorkerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
|
||||||
|
splitWorkerOutput[0][1])
|
||||||
if options.inPlace:
|
if options.inPlace:
|
||||||
rmtree(options.sourceDir)
|
rmtree(options.sourceDir)
|
||||||
move(options.targetDir, options.sourceDir)
|
move(options.targetDir, options.sourceDir)
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ class ComicPageParser:
|
|||||||
width, height = self.image.size
|
width, height = self.image.size
|
||||||
dstwidth, dstheight = self.size
|
dstwidth, dstheight = self.size
|
||||||
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
|
||||||
and not self.opt.webtoon:
|
and not self.opt.webtoon and self.opt.splitter == 1:
|
||||||
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
|
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
|
||||||
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
||||||
if self.opt.splitter != 1:
|
if self.opt.splitter != 1:
|
||||||
@@ -209,6 +209,8 @@ class ComicPage:
|
|||||||
def __init__(self, options, mode, path, image, color, fill):
|
def __init__(self, options, mode, path, image, color, fill):
|
||||||
self.opt = options
|
self.opt = options
|
||||||
_, self.size, self.palette, self.gamma = self.opt.profileData
|
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||||
|
if self.opt.hq:
|
||||||
|
self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5))
|
||||||
self.image = image
|
self.image = image
|
||||||
self.color = color
|
self.color = color
|
||||||
self.fill = fill
|
self.fill = fill
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from sys import version_info
|
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
from time import sleep
|
|
||||||
from shutil import rmtree, copy
|
from shutil import rmtree, copy
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from zipfile import ZipFile, ZIP_DEFLATED
|
from zipfile import ZipFile, ZIP_DEFLATED
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import sys
|
|||||||
from . import __version__
|
from . import __version__
|
||||||
from .shared import dependencyCheck
|
from .shared import dependencyCheck
|
||||||
|
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
dependencyCheck(3)
|
dependencyCheck(3)
|
||||||
from . import KCC_gui
|
from . import KCC_gui
|
||||||
@@ -40,12 +41,14 @@ def start():
|
|||||||
KCCUI.handleMessage(sys.argv[1])
|
KCCUI.handleMessage(sys.argv[1])
|
||||||
sys.exit(KCCAplication.exec_())
|
sys.exit(KCCAplication.exec_())
|
||||||
|
|
||||||
|
|
||||||
def startC2E():
|
def startC2E():
|
||||||
dependencyCheck(2)
|
dependencyCheck(2)
|
||||||
from .comic2ebook import main
|
from .comic2ebook import main
|
||||||
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||||
sys.exit(main(sys.argv[1:]))
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
|
||||||
|
|
||||||
def startC2P():
|
def startC2P():
|
||||||
dependencyCheck(1)
|
dependencyCheck(1)
|
||||||
from .comic2panel import main
|
from .comic2panel import main
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>MacOS/Kindle Comic Converter</string>
|
<string>MacOS/Kindle Comic Converter</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>KindleComicConverter 5.3.1, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
<string>KindleComicConverter 5.4.0, written 2012-2017 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>comic2ebook.icns</string>
|
<string>comic2ebook.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -42,11 +42,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.3.1</string>
|
<string>5.4.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.3.1</string>
|
<string>5.4.0</string>
|
||||||
<key>LSEnvironment</key>
|
<key>LSEnvironment</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>PATH</key>
|
<key>PATH</key>
|
||||||
|
|||||||
20
setup.py
20
setup.py
@@ -2,10 +2,10 @@
|
|||||||
"""
|
"""
|
||||||
pip/pyinstaller build script for KCC.
|
pip/pyinstaller build script for KCC.
|
||||||
|
|
||||||
Usage (Windows):
|
Install as Python package:
|
||||||
py -3 setup.py build_binary
|
python3 setup.py install
|
||||||
|
|
||||||
Usage (Linux/OS X):
|
Create EXE/APP/DEB:
|
||||||
python3 setup.py build_binary
|
python3 setup.py build_binary
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -14,32 +14,22 @@ import sys
|
|||||||
import shutil
|
import shutil
|
||||||
import setuptools
|
import setuptools
|
||||||
import distutils.cmd
|
import distutils.cmd
|
||||||
from distutils.command.build import build
|
|
||||||
from kindlecomicconverter import __version__
|
from kindlecomicconverter import __version__
|
||||||
|
|
||||||
NAME = 'KindleComicConverter'
|
NAME = 'KindleComicConverter'
|
||||||
MAIN = 'kcc.py'
|
MAIN = 'kcc.py'
|
||||||
VERSION = __version__
|
VERSION = __version__
|
||||||
|
|
||||||
|
|
||||||
class BuildBinaryCommand(distutils.cmd.Command):
|
class BuildBinaryCommand(distutils.cmd.Command):
|
||||||
description = 'build binary release'
|
description = 'build binary release'
|
||||||
user_options = [
|
|
||||||
('pyz', None, 'build PYZ package'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def initialize_options(self):
|
|
||||||
# noinspection PyAttributeOutsideInit
|
|
||||||
self.pyz = False
|
|
||||||
|
|
||||||
def finalize_options(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
if os.path.isfile('Kindle Comic Converter.spec'):
|
if os.path.isfile('Kindle Comic Converter.spec'):
|
||||||
os.system('pyinstaller "Kindle Comic Converter.spec"')
|
os.system('pyinstaller "Kindle Comic Converter.spec"')
|
||||||
else:
|
else:
|
||||||
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s --noupx kcc.py')
|
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||||
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
shutil.copy('other/osx/7za', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
shutil.copy('other/osx/unrar', 'dist/Kindle Comic Converter.app/Contents/Resources')
|
||||||
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
shutil.copy('other/osx/Info.plist', 'dist/Kindle Comic Converter.app/Contents')
|
||||||
|
|||||||
Reference in New Issue
Block a user