diff --git a/README.rst b/README.rst index 60b90c5..e7c718a 100644 --- a/README.rst +++ b/README.rst @@ -66,6 +66,7 @@ Image - **xcf** - ``image/x-xcf`` - **jpg** - ``image/jpeg`` - **jpx** - ``image/jpx`` +- **jxl** - ``image/jxl`` - **png** - ``image/png`` - **apng** - ``image/apng`` - **gif** - ``image/gif`` @@ -161,7 +162,7 @@ Font - **otf** - ``application/font-sfnt`` Application -^^^^^^^^^^^ +^^^^^^^^^^^ - **wasm** - ``application/wasm`` diff --git a/filetype/types/__init__.py b/filetype/types/__init__.py index 4d5a516..f449e86 100644 --- a/filetype/types/__init__.py +++ b/filetype/types/__init__.py @@ -17,6 +17,7 @@ image.Xcf(), image.Jpeg(), image.Jpx(), + image.Jxl(), image.Apng(), image.Png(), image.Gif(), diff --git a/filetype/types/image.py b/filetype/types/image.py index d55fce6..52502a1 100644 --- a/filetype/types/image.py +++ b/filetype/types/image.py @@ -48,6 +48,38 @@ def match(self, buf): ) +class Jxl(Type): + """ + Implements the JPEG XL image type matcher. + """ + + MIME = "image/jxl" + EXTENSION = "jxl" + + def __init__(self): + super(Jxl, self).__init__(mime=Jxl.MIME, extension=Jxl.EXTENSION) + + def match(self, buf): + return ( + (len(buf) > 1 and + buf[0] == 0xFF and + buf[1] == 0x0A) or + (len(buf) > 11 and + buf[0] == 0x00 and + buf[1] == 0x00 and + buf[2] == 0x00 and + buf[3] == 0x00 and + buf[4] == 0x0C and + buf[5] == 0x4A and + buf[6] == 0x58 and + buf[7] == 0x4C and + buf[8] == 0x20 and + buf[9] == 0x0D and + buf[10] == 0x87 and + buf[11] == 0x0A) + ) + + class Apng(Type): """ Implements the APNG image type matcher. diff --git a/tests/fixtures/sample.jxl b/tests/fixtures/sample.jxl new file mode 100644 index 0000000..993cd6c Binary files /dev/null and b/tests/fixtures/sample.jxl differ diff --git a/tests/test_types.py b/tests/test_types.py index 6b1031f..a69ff0a 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -32,6 +32,12 @@ def test_guess_jpx(self): self.assertEqual(kind.mime, 'image/jpx') self.assertEqual(kind.extension, 'jpx') + def test_guess_jxl(self): + kind = filetype.guess(FIXTURES + '/sample.jxl') + self.assertTrue(kind is not None) + self.assertEqual(kind.mime, 'image/jxl') + self.assertEqual(kind.extension, 'jxl') + def test_guess_gif(self): kind = filetype.guess(FIXTURES + '/sample.gif') self.assertTrue(kind is not None) @@ -56,7 +62,6 @@ def test_guess_m4a(self): self.assertEqual(kind.mime, 'audio/mp4') self.assertEqual(kind.extension, 'm4a') - def test_guess_mp4(self): kind = filetype.guess(FIXTURES + '/sample.mp4') self.assertTrue(kind is not None)