From 3e3710dd76fc73b9dccfc4eb455199ea334b007c Mon Sep 17 00:00:00 2001
From: Alex Xu
Date: Thu, 3 Apr 2025 10:11:14 -0700
Subject: [PATCH] Add preserve margin % toggle (#886)
* preserve margin
* set ratio to 0.5
* add preserve margin GUI
* increase step size to 5
* remove clear
* fix save
* save preserveMarginBox
* math
* max 99
---
README.md | 1 +
gui/KCC.ui | 35 +++++++++++++++--
kindlecomicconverter/KCC_gui.py | 3 ++
kindlecomicconverter/KCC_rc.py | 38 +++++++++---------
kindlecomicconverter/KCC_ui.py | 60 ++++++++++++++++++++---------
kindlecomicconverter/comic2ebook.py | 2 +
kindlecomicconverter/image.py | 5 +++
7 files changed, 103 insertions(+), 41 deletions(-)
diff --git a/README.md b/README.md
index a66de4d..6bc76bf 100644
--- a/README.md
+++ b/README.md
@@ -181,6 +181,7 @@ PROCESSING:
Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]
--cp CROPPINGP, --croppingpower CROPPINGP
Set cropping power [Default=1.0]
+ --preservemargin After calculating crop, "back up" a specified percentage amount [Default=0]
--cm CROPPINGM, --croppingminimum CROPPINGM
Set cropping minimum area ratio [Default=0.0]
--ipc INTERPANELCROP, --interpanelcrop INTERPANELCROP
diff --git a/gui/KCC.ui b/gui/KCC.ui
index 3abefaf..9c9bd58 100644
--- a/gui/KCC.ui
+++ b/gui/KCC.ui
@@ -330,7 +330,7 @@
false
-
+
0
@@ -343,14 +343,24 @@
0
- -
+
-
+
+
+ <html><head/><body><p>After calculating the cropping boundaries, "back up" a specified percentage amount.</p></body></html>
+
+
+ Preserve Margin %
+
+
+
+ -
Cropping power:
- -
+
-
300
@@ -363,6 +373,25 @@
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 99
+
+
+ 5
+
+
+ 0
+
+
+
diff --git a/kindlecomicconverter/KCC_gui.py b/kindlecomicconverter/KCC_gui.py
index db299b5..f78a066 100644
--- a/kindlecomicconverter/KCC_gui.py
+++ b/kindlecomicconverter/KCC_gui.py
@@ -246,6 +246,7 @@ class WorkerThread(QThread):
options.cropping = GUI.croppingBox.checkState().value
if GUI.croppingBox.checkState() != Qt.CheckState.Unchecked:
options.croppingp = float(GUI.croppingPowerValue)
+ options.preservemargin = GUI.preserveMarginBox.value()
options.interpanelcrop = GUI.interPanelCropBox.checkState().value
if GUI.borderBox.checkState() == Qt.CheckState.PartiallyChecked:
options.white_borders = True
@@ -803,6 +804,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'gammaBox': GUI.gammaBox.checkState().value,
'croppingBox': GUI.croppingBox.checkState().value,
'croppingPowerSlider': float(self.croppingPowerValue) * 100,
+ 'preserveMarginBox': self.preserveMarginBox.value(),
'interPanelCropBox': GUI.interPanelCropBox.checkState().value,
'upscaleBox': GUI.upscaleBox.checkState().value,
'borderBox': GUI.borderBox.checkState().value,
@@ -1159,6 +1161,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if GUI.croppingPowerSlider.isEnabled():
GUI.croppingPowerSlider.setValue(int(self.options[option]))
self.changeCroppingPower(int(self.options[option]))
+ GUI.preserveMarginBox.setValue(self.options.get('preserveMarginBox', 0))
elif str(option) == "chunkSizeBox":
GUI.chunkSizeBox.setValue(int(self.options[option]))
else:
diff --git a/kindlecomicconverter/KCC_rc.py b/kindlecomicconverter/KCC_rc.py
index 6ba25c0..bc8aa29 100644
--- a/kindlecomicconverter/KCC_rc.py
+++ b/kindlecomicconverter/KCC_rc.py
@@ -11612,51 +11612,51 @@ qt_resource_struct = b"\
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x01\xc0\x00\x00\x00\x00\x00\x01\x00\x02.\xed\
-\x00\x00\x01\x95\xcf\xe3\x00\xfc\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x01\xfe\x00\x00\x00\x00\x00\x01\x00\x02\x83\x87\
-\x00\x00\x01\x95\xcf\xe3\x00\xfb\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x02Y\x8c\
-\x00\x00\x01\x95\xcf\xe3\x00\xfb\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x02N)\
-\x00\x00\x01\x95\xcf\xe3\x00\xfb\
+\x00\x00\x01\x89\x89D9.\
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x0c\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x01(\x97\
-\x00\x00\x01\x95\xcf\xe3\x00\xfc\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x011\xef\
-\x00\x00\x01\x95\xcf\xe3\x00\xfd\
+\x00\x00\x01\x94\x1a\xa2\xa2\x92\
\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x90\
-\x00\x00\x01\x95\xcf\xe3\x00\xfc\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x01:\x05\
-\x00\x00\x01\x95\xcf\xe3\x00\xfd\
+\x00\x00\x01\x88;p\xbcB\
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x11\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x02B\x00\x00\x00\x00\x00\x01\x00\x02\xb5\xd3\
-\x00\x00\x01\x95\xcf\xe3\x01\x0c\
+\x00\x00\x01\x88;p\xbcJ\
\x00\x00\x02\x14\x00\x00\x00\x00\x00\x01\x00\x02\x9f\xd6\
-\x00\x00\x01\x95\xcf\xe3\x01\x0a\
+\x00\x00\x01\x88;p\xbcI\
\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x02\xa93\
-\x00\x00\x01\x95\xcf\xe3\x01\x09\
+\x00\x00\x01\x88;p\xbcI\
\x00\x00\x00X\x00\x02\x00\x00\x00\x07\x00\x00\x00\x15\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x01P\xb1\
-\x00\x00\x01\x95\xcf\xe3\x01\x0c\
+\x00\x00\x01\x88;p\xbcJ\
\x00\x00\x012\x00\x00\x00\x00\x00\x01\x00\x01yY\
-\x00\x00\x01\x95\xcf\xe3\x01\x0a\
+\x00\x00\x01\x88;p\xbcI\
\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xd2-\
-\x00\x00\x01\x95\xcf\xe3\x01\x0a\
+\x00\x00\x01\x94\xb4\xd4\xf0a\
\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x01\x8c\xe6\
-\x00\x00\x01\x95\xcf\xe3\x01\x09\
+\x00\x00\x01\x88;p\xbcH\
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x01LR\
-\x00\x00\x01\x95\xcf\xe3\x01\x02\
+\x00\x00\x01\x88;p\xbcF\
\x00\x00\x00\xe8\x00\x00\x00\x00\x00\x01\x00\x01?\xe9\
-\x00\x00\x01\x95\xcf\xe3\x01\x08\
+\x00\x00\x01\x88;p\xbcH\
\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x01\x82\xb0\
-\x00\x00\x01\x95\xcf\xe3\x01\x09\
+\x00\x00\x01\x88;p\xbcH\
\x00\x00\x00X\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1d\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x01\x95\xcf\xe3\x01\x08\
+\x00\x00\x01\x88;p\xbcH\
"
def qInitResources():
diff --git a/kindlecomicconverter/KCC_ui.py b/kindlecomicconverter/KCC_ui.py
index 7811ffd..34a50c3 100644
--- a/kindlecomicconverter/KCC_ui.py
+++ b/kindlecomicconverter/KCC_ui.py
@@ -190,13 +190,18 @@ class Ui_mainWindow(object):
self.croppingWidget = QWidget(self.centralWidget)
self.croppingWidget.setObjectName(u"croppingWidget")
self.croppingWidget.setVisible(False)
- self.horizontalLayout_3 = QHBoxLayout(self.croppingWidget)
- self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
- self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
+ self.gridLayout_5 = QGridLayout(self.croppingWidget)
+ self.gridLayout_5.setObjectName(u"gridLayout_5")
+ self.gridLayout_5.setContentsMargins(0, 0, 0, 0)
+ self.preserveMarginLabel = QLabel(self.croppingWidget)
+ self.preserveMarginLabel.setObjectName(u"preserveMarginLabel")
+
+ self.gridLayout_5.addWidget(self.preserveMarginLabel, 1, 0, 1, 1)
+
self.croppingPowerLabel = QLabel(self.croppingWidget)
self.croppingPowerLabel.setObjectName(u"croppingPowerLabel")
- self.horizontalLayout_3.addWidget(self.croppingPowerLabel)
+ self.gridLayout_5.addWidget(self.croppingPowerLabel, 0, 0, 1, 1)
self.croppingPowerSlider = QSlider(self.croppingWidget)
self.croppingPowerSlider.setObjectName(u"croppingPowerSlider")
@@ -204,7 +209,20 @@ class Ui_mainWindow(object):
self.croppingPowerSlider.setSingleStep(1)
self.croppingPowerSlider.setOrientation(Qt.Orientation.Horizontal)
- self.horizontalLayout_3.addWidget(self.croppingPowerSlider)
+ self.gridLayout_5.addWidget(self.croppingPowerSlider, 0, 1, 1, 1)
+
+ self.preserveMarginBox = QSpinBox(self.croppingWidget)
+ self.preserveMarginBox.setObjectName(u"preserveMarginBox")
+ sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
+ sizePolicy2.setHorizontalStretch(0)
+ sizePolicy2.setVerticalStretch(0)
+ sizePolicy2.setHeightForWidth(self.preserveMarginBox.sizePolicy().hasHeightForWidth())
+ self.preserveMarginBox.setSizePolicy(sizePolicy2)
+ self.preserveMarginBox.setMaximum(99)
+ self.preserveMarginBox.setSingleStep(5)
+ self.preserveMarginBox.setValue(0)
+
+ self.gridLayout_5.addWidget(self.preserveMarginBox, 1, 1, 1, 1)
self.gridLayout.addWidget(self.croppingWidget, 9, 0, 1, 2)
@@ -276,11 +294,11 @@ class Ui_mainWindow(object):
self.authorEdit = QLineEdit(self.optionWidget)
self.authorEdit.setObjectName(u"authorEdit")
- sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
- sizePolicy2.setHorizontalStretch(0)
- sizePolicy2.setVerticalStretch(0)
- sizePolicy2.setHeightForWidth(self.authorEdit.sizePolicy().hasHeightForWidth())
- self.authorEdit.setSizePolicy(sizePolicy2)
+ sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
+ sizePolicy3.setHorizontalStretch(0)
+ sizePolicy3.setVerticalStretch(0)
+ sizePolicy3.setHeightForWidth(self.authorEdit.sizePolicy().hasHeightForWidth())
+ self.authorEdit.setSizePolicy(sizePolicy3)
self.authorEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
self.authorEdit.setClearButtonEnabled(False)
@@ -355,8 +373,8 @@ class Ui_mainWindow(object):
self.chunkSizeWidget = QWidget(self.centralWidget)
self.chunkSizeWidget.setObjectName(u"chunkSizeWidget")
- sizePolicy2.setHeightForWidth(self.chunkSizeWidget.sizePolicy().hasHeightForWidth())
- self.chunkSizeWidget.setSizePolicy(sizePolicy2)
+ sizePolicy3.setHeightForWidth(self.chunkSizeWidget.sizePolicy().hasHeightForWidth())
+ self.chunkSizeWidget.setSizePolicy(sizePolicy3)
self.chunkSizeWidget.setVisible(False)
self.horizontalLayout_4 = QHBoxLayout(self.chunkSizeWidget)
self.horizontalLayout_4.setSpacing(0)
@@ -364,11 +382,11 @@ class Ui_mainWindow(object):
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
self.chunkSizeLabel = QLabel(self.chunkSizeWidget)
self.chunkSizeLabel.setObjectName(u"chunkSizeLabel")
- sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
- sizePolicy3.setHorizontalStretch(0)
- sizePolicy3.setVerticalStretch(0)
- sizePolicy3.setHeightForWidth(self.chunkSizeLabel.sizePolicy().hasHeightForWidth())
- self.chunkSizeLabel.setSizePolicy(sizePolicy3)
+ sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
+ sizePolicy4.setHorizontalStretch(0)
+ sizePolicy4.setVerticalStretch(0)
+ sizePolicy4.setHeightForWidth(self.chunkSizeLabel.sizePolicy().hasHeightForWidth())
+ self.chunkSizeLabel.setSizePolicy(sizePolicy4)
self.horizontalLayout_4.addWidget(self.chunkSizeLabel)
@@ -382,8 +400,8 @@ class Ui_mainWindow(object):
self.chunkSizeWarnLabel = QLabel(self.chunkSizeWidget)
self.chunkSizeWarnLabel.setObjectName(u"chunkSizeWarnLabel")
- sizePolicy3.setHeightForWidth(self.chunkSizeWarnLabel.sizePolicy().hasHeightForWidth())
- self.chunkSizeWarnLabel.setSizePolicy(sizePolicy3)
+ sizePolicy4.setHeightForWidth(self.chunkSizeWarnLabel.sizePolicy().hasHeightForWidth())
+ self.chunkSizeWarnLabel.setSizePolicy(sizePolicy4)
self.horizontalLayout_4.addWidget(self.chunkSizeWarnLabel)
@@ -472,6 +490,10 @@ class Ui_mainWindow(object):
#if QT_CONFIG(tooltip)
self.heightBox.setToolTip(QCoreApplication.translate("mainWindow", u"Resolution of the target device.
", None))
#endif // QT_CONFIG(tooltip)
+#if QT_CONFIG(tooltip)
+ self.preserveMarginLabel.setToolTip(QCoreApplication.translate("mainWindow", u"
After calculating the cropping boundaries, "back up" a specified percentage amount.
", None))
+#endif // QT_CONFIG(tooltip)
+ self.preserveMarginLabel.setText(QCoreApplication.translate("mainWindow", u"Preserve Margin %", None))
self.croppingPowerLabel.setText(QCoreApplication.translate("mainWindow", u"Cropping power:", None))
#if QT_CONFIG(tooltip)
self.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"Unchecked - Disabled
Disabled
Indeterminate - Margins
Margins
Checked - Margins + page numbers
Margins +page numbers
", None))
diff --git a/kindlecomicconverter/comic2ebook.py b/kindlecomicconverter/comic2ebook.py
index 85bad15..9f092b3 100755
--- a/kindlecomicconverter/comic2ebook.py
+++ b/kindlecomicconverter/comic2ebook.py
@@ -1050,6 +1050,8 @@ def makeParser():
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
processing_options.add_argument("--cp", "--croppingpower", type=float, dest="croppingp", default="1.0",
help="Set cropping power [Default=1.0]")
+ processing_options.add_argument("--preservemargin", type=int, dest="preservemargin", default="0",
+ help="After calculating crop, back up specified percentage amount. [Default=0]")
processing_options.add_argument("--cm", "--croppingminimum", type=float, dest="croppingm", default="0.0",
help="Set cropping minimum area ratio [Default=0.0]")
processing_options.add_argument("--ipc", "--interpanelcrop", type=int, dest="interpanelcrop", default="0",
diff --git a/kindlecomicconverter/image.py b/kindlecomicconverter/image.py
index fde911a..a99e222 100755
--- a/kindlecomicconverter/image.py
+++ b/kindlecomicconverter/image.py
@@ -390,6 +390,11 @@ class ComicPage:
return Image.Resampling.LANCZOS
def maybeCrop(self, box, minimum):
+ w, h = self.image.size
+ left, upper, right, lower = box
+ if self.opt.preservemargin:
+ ratio = 1 - self.opt.preservemargin / 100
+ box = left * ratio, upper * ratio, right + (w - right) * (1 - ratio), lower + (h - lower) * (1 - ratio)
box_area = (box[2] - box[0]) * (box[3] - box[1])
image_area = self.image.size[0] * self.image.size[1]
if (box_area / image_area) >= minimum: