Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JPEG-XL/ .jxl for conversion #788

Open
ProhorDas-0 opened this issue Dec 25, 2024 · 3 comments
Open

Add JPEG-XL/ .jxl for conversion #788

ProhorDas-0 opened this issue Dec 25, 2024 · 3 comments

Comments

@ProhorDas-0
Copy link

Describe the bug
Some jxl cbz files are failed to convert.

@ProhorDas-0
Copy link
Author

import os
import subprocess
import shutil
from pathlib import Path

# Define extensions and paths
COMIC_EXTENSIONS = ('.cbz', '.cbr', '.cb7')
SEVEN_ZIP_PATH = "C:/Program Files/7-Zip/7z.exe"
DJXL_PATH = "C:/jxl/djxl.exe"  # Update this path to your djxl executable


def extract_comic_files(directory):
    """
    Extracts comic files in the specified directory using 7zip.
    """
    comic_files = [file for file in Path(
        directory).iterdir() if file.suffix.lower() in COMIC_EXTENSIONS]
    if not comic_files:
        print("No comic files found in the directory.")
        return []

    extracted_folders = []
    for comic_file in comic_files:
        extract_to = comic_file.with_name(
            comic_file.stem + "-extracted")  # Extracted folder name
        # Keep track of the original name
        extracted_folders.append((extract_to, comic_file.name))
        print(f"Extracting '{comic_file}' to '{extract_to}'...")

        if not extract_to.exists():
            extract_to.mkdir(parents=True, exist_ok=True)

        try:
            # Call 7zip to extract the file
            subprocess.run([SEVEN_ZIP_PATH, "x", str(
                comic_file), f"-o{extract_to}"], check=True)
            print(f"Extraction complete for: {comic_file}")
            # Delete the original .cbz file
            comic_file.unlink()
        except subprocess.CalledProcessError as e:
            print(f"Error extracting '{comic_file}': {e}")

    print("Extraction process completed.")
    return extracted_folders


def convert_jxl_to_jpg(directory):
    """
    Converts .jxl images to .jpg using djxl and replaces them in the directory.
    """
    jpg_files = []
    for root, _, files in os.walk(directory):
        for file in files:
            if file.lower().endswith('.jxl'):
                jxl_path = Path(root) / file
                jpg_path = jxl_path.with_suffix('.jpg')

                try:
                    print(f"Converting '{jxl_path}' to '{jpg_path}'...")
                    # Use djxl to convert .jxl to .jpg
                    subprocess.run([DJXL_PATH, str(jxl_path),
                                   str(jpg_path)], check=True)

                    # Verify the .jpg file is created
                    if jpg_path.exists():
                        jpg_files.append(jpg_path)
                        # Remove the original .jxl file
                        jxl_path.unlink()
                        print(f"Converted and replaced '{
                              jxl_path}' with '{jpg_path}'.")
                except subprocess.CalledProcessError as e:
                    print(f"Error converting '{jxl_path}': {e}")
    return jpg_files


def compress_to_cbz(folder, output_cbz, original_name):
    """
    Compresses the folder into a .zip file and renames it to .cbz.
    """
    zip_path = folder.with_name(folder.stem + '.zip')
    print(f"Compressing '{folder}' into '{zip_path}'...")

    shutil.make_archive(str(zip_path.with_suffix('')), 'zip', folder)
    zip_path.rename(output_cbz)
    print(f"Compressed to '{output_cbz}'.")

    # Rename to original name
    final_cbz_path = folder.with_name(original_name.replace("-extracted", ""))
    output_cbz.rename(final_cbz_path)
    print(f"Renamed to original name '{final_cbz_path}'")


def clean_up(folder):
    """
    Deletes the specified folder.
    """
    print(f"Deleting folder: {folder}...")
    shutil.rmtree(folder, ignore_errors=True)
    print(f"Deleted: {folder}")


working_directory = os.getcwd()
print(f"Working directory: {working_directory}")

# Step 1: Extract comic files
extracted_folders = extract_comic_files(working_directory)

# Step 2: Process each extracted folder
for folder, original_name in extracted_folders:
    print(f"Processing folder: {folder}")

    # Convert .jxl to .jpg
    jpg_files = convert_jxl_to_jpg(folder)

    # Verify .jpg files
    if jpg_files:
        print(f"Converted {len(jpg_files)} .jxl files to .jpg.")
    else:
        print("No .jxl files were converted to .jpg.")

    # Compress folder back to .cbz
    cbz_output = folder.with_name(folder.stem.replace(
        "-extracted", "")).with_suffix('.cbz')
    compress_to_cbz(folder, cbz_output, original_name)

    # Clean up the extracted folder
    clean_up(folder)

print("Processing complete for all files.")

This code might help.
djxl obtained from "https://github.com/libjxl/libjxl"

@axu2
Copy link
Collaborator

axu2 commented Dec 25, 2024

Searching for "webp" in the hard coded list of allowed extensions might help.

Pillow doesn't support yet

@ProhorDas-0
Copy link
Author

Yep, Instead of Searching for "webp", this chunk of code actually converts using libjxl and bundles them with jpg ones. Then it can be converted using kcc. Yes, there might be support for jpeg xl later in pillow library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants