JPEG XL codestream media type and extension

ghost created this issue on 2021-04-07 · The issue is replied 18 times

JXL support is added in 12.23, and the code lists 2 types of JXL.
The code uses "JXC" and "image/x-jxc" for JPEG XL codestream type. These 2 values are invented and not a real extension and MIME type.

I asked @jonsneyers (JXL developer), and he said:

There is only image/jxl, which can be either a container containing a jxl codestream or just a jxl codestream.

There is no distinction in media type or extension between the with-container and without-container type (also not between lossless and lossy, animated and still, etc).

boardhead wrote this answer on 2021-04-07

Thanks. I understand this. I haven't yet figured out how to deal with two file types having the same extension. This is one of the reasons that JPEG XL support is currently considered experimental.

boardhead wrote this answer on 2021-04-07

Note that ExifTool only has write support for the ISO BMFF flavour.

ghost wrote this answer on 2021-04-07

Note that ExifTool only has write support for the ISO BMFF flavour.

Interestingly, Exiv2 (which recently has added support for JXL/bmff) only has read (but disabled by default) support for ISO BMFF.

I was told that BMFF is just a simple container format and thus there are no patent concerns.

jonsneyers wrote this answer on 2021-04-10

It's a single file type, it just happens to have two signatures.

If you have a naked codestream, it cannot have exif/xmp metadata. But you could add it, by simply wrapping the codestream in a container. This is as easy as just adding the isobmf signature (including the ftyp box) and making a jxlc box that contains the naked codestream. Then you can add an Exif box or xml box too.

Semantically, there is supposed to be no difference at all between a naked codestream and a codestream wrapped in an isobmff container — the only difference is a few dozen bytes of container overhead, and the fact that you can add other boxes when using the isobmff container.

boardhead wrote this answer on 2021-04-11

Thanks. I understand this. The problem is that I need to patch ExifTool specifically to be able to handle calling two different decoding functions for the same file type. And since ExifTool can only add metadata to one type, I need to figure out how the user can determine which type of file he has if they both have the same file type. Maybe you see the dilemma.

boardhead wrote this answer on 2021-04-11

Oh. I see. You are suggesting that I wrap the codestream in an ISO BMFF container to allow writing bare codestream files. Arg. This would be an ugly hack to the ISO BMFF code. And I don't like the idea of changing the file package without user consent, so the default would have to be to issue a warning and fail. But this may be do-able.

boardhead wrote this answer on 2021-04-13

I've just released ExifTool 12.24 which does the following:

  1. Changes the MIMEType to "image/jxl" for both flavours of JXL files.
  2. Sets FileType to "JXL Codestream" for JXL codestream files, and just "JXL" for ISO BMFF files (with suggested extensions of "JXL" for both).
  3. Issues a minor error when attempting to write JXL codestream files. If minor errors are ignored (-m option), issues a warning and wraps the JXL codestream in an ISO BMFF container.

I'm happy with this. I hope it is satisfactory.

But the JPEG XL support still needs to address a couple of issues before I remove the "experimental" status:

A. I don't know if the ImageWidth and ImageHeight are being properly decoded from the JXL codestream. I need an image of known dimensions to be able to verify this. (I can't run the JXL reference software on any of my systems.)
B. What is the 'jbrd' box I see in the JXL ISO BMFF sample I have obtained? When I wrap a bare JXL codestream in an ISO BMFF container, I am only creating a 'jxlc' box. So hopefully the 'jbrd' box is optional.

  • Phil
ghost wrote this answer on 2021-04-14

What is the 'jbrd' box I see in the JXL ISO BMFF sample I have obtained?

From Image Metadata and Exiv2 Architecture by Robin Mills:

Name ISO/IEC Specification Purpose
JXL 18181-2 9.1 File identifier
ftyp 15444-2 4.3.2 File type
Exif 18181-2 9.4 Embedded Tiff containing Exif metadata
xml 15444-2 8.11.1.2 XML (which is XMP)
jbrd 18181-2 JPEG Bitstream Reconstruction Data
jxlc 18181-2 9.8 JXL Code Stream

You can convert JPG to JXL losslessly (cjxl image.jpg image.jxl), and it is possible to get the original file back (djxl image.jxl image_1.jpg).
image.jpg and image_1.jpg will be bit-by-bit the same, i.e. their file checksums will be the same.

Thus we have jbrd (JPEG Bitstream Reconstruction Data).

ghost wrote this answer on 2021-04-14

I need an image of known dimensions

Reagan.zip in this comment contains Reagan.jxl and the dimension is 200x130.

boardhead wrote this answer on 2021-04-15

200x130. Darn. ExifTool isn't decoding this properly. I suspected this. Honestly, the documentation sucks, and the reference implementation is impossible to follow. I've already spent a number of hours this reading documentation and following through the reference code, but something is still wrong. My reading is that the size header should be (binary):

0 00 010000001 000 00 011000111
small=0, ysize_minus_1=129(select 9 bits), ratio=0, xsize_minus_1=199(select 9 bits)

but in this file it seems to be (if I am looking in the right place):

0 00 010000000 010
small=0, ysize_minus_1=128(select 9 bits), ratio=2(12/10)
...which gives an image size of 154x129.

If anyone can give a specific example of how to extract the size from this image, please let me know.

ghost wrote this answer on 2021-04-15

I also cannot follow the documentation and reference implementation. I read this document and tried to figure out the values, and I also get the incorrect result 154x129.

A more readable and easy-to-follow documentation would be nice.

e.g. This website explains the structure of ZIP file, and it has a sample ZIP file, prints the header, and it has images so that you can understand the structure easily.

I hope there will be something similar for JXL so that we can easily understand the (header) structure!

jan-wassenberg wrote this answer on 2021-04-15

Hi @boardhead , @jo620kix ,
unfortunately the final bitstream changed from the committee draft linked above.
SizeHeader starts 16 bits into the codestream, is that where you were looking?

We can offer a debug tool built into the decoder, if you don't mind recompiling from source?
In fields.h changing PrintRead to return true causes djxl Reagan.jxl to print the following:

SizeHeader
    u(1) = 0
    U32 = 130
    u(3) = 0
    U32 = 200

small=false, then we send 129 and the +1 gets added on top to obtain ysize 130; ratio=0 (the 3-bit "u(3)") so the xsize is signaled directly instead of computed as a ratio, and we send 199 and again get the +1 added.

(The +1 is because SizeHeader::VisitFields specifies e.g. BitsOffset(9,1) which means read 9 bits and add one to the result.)

Hope this helps?

boardhead wrote this answer on 2021-04-15

@jan-wassenberg Thanks! This gets me closer (must add 2, not 1 to the ysize_minus_one value). I am looking 16 bits into the codestream, so that is good. The start of the codestream is (hex):

ff 0a 08 04 8e 81 10 4e 19 06 4c 00 40 00 40 80

So the size header is

08 04 8e (hex)
0000100000000100 (binary)

which breaks down to
0 - small (false)
00 - select 9-bit integer
010000000 - 9-bit integer ysize_minus_1 (=128) --> plus 2 gives ysize=130
010 - ratio = 2 (12/10 aspect)

The remaining problem is that the 3-bit ratio is 010, not 000. Somehow some bits got misplaced. :/

veluca93 wrote this answer on 2021-04-15

The reason for the discrepancy is that bits are consumed from the least significant bit. So, in this case, we can write 08 04 8e as 000100000010000001110001 in binary (with lsb-bit-first), which breaks down to:

0 - small (false)
00 - 9-bit integer decreased by 1
100000010 - bit-reversed ysize_ - 1 = 129 -> ysize_ = 130
000 - ratio (0)
etc..

boardhead wrote this answer on 2021-04-15

That did it! Bits are LSB-first.
Thanks @veluca93

boardhead wrote this answer on 2021-04-15

OK. As a check, what do you get for 20200717_221452.jxl from here?:

https://cloud.reflexion.tv/nextcloud/index.php/s/tQpN2gp8eZtnrmT

ExifTool now returns height=6016, width=4000 for this one

veluca93 wrote this answer on 2021-04-15

That seems indeed correct :)

boardhead wrote this answer on 2021-04-15

Excellent, thanks! So I'll close this issue and remove the "experimental" status from the ExifTool JPEG XL support in the next release. The only difference from the current version (12.24) will be that ImageWidth and ImageHeight will be decoded properly. Metadata reading/writing seems to work fine as far as I can tell.

🤔
Didn't find what you were looking for ?
Create your own issue
More Details About Repo
Owner Name exiftool
Repo Name exiftool
Full Name exiftool/exiftool
Language Perl
Created Date 2018-05-09
Updated Date 2022-01-14
Star Count 1258
Watcher Count 40
Fork Count 175
Issue Count 18

YOU MAY BE INTERESTED

Issue Title State Comments Created Date Updated Date Closed Date