{"_id":"@eivu/ts-comic-compress","_rev":"5-d607e3e111cffd1589c6a8e455b3c695","name":"@eivu/ts-comic-compress","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"@eivu/ts-comic-compress","version":"1.0.0","keywords":["comic","compress","cbr","cbz","webp"],"author":{"name":"Rob Jenkins"},"license":"MIT","_id":"@eivu/ts-comic-compress@1.0.0","maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"bin":{"comic-compress":"dist/index.js"},"dist":{"shasum":"9f49498ffe2faf8e4f2863bef8bec104ea5d08fb","tarball":"https://registry.npmjs.org/@eivu/ts-comic-compress/-/ts-comic-compress-1.0.0.tgz","fileCount":60,"integrity":"sha512-5gNw1Ubwqpxil07nTh7CKTp0fESTZkSrBHvAz1HwphGuBR1c01BItVtNtF4drRT3MT21FvDDFyOBm82qW0CFjA==","signatures":[{"sig":"MEUCICcH7j9rjr1p7fVIzyMMZwMQ/6+15v7mwQqA90RpnJw7AiEAmkX+vGhYHFb4bTNfd6WhPq17Rf2vIWZwk6THU3WWkDE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":168128},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"ac6b08fa527bb3f6bb73b58c983848e49c428d35","scripts":{"dev":"ts-node src/index.ts","test":"jest","build":"tsc","start":"ts-node src/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"dabobert","email":"bobert@gmail.com"},"_npmVersion":"11.6.3","description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","directories":{},"_nodeVersion":"24.11.1","dependencies":{"yazl":"^2.5.1","chalk":"^4.1.2","sharp":"^0.33.2","yauzl":"^2.10.0","fs-extra":"^11.2.0","commander":"^11.1.0","pdfjs-dist":"^4.0.269","node-unrar-js":"^2.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.5","@types/yazl":"^3.3.0","@types/yauzl":"^2.10.3","@jest/globals":"^30.2.0","@types/fs-extra":"^11.0.4"},"_npmOperationalInternal":{"tmp":"tmp/ts-comic-compress_1.0.0_1770075527995_0.8509668409650639","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@eivu/ts-comic-compress","version":"1.1.0","keywords":["comic","compress","cbr","cbz","webp"],"author":{"name":"Rob Jenkins"},"license":"MIT","_id":"@eivu/ts-comic-compress@1.1.0","maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"bin":{"comic-compress":"dist/index.js"},"dist":{"shasum":"17f358f2d7ffbf5c00a6351daa72cc22afc97c89","tarball":"https://registry.npmjs.org/@eivu/ts-comic-compress/-/ts-comic-compress-1.1.0.tgz","fileCount":61,"integrity":"sha512-XLitJVQp5wtf7JusZK8cyjDd8z8vFLCFnGvGSpHG33pR/00N2lx6c6v3Q6+StS3dCgVIs4/0nB5Te9mYLCIV3Q==","signatures":[{"sig":"MEUCIQCXXConknNcU3kGwZ/HVheqQYFuNL6pursjvr6oD+rupwIgVHZf/UXTVrjWQuCfOSPslLWGCKsEPsv9T+LVP83Tqr0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":169795},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"1f47760526a1db308dacd665b0f845eff99dfddc","scripts":{"dev":"ts-node src/index.ts","test":"jest","build":"tsc","start":"ts-node src/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"dabobert","email":"bobert@gmail.com"},"_npmVersion":"11.6.3","description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","directories":{},"_nodeVersion":"24.11.1","dependencies":{"yazl":"^2.5.1","chalk":"^4.1.2","sharp":"^0.33.2","yauzl":"^2.10.0","fs-extra":"^11.2.0","commander":"^11.1.0","pdfjs-dist":"^4.0.269","node-unrar-js":"^2.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.5","@types/yazl":"^3.3.0","@types/yauzl":"^2.10.3","@jest/globals":"^30.2.0","@types/fs-extra":"^11.0.4"},"_npmOperationalInternal":{"tmp":"tmp/ts-comic-compress_1.1.0_1777671132752_0.45592140600486575","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@eivu/ts-comic-compress","version":"1.1.1","keywords":["comic","compress","cbr","cbz","webp"],"author":{"name":"Rob Jenkins"},"license":"MIT","_id":"@eivu/ts-comic-compress@1.1.1","maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"bin":{"comic-compress":"dist/index.js"},"dist":{"shasum":"32078ad9140b5b716bbb48ed24a8efd777fa6253","tarball":"https://registry.npmjs.org/@eivu/ts-comic-compress/-/ts-comic-compress-1.1.1.tgz","fileCount":61,"integrity":"sha512-wvAhfHDqrGHRzpWVvSKL6a0CkSnUeKzPEHpPh2C1EjnqQXF8oGTIHMwxreGrWZYsCQ2Fife2Acc5d34hw+f+qg==","signatures":[{"sig":"MEUCIQCleEIGCEpNjmPqwcskic1jYG7Bo7AeZ/+o4E15TLxNNAIgBAYl9pIb6XVR84Xt7HdEhwTeYFtxXIcThARUkGRPvrk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":170349},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"30d8392cc50f56d83f4eaff98ee1047187648d06","scripts":{"dev":"ts-node src/index.ts","test":"jest","build":"tsc","start":"ts-node src/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"dabobert","email":"bobert@gmail.com"},"_npmVersion":"11.6.3","description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","directories":{},"_nodeVersion":"24.11.1","dependencies":{"yazl":"^2.5.1","chalk":"^4.1.2","sharp":"^0.33.2","yauzl":"^2.10.0","fs-extra":"^11.2.0","commander":"^11.1.0","pdfjs-dist":"^4.0.269","node-unrar-js":"^2.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.5","@types/yazl":"^3.3.0","@types/yauzl":"^2.10.3","@jest/globals":"^30.2.0","@types/fs-extra":"^11.0.4"},"_npmOperationalInternal":{"tmp":"tmp/ts-comic-compress_1.1.1_1777671158021_0.02404733736218856","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@eivu/ts-comic-compress","version":"1.2.0","keywords":["comic","compress","cbr","cbz","webp"],"author":{"name":"Rob Jenkins"},"license":"MIT","_id":"@eivu/ts-comic-compress@1.2.0","maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"bin":{"comic-compress":"dist/index.js"},"dist":{"shasum":"2e6f69d09caa701d847665a0dbdc51af8d8c1a7d","tarball":"https://registry.npmjs.org/@eivu/ts-comic-compress/-/ts-comic-compress-1.2.0.tgz","fileCount":68,"integrity":"sha512-AgAgaxNN7Nx2IrtyqNS04SC7wtHXvkbr4oTpIVbLQZLz55XqmNYqa+NN9cYtfEmY4wtX26Y34m9ewHMNa0tzHQ==","signatures":[{"sig":"MEQCIH+Pg3vJhFbWOEJOJvlA4AlFaPmow9isw8u50PKHoqkFAiBnZUY3pU+GIuy0ZiY+OeIPPciK43ckJiuJ7L7/Hzgxiw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83208414},"main":"dist/index.js","types":"./dist/index.d.ts","gitHead":"99731a4963e502d7cb078a26a529ff7c7df778a9","scripts":{"dev":"ts-node src/index.ts","test":"jest","build":"tsc","start":"ts-node src/index.ts","test:watch":"jest --watch","test:coverage":"jest --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"dabobert","email":"bobert@gmail.com"},"_npmVersion":"11.6.3","description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","directories":{},"_nodeVersion":"24.11.1","dependencies":{"yazl":"^2.5.1","chalk":"^4.1.2","sharp":"^0.33.2","yauzl":"^2.10.0","fs-extra":"^11.2.0","commander":"^11.1.0","pdfjs-dist":"^4.0.269","node-unrar-js":"^2.0.2"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","ts-jest":"^29.4.6","ts-node":"^10.9.2","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.5","@types/yazl":"^3.3.0","@types/yauzl":"^2.10.3","@jest/globals":"^30.2.0","@types/fs-extra":"^11.0.4"},"_npmOperationalInternal":{"tmp":"tmp/ts-comic-compress_1.2.0_1777673819983_0.6699931711641367","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@eivu/ts-comic-compress","version":"2.0.0","description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","type":"module","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./processor":{"types":"./dist/processor.d.ts","default":"./dist/processor.js"},"./package.json":"./package.json"},"types":"./dist/index.d.ts","bin":{"comic-compress":"dist/index.js"},"engines":{"node":">=20.0.0"},"scripts":{"build":"tsc","postbuild":"node scripts/postbuild.js","start":"node --import tsx src/index.ts","dev":"node --import tsx src/index.ts","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"keywords":["comic","compress","cbr","cbz","webp"],"author":{"name":"Rob Jenkins"},"license":"MIT","dependencies":{"chalk":"^5.6.2","commander":"^14.0.3","node-unrar-js":"^2.0.2","pdfjs-dist":"^4.10.38","sharp":"^0.34.5","yauzl":"^2.10.0","yazl":"^3.3.1"},"devDependencies":{"@types/node":"^20.19.0","@types/yauzl":"^2.10.3","@types/yazl":"^3.3.0","@vitest/coverage-v8":"^4.1.5","tsx":"^4.21.0","typescript":"^5.6.3","vitest":"^4.1.5"},"gitHead":"7a921ec4b9b0efd8359a38ad1324b651ea462a87","_id":"@eivu/ts-comic-compress@2.0.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.3","dist":{"integrity":"sha512-hmep+LKwDvax7zR432I40jMKrq4rGJihaZVR6OlpKypd40W0oWAscIlQXSlStZQW281/d97SEvzJZvHUjpyiEw==","shasum":"b624da9660bae15befb5a0bfad39d1f826b4dfe4","tarball":"https://registry.npmjs.org/@eivu/ts-comic-compress/-/ts-comic-compress-2.0.0.tgz","fileCount":35,"unpackedSize":98279,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDEg3Zdu0JpOQ7EK6qILaoNpj0dzLjnYCBjd4Q3YMf7mAiBL5brbGQihk5zNFrfREF+GdphiBE/ZdQkEM1soC6dkIQ=="}]},"_npmUser":{"name":"dabobert","email":"bobert@gmail.com"},"directories":{},"maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ts-comic-compress_2.0.0_1777838543984_0.09328526335799547"},"_hasShrinkwrap":false}},"time":{"created":"2026-02-02T23:38:47.876Z","modified":"2026-05-03T20:02:24.274Z","1.0.0":"2026-02-02T23:38:48.152Z","1.1.0":"2026-05-01T21:32:12.912Z","1.1.1":"2026-05-01T21:32:38.195Z","1.2.0":"2026-05-01T22:17:02.054Z","2.0.0":"2026-05-03T20:02:24.133Z"},"author":{"name":"Rob Jenkins"},"license":"MIT","keywords":["comic","compress","cbr","cbz","webp"],"description":"Compresses comic books (CBR or CBZ extension) by using webp and decreasing the target height","maintainers":[{"name":"dabobert","email":"bobert@gmail.com"}],"readme":"# TypeScript Comic Compress\n\nA TypeScript/Node.js command-line tool **and** library that compresses comic books (CBR or CBZ extension) by converting images to WebP format and optionally resizing them. Also supports PDF files.\n\nThis is a TypeScript port of the Rust-based [compress_comics](https://github.com/erikvullings/compress_comics) project.\n\n> **2.0 is ESM-only.** The package now publishes as native ECMAScript modules and requires Node.js **>= 18.18**. If you were importing this package from a CommonJS project, see [Migrating from 1.x to 2.0](#migrating-from-1x-to-20).\n\n## Features\n\n- ✅ Supports CBR and CBZ comic archive formats\n- ✅ Supports PDF files (converts to CBZ)\n- ✅ Converts images to WebP format for better compression\n- ✅ Optional image resizing (maintains aspect ratio)\n- ✅ Recursive directory processing\n- ✅ Parallel processing support\n- ✅ Progress reporting with detailed statistics\n- ✅ Skip existing files option\n- ✅ Rename original files option\n- ✅ Strict error mode: exit non-zero when any image is skipped (`--raise-exception`)\n\n## Installation\n\nUse as a library in your own ESM Node.js project:\n\n```bash\nnpm install @eivu/ts-comic-compress\n```\n\nOr install globally for the CLI:\n\n```bash\nnpm install -g @eivu/ts-comic-compress\n```\n\n## Library usage (ESM)\n\n```ts\n// main entry — every public class\nimport { ComicProcessor, ImageSkippedError } from \"@eivu/ts-comic-compress\";\n\n// or import directly from the processor subpath if you want a smaller surface\nimport { ComicProcessor } from \"@eivu/ts-comic-compress/processor\";\n\nconst processor = new ComicProcessor({\n  outputDir: \"./compressed\",\n  quality: 75,\n  recursive: false,\n  skipExisting: false,\n  parallel: false,\n  renameOriginal: false,\n  moveOriginal: false,\n  raiseException: false,\n});\n\nawait processor.processFile(\"./input.cbz\");\nprocessor.printSummary();\n```\n\nThe package is published as **ESM only** with a `type: \"module\"` declaration. Consumers must be ESM (i.e. their own `package.json` must have `\"type\": \"module\"`, or they must use `.mjs` files). It does **not** ship a CommonJS build.\n\n## CLI usage\n\n```bash\ncomic-compress [options]\n```\n\n### Command Line Options\n\n```\n  -i, --input <FILE/FOLDER>     The file or folder to convert (required)\n  -o, --output <FOLDER>         Base path of the output (will be in output/subfolders if the recursive option is enabled), default: converted_comics\n  -r, --recursive               Recursively traverse the input folder (include all subfolders)\n  -s, --skip                    Skip processing file if it already exists in the output folder\n  -q, --quality <number>        Quality to use for the webp files (0-100), default: 75\n  -p, --parallel                Run in parallel, utilizing all computing resources\n  --rename-original             Rename original files to *_original instead of copying\n  --height <number>             Target height for images (maintains aspect ratio). If not specified, images are not resized\n  -e, --raise-exception         Exit with a non-zero status code if any image is skipped during processing\n  -m, --move-original           Move successfully compressed objects to a subfolder named done\n  -h, --help                    Display help for command\n```\n\n### Examples\n\n#### Process a single file:\n\n```bash\nnpm start -- -i comic.cbz -o output\n```\n\n#### Process a folder recursively:\n\n```bash\nnpm start -- -i ./comics -o ./compressed -r\n```\n\n#### Process with custom quality and resize:\n\n```bash\nnpm start -- -i comic.cbz -o output -q 80 --height 1200\n```\n\n#### Process in parallel and skip existing files:\n\n```bash\nnpm start -- -i ./comics -o ./compressed -r -p -s\n```\n\n#### Rename original files (creates backup):\n\n```bash\nnpm start -- -i comic.cbz -o output --rename-original\n```\n\n#### Fail fast if any image is skipped (useful for CI):\n\n```bash\nnpm start -- -i comic.cbz -o output --raise-exception\n```\n\n## Output\n\nThe tool provides detailed progress information and a summary report:\n\n```\n📊 Processing Summary:\n──────────────────────────────────────────────────\n📖 Comic1.cbz: 45.2% savings (23 images processed, 2 skipped) (15.2 MB saved)\n📖 Comic2.cbz: 38.7% savings (18 images processed, 1 skipped) (12.8 MB saved)\n\n🎯 Overall Results:\n   Total files processed: 2\n   Total images processed: 41\n   Total images skipped: 3\n   Overall size reduction: 42.1%\n   Original size: 125.43 MB\n   Compressed size: 72.65 MB\n   Space saved: 52.78 MB\n```\n\n## Technical Details\n\n- **Language**: TypeScript/Node.js\n- **Image Processing**: Sharp library (high-quality Lanczos3 resampling)\n- **Compression**: WebP lossy compression with configurable quality\n- **Archive Format**: ZIP-based CBZ files (universal comic reader compatibility)\n- **CBR Support**: Processes both ZIP-based and RAR-based CBR files (automatically detects format)\n- **PDF Support**: Extracts embedded images from PDF files and converts to CBZ format\n- **RAR Support**: Full support for RAR archives using node-unrar-js\n- **Threading**: Parallel file processing support\n\n## Supported File Formats\n\n### Input Formats\n\n- **CBZ**: ZIP archives containing images\n- **CBR**: RAR or ZIP archives containing images (automatically detects and handles both formats)\n- **PDF**: PDF files with embedded images (converted to CBZ)\n\n### Image Formats (within archives)\n\n- **JPEG/JPG**: Converted to WebP\n- **PNG**: Converted to WebP\n- **WebP**: Kept as-is (skipped)\n\n## Limitations\n\n- Output uses ZIP compression for CBR files (converts RAR-based CBR files to CBZ format)\n- WebP format may not be supported by very old comic readers\n- PDF processing only extracts embedded raster images (vector graphics are not rasterized)\n- RAR volume archives (multi-part RAR files) are not supported\n\n## Building\n\n```bash\nnpm run build\n```\n\nThis will compile TypeScript to JavaScript in the `dist/` directory.\n\n## Testing\n\nThis project includes a comprehensive test suite using Jest.\n\n```bash\n# Run all tests\nnpm test\n\n# Run tests in watch mode\nnpm run test:watch\n\n# Run tests with coverage report\nnpm run test:coverage\n```\n\nSee [TESTING.md](TESTING.md) for detailed testing documentation.\n\n## Development\n\n```bash\n# Run in development mode (uses tsx to run TypeScript directly under ESM)\nnpm run dev -- [options]\n```\n\n## Dependencies\n\n- **commander**: Command-line argument parsing\n- **sharp**: High-performance image processing and WebP conversion\n- **yauzl**: ZIP file reading\n- **yazl**: ZIP file writing\n- **node-unrar-js**: RAR archive extraction\n- **pdfjs-dist**: PDF file processing (ESM build)\n- **chalk**: Terminal colors\n\n`fs-extra` was dropped in 2.0 in favor of a thin wrapper around `node:fs/promises` (`src/fs-utils.ts`), eliminating a CJS-only runtime dependency.\n\n## Migrating from 1.x to 2.0\n\n2.0 is the first ESM-native release. Behavior is identical to 1.2.x; the breaking changes are purely about how the package is consumed.\n\n| Change | 1.x | 2.0 |\n| --- | --- | --- |\n| Module format | CommonJS (`require`-able) | ESM only (`import`/dynamic `import()`) |\n| Minimum Node | (unspecified) | **>= 18.18** |\n| `package.json` | `\"main\"` only, no `\"exports\"` map | `\"type\": \"module\"` + `\"exports\"` map |\n| Public import | `require(\"@eivu/ts-comic-compress/dist/processor.js\")` | `import \"@eivu/ts-comic-compress\"` or `import \"@eivu/ts-comic-compress/processor\"` |\n| chalk | `^4` (CJS) | `^5` (ESM-only) |\n| pdfjs-dist | `^4` via legacy CJS interop | `^4` ESM build, no `require()` interop |\n| Tests | Jest | Vitest |\n\nIf you were reaching into `dist/processor.js` directly, switch to the public subpath import — `@eivu/ts-comic-compress/processor` — which is now contractually exposed via the package's `exports` map.\n\n## License\n\nMIT\n\n## Credits\n\nOriginal Rust implementation: [erikvullings/compress_comics](https://github.com/erikvullings/compress_comics)\n","readmeFilename":"README.md"}