File conversion exchange for Linux: one command routes files to pandoc, ImageMagick, LibreOffice & more through an extensible converter registry.
Project description
fcx — File Conversion Exchange
fcx is a file conversion exchange for Linux — one command routes your files to the right backend (pandoc, ImageMagick, LibreOffice, Inkscape…) through an extensible converter registry.
Motivation
Linux power users who regularly convert files face a fragmented landscape: pandoc for documents, convert for images, loffice --headless for Office files, pdftotext for PDF extraction, ffmpeg for audio. Each tool has a different interface, different flag conventions, and different merging semantics. Scripting across them requires memorising or looking up the invocation for every combination.
fcx provides a single, consistent command for all of these:
fcx report.pdf intro.pdf chapter.docx diagram.svg # merge to pdf
fcx jpg:l2 photos/*.jpg # batch compress
fcx wav:16k recordings/*.mp3 # audio normalisation
The tool is especially useful in Makefiles, shell scripts, and AI coding agent pipelines where you want one deterministic command to handle whatever input format you have.
Installation
pip3 install fcx
# or in an isolated environment
pipx install fcx
# upgrade
pip3 install --upgrade fcx
From source
git clone https://github.com/sjjsy/fcx.git
cd fcx
pip3 install -e .
Quick start
fcx chapter.md appendix.md # → chapter.pdf (merge via pandoc)
fcx txt notes.md paper.pdf # → notes.txt (merge, pandoc + pdftotext)
fcx png *.svg # → per-file PNG (inkscape or ImageMagick)
fcx jpg:l1 photos/*.jpg # compress in-place, backup to Trash
fcx jpg:crop:50x50 *.jpg # center-crop 50% each axis, backup to Trash
fcx wav:16k recordings/*.mp3 # → per-file 16 kHz mono WAV
fcx -R # recover last in-place backup from Trash
System requirements
fcx itself requires only Python 3.8+ and docopt. Converters require their respective backend tools:
| Tool | Purpose | Install |
|---|---|---|
| pandoc | md/rst/html/docx → pdf/txt/md/rst/html | apt install pandoc |
| ImageMagick | image ↔ image, →pdf, in-place transforms | apt install imagemagick |
| LibreOffice | docx/pptx/xlsx/odt → pdf/txt | apt install libreoffice |
| wkhtmltopdf | html → pdf (also used by pandoc) | apt install wkhtmltopdf |
| Inkscape | svg → pdf/png | apt install inkscape |
| pdflatex | tex/tikz → pdf | apt install texlive-latex-base |
| poppler-utils | pdf → txt (pdftotext), pdf merge (pdfjam) |
apt install poppler-utils |
| ffmpeg | audio/video → wav | apt install ffmpeg |
| jpegoptim | JPG lossy compression | apt install jpegoptim |
| jpegtran | JPG lossless optimisation | apt install libjpeg-turbo-progs |
| optipng | PNG optimisation | apt install optipng |
Only the tools needed for your conversions need to be installed. Use fcx -d to check what is available.
CLI reference
fcx — File Converter
Convert files to a different format or apply in-place transforms.
Inputs are merged (pdf, txt) or converted individually (img, same-format).
Usage:
fcx [options] [ARGS ...]
fcx -h | --help
fcx --version
Options:
-h --help Show this screen.
--version Show version.
-I --init Copy built-in converter file(s) to ~/.config/fcx/converters/.
-d --deps Check deps for all converters, or for named TARGET ext(s).
-m --methods List all converters for each TARGET ext.
-i --inputs List input extensions that can produce each output ext.
-o --outputs List output extensions producible from each input ext.
-R --recover Restore most-recent fcx backup from Trash into CWD.
-O --overwrite Skip trash backup for same-format (in-place) transforms.
-v --verbose Stream live stdout/stderr from every shell command.
--dry-run Print commands without executing.
TARGET syntax:
The first positional argument is treated as TARGET when it does not name an
existing file on disk. It takes the form SPEC[:METHOD[:PARAMS]] where:
SPEC Output extension (pdf, txt, png, jpg, wav, ...) or explicit output
file path (report.pdf, out/notes.txt, ...).
Omit entirely to default to "pdf".
METHOD Name or unique prefix of the converter to prefer, e.g.
pandoc, loffice, wk, l1, crop. Fuzzy prefix-matched against
converter names; falls back to the next available converter.
PARAMS Parameter string passed verbatim to the converter function.
Some converters require it (e.g. crop:50x50, annotate:Draft v2).
Examples:
pdf pdf:pandoc jpg:l1
jpg:crop:50x50 jpg:annotate:Draft v2 report.pdf:loffice
wav:16k
Output file naming:
SPEC is a path → that is the output file.
SPEC is an ext, merge mode (→pdf/txt) → {first_input_stem}.{ext} in CWD.
SPEC is an ext, per-file mode → {each_input_stem}.{ext} in CWD.
Same-format transform → input file path (in-place).
Trash backup (same-format transforms):
Before in-place transforms, inputs are copied to:
~/.local/share/Trash/files/fcx_YYYYMMDD_HHMMSS_EXT/
with a matching .trashinfo sidecar. No external tools needed.
Use -R / --recover to restore the most recent backup into CWD.
Use -O / --overwrite to skip the backup entirely.
Examples:
fcx report.pdf intro.pdf chapter.docx diagram.svg # merge → pdf
fcx pdf report.pdf intro.pdf chapter.docx # same, explicit ext
fcx txt notes.txt paper.pdf slides.pptx # merge → txt
fcx png *.svg # batch svg → png
fcx report.pdf:pandoc chapter.md appendix.md # force pandoc
fcx jpg:l1 photos/*.jpg # compress to trash
fcx jpg:l1 -O photos/*.jpg # compress, no backup
fcx jpg:crop:50x50 photos/*.jpg # center-crop 50%
fcx jpg:annotate:Draft v2 *.jpg # annotate all
fcx wav:16k recordings/*.mp3 # audio → 16 kHz mono
fcx -R # recover last backup
fcx -R jpg # recover last jpg backup
fcx -d # check all deps
fcx -d pdf # check →pdf converter deps
fcx -m pdf # list all →pdf converters
fcx -o docx # what can docx become?
fcx -i pdf # what converts to pdf?
fcx -I # list built-in converter files
fcx -I pandoc # copy pandoc.py to user config dir
Registered converters
→ PDF (merge mode)
| From formats | Converter | Backend | Notes |
|---|---|---|---|
pdf |
builtin-copy-pdf | — | Passthrough / copy |
jpg, png, gif, bmp, tiff, webp |
imagemagick | convert |
Direct image→PDF |
svg |
inkscape-pdf | inkscape |
High-fidelity vector |
svg |
imagemagick-svg-pdf | convert |
Fallback |
docx, odt, pptx, xls, xlsx, rtf, csv |
libreoffice | loffice --headless |
|
md, rst, html, xhtml, docx, rtf, txt |
pandoc-wk | pandoc + wkhtmltopdf |
Best pandoc output |
md, rst, html, tex, csv, … |
pandoc | pandoc |
Fallback |
html, xhtml, htm |
wkhtmltopdf | wkhtmltopdf |
|
tex, tikz |
pdflatex | pdflatex |
Auto-runs biber/makeglossaries |
→ TXT (merge mode)
| From formats | Converter | Backend |
|---|---|---|
txt, md, rst |
builtin-copy-txt | — |
pdf |
pdftotext | pdftotext |
| any above | builtin-via-pdf | chains →pdf, then pdftotext |
→ Markup (merge mode)
| To format | Converter | Backend |
|---|---|---|
md |
pandoc-md | pandoc |
rst |
pandoc-rst | pandoc |
html |
pandoc-html | pandoc |
→ Image format conversion (per-file)
| From | To | Converter | Backend |
|---|---|---|---|
svg |
pdf |
inkscape-pdf | inkscape |
svg |
png |
inkscape-png | inkscape |
svg |
jpg |
inkscape-jpg | inkscape + convert |
| any image | png |
imagemagick-to-img | convert |
| any image | jpg |
imagemagick-to-jpg | convert |
→ JPG in-place transforms (per-file, trash backup)
| METHOD | Deps | Effect |
|---|---|---|
l0 |
jpegtran |
Lossless optimise + progressive |
l1 |
jpegoptim |
q 85 |
l2 |
jpegoptim, convert |
q 75; resize if > 2666 px |
l3 |
jpegoptim, convert |
q 60; resize if > 800 px |
luh |
convert |
Fit 3840×2160, q 90 |
lum |
convert |
Fit 3840×2160, q 60 |
lul |
convert |
Fit 3840×2160, q 40 |
lfh |
convert |
Fit 1920×1080, q 90 |
lfm |
convert |
Fit 1920×1080, q 60 |
lfl |
convert |
Fit 1920×1080, q 40 |
lm |
convert |
Fit 800×800, q 60 |
lb1 |
convert |
B&W document binarise |
crop |
convert, identify |
Center-crop percentage per axis (PARAMS: WxH) |
cropabs |
convert, identify |
Center-crop in pixels (PARAMS: WxH) |
annotate |
convert, identify |
Overlay text label at bottom (PARAMS: text) |
version |
convert, jpegtran, jpegoptim |
Creates ver/ with l0–l3 comparison set |
montage |
convert |
Square-crop + assemble montage grid (PARAMS: cell_px) |
→ PNG in-place transforms
| METHOD | Deps | Effect |
|---|---|---|
l0-png |
optipng |
Lossless optimise |
l1-png |
optipng |
Aggressive lossless optimise |
l2-png |
optipng, convert |
Resize if > 2666 px |
l3-png |
optipng, convert |
Resize if > 800 px |
lb1-png |
convert |
B&W document binarise |
crop-png |
convert, identify |
Center-crop percentage (PARAMS: WxH) |
cropabs-png |
convert, identify |
Center-crop in pixels (PARAMS: WxH) |
annotate-png |
convert, identify |
Overlay text label |
→ WAV (per-file)
| From formats | Converter | Backend | Effect |
|---|---|---|---|
mp3, m4a, ogg, flac, aac, opus, wma, wav, mp4, … |
ffmpeg-16k | ffmpeg |
16 kHz mono WAV |
Checking what is available
fcx -d # all converters and their deps
fcx -d pdf # deps for →pdf converters only
fcx -m pdf # list all →pdf converters, which would be selected
fcx -m jpg # list all →jpg converters
fcx -i pdf # what input formats can produce pdf?
fcx -o docx # what output formats can docx produce?
Extending fcx
Converters live in CONVERTERS lists inside Python files. Three layers are merged at startup — later layers win for same-named converters; unique names coexist with user/system versions listed first:
1. built-in fcx/converters/*.py (ships with fcx)
2. system /etc/xdg/fcx/converters/*.py
3. user ~/.config/fcx/converters/*.py ← highest priority
Add a custom converter
Copy a built-in converter file to your user config dir:
fcx -I pandoc # copies pandoc.py to ~/.config/fcx/converters/pandoc.py
fcx -I # list all built-in converter files
Then edit the copy. Delete the file to revert to the built-in.
Write one from scratch
Create ~/.config/fcx/converters/mytools.py:
from pathlib import Path
from typing import List, Optional
from fcx.core import Converter, run
def _my_converter(srcs: List[Path], dst: Path, params: Optional[str]) -> None:
run(["mytool", "--output", str(dst)] + [str(s) for s in srcs])
CONVERTERS = [
Converter(
name="mytool",
from_formats=("md",),
to_format="pdf",
deps=["mytool"],
params=None,
fn=_my_converter,
mode="merge", # "merge" | "per-file" | "in-place" | "auto"
),
]
Verify: fcx -d pdf and fcx -m pdf.
Converter dataclass
@dataclass
class Converter:
name: str # matched by METHOD prefix in TARGET
from_formats: tuple # input extensions (lowercase, no dot)
to_format: str # output extension
deps: list # binary names checked on PATH
params: str | None # human-readable PARAMS description, or None
fn: Callable # fn(srcs: list[Path], dst: Path, params: str | None)
mode: str = "auto" # dispatch mode (see above)
Dispatch mode
| mode | behaviour |
|---|---|
"auto" |
merge if to_format in (pdf, txt); in-place if to==from; else per-file |
"merge" |
all inputs passed to fn at once, one output |
"per-file" |
fn called once per input, no trash backup |
"in-place" |
fn called once per input, trash backup before first call |
Verbose and dry-run
fcx -v jpg:l1 photo.jpg # stream live output from jpegoptim
fcx --dry-run pdf *.md # print commands without running them
Examples
# Document conversion
fcx report.pdf chapter.md appendix.md # merge md → pdf
fcx txt notes.pdf slides.pptx # merge to txt
fcx html document.docx # docx → html via pandoc
# Image conversion
fcx png *.svg # batch svg → png (inkscape)
fcx jpg diagram.svg # svg → jpg
# In-place image compression (all backed up to Trash first)
fcx jpg:l1 photos/*.jpg # compress to q85
fcx jpg:l2 photos/*.jpg # q75, resize if > 2666px
fcx jpg:l3 -O photos/*.jpg # q60, no backup (--overwrite)
fcx jpg:luh portraits/*.jpg # fit 4K UHD, q90
# In-place image transforms
fcx jpg:crop:75x75 thumbnails/*.jpg # center-crop to 75%
fcx jpg:cropabs:800x800 pics/*.jpg # center-crop to 800×800px
fcx jpg:annotate:Draft *.jpg # overlay label "Draft"
fcx jpg:lb1 scans/*.jpg # binarise to B&W document
# PNG optimisation
fcx png:l1-png images/*.png # aggressive lossless optimise
fcx png:crop-png:80x80 icons/*.png # center-crop PNGs
# Comparison sets and montage
fcx jpg:version photo.jpg # creates ver/ with l0–l3 comparison
fcx jpg:montage *.jpg # assemble 300×300 montage grid
# Audio
fcx wav:16k recordings/*.mp3 # 16 kHz mono WAV for ASR
fcx wav:16k interview.m4a # single file
# Dependency check
fcx -d # all converters
fcx -d jpg # only jpg-related converters
# Discovery
fcx -m pdf # what converters exist for →pdf?
fcx -i pdf # what can be converted to pdf?
fcx -o docx # what can docx become?
# Recovery
fcx -R # restore last backup
fcx -R jpg # restore last jpg backup
Contributing
Fork the repository and open a pull request. Adding converters for new backend tools is the most welcome contribution — each converter file is self-contained and easy to write.
License
GNU Affero General Public License v3.0 — see LICENSE.
Related projects
fcx sits at the intersection of document conversion and image processing automation. The tables below place it in context.
Document conversion backends
These are the system tools that fcx dispatches to. Each has a different sweet spot; fcx selects the best available one automatically.
| Tool | License | Best for | Used in fcx |
|---|---|---|---|
| pandoc | GPL-2 | Universal markup converter; md/rst/html/docx → pdf/html/txt and 50+ formats | Yes — pandoc, pandoc-wk |
| LibreOffice | MPL-2 | Office formats (docx/pptx/xlsx/odt) headless conversion | Yes — libreoffice (via loffice --headless) |
| wkhtmltopdf | LGPL-3 | HTML → PDF with full CSS/JS rendering (WebKit engine) | Yes — wkhtmltopdf |
| ImageMagick | Apache-2 | Image ↔ image, raster → PDF, compositing | Yes — convert, identify, montage |
| Inkscape | GPL-3 | SVG → PDF/PNG with full vector fidelity | Yes — inkscape --export-type |
| pdflatex / TeX Live | Mixed/Free | TeX → PDF with bibliography and glossary management | Yes — pdflatex, biber, makeglossaries |
| poppler-utils | GPL-2 | PDF text extraction (pdftotext), PDF merge (pdfjam) |
Yes — pdftotext, pdfjam |
| ffmpeg | LGPL-2.1 | Audio/video format conversion | Yes — ffmpeg-16k |
| jpegoptim | GPL-2 | Lossy JPG compression with quality targets | Yes — l1–l3 converters |
| jpegtran | BSD | Lossless JPG transform and optimisation | Yes — l0 converter |
| optipng | zlib/libpng | Lossless PNG compression | Yes — l0-png–l3-png |
| Weasyprint | BSD | HTML → PDF via Python (no Qt/WebKit); CSS Paged Media | No — alternative to wkhtmltopdf |
| unoconv | GPL-2 | LibreOffice UNO bridge; similar to loffice --headless |
No — superseded by loffice --headless |
Python document conversion libraries
Pure Python or wrapper libraries that avoid shelling out. fcx prefers system tools for flexibility but these are useful when you need embedded conversion.
| Library | License | Stars | Best for |
|---|---|---|---|
| pypandoc | MIT | 1.3k | Python wrapper around pandoc; supports all pandoc formats |
| docx2pdf | MIT | 2.1k | DOCX → PDF on macOS (Word) / Linux (LibreOffice) |
| img2pdf | LGPL-3 | 1.0k | Lossless image → PDF; preserves original pixels without re-encoding |
| pdf2image | MIT | 1.8k | PDF → PIL Image objects via poppler |
| python-pptx | MIT | 2.6k | Read/write PPTX; no built-in PDF export |
| pymupdf | AGPL-3 / commercial | 4.8k | High-speed PDF/XPS/EPUB rendering, extraction, annotation |
| weasyprint | BSD | 7.1k | HTML/CSS → PDF in Python; CSS Paged Media support |
Batch file conversion tools
CLI and GUI tools that wrap multiple conversion backends — the category closest to fcx itself.
| Tool | Type | Platform | License | Formats | Notes |
|---|---|---|---|---|---|
| fcx (this) | CLI | Linux | AGPL-3 | docs, images, audio | Extensible registry; in-place transforms; trash backup; scriptable |
| fileConverter | GUI | Windows | GPL-3 | images, audio, video, docs | Right-click shell extension; uses ffmpeg/ImageMagick |
| unoconv | CLI | Linux/macOS | GPL-2 | office formats only | LibreOffice UNO bridge; no longer actively maintained |
| pandoc | CLI | Any | GPL-2 | markup/docs only | The gold standard for document conversion; no images or audio |
| Converseen | GUI | Linux/Windows | GPL-3 | images only | Qt/ImageMagick batch image converter |
| Kramdown-AsciiDoc | CLI | Any | MIT | md → asciidoc | Single format pair, deep conversion fidelity |
Image optimisation CLIs
Tools focused on reducing image file size. fcx wraps these under a consistent interface with trash backup.
| Tool | License | Algorithm | In fcx |
|---|---|---|---|
| jpegoptim | GPL-2 | Progressive JPEG; quality targets; strips metadata | Yes — l1, l2, l3 |
| jpegtran | BSD | Lossless DCT operations; progressive scan | Yes — l0 |
| optipng | zlib | Lossless PNG deflate optimisation | Yes — l0-png–l3-png |
| pngquant | GPL-3 | Lossy PNG palette quantisation (often 60–80% savings) | No — lossy; would fit a future l1-png lossy variant |
| oxipng | MIT | Multi-threaded lossless PNG (Rust); faster than optipng | No — could replace optipng as a future built-in |
| Squoosh CLI | Apache-2 | WASM-based multi-format image optimisation | No — Node.js dependency |
| ImageOptim-CLI | MIT | Orchestrates multiple tools (jpegtran, pngquant, …) | No — macOS-native tools |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fcx-0.1.3.tar.gz.
File metadata
- Download URL: fcx-0.1.3.tar.gz
- Upload date:
- Size: 30.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ac1fc6b99b17c7b0f5e5ebba6fb56822559177cfdf2c646348bf54ee434ef13
|
|
| MD5 |
370dae5f68753bcdb68a1212eb868782
|
|
| BLAKE2b-256 |
9df8b10a6229e0517b7fde89e4c38b467d7cef339f1a1b16353e76ebaaf22221
|
File details
Details for the file fcx-0.1.3-py3-none-any.whl.
File metadata
- Download URL: fcx-0.1.3-py3-none-any.whl
- Upload date:
- Size: 28.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.13 {"installer":{"name":"uv","version":"0.11.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a66975e28ccd508971d37737107ae214ac788d26d92d7ece999766b34473469
|
|
| MD5 |
bc50a0cb9a4826f771f744d7809ef891
|
|
| BLAKE2b-256 |
c72941582253f076ba567bd1e3fdf0ff64953f55fdd427c3f9bef28b397e73b6
|