Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d9758d4bd | ||
|
|
3e6cbcb91d | ||
|
|
2bae809e5f |
@@ -58,7 +58,7 @@ jobs:
|
||||
name: windows-build-${{ matrix.entry }}
|
||||
path: dist/*.exe
|
||||
- id: optional_step_id
|
||||
uses: signpath/github-action-submit-signing-request@v2.2
|
||||
uses: signpath/github-action-submit-signing-request@v2.3
|
||||
if: ${{ github.repository == 'ciromattia/kcc' }}
|
||||
with:
|
||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
name: windows7-build
|
||||
path: dist/*.exe
|
||||
- id: optional_step_id
|
||||
uses: signpath/github-action-submit-signing-request@v2.2
|
||||
uses: signpath/github-action-submit-signing-request@v2.3
|
||||
if: ${{ github.repository == 'ciromattia/kcc' }}
|
||||
with:
|
||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
Most manga conversion methods for ereaders add margins. But KCC enables true fullscreen from top to bottom.
|
||||
|
||||

|
||||
|
||||
(feat. Ya Boy Kongming! and Fire Force from a [Humble Bundle](https://humblebundleinc.sjv.io/xL6Zv1) PDF source.)
|
||||
<img src="header.jpg" alt="Header Image" width="400">
|
||||
|
||||
# KCC
|
||||
|
||||
@@ -15,77 +11,54 @@ Most manga conversion methods for ereaders add margins. But KCC enables true ful
|
||||
like Kindle, Kobo, ReMarkable, and more.
|
||||
Pages display in fullscreen without margins,
|
||||
with proper fixed layout support.
|
||||
KCC runs on Windows, macOS, and Linux.
|
||||
|
||||
Supported input formats include JPG/PNG image files in folders, archives like CBZ/EPUB, or PDF.
|
||||
|
||||
Supported input formats include JPG/PNG image files in folders, archives like CBZ, or PDFs.
|
||||
Supported output formats include MOBI/AZW3, EPUB, KEPUB, CBZ, and PDF.
|
||||
|
||||
The absolute highest quality source files are DRM-free PDFs from [Humble Bundle](https://humblebundleinc.sjv.io/xL6Zv1)/Fanatical.
|
||||
The PDFs are often x12000 resolution or better, while even the 10" Kindle Scribe is only x2480.
|
||||
|
||||
KCC's main goal is maximum image quality at significantly smaller file size. For example, KCC
|
||||
|
||||
1) can compress a 600 MB manga volume from Humble Bundle to 100 MB.
|
||||
This is mostly accomplished by downscaling to the native resolution of your specific device.
|
||||
This can also improve battery life, page turn speed, and general performance
|
||||
on underpowered ereaders with small memory and storage capacities.
|
||||
|
||||
2) fixes black levels to avoid gray/faded blacks found in many Kindle Store manga
|
||||
|
||||

|
||||
|
||||
3) fixes [the rainbow effect on Kaleido 3 color eink](https://www.youtube.com/watch?v=Dw2HTJCGMhw) without blur:
|
||||
|
||||

|
||||
|
||||
4) can [semi-automatically detect 2-page spreads](https://www.youtube.com/watch?v=kfIX67f7Aqk) from pre-split single pages:
|
||||
|
||||

|
||||
|
||||
You can view combined spreads either rotated or not:
|
||||
|
||||

|
||||
|
||||
You can view the split halves either before or after combined spreads:
|
||||
|
||||

|
||||
|
||||
## Demo
|
||||
KCC runs on Windows, macOS, and Linux.
|
||||
|
||||
Just drop your input files into the KCC window, hit convert, and USB drop the output files onto your device's `documents` folder!
|
||||
|
||||
https://github.com/user-attachments/assets/da73d625-e082-482d-91a4-ae4765e96fd7
|
||||
|
||||
Then all your usb loaded comic files will show up next to all your normal books in your ereader library!
|
||||
**WARNING**: Kindle Scribe 2025 support may not be possible. Does not work well currently.
|
||||
|
||||
The final result looks incredible on my 10" Kindle Scribe: https://www.youtube.com/watch?v=2CIHW2N9Enc
|
||||
**NEW**: PDF output is now supported for direct conversion to reMarkable devices!
|
||||
When using a reMarkable profile (Rmk1, Rmk2, RmkPP), the format automatically defaults to PDF
|
||||
for optimal compatibility with your device's native PDF reader.
|
||||
|
||||
**WARNING**: Kindle Scribe 2025 MOBI support may have blank pages. Use PDF instead.
|
||||
The absolute highest quality source files are print quality DRM-free PDFs from Kodansha/[Humble Bundle](https://humblebundleinc.sjv.io/xL6Zv1)/Fanatical,
|
||||
which can be directly converted by KCC.
|
||||
|
||||
The GUI looks like this, built in Qt6.
|
||||
There are a lot of options, but most people only care about the ones checked below.
|
||||
Hover over each option to see details in a tooltip.
|
||||
Its main feature is various optional image processing steps to look good on eink screens,
|
||||
which have different requirements than normal LCD screens.
|
||||
Combining that with downscaling to your specific device's screen resolution
|
||||
can result in filesize reductions of hundreds of MB per volume with no visible quality loss on eink.
|
||||
This can also improve battery life, page turn speed, and general performance
|
||||
on underpowered ereaders with small memory and storage capacities.
|
||||
|
||||

|
||||
KCC avoids many common formatting issues (some of which occur [even on the Kindle Store](https://github.com/ciromattia/kcc/wiki/Kindle-Store-bad-formatting)), such as:
|
||||
1) faded black levels causing unneccessarily low contrast, which is hard to see and can cause eyestrain.
|
||||
2) unneccessary margins at the bottom of the screen
|
||||
3) Not utilizing the full 1860x2480 resolution of the 10" Kindle Scribe
|
||||
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
|
||||
|
||||
If you are on macOS and use a 2022+ Kindle, you may need to use Amazon USB File Manager for Mac or OpenMTP.
|
||||
The GUI looks like this, built in Qt6, with my most commonly used settings:
|
||||
|
||||

|
||||
|
||||
Simply drag and drop your files/folders into the KCC window,
|
||||
adjust your settings (hover over each option to see details in a tooltip),
|
||||
and hit convert to create ereader optimized files.
|
||||
You can change the default output directory by holding `Shift` while clicking the convert button.
|
||||
Then just drag and drop the generated output files onto your device's documents folder via USB.
|
||||
If you are on macOS and use a 2022+ Kindle, you may need to use Amazon USB File Manager for Mac.
|
||||
|
||||
YouTube tutorial (please subscribe): https://www.youtube.com/watch?v=QQ6zJcMF2Iw
|
||||
|
||||
Installation tutorial: https://www.youtube.com/watch?v=IR2Fhcm9658
|
||||
|
||||
## Kindle Jailbreak for KOreader
|
||||
|
||||
Jailbreaking to use KOreader is optional. KCC works just fine with the native mobi manga viewer.
|
||||
|
||||
But if you jailbreak your Kindle, you'll unlock additional features like:
|
||||
|
||||
1) compatibility with image formats better suited for manga like 4-bit PNG and WEBP. This enables better quality at **half the file size** compared to JPG which must be 8-bit.
|
||||
This is visually lossless since eink screens are 4-bit.
|
||||
2) no dependency on kindlegen, which can mean **twice as fast conversions** since you can convert to CBZ directly.
|
||||
3) You can dither by partially checking the JPG/PNG box and can crop in KCC instead of KOreader. This may increase page turn speed and battery.
|
||||
|
||||
### A word of warning
|
||||
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
||||
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
||||
|
||||
@@ -779,9 +779,6 @@ Keeping this file may crash some readers like the Kobo native CBZ reader.</strin
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Hold shift while clicking for a higher quality preview.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Label Spreads</string>
|
||||
</property>
|
||||
|
||||
|
Before Width: | Height: | Size: 921 KiB After Width: | Height: | Size: 921 KiB |
|
Before Width: | Height: | Size: 351 KiB |
|
Before Width: | Height: | Size: 367 KiB |
|
Before Width: | Height: | Size: 438 KiB |
|
Before Width: | Height: | Size: 398 KiB |
|
Before Width: | Height: | Size: 358 KiB |
|
Before Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 374 KiB |
@@ -671,9 +671,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
GUI.jobList.scrollToBottom()
|
||||
|
||||
def labelSpreadsStart(self):
|
||||
low_quality_preview = True
|
||||
if QApplication.keyboardModifiers() == Qt.ShiftModifier:
|
||||
low_quality_preview = False
|
||||
currentJobs = []
|
||||
# TODO: make this a function since it's copy pasted
|
||||
for i in range(GUI.jobList.count()):
|
||||
@@ -707,34 +704,29 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
continue
|
||||
# TODO: with statements
|
||||
# TODO: ignore 1% of top and bottom too?
|
||||
im1 = Image.open(os.path.join(root, files[i]))
|
||||
im1 = Image.open(os.path.join(root, files[i])).convert('1', dither=Dither.NONE)
|
||||
size1 = im1.size
|
||||
preview_crop1 = im1.crop((0, 0, 0.2*size1[0], size1[1]))
|
||||
if low_quality_preview:
|
||||
preview_crop1 = preview_crop1.convert('1', dither=Dither.NONE)
|
||||
calculation_crop1 = im1.crop((0.01*size1[0], 0, 0.04*size1[0], size1[1])).convert('1', dither=Dither.NONE)
|
||||
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]))
|
||||
im2 = Image.open(os.path.join(root, files[i+1])).convert('1', dither=Dither.NONE)
|
||||
size2 = im2.size
|
||||
preview_crop2 = im2.crop((0.8*size2[0], 0, size2[0], size2[1]))
|
||||
if low_quality_preview:
|
||||
preview_crop2 = preview_crop2.convert('1', dither=Dither.NONE)
|
||||
calculation_crop2 = im2.crop((0.96*size2[0], 0, .99* size2[0], size2[1])).convert('1', dither=Dither.NONE)
|
||||
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 = calculation_crop1.histogram()
|
||||
hist2 = calculation_crop2.histogram()
|
||||
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
|
||||
|
||||
preview_mode = '1' if low_quality_preview else 'RGB'
|
||||
dst = Image.new(preview_mode, (preview_crop1.width + preview_crop2.width, preview_crop1.height))
|
||||
dst = Image.new('1', (crop1.width + crop2.width, crop1.height))
|
||||
|
||||
dst.paste(preview_crop2, (0, 0))
|
||||
dst.paste(preview_crop1, (preview_crop1.width, 0))
|
||||
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'))
|
||||
|
||||
|
||||
@@ -860,9 +860,6 @@ class Ui_mainWindow(object):
|
||||
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))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.labelSpreadsButton.setToolTip(QCoreApplication.translate("mainWindow", u"Hold shift while clicking for a higher quality preview.", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
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))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '11.0.2'
|
||||
__version__ = '11.0.1'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -1847,15 +1847,11 @@ def makeBook(source, qtgui=None, job_progress=''):
|
||||
|
||||
if os.path.exists(source+'.json'):
|
||||
flattenTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||
chapterNames = {}
|
||||
cover_path = None
|
||||
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(sorted_files)):
|
||||
if not cover_path:
|
||||
cover_path = os.path.join(root, sorted_files[i])
|
||||
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]))
|
||||
@@ -1866,8 +1862,6 @@ def makeBook(source, qtgui=None, job_progress=''):
|
||||
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]))
|
||||
if not os.path.exists(cover_path):
|
||||
cover_path = os.path.join(root, f'{base}-merged.png')
|
||||
|
||||
if options.filefusion:
|
||||
# Strip the fusion_0001_ sort prefix from makeFusion if present
|
||||
|
||||