1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-17 06:28:49 +00:00

Compare commits

..

19 Commits

Author SHA1 Message Date
Alex Xu
187475a424 add SignPath to Windows GUI workflow (#862) 2025-03-11 15:41:12 -07:00
Alex Xu
88fd54e2ba bump 7.3.2 2025-03-11 15:30:02 -07:00
Alex Xu
b23b67bbbe revert build windows gui with docker (#861) 2025-03-11 15:29:33 -07:00
Alex Xu
9992d895cf fix comicrack large files again (#860) 2025-03-11 15:07:48 -07:00
Alex Xu
561951a349 restore imgMetadata dict (#858)
* Revert "memory optimization: store metadata in filenames, not a global dict (…"

This reverts commit 9a2a09eab9.

* only remove imgOld
2025-03-11 09:57:11 -07:00
Alex Xu
b8b7926366 use release-signing 2025-03-10 09:04:55 -07:00
Alex Xu
92f3308e1c bump to 7.3.1 2025-03-10 08:59:18 -07:00
Alex Xu
9e87ccef4e Free code signing on Windows provided by SignPath.io, certificate by SignPath Foundation 2025-03-10 08:58:37 -07:00
Alex Xu
9a2a09eab9 memory optimization: store metadata in filenames, not a global dict (#853)
* remove options.imgMetadata and store metadata in filename

* make kcc much more memory efficient by removing imgMetadata and imgOld dicts
2025-03-09 16:52:07 -07:00
Alex Xu
88cf2fd21f fix sanitize-first bug 2025-03-09 16:50:15 -07:00
Vinh Quang Tran
7a3ed262b1 fix: disabled overriding title (#857) 2025-03-09 16:22:34 -07:00
Alex Xu
9e204aad76 rename images before processing to fix splitting issues (#852)
* rename images before processing to fix splitting issues

* import pathlib

* 9999 page limit
2025-03-07 07:59:04 -08:00
Alex Xu
e1f9d12676 add test-signing 2025-03-06 14:08:48 -08:00
Ciro Mattia Gonano
24ab72fcbc Update LICENSE.txt to reflect Alex is current main maintainer 2025-03-06 12:06:55 +01:00
Ciro Mattia Gonano
4af6a75874 Update LICENSE.txt to reflect Alex is current main maintainer 2025-03-06 12:06:08 +01:00
Alex Xu
28b6188a3f Delete appveyor.yml 2025-03-05 19:03:14 -08:00
iwa
f000af1207 Delete .travis.yml (#849)
* Delete .travis.yml

---------

Co-authored-by: Alex Xu <alexkurosakimh3@gmail.com>
2025-03-05 13:13:59 -08:00
Alex Xu
299f916580 add screenshot 2025-03-04 19:59:54 -08:00
Alex Xu
c39e403595 add screenshot 2025-03-04 19:58:24 -08:00
9 changed files with 60 additions and 88 deletions

View File

@@ -25,11 +25,6 @@ jobs:
# - name: build binary
# run: |
# pyi-makespec -F -i icons\\comic2ebook.ico -n KCC_test -w --noupx kcc.py
- name: Package Application
uses: JackMcKew/pyinstaller-action-windows@main
with:
path: .
spec: ./kcc.spec
- name: Package Application
uses: JackMcKew/pyinstaller-action-windows@main
with:
@@ -43,14 +38,27 @@ jobs:
- name: rename binaries
run: |
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
mv dist/windows/kcc.exe dist/windows/KCC_${version_built}.exe
mv dist/windows/kcc-c2e.exe dist/windows/KCC_c2e_${version_built}.exe
mv dist/windows/kcc-c2p.exe dist/windows/KCC_c2p_${version_built}.exe
- name: upload build
- name: upload-unsigned-artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
with:
name: windows-build
path: dist/windows/*.exe
- id: optional_step_id
uses: signpath/github-action-submit-signing-request@v1.1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '1dc1bad6-4a8c-4f85-af30-5c5d3d392ea6'
project-slug: 'kcc'
signing-policy-slug: 'release-signing'
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: 'dist/windows/signed/'
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
@@ -60,4 +68,4 @@ jobs:
files: |
CHANGELOG.md
LICENSE.txt
dist/windows/*.exe
dist/windows/signed/*.exe

View File

@@ -41,11 +41,22 @@ jobs:
- name: build binary
run: |
python setup.py build_binary
- name: upload build
- name: upload-unsigned-artifact
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
with:
name: windows-build
path: dist/*.exe
- id: optional_step_id
uses: signpath/github-action-submit-signing-request@v1.1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '1dc1bad6-4a8c-4f85-af30-5c5d3d392ea6'
project-slug: 'kcc'
signing-policy-slug: 'release-signing'
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: 'dist/windows/signed/'
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
@@ -55,4 +66,4 @@ jobs:
files: |
CHANGELOG.md
LICENSE.txt
dist/*.exe
dist/windows/signed/*.exe

View File

@@ -1,30 +0,0 @@
matrix:
include:
- os: osx
language: generic
osx_image: xcode11.1
before_install:
- pip3 install --upgrade pip setuptools wheel
install:
- pip3 install -r requirements.txt
- pip3 install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip
- npm install -g appdmg
script: python3 setup.py build_binary
before_deploy:
- shopt -s extglob
- rm -r dist/!(*.deb|*.dmg)
deploy:
provider: gcs
access_key_id: GOOG1EC62457RKUYFR2TIZUWV4EFSV2EP5LVLPPFXUAKADWJFDYPFW63BQSLA
secret_access_key:
secure: sxYjeho7U3im0Ezf6cz6TjYDiLvf0kAM2ETQHYoFNbD1VVvhJJyymDCnPH80zpFKmhc1MWTB6ndwsrPfcyZDLR2meSdWGPjZfFPY3RcrfImndKi7ln+mYQDBQ7W1lGit4YcH3Ju7LHceaTbRA7fVTX8pWKOcbXL2oM+lQxTJHH32+crVma+ChhbjzTWsSLRoakt3Nhiveec5p/qSW7AFe4Zq+b3C85IgwjSJI/xVwzaWrs6p915h1zZi7KL7YCMIxfQFrvRPFR2KTbh/DoLCCrqfbD4qh0PVy1li51Ac3hd/u3foiNnTNchzgE3Nv/nbKmtFU6huuLNgzkQGuLA+yn7mKYzBwA3ZmFgoimdH9+yRCMkZ8B5VHpvfN1hgpJcyEl1T98Kv4cdtRYNB4w9iAMy1qSVxhjeI+2rjuWGoXro0lU6L4LIRCOruY3AuLCAKG8Qw5Ak9ksmIKBhZ9soxpoIwu/TYDUQkFj29IrUQucg9TEp7uAoxu8/7EHxB7hWnBRaBAAQbMuIRg7yysT3FT0Os6SB0t9+RBsVMSPuIti9JJZ2Lu0uRI1+Se+g7ItzYtJoPhBJAzAa+J9OONj0RNj2z8Vq2oIBhH4z6b6zTRMVroos3cdfYl5qIKs9SQ7rmeHoPRROcqpCznsUZ/ESa4f2MewFU/7AYcEnCesZV4xg=
bucket: kcc-deploy
local-dir: dist
skip_cleanup: true
on:
repo: AcidWeb/KCC

View File

@@ -1,8 +1,9 @@
ISC LICENSE
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2012-2025 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
Copyright (c) 2021-2023 Darodi
Copyright (c) 2021-2023 Darodi (https://github.com/darodi)
Copyright (c) 2023-2025 Alex Xu (https://github.com/axu2)
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the

View File

@@ -11,6 +11,8 @@ It was initially developed for Kindle but since version 4.6 it outputs valid EPU
actually a comic/manga to EPUB converter that every e-reader owner can happily use**_.
It can also optionally optimize images by applying a number of transformations.
![image](https://github.com/user-attachments/assets/36ad2131-6677-4559-bd6f-314a90c27218)
### 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.
@@ -31,6 +33,9 @@ If you find **KCC** valuable you can consider donating to the authors:
- Alex Xu (active 2023-Present)
- [![Donate PayPal](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/donate/?business=QFJVE7A6LCP6U&no_recurring=0&item_name=Kindle+Comic+Converter&currency_code=USD)
## Sponsors
- Free code signing on Windows provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
## DOWNLOADS
@@ -319,5 +324,5 @@ The app relies and includes the following scripts:
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
## COPYRIGHT
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
Copyright (c) 2012-2025 Ciro Mattia Gonano, Paweł Jastrzębski, Darodi and Alex Xu.
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.

View File

@@ -1,14 +0,0 @@
environment:
PYTHON: "C:\\Python37-x64"
install:
- set PATH="%PYTHON%\\Scripts";%PATH%
- "%PYTHON%\\python.exe -m pip install --upgrade pip setuptools wheel"
- "%PYTHON%\\python.exe -m pip install -r requirements.txt"
- "%PYTHON%\\python.exe -m pip install certifi https://github.com/pyinstaller/pyinstaller/archive/develop.zip"
build_script:
- "%PYTHON%\\python.exe setup.py build_binary"
artifacts:
- path: dist\KCC*

View File

@@ -1,4 +1,4 @@
__version__ = '7.3.0'
__version__ = '7.3.2'
__license__ = 'ISC'
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
__docformat__ = 'restructuredtext en'

View File

@@ -78,13 +78,14 @@ def main(argv=None):
def buildHTML(path, imgfile, imgfilepath):
key = pathlib.Path(imgfilepath).name
filename = getImageFileName(imgfile)
deviceres = options.profileData[1]
if not options.noprocessing and "Rotated" in options.imgMetadata[imgfilepath]:
if not options.noprocessing and "Rotated" in options.imgMetadata[key]:
rotatedPage = True
else:
rotatedPage = False
if not options.noprocessing and "BlackBackground" in options.imgMetadata[imgfilepath]:
if not options.noprocessing and "BlackBackground" in options.imgMetadata[key]:
additionalStyle = 'background-color:#000000;'
else:
additionalStyle = ''
@@ -215,7 +216,7 @@ def buildNCX(dstdir, title, chapters, chapternames):
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
filename = getImageFileName(os.path.join(folder, chapter[1]))
navID = folder.replace('/', '_').replace('\\', '_')
if options.chapters:
if options.comicinfo_chapters:
title = chapternames[chapter[1]]
navID = filename[0].replace('/', '_').replace('\\', '_')
elif os.path.basename(folder) != "Text":
@@ -243,7 +244,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
for chapter in chapters:
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
filename = getImageFileName(os.path.join(folder, chapter[1]))
if options.chapters:
if options.comicinfo_chapters:
title = chapternames[chapter[1]]
elif os.path.basename(folder) != "Text":
title = chapternames[os.path.basename(folder)]
@@ -255,7 +256,7 @@ def buildNAV(dstdir, title, chapters, chapternames):
for chapter in chapters:
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
filename = getImageFileName(os.path.join(folder, chapter[1]))
if options.chapters:
if options.comicinfo_chapters:
title = chapternames[chapter[1]]
elif os.path.basename(folder) != "Text":
title = chapternames[os.path.basename(folder)]
@@ -521,7 +522,10 @@ def buildEPUB(path, chapternames, tomenumber, ischunked):
build_html_end = perf_counter()
print(f"buildHTML: {build_html_end - build_html_start} seconds")
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
if not chapternames and options.chapters and not ischunked:
if ischunked:
options.comicinfo_chapters = []
if not chapternames and options.comicinfo_chapters:
chapterlist = []
global_diff = 0
@@ -534,13 +538,13 @@ def buildEPUB(path, chapternames, tomenumber, ischunked):
elif options.splitter == 2:
diff_delta = 2
for aChapter in options.chapters:
for aChapter in options.comicinfo_chapters:
pageid = aChapter[0]
cur_diff = global_diff
global_diff = 0
for x in range(0, pageid + cur_diff + 1):
if '-kcc-b' in filelist[x][1]:
if '-KCC-B' in filelist[x][1]:
pageid += diff_delta
global_diff += diff_delta
@@ -557,7 +561,6 @@ def imgDirectoryProcessing(path):
workerPool = Pool(maxtasksperchild=100)
workerOutput = []
options.imgMetadata = {}
options.imgOld = []
work = []
pagenumber = 0
for dirpath, _, filenames in os.walk(path):
@@ -580,9 +583,6 @@ def imgDirectoryProcessing(path):
if len(workerOutput) > 0:
rmtree(os.path.join(path, '..', '..'), True)
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0][0], workerOutput[0][1])
for file in options.imgOld:
if os.path.isfile(file):
os.remove(file)
else:
rmtree(os.path.join(path, '..', '..'), True)
raise UserWarning("Source directory is empty.")
@@ -596,7 +596,6 @@ def imgFileProcessingTick(output):
for page in output:
if page is not None:
options.imgMetadata[page[0]] = page[1]
options.imgOld.append(page[2])
if GUI:
GUI.progressBarTick.emit('tick')
if not GUI.conversionAlive:
@@ -717,7 +716,7 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
def getComicInfo(path, originalpath):
xmlPath = os.path.join(path, 'ComicInfo.xml')
options.chapters = []
options.comicinfo_chapters = []
options.summary = ''
titleSuffix = ''
if options.title == 'defaulttitle':
@@ -740,9 +739,7 @@ def getComicInfo(path, originalpath):
except Exception:
os.remove(xmlPath)
return
if xml.data['Title']:
options.title = hescape(xml.data['Title'])
elif defaultTitle:
if defaultTitle:
if xml.data['Series']:
options.title = hescape(xml.data['Series'])
if xml.data['Volume']:
@@ -761,7 +758,7 @@ def getComicInfo(path, originalpath):
else:
options.authors = ['KCC']
if xml.data['Bookmarks']:
options.chapters = xml.data['Bookmarks']
options.comicinfo_chapters = xml.data['Bookmarks']
if xml.data['Summary']:
options.summary = hescape(xml.data['Summary'])
os.remove(xmlPath)
@@ -801,19 +798,14 @@ def sanitizeTree(filetree):
for name in files:
splitname = os.path.splitext(name)
# file needs kcc at front AND back to avoid renaming issues
# 9999 page limit
slugified = f'kcc-{page:04}'
page += 1
for suffix in '-KCC', '-KCC-A', '-KCC-B', '-KCC-C':
if splitname[0].endswith(suffix):
slugified += suffix.lower()
break
newKey = os.path.join(root, slugified + splitname[1])
key = os.path.join(root, name)
if key != newKey:
os.replace(key, newKey)
options.imgMetadata[newKey] = options.imgMetadata.pop(key)
for i, name in enumerate(dirs):
tmpName = name
slugified = slugify(name)
@@ -825,10 +817,6 @@ def sanitizeTree(filetree):
if key != newKey:
os.replace(key, newKey)
dirs[i] = newKey
existingImgPathKeys = list(options.imgMetadata.keys())
for imgPath in existingImgPathKeys:
if imgPath.startswith(key):
options.imgMetadata[newKey + imgPath.removeprefix(key)] = options.imgMetadata.pop(imgPath)
return chapterNames
@@ -1198,6 +1186,7 @@ def makeBook(source, qtgui=None):
print("Checking images...")
getComicInfo(os.path.join(path, "OEBPS", "Images"), source)
detectSuboptimalProcessing(os.path.join(path, "OEBPS", "Images"), source)
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
if options.webtoon:
y = image.ProfileData.Profiles[options.profile][1][1]
comic2panel.main(['-y ' + str(y), '-i', '-m', path], qtgui)
@@ -1210,7 +1199,6 @@ def makeBook(source, qtgui=None):
imgDirectoryProcessing(os.path.join(path, "OEBPS", "Images"))
if GUI:
GUI.progressBarTick.emit('1')
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
if options.batchsplit > 0:
tomes = chunk_directory(path)
else:

View File

@@ -20,6 +20,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import io
import os
from pathlib import Path
import mozjpeg_lossless_optimization
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
from .page_number_crop_alg import get_bbox_crop_margin_page_number, get_bbox_crop_margin
@@ -320,7 +321,9 @@ class ComicPage:
output_jpeg_file.write(output_jpeg_bytes)
else:
self.image.save(self.targetPath, 'JPEG', optimize=1, quality=85)
return [self.targetPath, flags, self.orgPath]
if os.path.isfile(self.orgPath):
os.remove(self.orgPath)
return [Path(self.targetPath).name, flags]
except IOError as err:
raise RuntimeError('Cannot save image. ' + str(err))