diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..91357cb
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,75 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Solution Structure
+
+Three projects in `ComicCompress.sln`, all targeting .NET 8.0:
+
+- **ComicCompress** (this directory) — Console application entry point. `Program.cs` handles CLI parsing via `McMaster.Extensions.CommandLineUtils` and orchestrates processing.
+- **iMGcompress-core** (`../iMGcompress-core`) — Class library containing all compression logic. Both the CLI and GUI depend on this.
+- **iMGcompress** (`../iMGcompress`) — Windows Forms GUI (`net8.0-windows`) wrapping the core library.
+
+## Build & Run
+
+```powershell
+# Development build
+dotnet build
+
+# Run CLI (from project root)
+dotnet run -- --help
+dotnet run -- -i -o -q 75 -p
+
+# Publish self-contained Windows executable
+dotnet publish -r win-x64 -c Release
+```
+
+`launchSettings.json` defines named profiles (e.g. `PROD`, `DEV_HOME`, `Compress Image to webp`) for common invocations.
+
+## CLI Flags
+
+| Flag | Description |
+|------|-------------|
+| `-i` | Input file or folder (required) |
+| `-o` | Output base path (default: `converted_comics`) |
+| `-r` | Recurse into subfolders |
+| `-s` | Skip if output already exists |
+| `-q` | WebP quality 0–100 (default: 75) |
+| `-p` | Parallel processing (all CPUs) |
+| `-c` | Parallel with N CPUs |
+| `-d` | PDF-only mode |
+| `-j` | Image-only mode |
+| `-n` | Zebra PRN mode (generates PNG + WebP Base64 URI) |
+| `-a` | Copy unprocessed files to output |
+
+## Architecture
+
+**Data flow:** Input (`.cbr`/`.cbz` archives or loose images) → extract → convert each image to WebP → repack as `.cbz`.
+
+### Core library (`iMGcompress-core`)
+
+- **`Compressor.cs`** — Central engine. Reads RAR/ZIP archives via `SharpCompress`, converts images to WebP via `Imazen.WebP`, and writes output `.cbz`. Handles solid and non-solid archives separately. The first image in an archive (cover) is preserved without conversion.
+- **`FileProcessor.cs`** — Orchestrates parallel or sequential processing over a file list. Inner class `ProcessorFlags` carries all options. Writes the final compression report.
+- **`FileParser.cs`** — Recursively enumerates input files.
+- **`ImageExtractor.cs`** — Implements `IRenderListener` (iText) to extract images from PDF pages and produce a `.cbz`.
+- **`PixelMap.cs`** — Parses Portable Bitmap formats (PBM/PGM/PPM, variants P1–P6) into `System.Drawing.Bitmap` before WebP encoding.
+- **`Logger.cs`** — Thread-safe colored console/file logger. `LogLevel`: Error, Warning, Info, Verbose.
+- **`file_stat.cs`** — Simple DTO tracking per-file uncompressed/compressed sizes for statistics.
+
+### Console app (`ComicCompress`)
+
+`Program.cs` parses flags, builds a `ProcessorFlags`, calls `FileParser` to enumerate targets, then hands off to `FileProcessor`. Video (MP4→WebM) conversion uses `Xabe.FFmpeg`. Zebra PRN rendering uses `BinaryKits.Zpl.Viewer`.
+
+## Key Dependencies
+
+| Package | Purpose |
+|---------|---------|
+| `SharpCompress` | Read/write RAR and ZIP archives |
+| `Imazen.WebP` + `libwebp.dll` | WebP encoding (requires `libwebp.dll` in output dir) |
+| `Magick.NET-Q8-x64` | Advanced image format support (TIFF, etc.) |
+| `iTextSharp` / `itext` | PDF parsing |
+| `Xabe.FFmpeg` | Video conversion |
+| `BinaryKits.Zpl.Viewer` | Zebra PRN label rendering |
+| `McMaster.Extensions.CommandLineUtils` | CLI argument parsing |
+
+**`libwebp.dll` must be present** alongside the executable at runtime — it is checked into the repo root.
diff --git a/ComicCompress.csproj b/ComicCompress.csproj
index d3608d8..ac9089a 100644
--- a/ComicCompress.csproj
+++ b/ComicCompress.csproj
@@ -7,7 +7,7 @@
ComicCompress
True
Debug;Release;ReleaseWDbg
- 1.1.0.0
+ 3.1.0.0
@@ -28,17 +28,17 @@
-
-
+
+
-
-
-
+
+
+
-
-
+
+
diff --git a/Program.cs b/Program.cs
index c696dc6..481cddd 100644
--- a/Program.cs
+++ b/Program.cs
@@ -30,7 +30,6 @@ using ImageMagick;
using javax.xml.transform;
using System.Collections.Concurrent;
using iText.Barcodes.Dmcode;
-using ZstdSharp;
using Xabe.FFmpeg.Downloader;
using System.Reflection;
using Microsoft.VisualBasic;
@@ -63,7 +62,10 @@ namespace ComicCompressor
//string progVersion = "Version 3.0.0 - (21/11/2024)";
// In core changed color of percent save to white
- string progVersion = "Version 3.0.1 - (23/01/2025)";
+ //string progVersion = "Version 3.0.1 - (23/01/2025)";
+
+ // In core changed color of percent save to white
+ string progVersion = "Version 3.1.0 - (27/06/2027)";
public static int Main(string[] args) => CommandLineApplication.Execute(args);
#region INPUT_FLAGS
@@ -103,6 +105,12 @@ namespace ComicCompressor
[Option("-a|--copyall", Description = "Copy all unprocessed files")]
public bool DoCopyAll { get; } = false;
+ [Option("-w|--new-webp", Description = "Use Imageflow encoder (faster JPEG→WebP transcoding, no full pixel decode)")]
+ public bool NewWebp { get; } = false;
+
+ [Option("-P|--par-archive", Description = "Parallel image compression within each archive (~4-5x faster, uses half the CPUs)")]
+ public bool ParArchive { get; } = false;
+
#endregion
#region STATISTICS
@@ -153,19 +161,18 @@ namespace ComicCompressor
new_webp: false
);
- private void OnExecute()
+ private async Task OnExecuteAsync()
{
-
File_statistics.Clear();
- flags.File_statistics = File_statistics;
+ flags.New_webp = NewWebp;
+ flags.Par_archive = ParArchive;
myColors = new Color[names.Count()];
- for(int i = 0; i< myColors.Length; i++)
+ for (int i = 0; i < myColors.Length; i++)
{
KnownColor randomColorName = names[randomGen.Next(names.Length)];
- myColors[i] = Color.FromKnownColor(randomColorName);
+ myColors[i] = Color.FromKnownColor(randomColorName);
}
- //ImageExtractor7.MainBox();
Stopwatch sw = Stopwatch.StartNew();
@@ -175,28 +182,15 @@ namespace ComicCompressor
Logger.Log(progVersion, LogLevel.Verbose, true);
- //var progress = new Progress( p => Logger.Log(p.ToString(), LogLevel.Verbose, true) );
- //FFmpeg.SetExecutablesPath(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
- //FFmpegDownloader.GetLatestVersion(FFmpegVersion.Official,progress);
-
-
- //==//FFmpeg.SetExecutablesPath (Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "FFmpeg"));
-
- //Logger.Log(FFmpeg.ExecutablesPath, LogLevel.Verbose, true);
-
-
IList files = new FileParser().ListAllFiles(Input, Recursive);
- Process(files);
+ await Process(files);
long time_query = sw.ElapsedMilliseconds;
Logger.Log($"ElapsedTime {time_query} ms", LogLevel.Verbose, true);
-
- Console.ReadKey();
-
}
- private async void Process(IList files)
+ private async Task Process(IList files)
{
Compressor compressor = new Compressor(Logger);
compressor.Quality = Quality;