jpegtran — Transform and Optimize JPEG Files Losslessly
Lossless JPEG transformations with jpegtran: rotate, flip, crop and optimize images without re-encoding or quality loss.
jpegtran transforms JPEG images entirely losslessly – without ever re-decoding and re-encoding them. Instead of re-rendering the picture, the tool rearranges the already-compressed DCT blocks directly: you rotate, flip, crop or optimize a file without losing a single extra bit of quality. That makes jpegtran the go-to choice when you want to slim down photos for the web or fix their orientation without introducing visible artifacts.
Optimization
jpegtran -optimize <input.jpg> > <output.jpg> — Optimize Huffman coding tables (smaller file, no quality loss).
jpegtran -optimize photo.jpg > optimized.jpgjpegtran -progressive <input.jpg> > <output.jpg> — Convert to progressive JPEG (better for web, loads gradually).
jpegtran -progressive photo.jpg > progressive.jpgjpegtran -optimize -progressive <input.jpg> > <output.jpg> — Optimize and convert to progressive (best lossless compression).
jpegtran -optimize -progressive photo.jpg > optimized.jpgjpegtran -copy none -optimize -progressive <input.jpg> > <output.jpg> — Optimize, make progressive, and strip all metadata.
jpegtran -copy none -optimize -progressive photo.jpg > clean.jpgjpegtran -arithmetic <input.jpg> > <output.jpg> — Use arithmetic coding (smaller files, limited browser support).
jpegtran -arithmetic photo.jpg > arithmetic.jpgRotation (Lossless)
jpegtran -rotate 90 <input.jpg> > <output.jpg> — Rotate 90 degrees clockwise (lossless).
jpegtran -rotate 90 photo.jpg > rotated.jpgjpegtran -rotate 180 <input.jpg> > <output.jpg> — Rotate 180 degrees (lossless).
jpegtran -rotate 180 photo.jpg > rotated.jpgjpegtran -rotate 270 <input.jpg> > <output.jpg> — Rotate 270 degrees / 90 counter-clockwise (lossless).
jpegtran -rotate 270 photo.jpg > rotated.jpgjpegtran -rotate 90 -trim <input.jpg> > <output.jpg> — Rotate and trim partial MCU blocks at edges (avoids green edge artifacts).
jpegtran -rotate 90 -trim photo.jpg > rotated.jpgjpegtran -rotate 90 -perfect <input.jpg> > <output.jpg> — Rotate only if it can be done perfectly (fail if dimensions not MCU-aligned).
jpegtran -rotate 90 -perfect photo.jpg > rotated.jpgFlip (Lossless)
jpegtran -flip horizontal <input.jpg> > <output.jpg> — Mirror horizontally (lossless).
jpegtran -flip horizontal photo.jpg > mirrored.jpgjpegtran -flip vertical <input.jpg> > <output.jpg> — Mirror vertically (lossless).
jpegtran -flip vertical photo.jpg > flipped.jpgjpegtran -transpose <input.jpg> > <output.jpg> — Transpose (mirror along top-left to bottom-right diagonal).
jpegtran -transpose photo.jpg > transposed.jpgjpegtran -transverse <input.jpg> > <output.jpg> — Transverse (mirror along top-right to bottom-left diagonal).
jpegtran -transverse photo.jpg > transversed.jpgCrop (Lossless)
jpegtran -crop <width>x<height>+<x>+<y> <input.jpg> > <output.jpg> — Crop a region (coordinates must align to MCU boundaries, usually 8px or 16px).
jpegtran -crop 640x480+0+0 photo.jpg > cropped.jpgjpegtran -crop <width>x<height> <input.jpg> > <output.jpg> — Crop from the top-left corner.
jpegtran -crop 800x600 photo.jpg > cropped.jpgjpegtran -crop <width>x<height>+<x>+<y> -trim <input.jpg> > <output.jpg> — Crop with trimming to align to MCU boundaries.
jpegtran -crop 500x400+100+50 -trim photo.jpg > cropped.jpgjpegtran -drop +<x>+<y> <overlay.jpg> <input.jpg> > <output.jpg> — Drop (overlay) another JPEG at a position (lossless splice).
jpegtran -drop +0+0 watermark.jpg photo.jpg > watermarked.jpgMetadata Control
jpegtran -copy none <input.jpg> > <output.jpg> — Strip all metadata (EXIF, comments, ICC profiles).
jpegtran -copy none photo.jpg > stripped.jpgjpegtran -copy comments <input.jpg> > <output.jpg> — Keep only comment markers (jpegtran's default), remove EXIF and other markers.
jpegtran -copy comments photo.jpg > clean.jpgjpegtran -copy all <input.jpg> > <output.jpg> — Preserve all extra markers, including EXIF, ICC profile and thumbnails.
jpegtran -copy all photo.jpg > output.jpgjpegtran -copy icc <input.jpg> > <output.jpg> — Keep only ICC color profile, strip EXIF and comments.
jpegtran -copy icc photo.jpg > color-preserved.jpgGrayscale & Color
jpegtran -grayscale <input.jpg> > <output.jpg> — Convert to grayscale (lossless, removes chroma channels).
jpegtran -grayscale photo.jpg > grayscale.jpgjpegtran -grayscale -optimize <input.jpg> > <output.jpg> — Convert to grayscale and optimize (significant size reduction).
jpegtran -grayscale -optimize photo.jpg > bw-optimized.jpgCommon Patterns
for f in *.jpg; do jpegtran -copy none -optimize -progressive "$f" > "opt-$f"; done — Batch optimize all JPEGs in a directory.
for f in *.jpg; do jpegtran -copy none -optimize -progressive "$f" > "opt-$f"; donefind . -name '*.jpg' -exec sh -c 'jpegtran -copy none -optimize -progressive "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {} \; — Recursively optimize all JPEGs in-place.
find . -name '*.jpg' -exec sh -c 'jpegtran -copy none -optimize -progressive "$1" > "$1.tmp" && mv "$1.tmp" "$1"' _ {} \;jpegtran -rotate 90 -copy all -optimize photo.jpg > rotated.jpg — Lossless rotate while preserving metadata and optimizing.
jpegtran -rotate 90 -copy all -optimize photo.jpg > rotated.jpgjpegtran -copy none -optimize -progressive -outfile <output.jpg> <input.jpg> — Use -outfile flag instead of stdout redirection.
jpegtran -copy none -optimize -progressive -outfile optimized.jpg photo.jpg Conclusion
jpegtran shines whenever every bit of quality matters: optimizing, rotating, flipping and cropping all run entirely losslessly, straight on the compressed data. Keep two things in mind, though. First, -copy none strips all metadata – including the EXIF orientation tag and the embedded ICC color profile; with smartphone photos in particular, the result can end up sideways or color-shifted. Use -copy all to keep those markers (the default -copy comments retains only comments). Second, lossless rotation only works cleanly when the image dimensions are divisible by the MCU size (8 or 16 pixels) – otherwise reach for -perfect (which aborts rather than rotating imperfectly) or -trim (which discards the incomplete edge blocks). And don't forget: jpegtran does not work in place but writes its result to stdout or via -outfile – redirect it to a different file, or you risk overwriting your original.
Further Reading
- libjpeg-turbo (GitHub) – source and documentation of the widely used JPEG library that ships jpegtran
- jpegtran(1) man page – complete reference for every command-line option