Skip to content

Commit efcfdb5

Browse files
committed
Add JpegXLDecompressor wrapper
1 parent fd5a279 commit efcfdb5

File tree

3 files changed

+212
-0
lines changed

3 files changed

+212
-0
lines changed

src/librawspeed/decompressors/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ FILE(GLOB SOURCES
2626
"JpegDecompressor.cpp"
2727
"JpegDecompressor.h"
2828
"JpegMarkers.h"
29+
"JpegXLDecompressor.cpp"
30+
"JpegXLDecompressor.h"
2931
"KodakDecompressor.cpp"
3032
"KodakDecompressor.h"
3133
"LJpegDecoder.cpp"
@@ -80,4 +82,8 @@ if(WITH_JPEG AND TARGET JPEG::JPEG)
8082
target_link_libraries(rawspeed_decompressors PUBLIC JPEG::JPEG)
8183
endif()
8284

85+
if(WITH_JXL AND TARGET JXL::jxl)
86+
target_link_libraries(rawspeed_decompressors PUBLIC JXL::jxl)
87+
endif()
88+
8389
target_link_libraries(rawspeed PRIVATE rawspeed_decompressors)
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
RawSpeed - RAW file decoder.
3+
4+
Copyright (C) 2009-2014 Klaus Post
5+
Copyright (C) 2017 Roman Lebedev
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#include "rawspeedconfig.h" // IWYU pragma: keep
23+
24+
#ifdef HAVE_JXL
25+
26+
#include "adt/Array2DRef.h"
27+
#include "decoders/RawDecoderException.h"
28+
#include "decompressors/JpegXLDecompressor.h"
29+
#include <algorithm>
30+
#include <array>
31+
#include <cstddef>
32+
#include <cstdint>
33+
#include <jxl/decode.h>
34+
#include <memory>
35+
#include <vector>
36+
37+
using std::min;
38+
39+
namespace rawspeed {
40+
41+
void JpegXLDecompressor::decode(
42+
uint32_t offX, uint32_t offY) { /* Each slice is a JPEG XL image */
43+
44+
JxlSignature signature = JxlSignatureCheck(input.begin(), input.getSize());
45+
46+
if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER)
47+
ThrowRDE("Unable to verify JPEG XL signature");
48+
49+
JxlDecoder* decoder = JxlDecoderCreate(nullptr);
50+
51+
if (!decoder)
52+
ThrowRDE("Unable to instantiate a JPEG XL decoder");
53+
54+
if (JxlDecoderSetInput(decoder, input.begin(), input.getSize()) !=
55+
JXL_DEC_SUCCESS) {
56+
JxlDecoderDestroy(decoder);
57+
ThrowRDE("Unable to set input data for JPEG XL decoder");
58+
}
59+
60+
if (JxlDecoderSubscribeEvents(decoder,
61+
JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) !=
62+
JXL_DEC_SUCCESS) {
63+
JxlDecoderDestroy(decoder);
64+
ThrowRDE("Unable to subscribe to JPEG XL decoder events");
65+
}
66+
67+
JxlDecoderStatus status;
68+
JxlBasicInfo basicinfo;
69+
70+
const JxlPixelFormat pixel_format = {
71+
mRaw->getCpp(), // number of channels
72+
JXL_TYPE_UINT16, // data type
73+
JXL_NATIVE_ENDIAN, // endianness
74+
0 // alignment
75+
};
76+
77+
std::vector<uint16_t> complete_buffer;
78+
79+
// Decoding loop
80+
while (1) {
81+
status = JxlDecoderProcessInput(decoder);
82+
83+
if (status == JXL_DEC_ERROR) {
84+
JxlDecoderDestroy(decoder);
85+
ThrowRDE("JPEG XL decoding error");
86+
}
87+
88+
if (status == JXL_DEC_NEED_MORE_INPUT) {
89+
JxlDecoderDestroy(decoder);
90+
ThrowRDE("JPEG XL stream input data incomplete");
91+
}
92+
93+
if (status == JXL_DEC_BASIC_INFO) {
94+
if (JxlDecoderGetBasicInfo(decoder, &basicinfo) != JXL_DEC_SUCCESS) {
95+
JxlDecoderDestroy(decoder);
96+
ThrowRDE("JPEG XL stream basic info not available");
97+
}
98+
99+
// Unlikely to happen, but let there be a sanity check
100+
if (basicinfo.xsize == 0 || basicinfo.ysize == 0) {
101+
JxlDecoderDestroy(decoder);
102+
ThrowRDE("JPEG XL image declares zero dimensions");
103+
}
104+
105+
if (basicinfo.num_color_channels != pixel_format.num_channels)
106+
ThrowRDE("Component count doesn't match");
107+
108+
continue; // go to next loop iteration to process rest of the input
109+
}
110+
111+
if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
112+
size_t size =
113+
basicinfo.xsize * basicinfo.ysize * basicinfo.num_color_channels;
114+
complete_buffer.resize(size);
115+
JxlDecoderSetImageOutBuffer(decoder, &pixel_format,
116+
complete_buffer.data(), size);
117+
continue; // go to next iteration to process rest of the input
118+
}
119+
120+
// If the image is an animation, more full frames may be decoded. We do not
121+
// check and reject the image if it is an animation, but only read the first
122+
// frame. It hardly makes sense to process such an image.
123+
if (status == JXL_DEC_FULL_IMAGE)
124+
break; // Terminate processing
125+
126+
} // end of processing loop
127+
128+
JxlDecoderDestroy(decoder);
129+
130+
const Array2DRef<uint16_t> tmp(complete_buffer.data(),
131+
basicinfo.num_color_channels * basicinfo.xsize,
132+
basicinfo.xsize);
133+
134+
// Now the image is decoded, and we copy the image data
135+
unsigned int copy_w = min(mRaw->dim.x - offX, basicinfo.xsize);
136+
unsigned int copy_h = min(mRaw->dim.y - offY, basicinfo.ysize);
137+
138+
const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
139+
for (unsigned int row = 0; row < copy_h; row++) {
140+
for (unsigned int col = 0; col < basicinfo.num_color_channels * copy_w;
141+
col++)
142+
out(offY + row, basicinfo.num_color_channels * offX + col) =
143+
tmp(row, col);
144+
}
145+
}
146+
147+
} // namespace rawspeed
148+
149+
#else
150+
151+
#pragma message \
152+
"JPEG XL is not present! JPEG XL compression will not be supported!"
153+
154+
#endif
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
RawSpeed - RAW file decoder.
3+
4+
Copyright (C) 2017 Roman Lebedev
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#pragma once
22+
23+
#include "rawspeedconfig.h"
24+
25+
#ifdef HAVE_JXL
26+
27+
#include "common/RawImage.h"
28+
#include "decompressors/AbstractDecompressor.h"
29+
#include "io/Buffer.h"
30+
#include <cstdint>
31+
32+
namespace rawspeed {
33+
34+
class JpegXLDecompressor final : public AbstractDecompressor {
35+
Buffer input;
36+
RawImage mRaw;
37+
38+
public:
39+
JpegXLDecompressor(Buffer bs, RawImage img)
40+
: input(bs), mRaw(std::move(img)) {}
41+
42+
void decode(uint32_t offsetX, uint32_t offsetY);
43+
};
44+
45+
} // namespace rawspeed
46+
47+
#else
48+
49+
#pragma message \
50+
"JPEG XL is not present! JPEG XL compression will not be supported!"
51+
52+
#endif

0 commit comments

Comments
 (0)