# JPEG 2000

Canonical URL: https://encode.wiki/codecs/images/jpeg2000/
Content version: ca42e61ede0a24f789d7287a0001244ad22f4abf
Status: current
License: CC BY-SA 4.0
Checksum (SHA-256): e9b5d4eddc1ed34e7d2dca3aa0bfeb0c94ea3ec389513ed91f8868ad308de376

JPEG 2000 (ISO/IEC 15444, 2000) replaces JPEG's 8×8 DCT with a wavelet transform. One codestream can be lossless or lossy, decodes at lower resolutions or quality layers by simply reading less of the file, and has no block artefacts (it blurs at low rates instead). Only Safari ever displayed it, and Safari 18 dropped it. Nothing about it beats modern formats for photo delivery, but it is firmly established in a few places.

## Where it is still used

- **Digital cinema**: the DCI specification mandates JPEG 2000 for the picture in a DCP. Containers are 2048×1080 (2K, 24 or 48 fps) or 4096×2160 (4K, 24 fps), 12 bits per sample, with a ceiling of 250 Mbit/s. That is a lossy, "visually lossless" encode, not mathematically lossless.
- **Medical imaging**: DICOM defines JPEG 2000 transfer syntaxes, including a lossless-only one.
- **Archives and libraries**: JP2 is used for lossless masters and access copies of scans; the resolution scalability suits large images.
- **Geospatial and satellite imagery**: huge images with random-access decoding, usually through GDAL.

For anything else, use [JPEG](/codecs/images/jpeg/), [AVIF](/codecs/images/avif/), [WebP](/codecs/images/webp/) or [JPEG XL](/codecs/images/jxl/). No current browser decodes JPEG 2000.

## Formats and variants

| Piece | What it is |
| --- | --- |
| `.j2k` / `.j2c` | Raw codestream, no colour or metadata boxes |
| `.jp2` | Part 1 file wrapper with colour space/ICC and channel definitions (use this by default) |
| JPX (Part 2) | Extensions: extended colour, multiple codestreams. Many decoders do not read it |
| MJ2 (Part 3) | Motion JPEG 2000, a sequence of independently coded frames |
| HTJ2K (Part 15) | High Throughput block coder, much faster to encode and decode; can be converted to and from classic Part 1 codestreams without loss. Older decoders cannot read it |

Lossless coding uses the reversible 5/3 wavelet; lossy uses the irreversible 9/7. Bit depth and component sampling are per component, so 16-bit, 4:2:0 and more are all legal.

## Encoders

| Tool | Notes |
| --- | --- |
| [OpenJPEG](https://www.openjpeg.org/) | BSD-licensed reference software; `opj_compress`/`opj_decompress`. Latest release 2.5.4 (September 2025); the repository's README now describes it as unmaintained. This is what ImageMagick, GDAL and FFmpeg's `libopenjpeg` wrapper use. |
| [Kakadu](https://kakadusoftware.com/) | Commercial SDK (`kdu_compress`) with the most complete feature set and HTJ2K. |
| [Grok](https://github.com/GrokImageCompression/grok) | AGPL-3.0 codec with HTJ2K, random-access decoding and a transcoder; integrated into GDAL. |
| [OpenJPH](https://github.com/aous72/OpenJPH) | HTJ2K only. |
| FFmpeg | Native `jpeg2000` encoder and the `libopenjpeg` wrapper. |

DCP mastering needs more than a JPEG 2000 file (X′Y′Z′ conversion, MXF wrapping, naming, subtitles and audio). Use a DCP tool such as [DCP-o-matic](https://dcpomatic.com/) instead of encoding frames by hand.

## OpenJPEG commands

Lossless JP2 from a PNG, TIFF, PPM or BMP input:

```sh
opj_compress -i input.png -o output.jp2
opj_decompress -i output.jp2 -o restored.png
```

The default is lossless (reversible 5/3, one layer). For lossy, switch to the irreversible transform and give a compression ratio:

```sh
opj_compress -i input.png -o output.jp2 -I -r 20
```

| Option | What it does |
| --- | --- |
| `-r 20` | Target compression ratio (source size divided by output size), not a quality score. A comma list such as `-r 20,10,1` makes quality layers; a final `1` keeps all coded data (lossless only with the reversible transform). |
| `-q 40` | Target PSNR in dB per layer. It steers rate allocation and says little about how the image looks; `-r` is easier to reason about. |
| `-I` | Irreversible 9/7 wavelet. Lossy even without rate limits. |
| `-n 6` | Resolution levels (default 6). Lower it for small images, otherwise the encode fails with "Number of resolutions is too high". |
| `-p RPCL` | Packet order. `RPCL` suits progressive-by-resolution delivery; the default `LRCP` is progressive by quality. |
| `-t 1024,1024` | Tile size. Tiling enables partial decoding of huge images but costs some efficiency. |
| `-threads ALL_CPUS` | Multithreaded encode. |

Decoding at reduced size is cheap: `opj_decompress -i big.jp2 -o half.png -r 1` skips the highest resolution level.

FFmpeg works for single frames and sequences: `ffmpeg -i input.png -c:v jpeg2000 output.jp2` (native) or `-c:v libopenjpeg`.

## Pitfalls

- **Compression ratio, not quality**: `-r` and `-q` are rate targets. Judge lossy output by eye or with [SSIMULACRA2](/reference/metrics/ssimulacra2/), not by the PSNR you asked for.
- **Profile mismatches**: a lossless JP2 does not make a DCI or IMF delivery. Those profiles restrict size, precision, colour and rate. `opj_compress` has `-cinema2K`, `-cinema4K` and `-IMF` switches that enforce parts of them, but they are not a full DCP workflow.
- **Decoder support**: JPX extensions and HTJ2K are not read by every decoder. For long-term archives, stay with plain Part 1 JP2.
- **Raw codestreams** (`.j2k`) carry no ICC profile. Use `.jp2` when colour matters.
- **Invalid options are not fatal**: `opj_compress` prints a warning, ignores the option and encodes anyway, so read its output.

## Full option reference

This table lists every option and default for OpenJPEG 2.5.4. The sections above are the practical summary. [Reading option tables](/reference/encoder-parameters/) explains the Default column.

## OpenJPEG opj_compress parameters

Defaults are for the ordinary profile; the cinema and IMF profiles override some of them. Informational options and paths have no numeric default. `opj_compress -h` prints the option list and exits with status 1.

<details>
<summary>All OpenJPEG opj_compress parameters and defaults</summary>

| Parameter / aliases     | Type / syntax                                 | Default                                                | Effect and limits                                                                                                                                                 |
| ----------------------- | --------------------------------------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-i`                    | file path                                     | required unless -ImgDir                                | Input image; the extension selects the reader (PNM, PGX, PNG, BMP, TIFF, RAW, RAWL, TGA). RAW and RAWL need -F.                                                   |
| `-o`                    | file path                                     | required with -i                                       | Output file: .jp2 writes a JP2 container, .j2k or .j2c a raw codestream.                                                                                          |
| `-ImgDir`               | directory path                                | unset                                                  | Encode every image in this directory. Needs -OutFor; excludes -i and -o.                                                                                          |
| `-OutFor`               | enum                                          | required with -ImgDir                                  | Output suffix for -ImgDir batches: JP2, J2K or J2C.                                                                                                               |
| `-F`                    | raw geometry descriptor                       | required for RAW/RAWL; sampling 1x1 if omitted         | Raw input layout: width,height,components,bitdepth,s or u, then optional @dxXdy per component. Required for RAW and RAWL.                                         |
| `-h`                    | action                                        | not requested                                          | Print the help text and exit with status 1.                                                                                                                       |
| `-r`                    | decreasing number list                        | one untruncated layer (internal rate 0)                | Target compression ratio per quality layer, in decreasing order; a final 1 means all data. Excludes -q.                                                           |
| `-q`                    | increasing number list, dB                    | unset                                                  | Target PSNR in dB per quality layer, in increasing order; a final 0 means lossless. Excludes -r.                                                                  |
| `-n`                    | integer                                       | 6                                                      | Resolution levels (DWT decompositions plus one), 1–33; limited by tile size.                                                                                      |
| `-TargetBitDepth`, `-X` | positive integer                              | 0 (keep input precision)                               | Reduce TIFF input to this many bits per component. Other input formats ignore it.                                                                                 |
| `-b`                    | width,height                                  | 64,64                                                  | Code-block width,height: powers of two from 4 to 1024, with area at most 4096.                                                                                    |
| `-c`                    | precinct-size list                            | 32768x32768 at each resolution                         | Precinct sizes as [w,h] pairs (powers of two), highest resolution first; the last pair is halved for each lower level.                                            |
| `-t`                    | width,height                                  | one tile covering the image                            | Tile width,height. Choose -n so the smallest tile still fits all levels.                                                                                          |
| `-p`                    | enum                                          | LRCP                                                   | Packet progression order: LRCP, RLCP, RPCL, PCRL or CPRL.                                                                                                         |
| `-s`                    | dx,dy                                         | 1,1                                                    | Reference-grid subsampling dx,dy; it does not resize the image. Values above 2 may error.                                                                         |
| `-POC`, `-P`            | progression-change list                       | unset                                                  | Progression-order changes as Tn=resStart,compStart,layerEnd,resEnd,compEnd,order, joined by /. Tile numbers start at 1.                                           |
| `-SOP`, `-S`            | flag                                          | disabled                                               | Write a start-of-packet marker before each packet, for error resilience.                                                                                          |
| `-EPH`, `-E`            | flag                                          | disabled                                               | Write an end-of-packet-header marker after each packet header.                                                                                                    |
| `-PLT`                  | flag                                          | disabled                                               | Write packet-length (PLT) markers in tile-part headers, for random access.                                                                                        |
| `-TLM`                  | flag                                          | disabled                                               | Write tile-part-length (TLM) markers in the main header.                                                                                                          |
| `-M`                    | integer bitmask                               | 0                                                      | Code-block mode bitmask: 1 bypass, 2 reset, 4 terminate each pass, 8 vertical causal, 16 predictable termination, 32 segmentation symbols. Add values to combine. |
| `-TP`, `-u`             | enum                                          | disabled                                               | Split each tile into tile-parts by resolution (R), layer (L) or component (C).                                                                                    |
| `-ROI`, `-R`            | component index and upshift                   | disabled (component index -1)                          | c=component,U=shift (0–37): upshift one whole component. Not a spatial region of interest.                                                                        |
| `-d`                    | x,y                                           | 0,0                                                    | Image origin x,y on the reference grid.                                                                                                                           |
| `-T`                    | x,y                                           | 0,0                                                    | Tile-grid origin x,y; neither value may exceed the image origin.                                                                                                  |
| `-I`                    | flag                                          | disabled (reversible 5/3 transform)                    | Use the lossy irreversible 9/7 wavelet instead of the reversible 5/3.                                                                                             |
| `-mct`, `-Y`            | integer enum                                  | 1 for at least 3 components; otherwise 0               | Component transform: 0 none, 1 RGB to YCC, 2 custom matrix (needs -m, which does not work). Subsampled RAW forces 0.                                              |
| `-m`                    | file path                                     | unset (option not registered)                          | Custom MCT matrix file. Listed in the help but missing from the option string, so it is rejected as invalid.                                                      |
| `-cinema2K`             | integer enum                                  | disabled                                               | Digital Cinema 2K profile at 24 or 48 fps; overrides other coding options.                                                                                        |
| `-cinema4K`             | flag                                          | disabled; profile assumes 24 fps when selected         | Digital Cinema 4K profile at 24 fps; overrides other coding options.                                                                                              |
| `-IMF`                  | profile descriptor                            | disabled; mainlevel 0, sublevel 0, no frame-rate limit | IMF profile 2K, 4K, 8K or the _R variants, with optional mainlevel (0–11), sublevel (0–9) and framerate.                                                          |
| `-GuardBits`, `-G`      | integer                                       | automatic: 2 ordinarily, 1 for cinema 2K               | Quantization guard bits, 0–7. The default is 2, or 1 for cinema 2K.                                                                                               |
| `-jpip`, `-J`           | flag                                          | disabled                                               | Add a JPIP index box to JP2 output; the help says it supports only RPCL order.                                                                                    |
| `-C`                    | string                                        | generated OpenJPEG version comment                     | Comment text for the COM marker, replacing the generated OpenJPEG comment.                                                                                        |
| `-threads`              | integer or ALL_CPUS                           | 0 (no workers unless OPJ_NUM_THREADS overrides)        | Encoder thread count or ALL_CPUS. OPJ_NUM_THREADS sets the default. Needs a threaded build.                                                                       |
| `-f`                    | legacy integer matrix string                  | disabled                                               | Hidden legacy fixed-layer allocation matrix. Fragile; use -r or -q instead.                                                                                       |
| `-x`                    | file path (ignored)                           | unset                                                  | Index file path. Ignored with a warning because index generation is broken.                                                                                       |
| `-W`                    | JPWL comma-separated descriptor (conditional) | disabled (needs USE_JPWL)                              | JPWL error-protection descriptor. Needs a build with USE_JPWL.                                                                                                    |

</details>

`-m` appears in the help and has a source branch but is missing from the registered option string, so it prints `Invalid option m` and is ignored. `-mct 2` (custom matrix) is therefore not usable. `-x` warns that index generation is broken and ignores its path. Neither is fatal, so read the log. The help says code blocks are limited to 64×64, but any power-of-two shape with area up to 4,096 (for example 128×32) works. `OPJ_NUM_THREADS` sets the default worker count when threading is built in; a positive `-threads` overrides it.
