UDeep

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

PartAt byteBytesWhat it holds
SOI02start of the primary image
APP121,790XMP: the gain map's container description (hdrgm, Container) and the UDeep declaration (profile 8.8)
APP21,79236ISO 21496-1 gain-map metadata, binary: its version
APP21,82890Multi-Picture Format index: where the gain-map image starts, and its size
APP01,91818JFIF header
SOF01,93619frame: 60 × 40 pixels, 3 components, 8-bit
DQT1,95569quantisation table
DQT2,02469quantisation table
DHT2,09333Huffman table
DHT2,126183Huffman table
DHT2,30933Huffman table
DHT2,342183Huffman table
SOS2,525760start of scan, then the coded image data: the picture itself: the fair SDR figure, the one every screen and print shows
EOI3,2852end of the primary image

The gain-map image

PartAt byteBytesWhat it holds
SOI3,2872start of the gain-map image
APP13,289478XMP: the gain map's own parameters (hdrgm)
APP23,76793ISO 21496-1 gain-map metadata, binary: the gain map's parameters
APP03,86018JFIF header
SOF03,87819frame: 60 × 40 pixels, 3 components, 8-bit
DQT3,89769quantisation table
DQT3,96669quantisation table
DHT4,03533Huffman table
DHT4,068183Huffman table
DHT4,25133Huffman table
DHT4,284183Huffman table
SOS4,467540start of scan, then the coded image data: the gain map: how much brighter each pixel may be on an HDR screen
EOI5,0072end 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.

PartAt byteBytesWhat it holds
signature08the eight bytes every PNG starts with
IHDR82560 × 40 pixels, 16-bit, RGB
cICP3316colour signalling 9, 16, 0, 1: BT.2020 primaries, the PQ transfer function, RGB, full range (profile 9.1)
iTXt491,261XML:com.adobe.xmp, not compressed: the UDeep declaration (profile 8.8), naming its SDR figure (9.1.2)
IDAT × 11,3103,281the image: PQ codes, 16 bits a channel, deflated
IEND4,59112the 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.

PropertyValue in valid.jpgMeaning
udeep:DataUnitcountsunit of the data values
udeep:Stretchlinearlinear, log, asinh or proportional
udeep:RangeLow0the declared range, in data units after StretchOffset has been subtracted (8.3)
udeep:RangeHigh100the declared range, in data units after StretchOffset has been subtracted (8.3)
udeep:Knee50data value mapped to diffuse white: the data value itself, before StretchOffset is subtracted (8.3)
udeep:KneeRulepreset; half of full scalephysical, statistical, preset or percentile, then a description
udeep:ReferenceHeadroom2headroom the figure was authored for (linear ratio), greater than 1
udeep:MaxDataStep0.34332799267566827largest Δx_q over the declared range, in data units
udeep:NoiseModelconstantconstant, poisson, relative, tolerance or unknown (§5.2)
udeep:NoiseParameter1the model's parameter (§5.2), greater than zero; required unless the model is unknown, and absent then
udeep:StretchWidth1the asinh width
udeep:StretchOffset0the value subtracted from the data before the stretch
udeep:AboveKneehermite; exit=1form of the segment above the knee, with its parameters: hermite; exit=s (§6.7)
udeep:Masked0number of pixels in the validity mask
udeep:DerivedMasked0the number of pixels that rule holds at white, beyond the validity mask
udeep:Recordrenderingdata-record or rendering (§7.3)
udeep:Presetextendoptional: highlight, extend or another named preset (informative)
udeep:ColourMapfire/3the map from light to colour (§6.10): grey, or a registered map as name/version (for example fire/2)
udeep:RoundingToNoise0.09911025449581548optional: 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:DataDigestsha256:c9f0ab72273ef44158a82022efea27d2c6124fd266da4210d7107fcd07c7e0c3optional: the digest of the array that was mapped, as defined in 8.6
udeep:DataSourcedoi:10.0000/udeep-conformance-exampleoptional: where the data is kept: doi:… where the data has one, otherwise a URL, otherwise a description; several are separated by ;
udeep:SdrDigestsha256:4242032dcdc7fe5a08c277a0807c36a9774468b1e9d428752427eafbbc994de8optional, 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:DataDigestSha3sha3-256:7c72d7eb969b2ea7f559bf2ef3d48639378d03090d73cbc3f2c6025f4cb95d93optional, 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:SdrDigestSha3sha3-256:8871bba8d6001e8f0525634bd1a8c8c8bc1b2b011fe3ca097799394f33099dceoptional, and only with SdrDigest: the SDR figure's bytes digested with SHA3-256 (8.6)
udeep:Version0.3profile version, "0.3"
udeep:ImageStatedata-referreddata-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 iTXt chunk named XML: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.