mirror of
https://github.com/ciromattia/kcc
synced 2026-08-01 17:41:29 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7206c0cd48 |
@@ -71,7 +71,7 @@ jobs:
|
||||
# apply provisioning profile
|
||||
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 16
|
||||
- run: npm install -g appdmg
|
||||
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
pip3 install --upgrade pip pyinstaller certifi
|
||||
pip3 install --upgrade -r requirements-osx-legacy.txt
|
||||
./gen_ui_files.sh
|
||||
- uses: actions/setup-node@v6
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 16
|
||||
- run: npm install -g appdmg
|
||||
|
||||
@@ -42,7 +42,6 @@ KCC avoids many common formatting issues (some of which occur [even on the Kindl
|
||||
4) incorrect page turn direction for manga that's read right to left
|
||||
5) unaligned two page spreads in landscape, where pages are shifted over by 1
|
||||
6) Removing without blur the rainbow effect on color eink Kaleido 3 due to manga screentones
|
||||
7) Fixing page order problems due to Windows sort being different than Kindle/Kobo sort
|
||||
|
||||
The GUI looks like this, built in Qt6, with my most commonly used settings:
|
||||
|
||||
|
||||
+69
-76
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>649</width>
|
||||
<width>644</width>
|
||||
<height>706</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -711,27 +711,7 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="editorButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Metadata Editor</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="humbleButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -748,7 +728,7 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="kofiButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -771,10 +751,23 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="labelSpreadsButton">
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="editorButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Label Spreads</string>
|
||||
<string>Metadata Editor</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -1081,56 +1074,6 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="deviceBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="clearButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear list</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="directoryButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=" font-weight:600;">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add input folder(s)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="convertButton">
|
||||
<property name="minimumSize">
|
||||
@@ -1156,6 +1099,36 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="clearButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Clear list</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="deviceBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>28</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="fileButton">
|
||||
<property name="minimumSize">
|
||||
@@ -1176,6 +1149,26 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="directoryButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=" font-weight:600;">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add input folder(s)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QComboBox" name="formatBox">
|
||||
<property name="minimumSize">
|
||||
|
||||
+131
-213
@@ -19,11 +19,10 @@
|
||||
|
||||
from datetime import datetime, timezone
|
||||
import itertools
|
||||
import json
|
||||
from pathlib import Path
|
||||
from PySide6.QtCore import (QSize, QUrl, Qt, Signal, QIODeviceBase, QEvent, QThread, QSettings)
|
||||
from PySide6.QtGui import (QColor, QIcon, QImage, QKeyEvent, QPixmap, QDesktopServices)
|
||||
from PySide6.QtWidgets import (QApplication, QDialogButtonBox, QHBoxLayout, QLabel, QListWidgetItem, QMainWindow, QSizePolicy, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog, QAbstractItemView, QListView, QTreeView, QWidget)
|
||||
from PySide6.QtGui import (QColor, QIcon, QPixmap, QDesktopServices)
|
||||
from PySide6.QtWidgets import (QApplication, QLabel, QListWidgetItem, QMainWindow, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog, QAbstractItemView, QListView, QTreeView)
|
||||
from PySide6.QtNetwork import (QLocalSocket, QLocalServer)
|
||||
|
||||
import os
|
||||
@@ -39,15 +38,10 @@ from xml.sax.saxutils import escape
|
||||
from psutil import Process
|
||||
from copy import copy
|
||||
from packaging.version import Version
|
||||
from tempfile import gettempdir, mkdtemp
|
||||
from PIL import Image
|
||||
from PIL.Image import Dither
|
||||
|
||||
from .KCC_spread_label import LabelSpreadsDialog
|
||||
from tempfile import gettempdir
|
||||
|
||||
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
|
||||
from .comicarchive import SEVENZIP, TAR, available_archive_tools
|
||||
from .comic2ebook import OS_SORT_KEY, flattenTree, getWorkFolder, removeNonImages, sanitizeTree
|
||||
from . import __version__
|
||||
from . import comic2ebook
|
||||
from . import metadata
|
||||
@@ -240,138 +234,6 @@ class ProgressThread(QThread):
|
||||
self.running = False
|
||||
|
||||
|
||||
def get_options():
|
||||
parser = comic2ebook.makeParser()
|
||||
options = parser.parse_args()
|
||||
|
||||
options.profile = GUI.profiles[str(GUI.deviceBox.currentText())]['Label']
|
||||
gui_current_format = GUI.formats[str(GUI.formatBox.currentText())]['format']
|
||||
options.format = gui_current_format
|
||||
if GUI.mangaBox.isChecked():
|
||||
options.righttoleft = True
|
||||
if GUI.lightnovelBox.isChecked():
|
||||
options.lightnovel = True
|
||||
if GUI.ebokBox.isChecked():
|
||||
options.ebok = True
|
||||
if GUI.invertDirectionBox.isChecked():
|
||||
options.invertdirection = True
|
||||
if GUI.rotateBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.splitter = 2
|
||||
elif GUI.rotateBox.checkState() == Qt.CheckState.Checked:
|
||||
options.splitter = 1
|
||||
if GUI.qualityBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.autoscale = True
|
||||
elif GUI.qualityBox.checkState() == Qt.CheckState.Checked:
|
||||
options.hq = True
|
||||
if GUI.vertical4PanelBox.isChecked():
|
||||
options.vertical4panel = True
|
||||
if GUI.webtoonBox.isChecked():
|
||||
options.webtoon = True
|
||||
if GUI.upscaleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.stretch = True
|
||||
elif GUI.upscaleBox.checkState() == Qt.CheckState.Checked:
|
||||
options.upscale = True
|
||||
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
|
||||
options.gamma = float(GUI.gammaValue)
|
||||
if GUI.autoLevelBox.isChecked():
|
||||
options.autolevel = True
|
||||
if GUI.autocontrastBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.noautocontrast = True
|
||||
elif GUI.autocontrastBox.checkState() == Qt.CheckState.Checked:
|
||||
options.colorautocontrast = True
|
||||
if GUI.croppingBox.isChecked():
|
||||
if GUI.croppingBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.cropping = 1
|
||||
else:
|
||||
options.cropping = 2
|
||||
else:
|
||||
options.cropping = 0
|
||||
if GUI.croppingBox.checkState() != Qt.CheckState.Unchecked:
|
||||
options.croppingp = float(GUI.croppingPowerValue)
|
||||
options.preservemargin = GUI.preserveMarginBox.value()
|
||||
if GUI.interPanelCropBox.isChecked():
|
||||
if GUI.interPanelCropBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.interpanelcrop = 1
|
||||
else:
|
||||
options.interpanelcrop = 2
|
||||
else:
|
||||
options.interpanelcrop = 0
|
||||
if GUI.borderBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.white_borders = True
|
||||
elif GUI.borderBox.checkState() == Qt.CheckState.Checked:
|
||||
options.black_borders = True
|
||||
if GUI.outputSplit.isChecked():
|
||||
options.batchsplit = 2
|
||||
if GUI.colorBox.isChecked():
|
||||
options.forcecolor = True
|
||||
if GUI.eraseRainbowBox.isChecked():
|
||||
options.eraserainbow = True
|
||||
if GUI.maximizeStrips.isChecked():
|
||||
options.maximizestrips = True
|
||||
if GUI.disableProcessingBox.isChecked():
|
||||
options.noprocessing = True
|
||||
if GUI.legacyExtractBox.isChecked():
|
||||
options.legacyextract = True
|
||||
if GUI.pdfWidthBox.isChecked():
|
||||
options.pdfwidth = True
|
||||
if GUI.smartCoverCropBox.isChecked():
|
||||
options.smartcovercrop = True
|
||||
if GUI.coverFillBox.isChecked():
|
||||
options.coverfill = True
|
||||
if GUI.metadataTitleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.metadatatitle = 1
|
||||
elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked:
|
||||
options.metadatatitle = 2
|
||||
if GUI.keepComicInfoBox.isChecked():
|
||||
options.keepcomicinfo = True
|
||||
if GUI.deleteBox.isChecked():
|
||||
options.delete = True
|
||||
if GUI.tempDirBox.isChecked():
|
||||
options.tempdir = True
|
||||
if GUI.spreadShiftBox.isChecked():
|
||||
options.spreadshift = True
|
||||
if GUI.onePageLandscapeBox.isChecked():
|
||||
options.onepagelandscape = True
|
||||
if GUI.fileFusionBox.isChecked():
|
||||
options.filefusion = True
|
||||
else:
|
||||
options.filefusion = False
|
||||
if GUI.noRotateBox.isChecked():
|
||||
options.norotate = True
|
||||
if GUI.rotateRightBox.isChecked():
|
||||
options.rotateright = True
|
||||
if GUI.rotateFirstBox.isChecked():
|
||||
options.rotatefirst = True
|
||||
if GUI.forcePngRgbBox.isChecked():
|
||||
options.force_png_rgb = True
|
||||
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.forcepng = True
|
||||
elif GUI.mozJpegBox.checkState() == Qt.CheckState.Checked:
|
||||
options.mozjpeg = True
|
||||
if GUI.webpBox.isChecked():
|
||||
options.webp = True
|
||||
if GUI.pngLegacyBox.isChecked():
|
||||
options.pnglegacy = True
|
||||
if GUI.noQuantizeBox.isChecked():
|
||||
options.noquantize = True
|
||||
if GUI.jpegQualityBox.isChecked():
|
||||
options.jpegquality = GUI.jpegQualitySpinBox.value()
|
||||
if GUI.currentMode > 2:
|
||||
options.customwidth = str(GUI.widthBox.value())
|
||||
options.customheight = str(GUI.heightBox.value())
|
||||
if GUI.targetDirectory != '':
|
||||
options.output = GUI.targetDirectory
|
||||
if GUI.titleEdit.text():
|
||||
options.title = str(GUI.titleEdit.text())
|
||||
if GUI.authorEdit.text():
|
||||
options.author = str(GUI.authorEdit.text())
|
||||
if GUI.languageEdit.text():
|
||||
options.language = str(GUI.languageEdit.text())
|
||||
if GUI.chunkSizeCheckBox.isChecked():
|
||||
options.targetsize = int(GUI.chunkSizeBox.value())
|
||||
|
||||
return options, gui_current_format
|
||||
|
||||
class WorkerThread(QThread):
|
||||
def __init__(self):
|
||||
QThread.__init__(self)
|
||||
@@ -401,9 +263,136 @@ class WorkerThread(QThread):
|
||||
def run(self):
|
||||
MW.modeConvert.emit(0)
|
||||
|
||||
parser = comic2ebook.makeParser()
|
||||
options = parser.parse_args()
|
||||
argv = ''
|
||||
currentJobs = []
|
||||
options, gui_current_format = get_options()
|
||||
|
||||
options.profile = GUI.profiles[str(GUI.deviceBox.currentText())]['Label']
|
||||
gui_current_format = GUI.formats[str(GUI.formatBox.currentText())]['format']
|
||||
options.format = gui_current_format
|
||||
if GUI.mangaBox.isChecked():
|
||||
options.righttoleft = True
|
||||
if GUI.lightnovelBox.isChecked():
|
||||
options.lightnovel = True
|
||||
if GUI.ebokBox.isChecked():
|
||||
options.ebok = True
|
||||
if GUI.invertDirectionBox.isChecked():
|
||||
options.invertdirection = True
|
||||
if GUI.rotateBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.splitter = 2
|
||||
elif GUI.rotateBox.checkState() == Qt.CheckState.Checked:
|
||||
options.splitter = 1
|
||||
if GUI.qualityBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.autoscale = True
|
||||
elif GUI.qualityBox.checkState() == Qt.CheckState.Checked:
|
||||
options.hq = True
|
||||
if GUI.vertical4PanelBox.isChecked():
|
||||
options.vertical4panel = True
|
||||
if GUI.webtoonBox.isChecked():
|
||||
options.webtoon = True
|
||||
if GUI.upscaleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.stretch = True
|
||||
elif GUI.upscaleBox.checkState() == Qt.CheckState.Checked:
|
||||
options.upscale = True
|
||||
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
|
||||
options.gamma = float(GUI.gammaValue)
|
||||
if GUI.autoLevelBox.isChecked():
|
||||
options.autolevel = True
|
||||
if GUI.autocontrastBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.noautocontrast = True
|
||||
elif GUI.autocontrastBox.checkState() == Qt.CheckState.Checked:
|
||||
options.colorautocontrast = True
|
||||
if GUI.croppingBox.isChecked():
|
||||
if GUI.croppingBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.cropping = 1
|
||||
else:
|
||||
options.cropping = 2
|
||||
else:
|
||||
options.cropping = 0
|
||||
if GUI.croppingBox.checkState() != Qt.CheckState.Unchecked:
|
||||
options.croppingp = float(GUI.croppingPowerValue)
|
||||
options.preservemargin = GUI.preserveMarginBox.value()
|
||||
if GUI.interPanelCropBox.isChecked():
|
||||
if GUI.interPanelCropBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.interpanelcrop = 1
|
||||
else:
|
||||
options.interpanelcrop = 2
|
||||
else:
|
||||
options.interpanelcrop = 0
|
||||
if GUI.borderBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.white_borders = True
|
||||
elif GUI.borderBox.checkState() == Qt.CheckState.Checked:
|
||||
options.black_borders = True
|
||||
if GUI.outputSplit.isChecked():
|
||||
options.batchsplit = 2
|
||||
if GUI.colorBox.isChecked():
|
||||
options.forcecolor = True
|
||||
if GUI.eraseRainbowBox.isChecked():
|
||||
options.eraserainbow = True
|
||||
if GUI.maximizeStrips.isChecked():
|
||||
options.maximizestrips = True
|
||||
if GUI.disableProcessingBox.isChecked():
|
||||
options.noprocessing = True
|
||||
if GUI.legacyExtractBox.isChecked():
|
||||
options.legacyextract = True
|
||||
if GUI.pdfWidthBox.isChecked():
|
||||
options.pdfwidth = True
|
||||
if GUI.smartCoverCropBox.isChecked():
|
||||
options.smartcovercrop = True
|
||||
if GUI.coverFillBox.isChecked():
|
||||
options.coverfill = True
|
||||
if GUI.metadataTitleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.metadatatitle = 1
|
||||
elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked:
|
||||
options.metadatatitle = 2
|
||||
if GUI.keepComicInfoBox.isChecked():
|
||||
options.keepcomicinfo = True
|
||||
if GUI.deleteBox.isChecked():
|
||||
options.delete = True
|
||||
if GUI.tempDirBox.isChecked():
|
||||
options.tempdir = True
|
||||
if GUI.spreadShiftBox.isChecked():
|
||||
options.spreadshift = True
|
||||
if GUI.onePageLandscapeBox.isChecked():
|
||||
options.onepagelandscape = True
|
||||
if GUI.fileFusionBox.isChecked():
|
||||
options.filefusion = True
|
||||
else:
|
||||
options.filefusion = False
|
||||
if GUI.noRotateBox.isChecked():
|
||||
options.norotate = True
|
||||
if GUI.rotateRightBox.isChecked():
|
||||
options.rotateright = True
|
||||
if GUI.rotateFirstBox.isChecked():
|
||||
options.rotatefirst = True
|
||||
if GUI.forcePngRgbBox.isChecked():
|
||||
options.force_png_rgb = True
|
||||
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.forcepng = True
|
||||
elif GUI.mozJpegBox.checkState() == Qt.CheckState.Checked:
|
||||
options.mozjpeg = True
|
||||
if GUI.webpBox.isChecked():
|
||||
options.webp = True
|
||||
if GUI.pngLegacyBox.isChecked():
|
||||
options.pnglegacy = True
|
||||
if GUI.noQuantizeBox.isChecked():
|
||||
options.noquantize = True
|
||||
if GUI.jpegQualityBox.isChecked():
|
||||
options.jpegquality = GUI.jpegQualitySpinBox.value()
|
||||
if GUI.currentMode > 2:
|
||||
options.customwidth = str(GUI.widthBox.value())
|
||||
options.customheight = str(GUI.heightBox.value())
|
||||
if GUI.targetDirectory != '':
|
||||
options.output = GUI.targetDirectory
|
||||
if GUI.titleEdit.text():
|
||||
options.title = str(GUI.titleEdit.text())
|
||||
if GUI.authorEdit.text():
|
||||
options.author = str(GUI.authorEdit.text())
|
||||
if GUI.languageEdit.text():
|
||||
options.language = str(GUI.languageEdit.text())
|
||||
if GUI.chunkSizeCheckBox.isChecked():
|
||||
options.targetsize = int(GUI.chunkSizeBox.value())
|
||||
|
||||
for i in range(GUI.jobList.count()):
|
||||
# Make sure that we don't consider any system message as job to do
|
||||
@@ -670,75 +659,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
GUI.jobList.addItem(dname)
|
||||
GUI.jobList.scrollToBottom()
|
||||
|
||||
def labelSpreadsStart(self):
|
||||
currentJobs = []
|
||||
# TODO: make this a function since it's copy pasted
|
||||
for i in range(GUI.jobList.count()):
|
||||
# Make sure that we don't consider any system message as job to do
|
||||
if GUI.jobList.item(i).icon().isNull():
|
||||
currentJobs.append(str(GUI.jobList.item(i).text()))
|
||||
for job in currentJobs:
|
||||
images = []
|
||||
spreads = []
|
||||
options, _ = get_options()
|
||||
options.profileData = [(600, 800), (600,800)]
|
||||
path = getWorkFolder(job, options)
|
||||
removeNonImages(path)
|
||||
sanitizeTree(path, options)
|
||||
flattenTree(path)
|
||||
|
||||
if options.tempdir:
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(job))
|
||||
else:
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
|
||||
for root, _, files in os.walk(path):
|
||||
files.sort(key=OS_SORT_KEY)
|
||||
start_index = 0
|
||||
if job.endswith('.pdf') or job.endswith('.epub'):
|
||||
start_index = 1
|
||||
if options.spreadshift:
|
||||
start_index = 0 if start_index == 1 else 1
|
||||
for i in range(start_index, len(files), 2):
|
||||
if i == len(files) - 1:
|
||||
continue
|
||||
# TODO: with statements
|
||||
# TODO: ignore 1% of top and bottom too?
|
||||
im1 = Image.open(os.path.join(root, files[i])).convert('1', dither=Dither.NONE)
|
||||
size1 = im1.size
|
||||
crop1 = im1.crop((0, 0, 0.2*size1[0], size1[1]))
|
||||
crop11 = im1.crop((0.01*size1[0], 0, 0.04*size1[0], size1[1]))
|
||||
#crop1 = crop11
|
||||
im2 = Image.open(os.path.join(root, files[i+1])).convert('1', dither=Dither.NONE)
|
||||
size2 = im2.size
|
||||
crop2 = im2.crop((0.8*size2[0], 0, size2[0], size2[1]))
|
||||
crop22 = im2.crop((0.96*size2[0], 0, .99* size2[0], size2[1]))
|
||||
#crop2 = crop22
|
||||
# dst = Image.new('1', (im1.width + im2.width, im1.height))
|
||||
# dst.paste(im2, (0, 0))
|
||||
# dst.paste(im1, (im1.width, 0))
|
||||
hist1 = crop11.histogram()
|
||||
hist2 = crop22.histogram()
|
||||
# TODO: small percentage instead of zero
|
||||
if hist1[0] == 0 or hist1[-1] == 0 or hist2[0] == 0 or hist2[-1] == 0:
|
||||
continue
|
||||
|
||||
dst = Image.new('1', (crop1.width + crop2.width, crop1.height))
|
||||
|
||||
dst.paste(crop2, (0, 0))
|
||||
dst.paste(crop1, (crop1.width, 0))
|
||||
dst.save(os.path.join(workdir, f'label-{i:04}.png'))
|
||||
images.append(os.path.join(workdir, f'label-{i:04}.png'))
|
||||
|
||||
dlg = LabelSpreadsDialog(APP.primaryScreen().availableGeometry().height(), images, spreads)
|
||||
dlg.setWindowTitle(job)
|
||||
if dlg.exec() == 1:
|
||||
with open(job+'.json', "w") as fp:
|
||||
# TODO: not very clean to grab index from filename
|
||||
spreads = [int(filename[6:10]) for filename in spreads]
|
||||
json.dump({'spreads': sorted(set(spreads))} , fp)
|
||||
rmtree(path, True)
|
||||
rmtree(workdir, True)
|
||||
|
||||
def selectFileMetaEditor(self, sname):
|
||||
files = []
|
||||
@@ -1516,7 +1436,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'README': "https://github.com/ciromattia/kcc?tab=readme-ov-file#kcc",
|
||||
'FAQ': "https://github.com/ciromattia/kcc/blob/master/README.md#faq",
|
||||
'WIKI': "https://github.com/ciromattia/kcc/wiki",
|
||||
'YOUTUBE': "https://www.youtube.com/@eink-dude",
|
||||
'TUTORIAL': "https://youtu.be/QQ6zJcMF2Iw?si=80rfm6DU6OUJdFqa",
|
||||
'EMAIL': "https://github.com/ciromattia/kcc?tab=readme-ov-file#commissions",
|
||||
'DONATE': "https://github.com/ciromattia/kcc/blob/master/README.md#issues--new-features--donations",
|
||||
@@ -1553,7 +1472,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
GUI.kofiButton.clicked.connect(self.openKofi)
|
||||
GUI.humbleButton.clicked.connect(self.openHumble)
|
||||
GUI.convertButton.clicked.connect(self.convertStart)
|
||||
GUI.labelSpreadsButton.clicked.connect(self.labelSpreadsStart)
|
||||
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
|
||||
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
|
||||
GUI.croppingBox.stateChanged.connect(self.togglecroppingBox)
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import os
|
||||
|
||||
from PySide6.QtCore import (Qt)
|
||||
from PySide6.QtGui import (QKeyEvent, QPixmap)
|
||||
from PySide6.QtWidgets import (QDialogButtonBox, QHBoxLayout, QLabel, QDialog)
|
||||
|
||||
class LabelSpreadsDialog(QDialog):
|
||||
def __init__(self, available_height, images, spreads):
|
||||
super().__init__()
|
||||
self.index = 0
|
||||
self.images = images
|
||||
self.spreads = spreads
|
||||
self.index2page = {i: os.path.basename(image) for i, image in enumerate(images)}
|
||||
|
||||
self.setWindowTitle("TODO: Filename goes here")
|
||||
# self.setGeometry(APP.primaryScreen().availableGeometry())
|
||||
# self.setMaximumSize(APP.primaryScreen().availableSize())
|
||||
self.available_height = available_height
|
||||
|
||||
QBtn = (
|
||||
QDialogButtonBox.Yes | QDialogButtonBox.No
|
||||
)
|
||||
|
||||
self.buttonBox = QDialogButtonBox(QBtn)
|
||||
self.buttonBox.accepted.connect(self.accept)
|
||||
self.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
layout = QHBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
label = QLabel()
|
||||
label2 = QLabel()
|
||||
self.label = label
|
||||
self.label2 = label2
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(label2)
|
||||
label2.setText("not a spread")
|
||||
|
||||
help_text = [
|
||||
"Press Yes to save labels to file.",
|
||||
"Use arrows to change index.",
|
||||
"Use space bar to confirm spreads.",
|
||||
"Use spread shift option to offset by 1.",
|
||||
]
|
||||
buttonLabel = QLabel('\n'.join(help_text))
|
||||
layout.addWidget(buttonLabel)
|
||||
layout.addWidget(self.buttonBox)
|
||||
# print(label.size())
|
||||
# print(label.maximumSize())
|
||||
# l, t, r, b = layout.getContentsMargins()
|
||||
|
||||
#label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
pixmap = QPixmap(images[0]).scaledToHeight(self.available_height * 0.9)
|
||||
label.setPixmap(pixmap)
|
||||
#label.setScaledContents(True)
|
||||
|
||||
#label2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
# pixmap2 = QPixmap(images[0]).scaledToHeight(self.frameGeometry().height() - t - b - t - b)
|
||||
# label2.setPixmap(pixmap2)
|
||||
#label2.setScaledContents(True)
|
||||
#self.resize(pixmap2.width(), pixmap2.height())
|
||||
def keyReleaseEvent(self, event):
|
||||
# t = 20
|
||||
# b = 20
|
||||
if isinstance(event, QKeyEvent):
|
||||
if event.key() == Qt.Key.Key_Left:
|
||||
self.index = max(0, self.index - 1)
|
||||
if self.index2page[self.index] in self.spreads:
|
||||
self.label2.setText('spread')
|
||||
else:
|
||||
self.label2.setText('not a spread')
|
||||
pixmap = QPixmap(self.images[self.index]).scaledToHeight(self.available_height * 0.9)
|
||||
self.label.setPixmap(pixmap)
|
||||
# pixmap2 = QPixmap(images[self.index]).scaledToHeight(self.frameGeometry().height() - t - b - t - b)
|
||||
# self.label2.setPixmap(pixmap2)
|
||||
elif event.key() == Qt.Key.Key_Right:
|
||||
self.index = min(self.index + 1, len(self.images) - 1)
|
||||
if self.index2page[self.index] in self.spreads:
|
||||
self.label2.setText('spread')
|
||||
else:
|
||||
self.label2.setText('not a spread')
|
||||
|
||||
pixmap = QPixmap(self.images[self.index]).scaledToHeight(self.available_height * 0.9)
|
||||
self.label.setPixmap(pixmap)
|
||||
# pixmap2 = QPixmap(images[self.index]).scaledToHeight(self.frameGeometry().height() - t - b - t - b)
|
||||
# self.label2.setPixmap(pixmap2)
|
||||
elif event.key() == Qt.Key.Key_Space:
|
||||
self.spreads.append(os.path.basename(self.images[self.index]))
|
||||
self.label2.setText('spread')
|
||||
else:
|
||||
super().keyReleaseEvent(event)
|
||||
else:
|
||||
super().keyReleaseEvent(event)
|
||||
@@ -26,7 +26,7 @@ class Ui_mainWindow(object):
|
||||
def setupUi(self, mainWindow):
|
||||
if not mainWindow.objectName():
|
||||
mainWindow.setObjectName(u"mainWindow")
|
||||
mainWindow.resize(649, 706)
|
||||
mainWindow.resize(644, 706)
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
mainWindow.setWindowIcon(icon)
|
||||
@@ -360,38 +360,33 @@ class Ui_mainWindow(object):
|
||||
self.gridLayout_6 = QGridLayout(self.toolWidget)
|
||||
self.gridLayout_6.setObjectName(u"gridLayout_6")
|
||||
self.gridLayout_6.setContentsMargins(0, 0, 0, 0)
|
||||
self.editorButton = QPushButton(self.toolWidget)
|
||||
self.editorButton.setObjectName(u"editorButton")
|
||||
self.editorButton.setMinimumSize(QSize(0, 30))
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.editorButton.setIcon(icon2)
|
||||
|
||||
self.gridLayout_6.addWidget(self.editorButton, 0, 0, 1, 1)
|
||||
|
||||
self.humbleButton = QPushButton(self.toolWidget)
|
||||
self.humbleButton.setObjectName(u"humbleButton")
|
||||
self.humbleButton.setMinimumSize(QSize(0, 30))
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/Brand/icons/Humble_H-Red.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.humbleButton.setIcon(icon3)
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Brand/icons/Humble_H-Red.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.humbleButton.setIcon(icon2)
|
||||
|
||||
self.gridLayout_6.addWidget(self.humbleButton, 0, 3, 1, 1)
|
||||
self.gridLayout_6.addWidget(self.humbleButton, 0, 2, 1, 1)
|
||||
|
||||
self.kofiButton = QPushButton(self.toolWidget)
|
||||
self.kofiButton.setObjectName(u"kofiButton")
|
||||
self.kofiButton.setMinimumSize(QSize(0, 30))
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.kofiButton.setIcon(icon4)
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.kofiButton.setIcon(icon3)
|
||||
self.kofiButton.setIconSize(QSize(19, 16))
|
||||
|
||||
self.gridLayout_6.addWidget(self.kofiButton, 0, 2, 1, 1)
|
||||
self.gridLayout_6.addWidget(self.kofiButton, 0, 1, 1, 1)
|
||||
|
||||
self.labelSpreadsButton = QPushButton(self.toolWidget)
|
||||
self.labelSpreadsButton.setObjectName(u"labelSpreadsButton")
|
||||
self.editorButton = QPushButton(self.toolWidget)
|
||||
self.editorButton.setObjectName(u"editorButton")
|
||||
self.editorButton.setMinimumSize(QSize(0, 30))
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.editorButton.setIcon(icon4)
|
||||
|
||||
self.gridLayout_6.addWidget(self.labelSpreadsButton, 0, 1, 1, 1)
|
||||
self.gridLayout_6.addWidget(self.editorButton, 0, 0, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.toolWidget, 0, 0, 1, 2)
|
||||
@@ -548,20 +543,39 @@ class Ui_mainWindow(object):
|
||||
self.gridLayout_4 = QGridLayout(self.buttonWidget)
|
||||
self.gridLayout_4.setObjectName(u"gridLayout_4")
|
||||
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||
self.convertButton = QPushButton(self.buttonWidget)
|
||||
self.convertButton.setObjectName(u"convertButton")
|
||||
self.convertButton.setMinimumSize(QSize(0, 30))
|
||||
self.convertButton.setFont(font)
|
||||
icon5 = QIcon()
|
||||
icon5.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.convertButton.setIcon(icon5)
|
||||
|
||||
self.gridLayout_4.addWidget(self.convertButton, 1, 3, 1, 1)
|
||||
|
||||
self.clearButton = QPushButton(self.buttonWidget)
|
||||
self.clearButton.setObjectName(u"clearButton")
|
||||
self.clearButton.setMinimumSize(QSize(0, 30))
|
||||
icon6 = QIcon()
|
||||
icon6.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.clearButton.setIcon(icon6)
|
||||
|
||||
self.gridLayout_4.addWidget(self.clearButton, 0, 3, 1, 1)
|
||||
|
||||
self.deviceBox = QComboBox(self.buttonWidget)
|
||||
self.deviceBox.setObjectName(u"deviceBox")
|
||||
self.deviceBox.setMinimumSize(QSize(0, 28))
|
||||
|
||||
self.gridLayout_4.addWidget(self.deviceBox, 1, 1, 1, 1)
|
||||
|
||||
self.clearButton = QPushButton(self.buttonWidget)
|
||||
self.clearButton.setObjectName(u"clearButton")
|
||||
self.clearButton.setMinimumSize(QSize(0, 30))
|
||||
icon5 = QIcon()
|
||||
icon5.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.clearButton.setIcon(icon5)
|
||||
self.fileButton = QPushButton(self.buttonWidget)
|
||||
self.fileButton.setObjectName(u"fileButton")
|
||||
self.fileButton.setMinimumSize(QSize(0, 30))
|
||||
icon7 = QIcon()
|
||||
icon7.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.fileButton.setIcon(icon7)
|
||||
|
||||
self.gridLayout_4.addWidget(self.clearButton, 0, 3, 1, 1)
|
||||
self.gridLayout_4.addWidget(self.fileButton, 0, 1, 1, 1)
|
||||
|
||||
self.directoryButton = QPushButton(self.buttonWidget)
|
||||
self.directoryButton.setObjectName(u"directoryButton")
|
||||
@@ -574,25 +588,6 @@ class Ui_mainWindow(object):
|
||||
|
||||
self.gridLayout_4.addWidget(self.directoryButton, 0, 4, 1, 1)
|
||||
|
||||
self.convertButton = QPushButton(self.buttonWidget)
|
||||
self.convertButton.setObjectName(u"convertButton")
|
||||
self.convertButton.setMinimumSize(QSize(0, 30))
|
||||
self.convertButton.setFont(font)
|
||||
icon6 = QIcon()
|
||||
icon6.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.convertButton.setIcon(icon6)
|
||||
|
||||
self.gridLayout_4.addWidget(self.convertButton, 1, 3, 1, 1)
|
||||
|
||||
self.fileButton = QPushButton(self.buttonWidget)
|
||||
self.fileButton.setObjectName(u"fileButton")
|
||||
self.fileButton.setMinimumSize(QSize(0, 30))
|
||||
icon7 = QIcon()
|
||||
icon7.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.fileButton.setIcon(icon7)
|
||||
|
||||
self.gridLayout_4.addWidget(self.fileButton, 0, 1, 1, 1)
|
||||
|
||||
self.formatBox = QComboBox(self.buttonWidget)
|
||||
self.formatBox.setObjectName(u"formatBox")
|
||||
self.formatBox.setMinimumSize(QSize(0, 28))
|
||||
@@ -853,13 +848,12 @@ class Ui_mainWindow(object):
|
||||
"Keeping this file may crash some readers like the Kobo native CBZ reader.", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.keepComicInfoBox.setText(QCoreApplication.translate("mainWindow", u"Keep ComicInfo.xml", None))
|
||||
self.humbleButton.setText(QCoreApplication.translate("mainWindow", u"Humble Bundle Referral", None))
|
||||
self.kofiButton.setText(QCoreApplication.translate("mainWindow", u"Support me on Ko-fi", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.editorButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to edit directory.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.editorButton.setText(QCoreApplication.translate("mainWindow", u"Metadata Editor", None))
|
||||
self.humbleButton.setText(QCoreApplication.translate("mainWindow", u"Humble Bundle Referral", None))
|
||||
self.kofiButton.setText(QCoreApplication.translate("mainWindow", u"Support me on Ko-fi", None))
|
||||
self.labelSpreadsButton.setText(QCoreApplication.translate("mainWindow", u"Label Spreads", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.chunkSizeWidget.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Warning: chunk size greater than default may cause<br/>performance/battery issues, especially on older devices.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
@@ -884,22 +878,22 @@ class Ui_mainWindow(object):
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.heightBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deviceBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.clearButton.setText(QCoreApplication.translate("mainWindow", u"Clear list", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.directoryButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add input folder(s)", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.convertButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory for this list.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.convertButton.setText(QCoreApplication.translate("mainWindow", u"Convert", None))
|
||||
self.clearButton.setText(QCoreApplication.translate("mainWindow", u"Clear list", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deviceBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Target device.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.fileButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add input file(s)", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.directoryButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add input folder(s)", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.formatBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Output format.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '11.0.0'
|
||||
__version__ = '10.4.0'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
@@ -873,7 +872,7 @@ def extract_page(vector):
|
||||
|
||||
|
||||
|
||||
def mupdf_pdf_process_pages_parallel(filename, output_dir, target_width, target_height, pdfwidth):
|
||||
def mupdf_pdf_process_pages_parallel(filename, output_dir, target_width, target_height):
|
||||
render = False
|
||||
with pymupdf.open(filename) as doc:
|
||||
for page in doc:
|
||||
@@ -893,7 +892,7 @@ def mupdf_pdf_process_pages_parallel(filename, output_dir, target_width, target_
|
||||
cpu = cpu_count()
|
||||
|
||||
# make vectors of arguments for the processes
|
||||
vectors = [(i, cpu, filename, output_dir, target_width, target_height, pdfwidth) for i in range(cpu)]
|
||||
vectors = [(i, cpu, filename, output_dir, target_width, target_height, options.pdfwidth) for i in range(cpu)]
|
||||
print("Starting %i processes for '%s'." % (cpu, filename))
|
||||
|
||||
|
||||
@@ -907,7 +906,7 @@ def mupdf_pdf_process_pages_parallel(filename, output_dir, target_width, target_
|
||||
|
||||
|
||||
|
||||
def getWorkFolder(afile, options, workdir=None):
|
||||
def getWorkFolder(afile, workdir=None):
|
||||
if not workdir:
|
||||
if options.tempdir:
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
@@ -956,7 +955,7 @@ def getWorkFolder(afile, options, workdir=None):
|
||||
target_height *= 1.25 #Account for possible margin at the top and bottom with page number
|
||||
target_width *= 1.25
|
||||
try:
|
||||
mupdf_pdf_process_pages_parallel(afile, fullPath, target_width, target_height, options.pdfwidth)
|
||||
mupdf_pdf_process_pages_parallel(afile, fullPath, target_width, target_height)
|
||||
except Exception as e:
|
||||
rmtree(path, True)
|
||||
raise UserWarning(f"Failed to extract images from PDF file. {e}")
|
||||
@@ -980,16 +979,9 @@ def getWorkFolder(afile, options, workdir=None):
|
||||
os.path.join(fullPath, tdir[0], 'ComicInfo.xml')
|
||||
)
|
||||
if len(tdir) == 1 and os.path.isdir(os.path.join(fullPath, tdir[0])):
|
||||
if options.tempdir:
|
||||
workdir2 = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
else:
|
||||
workdir2 = mkdtemp('', 'KCC-')
|
||||
fullPath2 = os.path.join(workdir2, 'OEBPS', 'Images')
|
||||
os.makedirs(fullPath2, exist_ok=True)
|
||||
for file in os.listdir(os.path.join(fullPath, tdir[0])):
|
||||
move(os.path.join(fullPath, tdir[0], file), fullPath2)
|
||||
rmtree(workdir, True)
|
||||
return workdir2
|
||||
move(os.path.join(fullPath, tdir[0], file), fullPath)
|
||||
os.rmdir(os.path.join(fullPath, tdir[0]))
|
||||
|
||||
if options.legacyextract:
|
||||
return workdir
|
||||
@@ -1230,7 +1222,7 @@ def removeNonImages(filetree):
|
||||
raise RuntimeError('\n'.join(warning))
|
||||
|
||||
|
||||
def sanitizeTree(filetree, options, prefix='kcc'):
|
||||
def sanitizeTree(filetree, prefix='kcc'):
|
||||
chapterNames = {}
|
||||
page = 1
|
||||
cover_path = None
|
||||
@@ -1255,7 +1247,7 @@ def sanitizeTree(filetree, options, prefix='kcc'):
|
||||
dirs.sort(key=OS_SORT_KEY)
|
||||
for i, name in enumerate(dirs):
|
||||
tmpName = name
|
||||
slugified = slugify(name, options, is_natural_sorted)
|
||||
slugified = slugify(name, is_natural_sorted)
|
||||
while os.path.exists(os.path.join(root, slugified)) and name.upper() != slugified.upper():
|
||||
slugified += "A"
|
||||
chapterNames[slugified] = tmpName
|
||||
@@ -1418,7 +1410,7 @@ def createNewTome(parent):
|
||||
return tomePath, tomePathRoot
|
||||
|
||||
|
||||
def slugify(value, options, is_natural_sorted):
|
||||
def slugify(value, is_natural_sorted):
|
||||
if options.format == 'CBZ' and is_natural_sorted:
|
||||
return value
|
||||
if options.format != 'CBZ':
|
||||
@@ -1783,10 +1775,10 @@ def makeFusion(sources: List[str]):
|
||||
else:
|
||||
targetpath = fusion_path.joinpath(f'{prefix}{source_path.name}')
|
||||
|
||||
path = getWorkFolder(source, options, str(targetpath))
|
||||
path = getWorkFolder(source, str(targetpath))
|
||||
if path != str(targetpath):
|
||||
move(os.path.join(path, 'OEBPS', 'Images'), targetpath)
|
||||
sanitizeTree(targetpath, options, prefix='fusion')
|
||||
sanitizeTree(targetpath, prefix='fusion')
|
||||
# TODO: remove flattenTree when subchapters are supported
|
||||
flattenTree(targetpath)
|
||||
|
||||
@@ -1809,7 +1801,7 @@ def makeBook(source, qtgui=None, job_progress=''):
|
||||
if not options.filefusion:
|
||||
checkPre('LLL-')
|
||||
print(f"{job_progress}Preparing source images...")
|
||||
path = getWorkFolder(source, options)
|
||||
path = getWorkFolder(source)
|
||||
print(f"{job_progress}Checking images...")
|
||||
|
||||
if options.lightnovel:
|
||||
@@ -1843,26 +1835,7 @@ def makeBook(source, qtgui=None, job_progress=''):
|
||||
getMetadata(os.path.join(path, "OEBPS", "Images"), source)
|
||||
removeNonImages(os.path.join(path, "OEBPS", "Images"))
|
||||
detectSuboptimalProcessing(os.path.join(path, "OEBPS", "Images"), source)
|
||||
chapterNames, cover_path = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'), options)
|
||||
|
||||
if os.path.exists(source+'.json'):
|
||||
flattenTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||
with open(source+'.json') as f:
|
||||
data = json.load(f)
|
||||
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||
sorted_files = os_sorted(files)
|
||||
for i in range(len(files)):
|
||||
if i in data['spreads']:
|
||||
im1 = Image.open(os.path.join(root, sorted_files[i]))
|
||||
im2 = Image.open(os.path.join(root, sorted_files[i+1]))
|
||||
dst = Image.new('RGB', (im1.width + im2.width, im1.height))
|
||||
dst.paste(im2, (0, 0))
|
||||
dst.paste(im1, (im1.width, 0))
|
||||
base, _ = os.path.splitext(os.path.basename(sorted_files[i]))
|
||||
dst.save(os.path.join(path, 'OEBPS', 'Images', f'{base}-merged.png'))
|
||||
os.remove(os.path.join(root, sorted_files[i]))
|
||||
os.remove(os.path.join(root, sorted_files[i+1]))
|
||||
|
||||
chapterNames, cover_path = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||
if options.filefusion:
|
||||
# Strip the fusion_0001_ sort prefix from makeFusion if present
|
||||
chapterNames = {k: sub(r'^fusion_\d{4}_', '', v) for k, v in chapterNames.items()}
|
||||
|
||||
Reference in New Issue
Block a user