Anatomy of a UDeep file
A UDeep figure is an ordinary image file with one thing added: a declaration of how its data became the picture, stored where the image format keeps metadata (profile 8.8). Below, the two valid conformance files are taken apart as they are. Both show the same synthetic data, a ramp with one bright spot, 40 by 60 values; the page is made from the files, so it shows what they hold.
A gain-map JPEG
valid.jpg, 5,009 bytes: two JPEG images in one file.
The first is the ordinary figure, which any program shows. The second, after it, is the gain map, which a screen
that can show HDR uses to make the bright parts brighter than white. The declaration is in the first image's XMP
segment, beside the gain map's own description.
the declaration's segmentother metadataimage data
In a figure this small (60 by 40 pixels) the metadata is a large share of the file. In the 18 HDR figures of this site's gallery, the declaration is 1.5 to 1.7 KiB of files from 184 KiB to 1 MiB, under 1 % of each.
The primary image: the ordinary figure
| Part | At byte | Bytes | What it holds |
|---|---|---|---|
SOI | 0 | 2 | start of the primary image |
APP1 | 2 | 1,790 | XMP: the gain map's container description (hdrgm, Container) and the UDeep declaration (profile 8.8) |
APP2 | 1,792 | 36 | ISO 21496-1 gain-map metadata, binary: its version |
APP2 | 1,828 | 90 | Multi-Picture Format index: where the gain-map image starts, and its size |
APP0 | 1,918 | 18 | JFIF header |
SOF0 | 1,936 | 19 | frame: 60 × 40 pixels, 3 components, 8-bit |
DQT | 1,955 | 69 | quantisation table |
DQT | 2,024 | 69 | quantisation table |
DHT | 2,093 | 33 | Huffman table |
DHT | 2,126 | 183 | Huffman table |
DHT | 2,309 | 33 | Huffman table |
DHT | 2,342 | 183 | Huffman table |
SOS | 2,525 | 760 | start of scan, then the coded image data: the picture itself: the fair SDR figure, the one every screen and print shows |
EOI | 3,285 | 2 | end of the primary image |
The gain-map image
| Part | At byte | Bytes | What it holds |
|---|---|---|---|
SOI | 3,287 | 2 | start of the gain-map image |
APP1 | 3,289 | 478 | XMP: the gain map's own parameters (hdrgm) |
APP2 | 3,767 | 93 | ISO 21496-1 gain-map metadata, binary: the gain map's parameters |
APP0 | 3,860 | 18 | JFIF header |
SOF0 | 3,878 | 19 | frame: 60 × 40 pixels, 3 components, 8-bit |
DQT | 3,897 | 69 | quantisation table |
DQT | 3,966 | 69 | quantisation table |
DHT | 4,035 | 33 | Huffman table |
DHT | 4,068 | 183 | Huffman table |
DHT | 4,251 | 33 | Huffman table |
DHT | 4,284 | 183 | Huffman table |
SOS | 4,467 | 540 | start of scan, then the coded image data: the gain map: how much brighter each pixel may be on an HDR screen |
EOI | 5,007 | 2 | end of the gain-map image |
A 16-bit PQ PNG
record.png, 4,603 bytes: the same figure as a data
record, fine enough that it reads back as the data. It has no ordinary SDR picture of its own, so its
declaration names the one that goes with it, by digest.
| Part | At byte | Bytes | What it holds |
|---|---|---|---|
signature | 0 | 8 | the eight bytes every PNG starts with |
IHDR | 8 | 25 | 60 × 40 pixels, 16-bit, RGB |
cICP | 33 | 16 | colour signalling 9, 16, 0, 1: BT.2020 primaries, the PQ transfer function, RGB, full range (profile 9.1) |
iTXt | 49 | 1,261 | XML:com.adobe.xmp, not compressed: the UDeep declaration (profile 8.8), naming its SDR figure (9.1.2) |
IDAT × 1 | 1,310 | 3,281 | the image: PQ codes, 16 bits a channel, deflated |
IEND | 4,591 | 12 | the end |
The declaration
The properties the JPEG declares, in the order the reference writes them, each with its meaning from the namespace page. The PNG's declaration is the same but for what depends on the encoding: the widest step, the rounding against the noise, and that it is a data record.
| Property | Value in valid.jpg | Meaning |
|---|---|---|
udeep:DataUnit | counts | unit of the data values |
udeep:Stretch | linear | linear, log, asinh or proportional |
udeep:RangeLow | 0 | the declared range, in data units after StretchOffset has been subtracted (8.3) |
udeep:RangeHigh | 100 | the declared range, in data units after StretchOffset has been subtracted (8.3) |
udeep:Knee | 50 | data value mapped to diffuse white: the data value itself, before StretchOffset is subtracted (8.3) |
udeep:KneeRule | preset; half of full scale | physical, statistical, preset or percentile, then a description |
udeep:ReferenceHeadroom | 2 | headroom the figure was authored for (linear ratio), greater than 1 |
udeep:MaxDataStep | 0.34332799267566827 | largest Δx_q over the declared range, in data units |
udeep:NoiseModel | constant | constant, poisson, relative, tolerance or unknown (§5.2) |
udeep:NoiseParameter | 1 | the model's parameter (§5.2), greater than zero; required unless the model is unknown, and absent then |
udeep:StretchWidth | 1 | the asinh width |
udeep:StretchOffset | 0 | the value subtracted from the data before the stretch |
udeep:AboveKnee | hermite; exit=1 | form of the segment above the knee, with its parameters: hermite; exit=s (§6.7) |
udeep:Masked | 0 | number of pixels in the validity mask |
udeep:DerivedMasked | 0 | the number of pixels that rule holds at white, beyond the validity mask |
udeep:Record | rendering | data-record or rendering (§7.3) |
udeep:Preset | extend | optional: highlight, extend or another named preset (informative) |
udeep:ColourMap | fire/3 | the map from light to colour (§6.10): grey, or a registered map as name/version (for example fire/2) |
udeep:RoundingToNoise | 0.09911025449581548 | optional: the worst value over the declared range of the rounding error divided by the stated uncertainty (§7.2.1); omitted when the noise model is unknown |
udeep:DataDigest | sha256:c9f0ab72273ef44158a82022efea27d2c6124fd266da4210d7107fcd07c7e0c3 | optional: the digest of the array that was mapped, as defined in 8.6 |
udeep:DataSource | doi:10.0000/udeep-conformance-example | optional: where the data is kept: doi:… where the data has one, otherwise a URL, otherwise a description; several are separated by ; |
udeep:SdrDigest | sha256:4242032dcdc7fe5a08c277a0807c36a9774468b1e9d428752427eafbbc994de8 | optional, except in a file with no SDR base of its own, which MUST declare it (9.1.2): the digest of the fair SDR rendering's 8-bit RGB pixels, before any lossy coding, as defined in 8.6 |
udeep:DataDigestSha3 | sha3-256:7c72d7eb969b2ea7f559bf2ef3d48639378d03090d73cbc3f2c6025f4cb95d93 | optional, and only with DataDigest: the same bytes digested with SHA3-256 (8.6), a hash function of another design, so that the link to the data holds if either function is ever broken |
udeep:SdrDigestSha3 | sha3-256:8871bba8d6001e8f0525634bd1a8c8c8bc1b2b011fe3ca097799394f33099dce | optional, and only with SdrDigest: the SDR figure's bytes digested with SHA3-256 (8.6) |
udeep:Version | 0.3 | profile version, "0.3" |
udeep:ImageState | data-referred | data-referred |
The whole XMP packet, one attribute to a line
<x:xmpmeta
xmlns:x="adobe:ns:meta/"
x:xmptk="udeep">
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description
rdf:about=""
xmlns:Container="http://ns.google.com/photos/1.0/container/"
xmlns:Item="http://ns.google.com/photos/1.0/container/item/"
xmlns:hdrgm="http://ns.adobe.com/hdr-gain-map/1.0/"
hdrgm:Version="1.0"><Container:Directory><rdf:Seq><rdf:li
rdf:parseType="Resource"><Container:Item
Item:Semantic="Primary"
Item:Mime="image/jpeg"/></rdf:li><rdf:li
rdf:parseType="Resource"><Container:Item
Item:Semantic="GainMap"
Item:Mime="image/jpeg"
Item:Length="1722"/></rdf:li></rdf:Seq></Container:Directory></rdf:Description>
<rdf:Description
rdf:about=""
xmlns:udeep="https://ultradeeprange.github.io/udeep/ns/0.3/"
udeep:DataUnit="counts"
udeep:Stretch="linear"
udeep:RangeLow="0"
udeep:RangeHigh="100"
udeep:Knee="50"
udeep:KneeRule="preset; half of full scale"
udeep:ReferenceHeadroom="2"
udeep:MaxDataStep="0.34332799267566827"
udeep:NoiseModel="constant"
udeep:NoiseParameter="1"
udeep:StretchWidth="1"
udeep:StretchOffset="0"
udeep:AboveKnee="hermite; exit=1"
udeep:Masked="0"
udeep:DerivedMasked="0"
udeep:Record="rendering"
udeep:Preset="extend"
udeep:ColourMap="fire/3"
udeep:RoundingToNoise="0.09911025449581548"
udeep:DataDigest="sha256:c9f0ab72273ef44158a82022efea27d2c6124fd266da4210d7107fcd07c7e0c3"
udeep:DataSource="doi:10.0000/udeep-conformance-example"
udeep:SdrDigest="sha256:4242032dcdc7fe5a08c277a0807c36a9774468b1e9d428752427eafbbc994de8"
udeep:DataDigestSha3="sha3-256:7c72d7eb969b2ea7f559bf2ef3d48639378d03090d73cbc3f2c6025f4cb95d93"
udeep:SdrDigestSha3="sha3-256:8871bba8d6001e8f0525634bd1a8c8c8bc1b2b011fe3ca097799394f33099dce"
udeep:Version="0.3"
udeep:ImageState="data-referred"/>
</rdf:RDF>
</x:xmpmeta>Where it must be, and what a reader does
- One declaration a file, in one XMP packet. A reader takes it only from the place below, and refuses a file that holds two.
- In a gain-map JPEG, the primary image's XMP segment (APP1), never the gain-map image's. One segment holds at most 65,533 bytes; this declaration is 1,757 bytes with its packet.
- In a PNG, an
iTXtchunk namedXML:com.adobe.xmp, not compressed, before the image data. In an SVG, the<metadata>element. - Properties are written as attributes; a reader also takes them written as elements, as other XMP tools may rewrite them.
- A signature, when there is one, is added after the declaration, so that it covers it.
The conformance files break these rules one at a time, with the verdict a validator must give.