Skip to content

Commit 0723adc

Browse files
committed
Add JpegXLDecompressor wrapper
1 parent fd5a279 commit 0723adc

File tree

3 files changed

+211
-0
lines changed

3 files changed

+211
-0
lines changed

src/librawspeed/decompressors/CMakeLists.txt

+6
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)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
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 <cstddef>
31+
#include <cstdint>
32+
#include <jxl/decode.h>
33+
#include <jxl/types.h>
34+
#include <vector>
35+
36+
using std::min;
37+
38+
namespace rawspeed {
39+
40+
void JpegXLDecompressor::decode(
41+
uint32_t offX, uint32_t offY) { /* Each slice is a JPEG XL image */
42+
43+
JxlSignature signature = JxlSignatureCheck(input.begin(), input.getSize());
44+
45+
if (signature != JXL_SIG_CODESTREAM && signature != JXL_SIG_CONTAINER)
46+
ThrowRDE("Unable to verify JPEG XL signature");
47+
48+
JxlDecoder* decoder = JxlDecoderCreate(nullptr);
49+
50+
if (!decoder)
51+
ThrowRDE("Unable to instantiate a JPEG XL decoder");
52+
53+
if (JxlDecoderSetInput(decoder, input.begin(), input.getSize()) !=
54+
JXL_DEC_SUCCESS) {
55+
JxlDecoderDestroy(decoder);
56+
ThrowRDE("Unable to set input data for JPEG XL decoder");
57+
}
58+
59+
if (JxlDecoderSubscribeEvents(decoder,
60+
JXL_DEC_BASIC_INFO | JXL_DEC_FULL_IMAGE) !=
61+
JXL_DEC_SUCCESS) {
62+
JxlDecoderDestroy(decoder);
63+
ThrowRDE("Unable to subscribe to JPEG XL decoder events");
64+
}
65+
66+
JxlDecoderStatus status;
67+
JxlBasicInfo basicinfo;
68+
69+
const JxlPixelFormat pixel_format = {
70+
mRaw->getCpp(), // number of channels
71+
JXL_TYPE_UINT16, // data type
72+
JXL_NATIVE_ENDIAN, // endianness
73+
0 // alignment
74+
};
75+
76+
std::vector<uint16_t> complete_buffer;
77+
78+
// Decoding loop
79+
while (true) {
80+
status = JxlDecoderProcessInput(decoder);
81+
82+
if (status == JXL_DEC_ERROR) {
83+
JxlDecoderDestroy(decoder);
84+
ThrowRDE("JPEG XL decoding error");
85+
}
86+
87+
if (status == JXL_DEC_NEED_MORE_INPUT) {
88+
JxlDecoderDestroy(decoder);
89+
ThrowRDE("JPEG XL stream input data incomplete");
90+
}
91+
92+
if (status == JXL_DEC_BASIC_INFO) {
93+
if (JxlDecoderGetBasicInfo(decoder, &basicinfo) != JXL_DEC_SUCCESS) {
94+
JxlDecoderDestroy(decoder);
95+
ThrowRDE("JPEG XL stream basic info not available");
96+
}
97+
98+
// Unlikely to happen, but let there be a sanity check
99+
if (basicinfo.xsize == 0 || basicinfo.ysize == 0) {
100+
JxlDecoderDestroy(decoder);
101+
ThrowRDE("JPEG XL image declares zero dimensions");
102+
}
103+
104+
if (basicinfo.num_color_channels != pixel_format.num_channels)
105+
ThrowRDE("Component count doesn't match");
106+
107+
continue; // go to next loop iteration to process rest of the input
108+
}
109+
110+
if (status == JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
111+
size_t size =
112+
basicinfo.xsize * basicinfo.ysize * basicinfo.num_color_channels;
113+
complete_buffer.resize(size);
114+
JxlDecoderSetImageOutBuffer(decoder, &pixel_format,
115+
complete_buffer.data(), size);
116+
continue; // go to next iteration to process rest of the input
117+
}
118+
119+
// If the image is an animation, more full frames may be decoded. We do not
120+
// check and reject the image if it is an animation, but only read the first
121+
// frame. It hardly makes sense to process such an image.
122+
if (status == JXL_DEC_FULL_IMAGE)
123+
break; // Terminate processing
124+
125+
} // end of processing loop
126+
127+
JxlDecoderDestroy(decoder);
128+
129+
const Array2DRef<uint16_t> tmp(complete_buffer.data(),
130+
basicinfo.num_color_channels * basicinfo.xsize,
131+
basicinfo.xsize);
132+
133+
// Now the image is decoded, and we copy the image data
134+
unsigned int copy_w = min(mRaw->dim.x - offX, basicinfo.xsize);
135+
unsigned int copy_h = min(mRaw->dim.y - offY, basicinfo.ysize);
136+
137+
const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());
138+
for (unsigned int row = 0; row < copy_h; row++) {
139+
for (unsigned int col = 0; col < basicinfo.num_color_channels * copy_w;
140+
col++)
141+
out(offY + row, basicinfo.num_color_channels * offX + col) =
142+
tmp(row, col);
143+
}
144+
}
145+
146+
} // namespace rawspeed
147+
148+
#else
149+
150+
#pragma message \
151+
"JPEG XL is not present! JPEG XL compression will not be supported!"
152+
153+
#endif
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)