From f5fe8d93b0e0c65d5583593c3434df4b11ffecc4 Mon Sep 17 00:00:00 2001
From: Alex Xu
Date: Tue, 17 Mar 2026 13:41:41 -0700
Subject: [PATCH] color images are always saved as JPG by default (#1272)
* use jpg for color images always
* add colorOutput variable
* fix typos
* remove dither
* add box
* clarify png
* remove debug code
* remove unneeded check
---
README.md | 3 ++-
gui/KCC.ui | 12 +++++++++++-
kindlecomicconverter/KCC_gui.py | 3 +++
kindlecomicconverter/KCC_ui.py | 11 ++++++++++-
kindlecomicconverter/comic2ebook.py | 9 +++++----
kindlecomicconverter/image.py | 7 ++++---
6 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/README.md b/README.md
index e77da46..14501b2 100644
--- a/README.md
+++ b/README.md
@@ -272,7 +272,8 @@ PROCESSING:
--whiteborders Disable autodetection and force white borders
--coverfill Center-crop only the cover to fill target device screen
--forcecolor Don't convert images to grayscale
- --forcepng Create PNG files instead JPEG
+ --forcepng Create PNG files instead JPEG for black and white images
+ --force-png-rgb Force color images to be saved as PNG
--pnglegacy Use a more compatible 8 bit PNG instead of 4 bit.
--noquantize Don't quantize PNG images to 16 colors
--mozjpeg Create JPEG files using mozJpeg
diff --git a/gui/KCC.ui b/gui/KCC.ui
index 1020b6a..4e75811 100644
--- a/gui/KCC.ui
+++ b/gui/KCC.ui
@@ -801,7 +801,7 @@ Useful for really weird PDFs.
-
- <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>
+ <html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG for black and white images</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>
JPEG/PNG/mozJpeg
@@ -965,6 +965,16 @@ May crop top/bottom or left/right depending on source aspect ratio. Not implemen
+ -
+
+
+ Force full color images to be saved in lossless PNG format, dramatically increases the filesize.
+
+
+ Force PNG RGB
+
+
+
diff --git a/kindlecomicconverter/KCC_gui.py b/kindlecomicconverter/KCC_gui.py
index 925a623..87910d5 100644
--- a/kindlecomicconverter/KCC_gui.py
+++ b/kindlecomicconverter/KCC_gui.py
@@ -351,6 +351,8 @@ class WorkerThread(QThread):
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:
@@ -1054,6 +1056,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'coverFillBox': GUI.coverFillBox.checkState(),
'metadataTitleBox': GUI.metadataTitleBox.checkState(),
'mozJpegBox': GUI.mozJpegBox.checkState(),
+ 'forcePngRgbBox': GUI.forcePngRgbBox.checkState(),
'pngLegacyBox': GUI.pngLegacyBox.checkState(),
'noQuantizeBox': GUI.noQuantizeBox.checkState(),
'jpegQualityBox': GUI.jpegQualityBox.checkState(),
diff --git a/kindlecomicconverter/KCC_ui.py b/kindlecomicconverter/KCC_ui.py
index b2e2fba..5f0c473 100644
--- a/kindlecomicconverter/KCC_ui.py
+++ b/kindlecomicconverter/KCC_ui.py
@@ -492,6 +492,11 @@ class Ui_mainWindow(object):
self.gridLayout_2.addWidget(self.pngLegacyBox, 11, 0, 1, 1)
+ self.forcePngRgbBox = QCheckBox(self.optionWidget)
+ self.forcePngRgbBox.setObjectName(u"forcePngRgbBox")
+
+ self.gridLayout_2.addWidget(self.forcePngRgbBox, 11, 2, 1, 1)
+
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
@@ -745,7 +750,7 @@ class Ui_mainWindow(object):
#endif // QT_CONFIG(tooltip)
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
#if QT_CONFIG(tooltip)
- self.mozJpegBox.setToolTip(QCoreApplication.translate("mainWindow", u"
Unchecked - JPEG
Use JPEG files
Indeterminate - force PNG
Create PNG files instead JPEG
Checked - mozJpeg
10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2
", None))
+ self.mozJpegBox.setToolTip(QCoreApplication.translate("mainWindow", u"Unchecked - JPEG
Use JPEG files
Indeterminate - force PNG
Create PNG files instead JPEG for black and white images
Checked - mozJpeg
10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2
", None))
#endif // QT_CONFIG(tooltip)
self.mozJpegBox.setText(QCoreApplication.translate("mainWindow", u"JPEG/PNG/mozJpeg", None))
#if QT_CONFIG(tooltip)
@@ -797,6 +802,10 @@ class Ui_mainWindow(object):
self.pngLegacyBox.setToolTip(QCoreApplication.translate("mainWindow", u"Use a more compatible 8 bit PNG instead of 4 bit.", None))
#endif // QT_CONFIG(tooltip)
self.pngLegacyBox.setText(QCoreApplication.translate("mainWindow", u"PNG Legacy Mode", None))
+#if QT_CONFIG(tooltip)
+ self.forcePngRgbBox.setToolTip(QCoreApplication.translate("mainWindow", u"Force full color images to be saved in lossless PNG format, dramatically increases the filesize.", None))
+#endif // QT_CONFIG(tooltip)
+ self.forcePngRgbBox.setText(QCoreApplication.translate("mainWindow", u"Force PNG RGB", None))
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
self.jpegQualityLabel.setText(QCoreApplication.translate("mainWindow", u"JPEG Quality:", None))
# retranslateUi
diff --git a/kindlecomicconverter/comic2ebook.py b/kindlecomicconverter/comic2ebook.py
index 40fe26d..9b017d4 100755
--- a/kindlecomicconverter/comic2ebook.py
+++ b/kindlecomicconverter/comic2ebook.py
@@ -689,7 +689,6 @@ def imgFileProcessing(work):
workImg = image.ComicPageParser((dirpath, afile), opt)
for i in workImg.payload:
img = image.ComicPage(opt, *i)
- is_color = (opt.forcecolor and img.color)
if opt.cropping == 2 and not opt.webtoon:
img.cropPageNumber(opt.croppingp, opt.croppingm)
if opt.cropping == 1 and not opt.webtoon:
@@ -701,9 +700,9 @@ def imgFileProcessing(work):
img.autocontrastImage()
img.resizeImage()
- img.optimizeForDisplay(opt.eraserainbow, is_color)
+ img.optimizeForDisplay(opt.eraserainbow, img.colorOutput)
- if is_color:
+ if img.colorOutput:
pass
elif opt.forcepng:
img.convertToGrayscale()
@@ -1412,7 +1411,9 @@ def makeParser():
output_options.add_argument("--eraserainbow", action="store_true", dest="eraserainbow", default=False,
help="Erase rainbow effect on color eink screen by attenuating interfering frequencies")
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
- help="Create PNG files instead JPEG")
+ help="Create PNG files instead JPEG for black and white images")
+ processing_options.add_argument("--force-png-rgb", action="store_true", dest="force_png_rgb", default=False,
+ help="Force color images to be saved as PNG")
processing_options.add_argument("--pnglegacy", action="store_true", dest="pnglegacy", default=False,
help="Use a more compatible 8 bit png instead of 4 bit")
processing_options.add_argument("--noquantize", action="store_true", dest="noquantize", default=False,
diff --git a/kindlecomicconverter/image.py b/kindlecomicconverter/image.py
index 6583ace..376203c 100755
--- a/kindlecomicconverter/image.py
+++ b/kindlecomicconverter/image.py
@@ -277,6 +277,8 @@ class ComicPage:
self.original_color_mode = image.mode
# TODO: color check earlier
self.image = image.convert("RGB")
+ self.color = self.colorCheck()
+ self.colorOutput = self.color and self.opt.forcecolor
self.fill = fill
self.rotated = False
self.orgPath = os.path.join(path[0], path[1])
@@ -295,8 +297,7 @@ class ComicPage:
if not hasattr(Image, 'Resampling'):
Image.Resampling = Image
- @cached_property
- def color(self):
+ def colorCheck(self):
if self.original_color_mode in ("L", "1"):
return False
if self.opt.webtoon:
@@ -405,7 +406,7 @@ class ComicPage:
raise RuntimeError('Cannot save image. ' + str(err))
def save_with_codec(self, image, targetPath):
- if self.opt.forcepng:
+ if self.opt.forcepng and (not self.colorOutput or self.opt.force_png_rgb):
image.info.pop('transparency', None)
if self.opt.iskindle and ('MOBI' in self.opt.format or 'EPUB' in self.opt.format):
targetPath += '.gif'