1
0
mirror of https://github.com/ciromattia/kcc synced 2026-01-29 16:37:34 +00:00

Merge pull request #457 from ciromattia/beta_release_merge_rebased

Beta release merge rebased
This commit is contained in:
darodi
2023-01-14 16:45:23 +01:00
committed by GitHub
27 changed files with 6788 additions and 5214 deletions

14
.dockerignore Normal file
View File

@@ -0,0 +1,14 @@
.git
.github
build
dist
KindleComicConverter.egg-info
.dockerignore
.gitignore
.travis.yml
Dockerfile
other
venv
*.md
LICENSE.txt
MANIFEST.in

25
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
# Enable version updates for Docker
- package-ecosystem: "docker"
# Look for a `Dockerfile` in the `root` directory
directory: "/"
# Check for updates once a week
schedule:
interval: "weekly"
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

74
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "beta_release" ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ "beta_release" ]
schedule:
- cron: '42 22 * * 3'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
category: "/language:${{matrix.language}}"

36
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Docker
on:
workflow_dispatch:
#schedule:
# - cron: '39 5 * * *'
push:
# branches: [ master, pipeline_test, docker_test ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
# Don't trigger if it's just a documentation update
paths-ignore:
- '**.md'
- '**.MD'
- '**.yml'
- 'docs/**'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- '.dockerignore'
jobs:
build_and_push:
uses: sdr-enthusiasts/common-github-workflows/.github/workflows/build_and_push_image.yml@main
with:
platform_linux_arm32v7_enabled: true
platform_linux_arm64v8_enabled: true
platform_linux_amd64_enabled: true
push_enabled: true
build_nohealthcheck: false
ghcr_repo_owner: ${{ github.repository_owner }}
ghcr_repo: ${{ github.repository }}
secrets:
ghcr_token: ${{ secrets.GITHUB_TOKEN }}

82
.github/workflows/package-linux.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: build KCC for Linux
on:
workflow_dispatch:
push:
tags:
- "v*.*.*"
# Don't trigger if it's just a documentation update
paths-ignore:
- '**.md'
- '**.MD'
- '**.yml'
- '**.sh'
- 'docs/**'
- 'Dockerfile'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- '.dockerignore'
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
cache: 'pip'
- name: Install python dependencies
run: |
sudo apt-get update
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full python3-pyqt5 squashfs-tools
python -m pip install --upgrade pip setuptools wheel pyinstaller
pip install -r requirements.txt
- name: build binary
run: |
python setup.py build_binary
chmod +x dist/kcc_linux*
- name: upload build
uses: actions/upload-artifact@v3
with:
name: linux-build
path: dist/kcc_linux*
# issue with this action, disabled and commented out
# see https://github.com/AppImageCrafters/build-appimage/issues/5
# see https://appimage-builder.readthedocs.io/en/latest/intro/install.html#install-appimagetool
# - name: Build AppImage
# uses: AppImageCrafters/build-appimage-action@master
# env:
# UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
# with:
# recipe: AppImageBuilder.yml
- name: Build AppImage
run: |
wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
chmod +x appimage-builder-x86_64.AppImage
sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
appimage-builder --recipe AppImageBuilder.yml --skip-test
env:
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
- name: upload artifact
uses: actions/upload-artifact@v2
with:
name: AppImage
path: './*.AppImage*'
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true
generate_release_notes: true
files: |
CHANGELOG.md
LICENSE.txt
dist/kcc_linux*
*.AppImage*

59
.github/workflows/package-macos.yml vendored Normal file
View File

@@ -0,0 +1,59 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: build KCC for mac os
on:
workflow_dispatch:
push:
tags:
- "v*.*.*"
# Don't trigger if it's just a documentation update
paths-ignore:
- '**.md'
- '**.MD'
- '**.yml'
- '**.sh'
- 'docs/**'
- 'Dockerfile'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- '.dockerignore'
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
cache: 'pip'
- name: Install python dependencies
run: |
python -m pip install --upgrade pip setuptools wheel pyinstaller
pip install -r requirements.txt
- uses: actions/setup-node@v3
with:
node-version: 16
- run: npm install -g appdmg
- name: build binary
run: |
python setup.py build_binary
- name: upload build
uses: actions/upload-artifact@v3
with:
name: mac-os-build
path: dist/*.dmg
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true
generate_release_notes: true
files: |
CHANGELOG.md
LICENSE.txt
dist/*.dmg

55
.github/workflows/package-windows.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: build KCC for windows
on:
workflow_dispatch:
push:
tags:
- "v*.*.*"
# Don't trigger if it's just a documentation update
paths-ignore:
- '**.md'
- '**.MD'
- '**.yml'
- '**.sh'
- 'docs/**'
- 'Dockerfile'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- '.dockerignore'
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
cache: 'pip'
- name: Install python dependencies
run: |
python -m pip install --upgrade pip setuptools wheel pyinstaller
pip install -r requirements.txt
- name: build binary
run: |
python setup.py build_binary
- name: upload build
uses: actions/upload-artifact@v3
with:
name: windows-build
path: dist/*.exe
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
with:
prerelease: true
generate_release_notes: true
files: |
CHANGELOG.md
LICENSE.txt
dist/*.exe

52
.github/workflows/python-package.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Publish Python distributions to PyPI
on:
push:
tags:
- "v*.*.*"
# Don't trigger if it's just a documentation update
paths-ignore:
- '**.md'
- '**.MD'
- '**.yml'
- '**.sh'
- 'docs/**'
- 'Dockerfile'
- 'LICENSE'
- '.gitattributes'
- '.gitignore'
- '.dockerignore'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
cache: 'pip'
- name: Install python dependencies
run: |
python -m pip install --upgrade pip setuptools wheel pyinstaller
pip install -r requirements.txt
- name: Build Dist
run: |
python setup.py sdist
# - name: Release On TestPyPI
# uses: pypa/gh-action-pypi-publish@release/v1
# with:
# user: __token__
# password: ${{ secrets.TEST_PYPI_API_TOKEN }}
# repository_url: https://test.pypi.org/legacy/
# skip_existing: true
# verbose: true
# print_hash: true
- name: Publish a Python distribution to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}

5
.gitignore vendored
View File

@@ -6,7 +6,8 @@ kindlecomicconverter/sentry.py
other/windows/kindlegen.exe
dist/
build/
KindleComicConverter.egg-info/
KindleComicConverter*.egg-info/
.idea/
/venv/
/kindlegen.exe
/kindlegen*
/kcc.bat

70
AppImageBuilder.yml Normal file
View File

@@ -0,0 +1,70 @@
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
version: 1
script:
- rm -rf AppDir || true
- mkdir -p AppDir/usr/share/icons/hicolor/64x64/apps/
- cp -a dist/kcc_linux* AppDir/ && mv AppDir/kcc_linux* AppDir/kcc_linux
- cp icons/comic2ebook.png AppDir/usr/share/icons/hicolor/64x64/apps/
AppDir:
path: AppDir
app_info:
id: com.github.ciromattia.kcc
name: kindleComicConverter
icon: comic2ebook
version: latest
exec: ./kcc_linux
exec_args: $@
apt:
arch:
- amd64
allow_unauthenticated: true
sources:
- sourceline: deb http://archive.ubuntu.com/ubuntu focal main restricted
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates main restricted
- sourceline: deb http://archive.ubuntu.com/ubuntu focal universe
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates universe
- sourceline: deb http://archive.ubuntu.com/ubuntu focal multiverse
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-updates multiverse
- sourceline: deb http://archive.ubuntu.com/ubuntu focal-backports main restricted
universe multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse
include:
- zlib1g:amd64
files:
include:
- /lib/x86_64-linux-gnu/libGLX.so.0
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
- /usr/lib/locale/locale-archive
exclude:
- usr/share/man
- usr/share/doc/*/README.*
- usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
test:
fedora-30:
image: appimagecrafters/tests-env:fedora-30
command: ./AppRun
use_host_x: true
debian-stable:
image: appimagecrafters/tests-env:debian-stable
command: ./AppRun
use_host_x: true
archlinux-latest:
image: appimagecrafters/tests-env:archlinux-latest
command: ./AppRun
use_host_x: true
centos-7:
image: appimagecrafters/tests-env:centos-7
command: ./AppRun
use_host_x: true
ubuntu-xenial:
image: appimagecrafters/tests-env:ubuntu-xenial
command: ./AppRun
use_host_x: true
AppImage:
arch: x86_64
update-information: !ENV ${UPDATE_INFO}
sign-key: None

View File

@@ -1,4 +1,38 @@
# CHANGELOG
#### 5.5.3:
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
* update to python 3.11, thanks [@darodi](https://github.com/darodi)
* Bump python from 3.8-slim-buster to 3.11-slim-buster dependabot[bot]
* More precise type in slugify dependency check, thanks [@bamless](https://github.com/bamless)
* Fix 'slugify' dependency check, thanks [@bamless](https://github.com/bamless)
* Update python-slugify requirement from <3.0.0,>=1.2.1 to >=1.2.1,<8.0.0 dependabot[bot]
* Bump actions/setup-python from 3 to 4 [darodi/kcc#32](https://github.com/darodi/kcc/issues/32) dependabot[bot]
* Bump actions/setup-node from 2 to 3 [darodi/kcc#34](https://github.com/darodi/kcc/issues/34) dependabot[bot]
* Fix Docker 7z missing [darodi/kcc#31](https://github.com/darodi/kcc/issues/31), thanks [@darodi](https://github.com/darodi)
* Spread splitter not keeping aspect ratio [darodi/kcc#27](https://github.com/darodi/kcc/issues/27), thanks [@darodi](https://github.com/darodi)
* activate batchsplit only for EPUB-200 [darodi/kcc#24](https://github.com/darodi/kcc/issues/24), thanks [@darodi](https://github.com/darodi)
* Feature Request: allow split for epub and set target (email, web upload) [darodi/kcc#21](https://github.com/darodi/kcc/issues/21), thanks [@darodi](https://github.com/darodi)
* Adding a switch on GUI interface in order to control cropping options [darodi/kcc#18](https://github.com/darodi/kcc/issues/18), thanks [@darodi](https://github.com/darodi)
* profiles: add Kindle11 and Kindle Scribe [darodi/kcc#16](https://github.com/darodi/kcc/issues/16), thanks [@darodi](https://github.com/darodi)
* Update with new Kobo models [darodi/kcc#15](https://github.com/darodi/kcc/issues/15), thanks [@lennie420](https://github.com/lennie420)
* Keep epub file when selecting another type of output file [darodi/kcc#12](https://github.com/darodi/kcc/issues/12), thanks [@darodi](https://github.com/darodi)
* fix Using 'Disable processing' option using my processed image get an error [darodi/kcc#1](https://github.com/darodi/kcc/issues/1), thanks [@darodi](https://github.com/darodi)
* KFX Output in GUI [darodi/kcc#9](https://github.com/darodi/kcc/issues/9), thanks [@darodi](https://github.com/darodi)
* Linux version and appImage [darodi/kcc#6](https://github.com/darodi/kcc/issues/6), thanks [@darodi](https://github.com/darodi)
* docker image for command line [darodi/kcc#5](https://github.com/darodi/kcc/issues/5), thanks [@darodi](https://github.com/darodi)
* Fix type error in autocontrastImage [ciromattia/kcc#432](https://github.com/ciromattia/kcc/issues/432), thanks [@darodi](https://github.com/darodi)
* Option to turn 1x4 strips into 2x2 strips [ciromattia/kcc#439](https://github.com/ciromattia/kcc/issues/439), thanks [@darodi](https://github.com/darodi)
* Option in GUI to have PNG instead of jpg images [darodi/kcc#3](https://github.com/darodi/kcc/issues/3), thanks [@darodi](https://github.com/darodi)
* Use MozJPEG as the JPEG encoder : cli and GUI option [ciromattia/kcc#416](https://github.com/ciromattia/kcc/pull/416), thanks [@darodi](https://github.com/darodi)
* Disable all image transformation : cli and GUI option [ciromattia/kcc#388](https://github.com/ciromattia/kcc/pull/388), thanks [@StudioEtrange](https://github.com/StudioEtrange)
* file selector add All `*.*` [ciromattia/kcc#412](https://github.com/ciromattia/kcc/pull/412), thanks [@StudioEtrange](https://github.com/StudioEtrange)
* Clarify Pillow version requirement [ciromattia/kcc#366](https://github.com/ciromattia/kcc/pull/366), thanks [@clach04](https://github.com/clach04)
* sync requirements between setup.py and requirements.txt [ciromattia/kcc#411](https://github.com/ciromattia/kcc/pull/411), thanks [@StudioEtrange](https://github.com/StudioEtrange)
* Add profile for Kindle PW5/Signature [ciromattia/kcc#405](https://github.com/ciromattia/kcc/pull/405), thanks [@Einlar](https://github.com/Einlar), [@darodi](https://github.com/darodi)
* Fixed the skipped/missed images and/or panels [ciromattia/kcc#393](https://github.com/ciromattia/kcc/pull/393), thanks [@FulyaDemirkan](https://github.com/FulyaDemirkan)
* Add profiles for the Kobo Clara HD and Libra H2O [ciromattia/kcc#331](https://github.com/ciromattia/kcc/pull/331), thanks [@fbriere](https://github.com/fbriere)
#### 5.5.2:
* Fixed KindleGen detection on macOS 10.15
* Fixed multiple smaller issues

167
Dockerfile Normal file
View File

@@ -0,0 +1,167 @@
FROM --platform=linux/amd64 python:3.11-slim-buster as compile-amd64
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
COPY requirements.txt /opt/kcc/
ENV PATH="/opt/venv/bin:$PATH"
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
apt-get install -y libpng-dev libjpeg-dev p7zip-full unrar-free libgl1 python3-pyqt5 && \
python -m pip install --upgrade pip && \
python -m venv /opt/venv && \
python -m pip install -r /opt/kcc/requirements.txt
######################################################################################
FROM --platform=linux/arm64 python:3.11-slim-buster as compile-arm64
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
ENV LC_ALL=C.UTF-8 \
LANG=C.UTF-8 \
LANGUAGE=en_US:en
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN set -x && \
TEMP_PACKAGES=() && \
KEPT_PACKAGES=() && \
# Packages only required during build
TEMP_PACKAGES+=(build-essential) && \
TEMP_PACKAGES+=(cmake) && \
TEMP_PACKAGES+=(libfreetype6-dev) && \
TEMP_PACKAGES+=(libfontconfig1-dev) && \
TEMP_PACKAGES+=(libpng-dev) && \
TEMP_PACKAGES+=(libjpeg-dev) && \
TEMP_PACKAGES+=(libssl-dev) && \
TEMP_PACKAGES+=(libxft-dev) && \
TEMP_PACKAGES+=(make) && \
TEMP_PACKAGES+=(python3-dev) && \
TEMP_PACKAGES+=(python3-setuptools) && \
TEMP_PACKAGES+=(python3-wheel) && \
# Packages kept in the image
KEPT_PACKAGES+=(bash) && \
KEPT_PACKAGES+=(ca-certificates) && \
KEPT_PACKAGES+=(chrpath) && \
KEPT_PACKAGES+=(locales) && \
KEPT_PACKAGES+=(locales-all) && \
KEPT_PACKAGES+=(libfreetype6) && \
KEPT_PACKAGES+=(libfontconfig1) && \
KEPT_PACKAGES+=(p7zip-full) && \
KEPT_PACKAGES+=(python3) && \
KEPT_PACKAGES+=(python3-pip) && \
KEPT_PACKAGES+=(python-pyqt5) && \
KEPT_PACKAGES+=(qt5-default) && \
KEPT_PACKAGES+=(unrar-free) && \
# Install packages
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
${KEPT_PACKAGES[@]} \
${TEMP_PACKAGES[@]} \
&& \
# Install required python modules
python -m pip install --upgrade pip && \
# python -m pip install -r /opt/kcc/requirements.txt && \
python -m venv /opt/venv && \
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
######################################################################################
FROM --platform=linux/arm/v7 python:3.11-slim-buster as compile-armv7
ARG TARGETOS
ARG TARGETARCH
ARG TARGETVARIANT
RUN echo "I'm building for $TARGETOS/$TARGETARCH/$TARGETVARIANT"
ENV LC_ALL=C.UTF-8 \
LANG=C.UTF-8 \
LANGUAGE=en_US:en
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN set -x && \
TEMP_PACKAGES=() && \
KEPT_PACKAGES=() && \
# Packages only required during build
TEMP_PACKAGES+=(build-essential) && \
TEMP_PACKAGES+=(cmake) && \
TEMP_PACKAGES+=(libffi-dev) && \
TEMP_PACKAGES+=(libfreetype6-dev) && \
TEMP_PACKAGES+=(libfontconfig1-dev) && \
TEMP_PACKAGES+=(libpng-dev) && \
TEMP_PACKAGES+=(libjpeg-dev) && \
TEMP_PACKAGES+=(libssl-dev) && \
TEMP_PACKAGES+=(libxft-dev) && \
TEMP_PACKAGES+=(make) && \
TEMP_PACKAGES+=(python3-dev) && \
TEMP_PACKAGES+=(python3-setuptools) && \
TEMP_PACKAGES+=(python3-wheel) && \
# Packages kept in the image
KEPT_PACKAGES+=(bash) && \
KEPT_PACKAGES+=(ca-certificates) && \
KEPT_PACKAGES+=(chrpath) && \
KEPT_PACKAGES+=(locales) && \
KEPT_PACKAGES+=(locales-all) && \
KEPT_PACKAGES+=(libfreetype6) && \
KEPT_PACKAGES+=(libfontconfig1) && \
KEPT_PACKAGES+=(p7zip-full) && \
KEPT_PACKAGES+=(python3) && \
KEPT_PACKAGES+=(python3-pip) && \
KEPT_PACKAGES+=(python-pyqt5) && \
KEPT_PACKAGES+=(qt5-default) && \
KEPT_PACKAGES+=(unrar-free) && \
# Install packages
DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
${KEPT_PACKAGES[@]} \
${TEMP_PACKAGES[@]} \
&& \
# Install required python modules
python -m pip install --upgrade pip && \
# python -m pip install -r /opt/kcc/requirements.txt && \
python -m venv /opt/venv && \
python -m pip install --upgrade pillow python-slugify psutil raven mozjpeg-lossless-optimization
######################################################################################
FROM --platform=linux/amd64 python:3.11-slim-buster as build-amd64
COPY --from=compile-amd64 /opt/venv /opt/venv
FROM --platform=linux/arm64 python:3.11-slim-buster as build-arm64
COPY --from=compile-arm64 /opt/venv /opt/venv
FROM --platform=linux/arm/v7 python:3.11-slim-buster as build-armv7
COPY --from=compile-armv7 /opt/venv /opt/venv
######################################################################################
# Select final stage based on TARGETARCH ARG
FROM build-${TARGETARCH}${TARGETVARIANT}
LABEL com.kcc.name="Kindle Comic Converter"
LABEL com.kcc.author="Ciro Mattia Gonano, Paweł Jastrzębski and Darodi"
LABEL org.opencontainers.image.description='Kindle Comic Converter'
LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc'
LABEL org.opencontainers.image.source='https://github.com/ciromattia/kcc'
LABEL org.opencontainers.image.authors='darodi'
LABEL org.opencontainers.image.url='https://github.com/ciromattia/kcc'
LABEL org.opencontainers.image.documentation='https://github.com/ciromattia/kcc'
LABEL org.opencontainers.image.vendor='ciromattia'
LABEL org.opencontainers.image.licenses='ISC'
LABEL org.opencontainers.image.title="Kindle Comic Converter"
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
COPY . /opt/kcc
RUN DEBIAN_FRONTEND=noninteractive apt-get update -y && apt-get -yq upgrade && \
apt-get install -y p7zip-full unrar-free && \
ln -s /app/kindlegen /bin/kindlegen && \
cat /opt/kcc/kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/'//g" > /IMAGE_VERSION
ENTRYPOINT ["/opt/kcc/kcc-c2e.py"]
CMD ["-h"]

View File

@@ -2,6 +2,7 @@
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013-2019 Paweł Jastrzębski <pawelj@iosphe.re>
Copyright (c) 2021-2023 Darodi
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the

208
README.md
View File

@@ -1,6 +1,8 @@
# KCC
[![GitHub release](https://img.shields.io/github/release/ciromattia/kcc.svg)](https://github.com/ciromattia/kcc/releases) [![PyPI](https://img.shields.io/pypi/v/KindleComicConverter.svg)](https://pypi.python.org/pypi/KindleComicConverter) [![AUR](https://img.shields.io/aur/version/kcc.svg)](https://aur.archlinux.org/packages/kcc/)
[![GitHub release](https://img.shields.io/github/release/ciromattia/kcc.svg)](https://github.com/ciromattia/kcc/releases)
[![PyPI](https://img.shields.io/pypi/v/KindleComicConverter.svg)](https://pypi.python.org/pypi/KindleComicConverter)
[![AUR](https://img.shields.io/aur/version/kcc.svg)](https://aur.archlinux.org/packages/kcc/)
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
@@ -25,37 +27,169 @@ If you find **KCC** valuable you can consider donating to the authors:
- [![Donate PayPal](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
- [![Donate Bitcoin](https://img.shields.io/badge/Donate-Bitcoin-green.svg)](https://jastrzeb.ski/donate/)
## BINARY RELEASES
## INSTALLATION
### BINARY RELEASES
You can find the latest released binary at the following links:
- **[Windows](http://kcc.iosphe.re/Windows/) (64-bit only)**
- **[macOS](http://kcc.iosphe.re/OSX/) (10.14+)**
- **Linux:** Currently unavailable.
## PYPI
### PYPI
**KCC** is also available on PyPI.
```
pip install --user KindleComicConverter
```
## DEPENDENCIES
### APPIMAGE
- install 7zip
```bash
$ sudo apt-get install -y p7zip-full
```
- Download kindlegen
```bash
$ wget -qO- https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvz kindlegen
```
- copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
```bash
$ sudo cp -R kindlegen /usr/local/bin && sudo chmod a+x /usr/local/bin/kindlegen
```
- make appImage executable
```bash
$ chmod a+x kindleComicConverter-latest-x86_64.AppImage
```
- run with backend x11 or it might not work with fedora
```bash
$ GDK_BACKEND=x11 ./kindleComicConverter-latest-x86_64.AppImage
```
### DOCKER
install kindlegen in your working directory and get last docker image
```bash
$ wget -qO- https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvz kindlegen
```
```bash
$ docker pull ghcr.io/ciromattia/kcc:latest
```
execute kcc-c2e
```bash
$ docker run --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest
```
example
```bash
$ docker run --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest -p KPW5 ./1.cbz
```
execute kcc-c2p
```bash
$ docker run --entrypoint /opt/kcc/kcc-c2p.py --rm -v "$(pwd):/app" ghcr.io/ciromattia/kcc:latest
```
### DEPENDENCIES
Following software is required to run Linux version of **KCC** and/or bare sources:
- Python 3.3+
- [PyQt5](https://pypi.python.org/pypi/PyQt5) 5.6.0+ (only needed for GUI)
- [Pillow](https://pypi.python.org/pypi/Pillow/) 4.0.0+ (5.2.0+ needed for WebP support)
- [psutil](https://pypi.python.org/pypi/psutil) 5.0.0+
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+, <3.0.0
- [python-slugify](https://pypi.python.org/pypi/python-slugify) 1.2.1+, <8.0.0
- [raven](https://pypi.python.org/pypi/raven) 6.0.0+ (only needed for GUI)
On Debian based distributions these two commands should install all needed dependencies:
```
sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full
pip3 install --user --upgrade pillow python-slugify psutil pyqt5 raven
```bash
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
$ pip3 install --user --upgrade pillow python-slugify psutil pyqt5 raven
```
### Optional dependencies
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
#### Optional dependencies
- KindleGen ~~[deprecated link](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211)~~ v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)
which offers a command line interface and supports [Linux](https://archive.org/details/kindlegen2.9) [(mirror1)](https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz), [Mac OSX](https://web.archive.org/web/20190905040839/https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) and [Windows](https://archive.org/details/kindlegen_win32_v2_9) has been deprecated, but binaries can still be found on the internet.
- [7z](http://www.7-zip.org/download.html) *(For CBZ/ZIP, CBR/RAR, 7z/CB7 support)*
### INSTALL FROM SOURCES
_Originally posted by @hhtien1408 in https://github.com/ciromattia/kcc/issues/438#issuecomment-1281159452_
```bash
$ git clone https://github.com/ciromattia/kcc.git
```
On Debian based distributions these two commands should install all needed dependencies:
```bash
$ sudo apt-get install python3 python3-dev python3-pip libpng-dev libjpeg-dev p7zip-full python3-pyqt5
```
Then install the necessary packages. You can do it by running the following command. The requirements.txt file is inside this repository, you will see it when you clone the repo.
```bash
$ pip3 install -r 'requirements.txt'
```
This should install the required packages. You can check the version by running
```bash
$ pip3 freeze
```
If the packages are in the wrong version, you can try to upgrade them by running
```bash
$ pip3 install --upgrade name_of_the_package
```
Download kindlegen.
```bash
$ wget https://archive.org/download/kindlegen_linux_2_6_i386_v2_9/kindlegen_linux_2.6_i386_v2_9.tar.gz | tar xvzf kindlegen
```
Copy kindlegen into '/usr/local/bin' and grant execute permissions for MOBI conversion.
```bash
$ sudo cp -R '/home/user/Desktop/kindlegen' '/usr/local/bin'
$ sudo chmod +rwx '/usr/local/bin/kindlegen'
```
Run python file for KCC GUI
```bash
$ python3 kcc.py
```
If everything goes well, you now should be able to use it.
Create destop file in '~/.local/share/applications' with codes:
```
#!/usr/bin/env xdg-open
[Desktop Entry]
Type=Application
Name=Kindle Comic Converter
Icon=kcc
Exec=python3 '/home/user/kcc/kcc.py'
Terminal=false
StartupWMClass=kcc
Name[en_US]=Kindle Comic Converter
```
Copy icon file into '/home/user/.local/share/icons'
```bash
$ sudo cp -R 'icons/comic2ebook.png' '/home/user/.local/share/icons'
```
## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following input types:
- Folders containing: PNG, JPG, GIF or WebP files
@@ -73,6 +207,37 @@ Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more detail
CLI version of **KCC** is intended for power users. It allows using options that might not be compatible and decrease the quality of output.
### Profiles:
```
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
'K578': ("Kindle", (600, 800), Palette16, 1.8),
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
'KV': ("Kindle Paperwhite 3/4/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.8),
'KO': ("Kindle Oasis 2/3", (1264, 1680), Palette16, 1.8),
'KS': ("Kindle Scribe", (1860, 2480), Palette16, 1.8),
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8),
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
'OTHER': ("Other", (0, 0), Palette16, 1.8),
```
### Standalone `kcc-c2e.py` usage:
```
@@ -82,12 +247,16 @@ Options:
MAIN:
-p PROFILE, --profile=PROFILE
Device profile (Available options: K1, K2, K34, K578,
KDX, KPW, KPW5, KV, KO, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
KoAO, KoC, KoL, KoF) [Default=KV]
KDX, KPW, KPW5, KV, KO, K11, KS, KoMT, KoG, KoGHD,
KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS,
KoE) [Default=KV]
-m, --manga-style Manga style (right-to-left reading and splitting)
-q, --hq Try to increase the quality of magnification
-2, --two-panel Display two not four panels in Panel View mode
-w, --webtoon Webtoon processing mode
--targetsize=TARGETSIZE
the maximal size of output file in MB. [Default=100MB
for webtoon and 400MB for others]
OUTPUT SETTINGS:
-o OUTPUT, --output=OUTPUT
@@ -96,13 +265,15 @@ Options:
Comic title [Default=filename or directory name]
-f FORMAT, --format=FORMAT
Output format (Available options: Auto, MOBI, EPUB,
CBZ, KFX) [Default=Auto]
CBZ, KFX, MOBI+EPUB) [Default=Auto]
-b BATCHSPLIT, --batchsplit=BATCHSPLIT
Split output into multiple files. 0: Don't split 1:
Automatic mode 2: Consider every subdirectory as
separate volume [Default=0]
PROCESSING:
-n, --noprocessing Do not modify image and ignore any profil or
processing option
-u, --upscale Resize images smaller than device's resolution
-s, --stretch Stretch images to device's resolution
-r SPLITTER, --splitter=SPLITTER
@@ -120,6 +291,8 @@ Options:
--whiteborders Disable autodetection and force white borders
--forcecolor Don't convert images to grayscale
--forcepng Create PNG files instead JPEG
--mozjpeg Create JPEG files using mozJpeg
--maximizestrips Turn 1x4 strips to 2x2 strips
CUSTOM PROFILE:
--customwidth=CUSTOMWIDTH
@@ -141,7 +314,8 @@ Options:
-y HEIGHT, --height=HEIGHT
Height of the target device screen
-i, --in-place Overwrite source directory
-m, --merge Combine every directory into a single image before splitting
-m, --merge Combine every directory into a single image before
splitting
OTHER:
-d, --debug Create debug file for every split image
@@ -149,7 +323,7 @@ Options:
```
## CREDITS
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia) and [Paweł Jastrzębski](http://github.com/AcidWeb).
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia), [Paweł Jastrzębski](http://github.com/AcidWeb) and [Darodi](http://github.com/darodi) .
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
@@ -179,5 +353,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-2019 Ciro Mattia Gonano and Paweł Jastrzębski.
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
Copyright (c) 2012-2023 Ciro Mattia Gonano, Paweł Jastrzębski and Darodi.
**KCC** is released under ISC LICENSE; see [LICENSE.txt](./LICENSE.txt) for further details.

View File

@@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48px"
height="48px"
id="svg3832"
version="1.1"
inkscape:version="0.47 r22583"
sodipodi:docname="appimage-assistant_alt3.svg">
<defs
id="defs3834">
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3308-4-6-931-761-0"
id="linearGradient2975"
gradientUnits="userSpaceOnUse"
x1="24.3125"
y1="22.96875"
x2="24.3125"
y2="41.03125" />
<linearGradient
id="linearGradient3308-4-6-931-761-0">
<stop
id="stop2919-2"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop2921-76"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient4222"
id="linearGradient2979"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,0.3704967,-0.3617496,0,33.508315,6.1670925)"
x1="7.6485429"
y1="26.437023"
x2="41.861729"
y2="26.437023" />
<linearGradient
id="linearGradient4222">
<stop
id="stop4224"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop4226"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3308-4-6-931-761"
id="linearGradient2982"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,0.9999987)"
x1="23.99999"
y1="4.999989"
x2="23.99999"
y2="43" />
<linearGradient
id="linearGradient3308-4-6-931-761">
<stop
id="stop2919"
style="stop-color:#ffffff;stop-opacity:1"
offset="0" />
<stop
id="stop2921"
style="stop-color:#ffffff;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3575"
id="radialGradient2985"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,1.0262008,-1.6561124,9.4072203e-4,-56.097482,-45.332325)"
cx="48.42384"
cy="-48.027504"
fx="48.42384"
fy="-48.027504"
r="38.212933" />
<linearGradient
id="linearGradient3575">
<stop
id="stop3577"
style="stop-color:#fafafa;stop-opacity:1"
offset="0" />
<stop
id="stop3579"
style="stop-color:#e6e6e6;stop-opacity:1"
offset="1" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient3993"
id="radialGradient2990"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,2.0478765,-2.7410544,-8.6412258e-8,47.161382,-8.837436)"
cx="9.3330879"
cy="8.4497671"
fx="9.3330879"
fy="8.4497671"
r="19.99999" />
<linearGradient
id="linearGradient3993">
<stop
offset="0"
style="stop-color:#a3c0d0;stop-opacity:1"
id="stop3995" />
<stop
offset="1"
style="stop-color:#427da1;stop-opacity:1"
id="stop4001" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient2508"
id="linearGradient2992"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0,0.9674382)"
x1="14.048676"
y1="44.137306"
x2="14.048676"
y2="4.0000005" />
<linearGradient
id="linearGradient2508">
<stop
offset="0"
style="stop-color:#2e4a5a;stop-opacity:1"
id="stop2510" />
<stop
offset="1"
style="stop-color:#6e8796;stop-opacity:1"
id="stop2512" />
</linearGradient>
<radialGradient
cx="4.9929786"
cy="43.5"
r="2.5"
fx="4.9929786"
fy="43.5"
id="radialGradient2873-966-168"
xlink:href="#linearGradient3688-166-749"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)" />
<linearGradient
id="linearGradient3688-166-749">
<stop
id="stop2883"
style="stop-color:#181818;stop-opacity:1"
offset="0" />
<stop
id="stop2885"
style="stop-color:#181818;stop-opacity:0"
offset="1" />
</linearGradient>
<radialGradient
cx="4.9929786"
cy="43.5"
r="2.5"
fx="4.9929786"
fy="43.5"
id="radialGradient2875-742-326"
xlink:href="#linearGradient3688-464-309"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)" />
<linearGradient
id="linearGradient3688-464-309">
<stop
id="stop2889"
style="stop-color:#181818;stop-opacity:1"
offset="0" />
<stop
id="stop2891"
style="stop-color:#181818;stop-opacity:0"
offset="1" />
</linearGradient>
<linearGradient
x1="25.058096"
y1="47.027729"
x2="25.058096"
y2="39.999443"
id="linearGradient2877-634-617"
xlink:href="#linearGradient3702-501-757"
gradientUnits="userSpaceOnUse" />
<linearGradient
id="linearGradient3702-501-757">
<stop
id="stop2895"
style="stop-color:#181818;stop-opacity:0"
offset="0" />
<stop
id="stop2897"
style="stop-color:#181818;stop-opacity:1"
offset="0.5" />
<stop
id="stop2899"
style="stop-color:#181818;stop-opacity:0"
offset="1" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7"
inkscape:cx="24"
inkscape:cy="24"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="603"
inkscape:window-height="484"
inkscape:window-x="417"
inkscape:window-y="162"
inkscape:window-maximized="0" />
<metadata
id="metadata3837">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
style="display:inline"
id="g2036"
transform="matrix(1.1,0,0,0.4444449,-2.4000022,25.11107)">
<g
style="opacity:0.4"
id="g3712"
transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)">
<rect
style="fill:url(#radialGradient2873-966-168);fill-opacity:1;stroke:none"
id="rect2801"
y="40"
x="38"
height="7"
width="5" />
<rect
style="fill:url(#radialGradient2875-742-326);fill-opacity:1;stroke:none"
id="rect3696"
transform="scale(-1,-1)"
y="-47"
x="-10"
height="7"
width="5" />
<rect
style="fill:url(#linearGradient2877-634-617);fill-opacity:1;stroke:none"
id="rect3700"
y="40"
x="10"
height="7.0000005"
width="28" />
</g>
</g>
<rect
style="fill:url(#radialGradient2990);fill-opacity:1;stroke:url(#linearGradient2992);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="rect5505"
y="5.4674392"
x="4.5"
ry="2.2322156"
rx="2.2322156"
height="39"
width="39" />
<path
style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path4294-1"
d="m 21,6.9687498 a 2.0165107,2.0165107 0 0 0 -2.03125,2.03125 l 0,3.9687502 -1.15625,0 a 2.0165107,2.0165107 0 0 0 -1.5,3.375 l 5.0625,5.75 c -0.06312,0.110777 -0.178724,0.246032 -0.21875,0.34375 -0.195898,0.478256 -0.25,0.83653 -0.25,1.21875 l 0,0.125 L 20.8125,23.6875 C 20.534322,23.409323 20.213169,23.162739 19.71875,22.96875 19.47154,22.87176 19.185456,22.791748 18.75,22.8125 c -0.435456,0.02075 -1.054055,0.210302 -1.46875,0.625 L 15.75,24.96875 c -0.414689,0.414689 -0.604245,1.033294 -0.625,1.46875 -0.02075,0.435456 0.05925,0.721537 0.15625,0.96875 C 15.475241,27.900677 15.721817,28.221821 16,28.5 l 0.09375,0.09375 -0.125,0 c -0.382218,0 -0.740493,0.0541 -1.21875,0.25 -0.239128,0.09795 -0.538285,0.214988 -0.84375,0.53125 -0.305465,0.316262 -0.625,0.914788 -0.625,1.53125 l 0,2.1875 c 0,0.616465 0.319536,1.214989 0.625,1.53125 0.305464,0.316261 0.604622,0.433301 0.84375,0.53125 0.478256,0.195898 0.83653,0.25 1.21875,0.25 l 0.125,0 L 16,35.5 c -0.278175,0.278176 -0.52476,0.599329 -0.71875,1.09375 -0.09699,0.24721 -0.177003,0.533292 -0.15625,0.96875 0.02075,0.435458 0.210304,1.054058 0.625,1.46875 l 1.53125,1.53125 c 0.414691,0.414697 1.033292,0.604245 1.46875,0.625 0.435458,0.02076 0.721537,-0.05926 0.96875,-0.15625 0.494425,-0.19399 0.81557,-0.440568 1.09375,-0.71875 l 0.09375,-0.09375 0,0.125 c 0,0.38222 0.0541,0.740495 0.25,1.21875 0.09795,0.239127 0.214989,0.538285 0.53125,0.84375 0.316261,0.305465 0.914783,0.625 1.53125,0.625 l 2.1875,0 c 0.616466,0 1.214989,-0.319534 1.53125,-0.625 0.316261,-0.305466 0.433302,-0.604622 0.53125,-0.84375 0.195896,-0.478255 0.25,-0.836532 0.25,-1.21875 l 0,-0.125 0.09375,0.09375 c 0.278176,0.278175 0.599329,0.52476 1.09375,0.71875 0.24721,0.09699 0.533292,0.177003 0.96875,0.15625 0.435458,-0.02075 1.054058,-0.210304 1.46875,-0.625 L 32.875,39.03125 C 33.289697,38.616559 33.479245,37.997958 33.5,37.5625 33.52076,37.127042 33.44074,36.840963 33.34375,36.59375 33.14976,36.099325 32.903182,35.77818 32.625,35.5 l -0.09375,-0.09375 0.125,0 c 0.38222,0 0.740494,-0.0541 1.21875,-0.25 0.239128,-0.09795 0.538286,-0.214988 0.84375,-0.53125 0.305464,-0.316262 0.625,-0.914787 0.625,-1.53125 l 0,-2.1875 c 0,-0.61646 -0.319535,-1.214987 -0.625,-1.53125 -0.305465,-0.316263 -0.604621,-0.433301 -0.84375,-0.53125 -0.478257,-0.195898 -0.836532,-0.25 -1.21875,-0.25 l -0.125,0 L 32.625,28.5 c 0.278177,-0.278177 0.52476,-0.599329 0.71875,-1.09375 C 33.44074,27.15904 33.520753,26.872957 33.5,26.4375 33.47925,26.002043 33.289697,25.383443 32.875,24.96875 L 31.34375,23.4375 c -0.414688,-0.414694 -1.03329,-0.604245 -1.46875,-0.625 -0.43546,-0.02076 -0.721537,0.05925 -0.96875,0.15625 -0.494426,0.193991 -0.815572,0.44057 -1.09375,0.71875 l -0.09375,0.09375 0,-0.125 c 0,-0.382218 -0.0541,-0.740493 -0.25,-1.21875 -0.09112,-0.22245 -0.228127,-0.500183 -0.5,-0.78125 l 4.71875,-5.3125 a 2.0165107,2.0165107 0 0 0 -1.5,-3.375 l -1.15625,0 0,-3.9687502 A 2.0165107,2.0165107 0 0 0 27,6.9687498 l -6,0 z M 24.3125,31.25 c 0.427097,0 0.75,0.322904 0.75,0.75 0,0.427096 -0.322903,0.75 -0.75,0.75 -0.427094,0 -0.75,-0.322906 -0.75,-0.75 0,-0.427094 0.322906,-0.75 0.75,-0.75 z" />
<path
style="opacity:0.05;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path4294"
d="m 20.90625,8.0312498 a 0.96385067,0.96385067 0 0 0 -0.875,0.96875 l 0,5.0312502 -2.21875,0 A 0.96385067,0.96385067 0 0 0 17.09375,15.625 l 5.78125,6.53125 c -0.158814,0.0616 -0.341836,0.0951 -0.4375,0.1875 -0.169161,0.163386 -0.252971,0.323419 -0.3125,0.46875 -0.119058,0.290663 -0.15625,0.566746 -0.15625,0.84375 l 0,1.65625 C 21.718163,25.40233 21.485871,25.509772 21.25,25.625 l -1.1875,-1.1875 c -0.199651,-0.19965 -0.421433,-0.352095 -0.71875,-0.46875 -0.148659,-0.05833 -0.329673,-0.104846 -0.5625,-0.09375 -0.232827,0.0111 -0.53583,0.09833 -0.75,0.3125 L 16.5,25.71875 c -0.214168,0.214168 -0.301403,0.517173 -0.3125,0.75 -0.0111,0.232827 0.03542,0.41384 0.09375,0.5625 0.116655,0.297321 0.269096,0.519099 0.46875,0.71875 l 1.1875,1.1875 c -0.115228,0.235871 -0.222668,0.468163 -0.3125,0.71875 l -1.65625,0 c -0.277003,0 -0.553087,0.03719 -0.84375,0.15625 -0.145332,0.05953 -0.305363,0.143338 -0.46875,0.3125 -0.163387,0.169162 -0.3125,0.46403 -0.3125,0.78125 l 0,2.1875 c 0,0.317221 0.149114,0.612089 0.3125,0.78125 0.163386,0.169161 0.323419,0.252971 0.46875,0.3125 0.290663,0.119058 0.566746,0.15625 0.84375,0.15625 l 1.65625,0 c 0.08983,0.250587 0.197272,0.482879 0.3125,0.71875 L 16.75,36.25 c -0.199649,0.19965 -0.352095,0.421432 -0.46875,0.71875 -0.05833,0.148659 -0.104846,0.329672 -0.09375,0.5625 0.0111,0.232828 0.09833,0.535831 0.3125,0.75 l 1.53125,1.53125 c 0.214168,0.214172 0.517172,0.301403 0.75,0.3125 0.232828,0.0111 0.41384,-0.03542 0.5625,-0.09375 0.29732,-0.116655 0.519098,-0.269096 0.71875,-0.46875 L 21.25,38.375 c 0.235871,0.115228 0.468164,0.222668 0.71875,0.3125 l 0,1.65625 c 0,0.277003 0.03719,0.553087 0.15625,0.84375 0.05953,0.145331 0.143339,0.305364 0.3125,0.46875 0.169161,0.163386 0.464028,0.3125 0.78125,0.3125 l 2.1875,0 c 0.317221,0 0.612089,-0.149113 0.78125,-0.3125 0.169161,-0.163387 0.252971,-0.323419 0.3125,-0.46875 0.119057,-0.290663 0.15625,-0.566748 0.15625,-0.84375 l 0,-1.65625 c 0.250586,-0.08983 0.482879,-0.197272 0.71875,-0.3125 l 1.1875,1.1875 c 0.19965,0.199649 0.421432,0.352095 0.71875,0.46875 0.148659,0.05833 0.329672,0.104846 0.5625,0.09375 0.232828,-0.0111 0.535831,-0.09833 0.75,-0.3125 L 32.125,38.28125 c 0.214172,-0.214168 0.301403,-0.517172 0.3125,-0.75 0.0111,-0.232828 -0.03542,-0.41384 -0.09375,-0.5625 C 32.227095,36.67143 32.074654,36.449652 31.875,36.25 L 30.6875,35.0625 C 30.802728,34.82663 30.910168,34.594337 31,34.34375 l 1.65625,0 c 0.277004,0 0.553087,-0.03719 0.84375,-0.15625 0.145332,-0.05953 0.305364,-0.143339 0.46875,-0.3125 0.163386,-0.169161 0.3125,-0.46403 0.3125,-0.78125 l 0,-2.1875 c 0,-0.317219 -0.149114,-0.612088 -0.3125,-0.78125 C 33.805364,29.955838 33.645332,29.872029 33.5,29.8125 33.209336,29.693442 32.933253,29.65625 32.65625,29.65625 l -1.65625,0 C 30.91017,29.405663 30.802728,29.17337 30.6875,28.9375 L 31.875,27.75 c 0.19965,-0.19965 0.352095,-0.421432 0.46875,-0.71875 0.05833,-0.148659 0.104846,-0.329672 0.09375,-0.5625 -0.0111,-0.232828 -0.09833,-0.535831 -0.3125,-0.75 L 30.59375,24.1875 c -0.214167,-0.21417 -0.517171,-0.301403 -0.75,-0.3125 -0.232829,-0.0111 -0.41384,0.03542 -0.5625,0.09375 -0.29732,0.116656 -0.519099,0.269097 -0.71875,0.46875 L 27.375,25.625 c -0.235871,-0.115228 -0.468163,-0.222668 -0.71875,-0.3125 l 0,-1.65625 c 0,-0.277003 -0.03719,-0.553087 -0.15625,-0.84375 -0.05953,-0.145332 -0.143338,-0.305363 -0.3125,-0.46875 -0.169162,-0.163387 -0.46403,-0.3125 -0.78125,-0.3125 l -0.15625,0 5.65625,-6.40625 A 0.96385067,0.96385067 0 0 0 30.1875,14.03125 l -2.21875,0 0,-5.0312502 A 0.96385067,0.96385067 0 0 0 27,8.0312498 l -6,0 a 0.96385067,0.96385067 0 0 0 -0.09375,0 z M 24.3125,30.1875 c 1.002113,0 1.8125,0.810388 1.8125,1.8125 0,1.002112 -0.810387,1.8125 -1.8125,1.8125 C 23.31039,33.8125 22.5,33.002111 22.5,32 c 0,-1.002111 0.81039,-1.8125 1.8125,-1.8125 z" />
<path
style="fill:url(#radialGradient2985);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00178742;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path2317"
d="M 21,8.9999996 21,15 17.8125,15 24,22 30.1875,15 27,15 l 0,-6.0000004 -6,0 z M 23.21875,23 c -0.172892,0 -0.28125,0.294922 -0.28125,0.65625 l 0,2.28125 C 22.24145,26.095996 21.585954,26.379869 21,26.75 l -1.625,-1.625 c -0.255498,-0.255497 -0.533998,-0.372253 -0.65625,-0.25 l -1.53125,1.53125 c -0.122254,0.122254 -0.0055,0.400753 0.25,0.65625 l 1.625,1.625 c -0.37013,0.585953 -0.654003,1.24145 -0.8125,1.9375 l -2.28125,0 c -0.361328,0 -0.65625,0.108357 -0.65625,0.28125 l 0,2.1875 c 0,0.172892 0.294922,0.28125 0.65625,0.28125 l 2.28125,0 c 0.158497,0.69605 0.44237,1.351546 0.8125,1.9375 l -1.625,1.625 c -0.255497,0.255498 -0.372254,0.533997 -0.25,0.65625 l 1.53125,1.53125 c 0.122252,0.122254 0.400752,0.0055 0.65625,-0.25 L 21,37.25 c 0.585954,0.37013 1.24145,0.654002 1.9375,0.8125 l 0,2.28125 C 22.9375,40.705077 23.045858,41 23.21875,41 l 2.1875,0 c 0.172893,0 0.28125,-0.294924 0.28125,-0.65625 l 0,-2.28125 c 0.69605,-0.158498 1.351546,-0.44237 1.9375,-0.8125 l 1.625,1.625 c 0.255498,0.255497 0.533997,0.372254 0.65625,0.25 l 1.53125,-1.53125 c 0.122254,-0.122252 0.0055,-0.400752 -0.25,-0.65625 l -1.625,-1.625 c 0.370129,-0.585954 0.654003,-1.24145 0.8125,-1.9375 l 2.28125,0 c 0.361329,0 0.65625,-0.108358 0.65625,-0.28125 l 0,-2.1875 c 0,-0.172893 -0.294921,-0.28125 -0.65625,-0.28125 l -2.28125,0 c -0.158497,-0.69605 -0.442371,-1.351547 -0.8125,-1.9375 l 1.625,-1.625 c 0.255497,-0.255497 0.372254,-0.533997 0.25,-0.65625 L 29.90625,24.875 C 29.783997,24.752745 29.505498,24.8695 29.25,25.125 l -1.625,1.625 c -0.585954,-0.370131 -1.24145,-0.654004 -1.9375,-0.8125 l 0,-2.28125 C 25.6875,23.294922 25.579143,23 25.40625,23 l -2.1875,0 z m 1.09375,6.21875 c 1.528616,0 2.78125,1.252635 2.78125,2.78125 0,1.528615 -1.252634,2.78125 -2.78125,2.78125 -1.528614,0 -2.78125,-1.252635 -2.78125,-2.78125 0,-1.528615 1.252636,-2.78125 2.78125,-2.78125 z" />
<rect
style="opacity:0.4;fill:none;stroke:url(#linearGradient2982);stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
id="rect6741"
y="6.4999886"
x="5.4999981"
ry="1.365193"
rx="1.365193"
height="37.000011"
width="36.999985" />
<path
style="fill:none;stroke:url(#linearGradient2979);stroke-width:0.99829447;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible"
id="path2777"
d="M 28.926376,15.466668 24,21.177578 18.963089,15.5 21.5,15.5 l 0,-6.0000004 5,0 0,6.0000004 2.426376,-0.03333 z" />
<path
style="fill:none;stroke:url(#linearGradient2975);stroke-width:1;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path4243"
d="m 23.4375,23.46875 c -0.01166,0.05381 -0.03125,0.100205 -0.03125,0.1875 l 0,2.28125 a 0.48185467,0.48185467 0 0 1 -0.375,0.46875 c -0.638467,0.145384 -1.238423,0.407111 -1.78125,0.75 a 0.48185467,0.48185467 0 0 1 -0.59375,-0.0625 l -1.625,-1.625 C 18.9779,25.4154 18.9477,25.40242 18.90625,25.375 l -1.21875,1.21875 c 0.02742,0.04145 0.0404,0.07165 0.09375,0.125 l 1.625,1.625 a 0.48185467,0.48185467 0 0 1 0.0625,0.59375 c -0.342888,0.542826 -0.604615,1.142782 -0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.46875,0.375 l -2.28125,0 c -0.08729,0 -0.133695,0.01959 -0.1875,0.03125 l 0,1.75 c 0.05381,0.01166 0.100205,0.03125 0.1875,0.03125 l 2.28125,0 a 0.48185467,0.48185467 0 0 1 0.46875,0.375 c 0.145385,0.638468 0.407112,1.238423 0.75,1.78125 a 0.48185467,0.48185467 0 0 1 -0.0625,0.59375 l -1.625,1.625 c -0.05335,0.05335 -0.06633,0.08355 -0.09375,0.125 l 1.21875,1.21875 c 0.04145,-0.02742 0.07165,-0.0404 0.125,-0.09375 l 1.625,-1.625 A 0.48185467,0.48185467 0 0 1 21.25,36.84375 c 0.542827,0.342888 1.142781,0.604614 1.78125,0.75 a 0.48185467,0.48185467 0 0 1 0.375,0.46875 l 0,2.28125 c 0,0.08729 0.01959,0.133695 0.03125,0.1875 l 1.75,0 c 0.01166,-0.0538 0.03125,-0.100206 0.03125,-0.1875 l 0,-2.28125 a 0.48185467,0.48185467 0 0 1 0.375,-0.46875 c 0.638469,-0.145386 1.238423,-0.407112 1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 0.59375,0.0625 l 1.625,1.625 c 0.05335,0.05335 0.08355,0.06633 0.125,0.09375 l 1.21875,-1.21875 c -0.02742,-0.04145 -0.0404,-0.07165 -0.09375,-0.125 l -1.625,-1.625 a 0.48185467,0.48185467 0 0 1 -0.0625,-0.59375 c 0.342888,-0.542828 0.604615,-1.142783 0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.46875,-0.375 l 2.28125,0 c 0.08729,0 0.133695,-0.01959 0.1875,-0.03125 l 0,-1.75 c -0.0538,-0.01166 -0.100204,-0.03125 -0.1875,-0.03125 l -2.28125,0 a 0.48185467,0.48185467 0 0 1 -0.46875,-0.375 c -0.145385,-0.638467 -0.407113,-1.238424 -0.75,-1.78125 a 0.48185467,0.48185467 0 0 1 0.0625,-0.59375 l 1.625,-1.625 c 0.05335,-0.05335 0.06633,-0.08355 0.09375,-0.125 L 29.71875,25.375 c -0.04145,0.02742 -0.07165,0.0404 -0.125,0.09375 l -1.625,1.625 a 0.48185467,0.48185467 0 0 1 -0.59375,0.0625 c -0.542827,-0.342889 -1.142783,-0.604616 -1.78125,-0.75 a 0.48185467,0.48185467 0 0 1 -0.375,-0.46875 l 0,-2.28125 c 0,-0.0873 -0.01959,-0.133695 -0.03125,-0.1875 l -1.75,0 z m 0.875,5.28125 c 1.791829,0 3.25,1.458172 3.25,3.25 0,1.791828 -1.458171,3.25 -3.25,3.25 -1.791827,0 -3.25,-1.458172 -3.25,-3.25 0,-1.791828 1.458173,-3.25 3.25,-3.25 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -11,6 +11,7 @@
<file>../icons/CBZ.png</file>
<file>../icons/EPUB.png</file>
<file>../icons/MOBI.png</file>
<file>../icons/KFX.png</file>
</qresource>
<qresource prefix="Status">
<file>../icons/error.png</file>

View File

@@ -22,7 +22,7 @@
<property name="bottomMargin">
<number>5</number>
</property>
<item row="4" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QWidget" name="optionWidget" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
@@ -139,7 +139,43 @@
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="mozJpegBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - JPEG&lt;br/&gt;&lt;/span&gt;Use JPEG files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - force PNG&lt;br/&gt;&lt;/span&gt;Create PNG files instead JPEG&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - mozJpeg&lt;br/&gt;&lt;/span&gt;10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>JPEG/PNG/mozJpeg</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="maximizeStrips">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - 1x4&lt;br/&gt;&lt;/span&gt;Keep format 1x4 panels strips.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - 2x2&lt;br/&gt;&lt;/span&gt;Turn 1x4 strips to 2x2 to maximize screen usage.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>1x4 to 2x2 strips</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="croppingBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Disabled&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Disabled&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Margins&lt;br/&gt;&lt;/span&gt;Margins&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Margins + page numbers&lt;br/&gt;&lt;/span&gt;Margins +page numbers&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Cropping mode</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QCheckBox" name="disableProcessingBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Do not process any image, ignore profil and processing options&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@@ -149,16 +185,6 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="mozJpegBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Off&lt;br/&gt;&lt;/span&gt;Faster&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - On&lt;br/&gt;&lt;/span&gt;10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>use mozJpeg</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -203,6 +229,47 @@
</layout>
</widget>
</item>
<item row="8" column="0" colspan="2">
<widget class="QWidget" name="croppingWidget" native="true">
<property name="visible">
<bool>false</bool>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="croppingPowerLabel">
<property name="text">
<string>Cropping power:</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="croppingPowerSlider">
<property name="maximum">
<number>10</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QWidget" name="buttonWidget" native="true">
<property name="sizePolicy">
@@ -275,9 +342,6 @@
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
</item>
<item row="1" column="3">
@@ -291,9 +355,6 @@
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
</item>
<item row="1" column="2">
@@ -306,7 +367,6 @@
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@@ -429,7 +489,6 @@
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
@@ -538,12 +597,17 @@
<tabstop>borderBox</tabstop>
<tabstop>outputSplit</tabstop>
<tabstop>colorBox</tabstop>
<tabstop>croppingBox</tabstop>
<tabstop>mozJpegBox</tabstop>
<tabstop>maximizeStrips</tabstop>
<tabstop>disableProcessingBox</tabstop>
<tabstop>editorButton</tabstop>
<tabstop>wikiButton</tabstop>
<tabstop>jobList</tabstop>
<tabstop>gammaSlider</tabstop>
<tabstop>widthBox</tabstop>
<tabstop>heightBox</tabstop>
<tabstop>croppingPowerSlider</tabstop>
</tabstops>
<resources>
<include location="KCC.qrc"/>

BIN
icons/KFX.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -18,16 +18,14 @@
# PERFORMANCE OF THIS SOFTWARE.
import os
import re
import sys
from urllib.parse import unquote
from urllib.request import urlopen, urlretrieve, Request
from urllib.request import urlretrieve
from time import sleep
from shutil import move, rmtree
from subprocess import STDOUT, PIPE
# noinspection PyUnresolvedReferences
from PyQt5 import QtGui, QtCore, QtWidgets, QtNetwork
from xml.dom.minidom import parse
from xml.sax.saxutils import escape
from psutil import Popen, Process
from copy import copy
@@ -114,6 +112,12 @@ class Icons:
self.CBZFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/CBZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.EPUBFormat = QtGui.QIcon()
self.EPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.KFXFormat = QtGui.QIcon()
self.KFXFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/KFX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.MOBIEPUBFormat = QtGui.QIcon()
self.MOBIEPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/MOBI.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.EPUB200MBFormat = QtGui.QIcon()
self.EPUB200MBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.info = QtGui.QIcon()
self.info.addPixmap(QtGui.QPixmap(":/Status/icons/info.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -138,28 +142,31 @@ class VersionThread(QtCore.QThread):
self.wait()
def run(self):
try:
XML = parse(urlopen(Request('https://kcc.iosphe.re/Version/',
headers={'User-Agent': 'KindleComicConverter/' + __version__})))
except Exception:
return
latestVersion = XML.childNodes[0].getElementsByTagName('LatestVersion')[0].childNodes[0].toxml()
if ("beta" not in __version__ and StrictVersion(latestVersion) > StrictVersion(__version__)) \
or ("beta" in __version__
and StrictVersion(latestVersion) >= StrictVersion(re.sub(r'-beta.*', '', __version__))):
if sys.platform.startswith('win'):
self.newVersion = latestVersion
self.md5 = XML.childNodes[0].getElementsByTagName('MD5')[0].childNodes[0].toxml()
MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
'See changelog.</a><br/><br/>Installed version: ' + __version__ +
'<br/>Current version: ' + latestVersion +
'<br/><br/>Would you like to start automatic update?', 'question')
self.getNewVersion()
else:
MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
'<b>The new version is available!</b></a> '
'(<a href="https://github.com/ciromattia/kcc/releases/">'
'Changelog</a>)', 'warning', False)
# TODO adapt with github releases
pass
# try:
# XML = parse(urlopen(Request('https://kcc.iosphe.re/Version/',
# headers={'User-Agent': 'KindleComicConverter/' + __version__})))
# except Exception:
# return
# latestVersion = XML.childNodes[0].getElementsByTagName('LatestVersion')[0].childNodes[0].toxml()
# if ("beta" not in __version__ and StrictVersion(latestVersion) > StrictVersion(__version__)) \
# or ("beta" in __version__
# and StrictVersion(latestVersion) >= StrictVersion(re.sub(r'-beta.*', '', __version__))):
# if sys.platform.startswith('win'):
# self.newVersion = latestVersion
# self.md5 = XML.childNodes[0].getElementsByTagName('MD5')[0].childNodes[0].toxml()
# MW.showDialog.emit('<b>New version released!</b> <a href="https://github.com/ciromattia/kcc/releases/">'
# 'See changelog.</a><br/><br/>Installed version: ' + __version__ +
# '<br/>Current version: ' + latestVersion +
# '<br/><br/>Would you like to start automatic update?', 'question')
# self.getNewVersion()
# else:
# MW.addMessage.emit('<a href="https://kcc.iosphe.re/">'
# '<b>The new version is available!</b></a> '
# '(<a href="https://github.com/ciromattia/kcc/releases/">'
# 'Changelog</a>)', 'warning', False)
def setAnswer(self, dialoganswer):
self.answer = dialoganswer
@@ -272,6 +279,9 @@ class WorkerThread(QtCore.QThread):
options.upscale = True
if GUI.gammaBox.isChecked() and float(GUI.gammaValue) > 0.09:
options.gamma = float(GUI.gammaValue)
options.cropping = GUI.croppingBox.checkState()
if GUI.croppingBox.checkState() >= 1:
options.croppingp = float(GUI.croppingPowerValue)
if GUI.borderBox.checkState() == 1:
options.white_borders = True
elif GUI.borderBox.checkState() == 2:
@@ -280,9 +290,13 @@ class WorkerThread(QtCore.QThread):
options.batchsplit = 2
if GUI.colorBox.isChecked():
options.forcecolor = True
if GUI.maximizeStrips.isChecked():
options.maximizestrips = True
if GUI.disableProcessingBox.isChecked():
options.noprocessing = True
if GUI.mozJpegBox.isChecked():
if GUI.mozJpegBox.checkState() == 1:
options.forcepng = True
elif GUI.mozJpegBox.checkState() == 2:
options.mozjpeg = True
if GUI.currentMode > 2:
options.customwidth = str(GUI.widthBox.value())
@@ -309,8 +323,7 @@ class WorkerThread(QtCore.QThread):
jobargv = list(argv)
jobargv.append(job)
try:
comic2ebook.options = copy(options)
comic2ebook.checkOptions()
comic2ebook.options = comic2ebook.checkOptions(copy(options))
outputPath = comic2ebook.makeBook(job, self)
MW.hideProgressBar.emit()
except UserWarning as warn:
@@ -355,7 +368,7 @@ class WorkerThread(QtCore.QThread):
MW.addMessage.emit('Creating CBZ files... <b>Done!</b>', 'info', True)
else:
MW.addMessage.emit('Creating EPUB files... <b>Done!</b>', 'info', True)
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3':
if str(GUI.formatBox.currentText()) == 'MOBI/AZW3' or str(GUI.formatBox.currentText()) == 'MOBI+EPUB':
MW.progressBarTick.emit('Creating MOBI files')
MW.progressBarTick.emit(str(len(outputPath) * 2 + 1))
MW.progressBarTick.emit('tick')
@@ -600,6 +613,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if self.currentMode != 3:
self.modeChange(1)
def togglecroppingBox(self, value):
if value:
GUI.croppingWidget.setVisible(True)
else:
GUI.croppingWidget.setVisible(False)
self.changeCroppingPower(100) # 1.0
def togglewebtoonBox(self, value):
if value:
GUI.qualityBox.setEnabled(False)
@@ -640,6 +660,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.gammaSlider.setValue(valueRaw)
self.gammaValue = value
def changeCroppingPower(self, value):
valueRaw = int(5 * round(float(value) / 5))
value = '%.2f' % (float(valueRaw) / 100)
GUI.croppingPowerLabel.setText('Cropping Power: ' + str(value))
GUI.croppingPowerSlider.setValue(valueRaw)
self.croppingPowerValue = value
def changeDevice(self):
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
if profile['ForceExpert']:
@@ -785,6 +812,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'rotateBox': GUI.rotateBox.checkState(),
'qualityBox': GUI.qualityBox.checkState(),
'gammaBox': GUI.gammaBox.checkState(),
'croppingBox': GUI.croppingBox.checkState(),
'croppingPowerSlider': float(self.croppingPowerValue) * 100,
'upscaleBox': GUI.upscaleBox.checkState(),
'borderBox': GUI.borderBox.checkState(),
'webtoonBox': GUI.webtoonBox.checkState(),
@@ -794,6 +823,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'mozJpegBox': GUI.mozJpegBox.checkState(),
'widthBox': GUI.widthBox.value(),
'heightBox': GUI.heightBox.value(),
'maximizeStrips': GUI.maximizeStrips.checkState(),
'gammaSlider': float(self.gammaValue) * 100})
self.settings.sync()
self.tray.hide()
@@ -886,7 +916,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
self.startNumber = self.settings.value('startNumber', 0, type=int)
self.windowSize = self.settings.value('windowSize', '0x0', type=str)
self.options = self.settings.value('options', {'gammaSlider': 0})
self.options = self.settings.value('options', {'gammaSlider': 0, 'croppingBox': 2, 'croppingPowerSlider': 100})
self.worker = WorkerThread()
self.versionCheck = VersionThread()
self.progress = ProgressThread()
@@ -895,6 +925,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.needClean = True
self.kindleGen = False
self.gammaValue = 1.0
self.croppingPowerValue = 1.0
self.currentMode = 1
self.targetDirectory = ''
self.sentry = Client(release=__version__)
@@ -925,8 +956,14 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'DefaultUpscale': True, 'Label': 'KV'},
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KV'},
"Kindle Scribe": {
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KS',
},
"Kindle 11": {
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
},
"Kindle PW 5": {
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KPW5',
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KPW5',
},
"Kindle PW 3/4": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': True, 'Label': 'KV'},
@@ -951,13 +988,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoAO'},
"Kobo Clara HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoC'},
'DefaultUpscale': True, 'Label': 'KoC'},
"Kobo Libra H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoL'},
'DefaultUpscale': True, 'Label': 'KoL'},
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
'DefaultUpscale': True, 'Label': 'KoF'},
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1,
'DefaultUpscale': False, 'Label': 'OTHER'},
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K1'},
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
@@ -966,34 +1001,53 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'DefaultUpscale': False, 'Label': 'K34'},
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
'DefaultUpscale': False, 'Label': 'K34'},
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
'Label': 'KoN'},
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
'Label': 'KoC'},
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
'Label': 'KoL'},
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
'Label': 'KoS'},
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
'Label': 'KoE'},
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False,
'Label': 'OTHER'},
}
profilesGUI = [
"Kindle Oasis 2/3",
"Kindle Oasis",
"Kindle Voyage",
"Kindle PW 5",
"Kindle PW 3/4",
"Kindle PW 1/2",
"Kindle",
"Kindle 11",
"Kindle Scribe",
"Separator",
"Kobo Forma",
"Kobo Libra H2O",
"Kobo Clara HD",
"Kobo Aura ONE",
"Kobo Aura H2O",
"Kobo Aura HD",
"Kobo Aura",
"Kobo Clara 2E",
"Kobo Sage",
"Kobo Libra 2",
"Kobo Elipsa",
"Kobo Nia",
"Separator",
"Other",
"Separator",
"Kindle Oasis",
"Kindle Touch",
"Kindle Keyboard",
"Kindle DX/DXG",
"Kindle PW 3/4",
"Kindle PW 1/2",
"Kindle Voyage",
"Kindle 2",
"Kindle 1",
"Kindle",
"Separator",
"Kobo Aura",
"Kobo Aura ONE",
"Kobo Aura H2O",
"Kobo Aura HD",
"Kobo Clara HD",
"Kobo Forma",
"Kobo Glo HD",
"Kobo Glo",
"Kobo Libra H2O",
"Kobo Mini/Touch",
]
@@ -1030,6 +1084,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.convertButton.clicked.connect(self.convertStart)
GUI.gammaSlider.valueChanged.connect(self.changeGamma)
GUI.gammaBox.stateChanged.connect(self.togglegammaBox)
GUI.croppingBox.stateChanged.connect(self.togglecroppingBox)
GUI.croppingPowerSlider.valueChanged.connect(self.changeCroppingPower)
GUI.webtoonBox.stateChanged.connect(self.togglewebtoonBox)
GUI.qualityBox.stateChanged.connect(self.togglequalityBox)
GUI.deviceBox.activated.connect(self.changeDevice)
@@ -1057,8 +1113,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.deviceBox.addItem(self.icons.deviceKobo, profile)
else:
GUI.deviceBox.addItem(self.icons.deviceKindle, profile)
for f in ['MOBI/AZW3', 'EPUB', 'CBZ']:
GUI.formatBox.addItem(eval('self.icons.' + f.replace('/AZW3', '') + 'Format'), f)
for f in ['MOBI/AZW3', 'EPUB', 'CBZ', 'KFX', 'MOBI+EPUB', 'EPUB-200MB']:
format_prefix = f.replace('/AZW3', '').replace('+', '').replace('-', '')
GUI.formatBox.addItem(eval('self.icons.' + format_prefix + 'Format'), f)
if self.lastDevice > GUI.deviceBox.count():
self.lastDevice = 0
if profilesGUI[self.lastDevice] == "Separator":
@@ -1078,6 +1135,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if GUI.gammaSlider.isEnabled():
GUI.gammaSlider.setValue(int(self.options[option]))
self.changeGamma(int(self.options[option]))
elif str(option) == "croppingPowerSlider":
if GUI.croppingPowerSlider.isEnabled():
GUI.croppingPowerSlider.setValue(int(self.options[option]))
self.changeCroppingPower(int(self.options[option]))
else:
try:
if eval('GUI.' + str(option)).isEnabled():

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'gui/KCC.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -59,13 +59,21 @@ class Ui_mainWindow(object):
self.qualityBox.setTristate(True)
self.qualityBox.setObjectName("qualityBox")
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
self.mozJpegBox = QtWidgets.QCheckBox(self.optionWidget)
self.mozJpegBox.setTristate(True)
self.mozJpegBox.setObjectName("mozJpegBox")
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 0, 1, 1)
self.maximizeStrips = QtWidgets.QCheckBox(self.optionWidget)
self.maximizeStrips.setObjectName("maximizeStrips")
self.gridLayout_2.addWidget(self.maximizeStrips, 3, 1, 1, 1)
self.croppingBox = QtWidgets.QCheckBox(self.optionWidget)
self.croppingBox.setTristate(True)
self.croppingBox.setObjectName("croppingBox")
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
self.disableProcessingBox = QtWidgets.QCheckBox(self.optionWidget)
self.disableProcessingBox.setObjectName("disableProcessingBox")
self.gridLayout_2.addWidget(self.disableProcessingBox, 3, 2, 1, 1)
self.mozJpegBox = QtWidgets.QCheckBox(self.optionWidget)
self.mozJpegBox.setObjectName("mozJpegBox")
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 1, 1, 1)
self.gridLayout.addWidget(self.optionWidget, 4, 0, 1, 2)
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
self.gammaWidget.setVisible(False)
self.gammaWidget.setObjectName("gammaWidget")
@@ -82,6 +90,22 @@ class Ui_mainWindow(object):
self.gammaSlider.setObjectName("gammaSlider")
self.horizontalLayout_2.addWidget(self.gammaSlider)
self.gridLayout.addWidget(self.gammaWidget, 6, 0, 1, 2)
self.croppingWidget = QtWidgets.QWidget(self.centralWidget)
self.croppingWidget.setVisible(False)
self.croppingWidget.setObjectName("croppingWidget")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.croppingWidget)
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.croppingPowerLabel = QtWidgets.QLabel(self.croppingWidget)
self.croppingPowerLabel.setObjectName("croppingPowerLabel")
self.horizontalLayout_3.addWidget(self.croppingPowerLabel)
self.croppingPowerSlider = QtWidgets.QSlider(self.croppingWidget)
self.croppingPowerSlider.setMaximum(200)
self.croppingPowerSlider.setSingleStep(1)
self.croppingPowerSlider.setOrientation(QtCore.Qt.Horizontal)
self.croppingPowerSlider.setObjectName("croppingPowerSlider")
self.horizontalLayout_3.addWidget(self.croppingPowerSlider)
self.gridLayout.addWidget(self.croppingWidget, 8, 0, 1, 2)
self.buttonWidget = QtWidgets.QWidget(self.centralWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
@@ -108,19 +132,16 @@ class Ui_mainWindow(object):
self.gridLayout_4.addWidget(self.fileButton, 0, 3, 1, 1)
self.deviceBox = QtWidgets.QComboBox(self.buttonWidget)
self.deviceBox.setMinimumSize(QtCore.QSize(0, 28))
self.deviceBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
self.deviceBox.setObjectName("deviceBox")
self.gridLayout_4.addWidget(self.deviceBox, 1, 0, 1, 1)
self.formatBox = QtWidgets.QComboBox(self.buttonWidget)
self.formatBox.setMinimumSize(QtCore.QSize(0, 28))
self.formatBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
self.formatBox.setObjectName("formatBox")
self.gridLayout_4.addWidget(self.formatBox, 1, 3, 1, 1)
self.convertButton = QtWidgets.QPushButton(self.buttonWidget)
self.convertButton.setMinimumSize(QtCore.QSize(0, 30))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.convertButton.setFont(font)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -172,7 +193,6 @@ class Ui_mainWindow(object):
self.progressBar.setMinimumSize(QtCore.QSize(0, 30))
font = QtGui.QFont()
font.setBold(True)
font.setWeight(75)
self.progressBar.setFont(font)
self.progressBar.setVisible(False)
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
@@ -231,12 +251,17 @@ class Ui_mainWindow(object):
mainWindow.setTabOrder(self.gammaBox, self.borderBox)
mainWindow.setTabOrder(self.borderBox, self.outputSplit)
mainWindow.setTabOrder(self.outputSplit, self.colorBox)
mainWindow.setTabOrder(self.colorBox, self.editorButton)
mainWindow.setTabOrder(self.colorBox, self.croppingBox)
mainWindow.setTabOrder(self.croppingBox, self.mozJpegBox)
mainWindow.setTabOrder(self.mozJpegBox, self.maximizeStrips)
mainWindow.setTabOrder(self.maximizeStrips, self.disableProcessingBox)
mainWindow.setTabOrder(self.disableProcessingBox, self.editorButton)
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
mainWindow.setTabOrder(self.wikiButton, self.jobList)
mainWindow.setTabOrder(self.jobList, self.gammaSlider)
mainWindow.setTabOrder(self.gammaSlider, self.widthBox)
mainWindow.setTabOrder(self.widthBox, self.heightBox)
mainWindow.setTabOrder(self.heightBox, self.croppingPowerSlider)
def retranslateUi(self, mainWindow):
_translate = QtCore.QCoreApplication.translate
@@ -259,11 +284,16 @@ class Ui_mainWindow(object):
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>"))
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2/HQ"))
self.mozJpegBox.setToolTip(_translate("mainWindow", "<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>"))
self.mozJpegBox.setText(_translate("mainWindow", "JPEG/PNG/mozJpeg"))
self.maximizeStrips.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html>"))
self.maximizeStrips.setText(_translate("mainWindow", "1x4 to 2x2 strips"))
self.croppingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>"))
self.croppingBox.setText(_translate("mainWindow", "Cropping mode"))
self.disableProcessingBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Do not process any image, ignore profil and processing options</p></body></html>"))
self.disableProcessingBox.setText(_translate("mainWindow", "Disable processing"))
self.mozJpegBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Off<br/></span>Faster</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - On<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>"))
self.mozJpegBox.setText(_translate("mainWindow", "use mozJpeg"))
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
self.croppingPowerLabel.setText(_translate("mainWindow", "Cropping power:"))
self.directoryButton.setToolTip(_translate("mainWindow", "<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>"))
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
self.fileButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))

View File

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

View File

@@ -68,7 +68,7 @@ def main(argv=None):
for source in sources:
source = source.rstrip('\\').rstrip('/')
options = copy(optionstemplate)
checkOptions()
options = checkOptions(options)
if len(sources) > 1:
print('Working on ' + source + '...')
makeBook(source)
@@ -789,7 +789,9 @@ def splitProcess(path, mode):
output = []
currentSize = 0
currentTarget = path
if options.webtoon:
if options.targetsize:
targetSize = options.targetsize * 1048576
elif options.webtoon:
targetSize = 104857600
else:
targetSize = 419430400
@@ -909,8 +911,9 @@ def makeParser():
otherOptions = OptionGroup(psr, "OTHER")
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, KoMT, KoG,"
" KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoC, KoL, KoF) [Default=KV]")
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
" [Default=KV]")
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
help="Manga style (right-to-left reading and splitting)")
mainOptions.add_option("-q", "--hq", action="store_true", dest="hq", default=False,
@@ -919,13 +922,17 @@ def makeParser():
help="Display two not four panels in Panel View mode")
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
help="Webtoon processing mode"),
mainOptions.add_option("--targetsize", type="int", dest="targetsize", default=None,
help="the maximal size of output file in MB."
" [Default=100MB for webtoon and 400MB for others]")
outputOptions.add_option("-o", "--output", action="store", dest="output", default=None,
help="Output generated file to specified directory or file")
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
help="Comic title [Default=filename or directory name]")
outputOptions.add_option("-f", "--format", action="store", dest="format", default="Auto",
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX) [Default=Auto]")
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
"[Default=Auto]")
outputOptions.add_option("-b", "--batchsplit", type="int", dest="batchsplit", default="0",
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
"2: Consider every subdirectory as separate volume [Default=0]")
@@ -954,7 +961,8 @@ def makeParser():
help="Create PNG files instead JPEG")
processingOptions.add_option("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
help="Create JPEG files using mozJpeg")
processingOptions.add_option("--maximizestrips", action="store_true", dest="maximizestrips", default=False,
help="Turn 1x4 strips to 2x2 strips")
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
help="Replace screen width provided by device profile")
customProfileOptions.add_option("--customheight", type="int", dest="customheight", default=0,
@@ -971,20 +979,29 @@ def makeParser():
return psr
def checkOptions():
global options
def checkOptions(options):
options.panelview = True
options.iskindle = False
options.bordersColor = None
options.keep_epub = False
if options.format == 'EPUB-200MB':
options.targetsize = 200
options.format = 'EPUB'
if options.batchsplit != 2:
options.batchsplit = 1
if options.format == 'MOBI+EPUB':
options.keep_epub = True
options.format = 'MOBI'
options.kfx = False
if options.format == 'Auto':
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO']:
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
options.format = 'MOBI'
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO']:
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO',
'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
options.format = 'EPUB'
elif options.profile in ['KDX']:
options.format = 'CBZ'
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO']:
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
options.iskindle = True
if options.white_borders:
options.bordersColor = 'white'
@@ -1031,6 +1048,7 @@ def checkOptions():
image.ProfileData.Profiles["Custom"] = newProfile
options.profile = "Custom"
options.profileData = image.ProfileData.Profiles[options.profile]
return options
def checkTools(source):
@@ -1165,7 +1183,8 @@ def makeBook(source, qtgui=None):
def makeMOBIFix(item, uuid):
os.remove(item)
if not options.keep_epub:
os.remove(item)
mobiPath = item.replace('.epub', '.mobi')
move(mobiPath, mobiPath + '_toclean')
try:

View File

@@ -78,6 +78,7 @@ class ProfileData:
Profiles = {
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
'K578': ("Kindle", (600, 800), Palette16, 1.8),
@@ -86,6 +87,7 @@ class ProfileData:
'KV': ("Kindle Paperwhite 3/4/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.8),
'KO': ("Kindle Oasis 2/3", (1264, 1680), Palette16, 1.8),
'KS': ("Kindle Scribe", (1860, 2480), Palette16, 1.8),
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
@@ -93,9 +95,12 @@ class ProfileData:
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
'KoC': ("Kobo Clara HD", (1072, 1448), Palette16, 1.8),
'KoL': ("Kobo Libra H2O", (1264, 1680), Palette16, 1.8),
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
'OTHER': ("Other", (0, 0), Palette16, 1.8),
}
@@ -111,6 +116,9 @@ class ComicPageParser:
self.color = self.colorCheck()
self.fill = self.fillCheck()
self.splitCheck()
# backwards compatibility for Pillow >9.1.0
if not hasattr(Image, 'Resampling'):
Image.Resampling = Image
def getImageHistogram(self, image):
histogram = image.histogram()
@@ -124,9 +132,22 @@ class ComicPageParser:
def splitCheck(self):
width, height = self.image.size
dstwidth, dstheight = self.size
if (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
if self.opt.maximizestrips:
leftbox = (0, 0, int(width / 2), height)
rightbox = (int(width / 2), 0, width, height)
if self.opt.righttoleft:
pageone = self.image.crop(rightbox)
pagetwo = self.image.crop(leftbox)
else:
pageone = self.image.crop(leftbox)
pagetwo = self.image.crop(rightbox)
new_image = Image.new("RGB", (int(width / 2), int(height*2)))
new_image.paste(pageone, (0, 0))
new_image.paste(pagetwo, (0, height))
self.payload.append(['N', self.source, new_image, self.color, self.fill])
elif (width > height) != (dstwidth > dstheight) and width <= dstheight and height <= dstwidth \
and not self.opt.webtoon and self.opt.splitter == 1:
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True), self.color, self.fill])
self.payload.append(['R', self.source, self.image.rotate(90, Image.Resampling.BICUBIC, True), self.color, self.fill])
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
if self.opt.splitter != 1:
if width > height:
@@ -144,7 +165,7 @@ class ComicPageParser:
self.payload.append(['S1', self.source, pageone, self.color, self.fill])
self.payload.append(['S2', self.source, pagetwo, self.color, self.fill])
if self.opt.splitter > 0:
self.payload.append(['R', self.source, self.image.rotate(90, Image.BICUBIC, True),
self.payload.append(['R', self.source, self.image.rotate(90, Image.Resampling.BICUBIC, True),
self.color, self.fill])
else:
self.payload.append(['N', self.source, self.image, self.color, self.fill])
@@ -230,6 +251,9 @@ class ComicPage:
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-B'
elif 'S2' in mode:
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC-C'
# backwards compatibility for Pillow >9.1.0
if not hasattr(Image, 'Resampling'):
Image.Resampling = Image
def saveToDir(self):
try:
@@ -267,7 +291,7 @@ class ComicPage:
if gamma == 1.0:
self.image = ImageOps.autocontrast(self.image)
else:
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: 255 * (a / 255.) ** gamma))
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: int(255 * (a / 255.) ** gamma)))
def quantizeImage(self):
colors = len(self.palette) // 3
@@ -282,10 +306,11 @@ class ComicPage:
def resizeImage(self):
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
method = Image.BICUBIC
method = Image.Resampling.BICUBIC
else:
method = Image.LANCZOS
if self.opt.stretch or (self.opt.kfx and ('-KCC-B' in self.targetPath or '-KCC-C' in self.targetPath)):
method = Image.Resampling.LANCZOS
if self.opt.stretch:
# if self.opt.stretch or (self.opt.kfx and ('-KCC-B' in self.targetPath or '-KCC-C' in self.targetPath)):
self.image = self.image.resize(self.size, method)
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
if self.opt.format == 'CBZ' or self.opt.kfx:
@@ -293,7 +318,7 @@ class ComicPage:
borderh = int((self.size[1] - self.image.size[1]) / 2)
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
self.image = ImageOps.fit(self.image, self.size, method=Image.Resampling.BICUBIC, centering=(0.5, 0.5))
else:
if self.opt.format == 'CBZ' or self.opt.kfx:
ratioDev = float(self.size[0]) / float(self.size[1])
@@ -309,7 +334,7 @@ class ComicPage:
wsize = int((float(self.image.size[0]) * float(hpercent)))
self.image = self.image.resize((wsize, self.size[1]), method)
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
self.image.thumbnail(self.size, Image.LANCZOS)
self.image.thumbnail(self.size, Image.Resampling.LANCZOS)
def getBoundingBox(self, tmptmg):
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
@@ -357,13 +382,16 @@ class Cover:
self.tomeid = tomeid
self.image = Image.open(source)
self.process()
# backwards compatibility for Pillow >9.1.0
if not hasattr(Image, 'Resampling'):
Image.Resampling = Image
def process(self):
self.image = self.image.convert('RGB')
self.image = ImageOps.autocontrast(self.image)
if not self.options.forcecolor:
self.image = self.image.convert('L')
self.image.thumbnail(self.options.profileData[1], Image.LANCZOS)
self.image.thumbnail(self.options.profileData[1], Image.Resampling.LANCZOS)
self.save()
def save(self):
@@ -373,7 +401,7 @@ class Cover:
raise RuntimeError('Failed to save cover.')
def saveToKindle(self, kindle, asin):
self.image = self.image.resize((300, 470), Image.ANTIALIAS)
self.image = self.image.resize((300, 470), Image.Resampling.LANCZOS)
try:
self.image.save(os.path.join(kindle.path.split('documents')[0], 'system', 'thumbnails',
'thumbnail_' + asin + '_EBOK_portrait.jpg'), 'JPEG', optimize=1, quality=85)

View File

@@ -117,7 +117,10 @@ def dependencyCheck(level):
except ImportError:
missing.append('psutil 5.0.0+')
try:
from types import ModuleType
from slugify import __version__ as slugifyVersion
if isinstance(slugifyVersion, ModuleType):
slugifyVersion = slugifyVersion.__version__
if StrictVersion('1.2.1') > StrictVersion(slugifyVersion):
missing.append('python-slugify 1.2.1+')
except ImportError:

View File

@@ -1,7 +1,7 @@
PyQt5>=5.6.0
Pillow>=5.2.0
psutil>=5.0.0
python-slugify>=1.2.1,<3.0.0
python-slugify>=1.2.1,<8.0.0
raven>=6.0.0
# PyQt5-tools
mozjpeg-lossless-optimization

17
setup.py Executable file → Normal file
View File

@@ -17,6 +17,8 @@ import setuptools
import distutils.cmd
from kindlecomicconverter import __version__
OSX_INFO_PLIST = "other/osx/Info.plist"
NAME = 'KindleComicConverter'
MAIN = 'kcc.py'
VERSION = __version__
@@ -37,6 +39,13 @@ class BuildBinaryCommand(distutils.cmd.Command):
def run(self):
VERSION = __version__
if sys.platform == 'darwin':
with open(OSX_INFO_PLIST, 'r') as file:
filedata = file.read()
filedata = filedata.replace('5.5.2', VERSION)
with open(OSX_INFO_PLIST, 'w') as file:
file.write(filedata)
os.system('pyinstaller -y -F -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
os.makedirs('dist/Kindle Comic Converter.app/Contents/Resources/Codecs')
shutil.copy('other/osx/7z', 'dist/Kindle Comic Converter.app/Contents/Resources')
@@ -49,7 +58,11 @@ class BuildBinaryCommand(distutils.cmd.Command):
os.system('appdmg kcc.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
exit(0)
elif sys.platform == 'win32':
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC -w --noupx kcc.py')
os.system('pyinstaller -y -F -i icons\\comic2ebook.ico -n KCC_' + VERSION + ' -w --noupx kcc.py')
exit(0)
elif sys.platform == 'linux':
os.system(
'pyinstaller --hidden-import=queue -y -F -i icons/comic2ebook.ico -n kcc_linux_' + VERSION + ' kcc.py')
exit(0)
else:
exit(0)
@@ -81,7 +94,7 @@ setuptools.setup(
'PyQt5>=5.6.0',
'Pillow>=5.2.0',
'psutil>=5.0.0',
'python-slugify>=1.2.1,<3.0.0',
'python-slugify>=1.2.1,<8.0.0',
'raven>=6.0.0',
],
classifiers=[],