Skip to content

Repository files navigation

chisel

chisel is a CLI tool and library that losslessly optimizes files.

It recursively explores folders, files inside ZIPs or cover arts inside music files (IDv3, APE tags etc.), and supports 160+ file formats by integrating many specialized encoders. It does NOT change the format of files (even when it would be beneficial to do so), supports checksum verification to verify that the raw data of files hasn't been altered, and doesn't discard metadata by default.


Installation

Quick install

The easiest way to install chisel is via your package manager. Chisel is available on homebrew:

brew update
brew tap snesnopic/tools
brew install chsl

It is also available on winget:

winget update
winget install Snesnopic.Chisel

The executable name is 'chsl' because 'chisel' already exists in brew.

Building from source

If you prefer to compile chisel manually, please follow the build instructions below.

Requirements

The project fetches all its dependencies automatically via Git submodules.

  • All Platforms:
  • git (with LFS support: run git lfs install once)
  • cmake (≥ 3.20)
  • ninja (recommended)
  • Rust toolchain (required for OptiVorbis integration; install via rustup.rs)
  • Linux:
  • A modern C++20 compiler (GCC ≥ 11 or Clang ≥ 14)
  • build-essential, pkg-config
  • autoconf, automake, libtool, m4, nasm, yasm (required by some submodules)
  • macOS:
  • Xcode Command Line Tools (Clang with C++20 support)
  • pkg-config
  • autoconf, automake, libtool, nasm, yasm (required by some submodules)
  • Windows:
  • Visual Studio 2022 (with MSVC C++20 toolchain), vcpkg

Installing dependencies

Linux

This command installs only the build tools. All libraries are submodules.

sudo apt-get update
sudo apt-get install -y build-essential cmake ninja-build help2man pkg-config git \
autoconf automake libtool m4 nasm yasm ccache
curl https://sh.rustup.rs -sSf | sh

macOS (Homebrew)

brew update
brew install cmake ninja pkg-config git autoconf help2man automake libtool nasm yasm
curl https://sh.rustup.rs -sSf | sh

Windows

Ensure you have installed Visual Studio 2022 (with the "Desktop development with C++" workload), Git and vcpkg configured.

# Download Visual Studio 2022 Community bootstrapperInvoke-WebRequest"https://aka.ms/vs/17/release/vs_community.exe"-OutFile vs.exe# Install "Desktop development with C++" workload
.\vs.exe--quiet --wait --norestart --nocache `--add Microsoft.VisualStudio.Workload.NativeDesktop `--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `--add Microsoft.VisualStudio.Component.Windows10SDK.22621# Install Rust toolchainInvoke-WebRequest https://win.rustup.rs/x86_64 -OutFile rustup-init.exe
.\rustup-init.exe-y

Building chisel

Clone the repository and initialize all submodules:

 git clone https://github.com/Snesnopic/chisel.git
cd chisel
git lfs install
git lfs pull
git submodule update --init --recursive

Configure and build with CMake:

mkdir build &&cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release

If you have Ninja, you can add -G "Ninja" to the first command.

Opting out of specific encoders

You can also opt out of the OptiVorbis integration (which requires Rust) with -DENABLE_OPTIVORBIS=OFF. You can do the same for MKV optimizations (libmkclean specifically) with -DENABLE_MATROSKA=OFF.

Usage

./chsl <file-or-directory>... [options]

Arguments:

  • inputs... One or more files or directories to process. Use - to read from stdin.

Options:

  • -h, --help Show the help message and exit.

  • --version Display program version information and exit.

  • -o, --output <PATH> Write optimized files to PATH instead of modifying them in-place. If the input is stdin (-), PATH must be a file. Otherwise, PATH must be a directory.

  • --report <FILE> Export a final CSV report to the specified file.

  • -r, --recursive Recursively scan input folders.

  • -q, --quiet Suppress non-error console output (progress bar, results).

  • --dry-run Use chisel without replacing original files.

  • --no-meta Don't preserve files metadata. (Metadata is preserved by default).

  • --verify-checksums Verify raw checksums before replacing files.

  • --threads <N> Number of worker threads to use (default: half of available cores).

  • --log-level <LEVEL> Set logging verbosity (ERROR, WARNING, INFO, DEBUG, NONE). Default is ERROR.

  • --log-file <FILE> Write logs to the specified file (default: no file logging).

  • --include <PATTERN> Process only files matching regex PATTERN. (Can be used multiple times).

  • --exclude <PATTERN> Do not process files matching regex PATTERN. (Can be used multiple times).

  • --iterations <N> Number of iterations for Zopfli based compression (default: 15).

  • --iterations-large <N> Number of iterations for Zopfli on large images (default: 5).

  • --max-tokens <N> Number of tokens for FlexiGif compression (default: 10000).

  • --mode <MODE> Select how multiple encoders are applied to a file (pipe or parallel). pipe (default): Encoders are chained; output of one is input to the next. parallel: All encoders run on the original file; the smallest result is chosen.

Examples:

  • ./chsl file.jpg dir/ --recursive --threads 4
  • ./chsl archive.zip
  • ./chsl dir/ --report report.csv
  • cat file.png | ./chsl - -o out.png
  • cat file.png | ./chsl - > out.png

How it works

chisel scans the input file(s) to understand their actual format. If a relevant Processor is found for the input, the file goes through a pipeline with 3 phases:

Phase 1: Extraction & discovery The system identifies files whose compatible Processors are flagged as containers. This includes traditional archives (like ZIP or Tar), PDF documents, and even audio files (like MP3 or FLAC) that contain embedded cover art within their ID3/APE tags. These internal files are extracted to a temporary location and exposed to the pipeline recursively. This means chisel is perfectly capable of compressing an image inside a ZIP archive, inside another ZIP archive.

Phase 2: Recompression All discovered and extracted files are delegated to a thread pool. The worker thread will invoke the recompress function of the file's designated Processor (if available;not all formats are compressible, just like not all formats are containers).

If multiple processors are registered for the same file type, two modes of operation can occur, depending on the --mode flag:

  • PIPE (Default): Processors are chained sequentially. The optimized output of the first processor becomes the input for the next one, in the exact order they are registered in processor_registry.cpp.
  • PARALLEL: Every processor runs its recompress function simultaneously on a fresh copy of the original file, and the smallest resulting file is chosen. (Note: This behavior is likely to be deprecated soon, as PIPE mode typically yields better cumulative results, and scenarios with multiple encoders for the exact same format are rare).

If, at the end of this phase, the recompressed file is not strictly smaller than its original counterpart, the new file is discarded and the original is preserved.

Phase 3: Finalization All files that were originally classified as containers, and whose contents were extracted in Phase 1, are now rebuilt. The Processor will repack the container using the newly optimized internal files, preserving the original structure.


Adding a new Processor

Extending chisel with a new encoder or format requires just a few operations:

  1. Define the Processor: Create a new header in libchisel/include/processors/, inheriting from IProcessor. You must meaningfully implement the required metadata methods:

    • get_name()
    • get_supported_mime_types()
    • get_supported_extensions()
    • can_recompress()
    • can_extract_contents()
  2. Implement the core logic: Write the implementation in libchisel/src/processors/.

    • Implement recompress(), making sure to respect the options.preserve_metadata flag if applicable for your format.
    • If your processor is a container, you must override prepare_extraction() and finalize_extraction(), ensuring the exact structure of the container is restored during finalization.
    • Note: Implementing the raw_equal() method (used to verify that the meaningful content is bit-identical before and after compression) isn't strictly required to run the tool, but all tests run on the GitHub CI workers will execute with the --verify-checksums flag enabled, so it is highly recommended.
  3. Register the Processor: The final step is to instantiate and register your new class inside the constructor of ProcessorRegistry in libchisel/src/processor_registry.cpp.


Supported formats

CategoryFormatMIMEExtensionsLibraries
ImagesJPEGimage/jpeg, image/jpg.jpg, .jpeg, .jpe, .jif, .jfif, .jfi, .thmmozjpeg
ImagesGIFimage/gif.gifgifsicle, flexigif
ImagesJPEG XLimage/jxl.jxllibjxl
ImagesWebPimage/webp, image/x-webp.webplibwebp
ImagesPNG / Android 9-Patchimage/png, image/apng.png, .apngzopflipng
ImagesTIFFimage/tiff, image/tiff-fx.tif, .tifflibtiff
ImagesTrueVision TGAimage/x-tga, image/tga.tga, .targa, .icb, .vda, .vststb
ImagesWindows Bitmapimage/bmp, image/x-ms-bmp.bmp, .dibbmplib
ImagesWindows Icon / Cursorimage/x-icon, image/vnd.microsoft.icon.ico, .curinternal, bmplib, zopflipng
ImagesApple Icon Imageimage/x-icns.icnsinternal, zopflipng
ImagesTencent Image Containerapplication/x-gft.gftinternal
ImagesPortable Anymapimage/x-portable-anymap, image/x-portable-pixmap, image/x-portable-graymap, image/x-portable-bitmap.pnm, .ppm, .pgm, .pbmstb (read P5/P6), internal (read P1-P4, write)
ImagesJPEG 2000image/jp2, image/jpx.jp2, .j2k, .j2cOpenJPEG
ImagesMNG / JNGvideo/x-mng, image/x-jng.mng, .jngInternal (Zopfli, mozjpeg)
ImagesPCX / DCXimage/x-pcx, image/vnd.zbrush.pcx.pcx, .dcx, .pccInternal (RLE)
ImagesOpenRasterimage/openraster.oralibarchive (ZIP-based)
ImagesSVGimage/svg+xml.svgpugixml
DocumentsXML Dataapplication/xml, text/xml, text/xsl, application/xhtml+xml, application/vnd.google-earth.kml+xml, application/gpx+xml, model/vnd.collada+xml, application/rss+xml, application/atom+xml, application/rdf+xml.xml, .xhtml, .kml, .gpx, .dae, .rss, .atom, .xmp, .xsl, .xsltpugixml
DocumentsJSON Dataapplication/json.jsonyyjson
DocumentsMicrosoft Office OOXMLdocx: application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.wordprocessingml.template
xlsx: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.openxmlformats-officedocument.spreadsheetml.template
pptx: application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.presentationml.template
.docx, .docm, .dotm, .dotx, .xlsx, .xlsm, .xltm, .xltx, .pptx, .pptm, .potm, .potx, .ppsm, .ppsx-
DocumentsPDFapplication/pdf.pdfqpdf
DocumentsCFBF (Legacy Office / MSI)application/x-ole-storage, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/x-msi, application/x-ms-spool.doc, .xls, .ppt, .msi, .msp, .mst, .pub, .vsd, .vss, .vst, .adp, .mdb, .mdt, .mpd, .mpp, .mpt, .rvt, .sldasm, .slddrw, .sldprt, .snt, .thumbs.db, .spl, .dot, .xlt, .pps, .chm, .fla, .one, .ost, .rfa, .rte, .wps-
DocumentsOpenDocumentodt: application/vnd.oasis.opendocument.text
ods: application/vnd.oasis.opendocument.spreadsheet
odp: application/vnd.oasis.opendocument.presentation
odg: application/vnd.oasis.opendocument.graphics
odf: application/vnd.oasis.opendocument.formula
odb: application/vnd.oasis.opendocument.database
.odt, .ods, .odp, .odg, .odf, .odb-
DocumentsEPUBapplication/epub+zip.epublibarchive (ZIP-based)
DocumentsFictionBookapplication/x-fictionbook+xml.fb2pugixml
DocumentsComic BookCBZ: application/vnd.comicbook+zip
CBT: application/vnd.comicbook+tar
.cbz, .cbtlibarchive
DocumentsvCard (Photo only)text/vcard, text/x-vcard.vcfTagLib (base64)
DocumentsMIME Emails / Archivesmessage/rfc822, application/vnd.ms-outlook, multipart/related, message/x-mixed-replace.eml, .msg, .mht, .mhtml, .mbxInternal
DocumentsXPSapplication/vnd.ms-xpsdocument, application/oxps.xps, .oxpslibarchive (ZIP-based)
DocumentsPortable Executable (PE)application/x-msdownload, application/vnd.microsoft.portable-executable.exe, .dll, .ocx, .scr, .cpl, .sys, .drv, .bpl, .icl, .rll, .vbxInternal
DocumentsDWFXmodel/vnd.dwfx+xps.dwfxlibarchive (ZIP-based)
Documents3MF (3D)application/vnd.ms-package.3mflibarchive (ZIP-based)
DocumentsKMZ (Google Earth)application/vnd.google-earth.kmz.kmzlibarchive (ZIP-based)
AudioFLACaudio/flac, audio/x-flac.flaclibFLAC, TagLib
AudioOgg (FLAC stream)audio/ogg, audio/oga.ogg, .ogalibFLAC, libogg
AudioOgg Vorbis/Opusaudio/ogg, audio/vorbis, audio/opus.ogg, .opusOptiVorbis, TagLib (covers)
AudioMP3audio/mpeg.mp3mp3packercpp, vbrfix, TagLib (covers)
AudioM4A/MP4 (Cover Art only)audio/mp4, audio/x-m4a, video/mp4, video/quicktime, video/3gpp, video/3gpp2.m4a, .mp4, .m4b, .m4v, .mov, .qt, .3gp, .3g2TagLib (covers)
AudioWAV (Cover Art only)audio/wav, audio/x-wav, audio/vnd.wave, audio/wave.wavTagLib (covers)
AudioAIFF (Cover Art only)audio/x-aiff, audio/aiff.aif, .aiff, .aifcTagLib (covers)
AudioMonkey's Audioaudio/ape, audio/x-ape.apeMACLib, TagLib
AudioWavPackaudio/x-wavpack, audio/x-wavpack-correction.wv, .wvp, .wvcwavpack
AudioDSF (DSD Stream File)audio/dsf, audio/x-dsf.dsfTagLib (covers)
AudioDSDIFFaudio/dff, audio/x-dff.dffTagLib (covers)
AudioMusepackaudio/musepack, audio/x-musepack.mpc, .mp+, .mppTagLib (covers)
AudioTrueAudioaudio/tta, audio/x-tta.ttaTagLib (covers)
Video / AudioMatroska / WebMvideo/x-matroska, audio/x-matroska, video/webm, audio/webm.mkv, .mka, .webmmkclean, TagLib (attachments)
Video / AudioASF / WMA / WMVaudio/x-ms-wma, video/x-ms-wmv, video/x-ms-asf.wma, .wmv, .asfTagLib (covers)
Video / AudioShockwave Flashapplication/x-shockwave-flash.swfzlib
ArchivesBrotliapplication/x-brotli, application/brotli.brbrotli
ArchivesZipapplication/zip, application/x-zip-compressed.zip, .air, .bsz, .cdr, .csl, .gallery, .gallerycollection, .galleryitem, .grs, .ita, .itz, .nbk, .notebook, .oex, .osk, .pk3, .puz, .stz, .vlt, .wal, .wba, .wmz, .wsz, .xap, .xl, .xmz, .xsn, .appx, .bar, .dwf, .easm, .rmskin, .sldx, .zipxlibarchive
ArchivesTarapplication/x-tar.tarlibarchive
ArchivesGZipapplication/gzip, application/x-gzip.gz, .tgz, .svgz, .emz, .wmzlibdeflate
ArchivesBZip2application/x-bzip2.bz2bzip2
ArchivesXzapplication/x-xz.xzliblzma
ArchivesLZMAapplication/x-lzma.lzmaliblzma
ArchivesLZ4application/x-lz4.lz4liblz4
ArchivesZstandardapplication/zstd, application/x-zstd.zst, .tzst, .tar.zstlibzstd, libarchive
ArchivesISOapplication/x-iso9660-image.isolibarchive
ArchivesCPIOapplication/x-cpio.cpiolibarchive
ArchivesAR (Static Lib)application/x-archive.a, .ar, .liblibarchive
ArchivesJARapplication/java-archive.jarlibarchive (ZIP-based)
ArchivesXPIapplication/x-xpinstall.xpilibarchive (ZIP-based)
ArchivesAPKapplication/vnd.android.package-archive.apk, .ipa, .ipswlibarchive (ZIP-based)
ArchivesVSIX / NuGetapplication/zip.vsix, .nupkglibarchive (ZIP-based)
ArchivesJava EEapplication/java-archive.war, .earlibarchive (ZIP-based)
ArchivesAndroid Bundleapplication/vnd.android.package-archive.aablibarchive (ZIP-based)
ArchivesTencent Resource DBapplication/x-rdb.rdbinternal
ArchivesKanziapplication/x-kanzi.knzkanzi
ArchivesCabinet (MSZIP)application/vnd.ms-cab-compressed, application/x-cab.cablibdeflate
FontsWOFFfont/woff, application/font-woff.woffzlib
FontsWOFF2font/woff2.woff2woff2
ScientificMSEEDapplication/vnd.fdsn.mseed.mseed, .mseed2, .mseed3libmseed
DatabasesSQLiteapplication/vnd.sqlite3, application/x-sqlite3.sqlite, .db, .sqlite3sqlite3
3D ModelsSTLmodel/stl, model/x.stl-ascii.stlinternal
ScriptingLua Bytecodeapplication/x-lua-bytecode.lua, .luacinternal

Third-party libraries

Chisel works because it makes use of so many libraries. Here is a list of the incredible open-source projects that power its processors:

  • TagLib: Audio metadata and cover art extraction.
  • libarchive: Multi-format archive reading and writing (ZIP, Tar, GZip, etc.).
  • mozjpeg: High-performance JPEG recompression.
  • libwebp: WebP image encoding and decoding.
  • libpng: PNG image handling.
  • zopfli: Deflate/PNG optimization.
  • libflac: Free Lossless Audio Codec handling.
  • libogg: Ogg container support.
  • libjxl: JPEG XL support.
  • wavpack: WavPack lossless audio compressor.
  • libebml & libmatroska: EBML and Matroska container handling.
  • mkclean: Matroska/WebM optimization tool.
  • qpdf: PDF transformation and optimization.
  • zstd: ZSTD compression.
  • xz: LZMA compression.
  • lz4: LZ4 frame compression.
  • brotli: Generic-purpose lossless compression.
  • sqlite3: SQLite database engine.
  • OptiVorbis: Ogg Vorbis recompression (Rust-based).
  • gifsicle & flexigif: GIF optimization.
  • libmseed: miniSEED data format library.
  • pugixml: Light-weight, simple and fast XML parser.
  • yyjson: High-performance JSON library.
  • libtiff: TIFF image support.
  • stb: Single-file public domain libraries for images.
  • OpenJPEG: Open-source JPEG 2000 codec.
  • kanzi-cpp: Lossless data compressor port.
  • mp3packercpp: mp3packer port.
  • corrosion: CMake integration for Rust.

Why?

Chisel exists because I've been inspired by larger and more mature projects that have had something missing. Specifically, I've always needed a cross-platform utility, that was contained in its size, that didn't require an interpreter or a terminal script to use it, and that could automatically handle IDv3 tags inside music files. These are the tools that I have used, both personally and for research for this project.

About

Lossless file optimizer and re-compressor

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages