1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style
4 // license that can be found in the LICENSE file.
6 // This C++ example decodes a JPEG XL image in one shot (all input bytes
7 // available at once). The example outputs the pixels and color information to a
8 // floating point image and an ICC profile on disk.
10 #include <jxl/decode.h>
11 #include <jxl/decode_cxx.h>
19 bool DecodeJpegXlExif(const uint8_t* jxl
, size_t size
,
20 std::vector
<uint8_t>* exif
) {
21 auto dec
= JxlDecoderMake(nullptr);
23 // We're only interested in the Exif boxes in this example, so don't
24 // subscribe to events related to pixel data.
25 if (JXL_DEC_SUCCESS
!= JxlDecoderSubscribeEvents(
26 dec
.get(), JXL_DEC_BOX
| JXL_DEC_BOX_COMPLETE
)) {
27 fprintf(stderr
, "JxlDecoderSubscribeEvents failed\n");
30 bool support_decompression
= true;
31 if (JXL_DEC_SUCCESS
!= JxlDecoderSetDecompressBoxes(dec
.get(), JXL_TRUE
)) {
33 "NOTE: decompressing brob boxes not supported with the currently "
34 "used jxl library.\n");
35 support_decompression
= false;
38 JxlDecoderSetInput(dec
.get(), jxl
, size
);
39 JxlDecoderCloseInput(dec
.get());
41 const constexpr size_t kChunkSize
= 65536;
42 size_t output_pos
= 0;
45 JxlDecoderStatus status
= JxlDecoderProcessInput(dec
.get());
46 if (status
== JXL_DEC_ERROR
) {
47 fprintf(stderr
, "Decoder error\n");
49 } else if (status
== JXL_DEC_NEED_MORE_INPUT
) {
50 fprintf(stderr
, "Error, already provided all input\n");
52 } else if (status
== JXL_DEC_BOX
) {
54 size_t remaining
= JxlDecoderReleaseBoxBuffer(dec
.get());
55 exif
->resize(exif
->size() - remaining
);
56 // No need to wait for JXL_DEC_SUCCESS or decode other boxes.
60 status
= JxlDecoderGetBoxType(dec
.get(), type
,
61 TO_JXL_BOOL(support_decompression
));
62 if (JXL_DEC_SUCCESS
!= status
) {
63 fprintf(stderr
, "Error, failed to get box type\n");
66 if (!memcmp(type
, "Exif", 4)) {
67 exif
->resize(kChunkSize
);
68 JxlDecoderSetBoxBuffer(dec
.get(), exif
->data(), exif
->size());
70 } else if (status
== JXL_DEC_BOX_NEED_MORE_OUTPUT
) {
71 size_t remaining
= JxlDecoderReleaseBoxBuffer(dec
.get());
72 output_pos
+= kChunkSize
- remaining
;
73 exif
->resize(exif
->size() + kChunkSize
);
74 JxlDecoderSetBoxBuffer(dec
.get(), exif
->data() + output_pos
,
75 exif
->size() - output_pos
);
76 } else if (status
== JXL_DEC_BOX_COMPLETE
) {
78 size_t remaining
= JxlDecoderReleaseBoxBuffer(dec
.get());
79 exif
->resize(exif
->size() - remaining
);
84 fprintf(stderr
, "Unknown decoder status\n");
90 bool LoadFile(const char* filename
, std::vector
<uint8_t>* out
) {
91 FILE* file
= fopen(filename
, "rb");
96 if (fseek(file
, 0, SEEK_END
) != 0) {
101 long size
= ftell(file
); // NOLINT
102 // Avoid invalid file or directory.
103 if (size
>= LONG_MAX
|| size
< 0) {
108 if (fseek(file
, 0, SEEK_SET
) != 0) {
114 size_t readsize
= fread(out
->data(), 1, size
, file
);
115 if (fclose(file
) != 0) {
119 return readsize
== static_cast<size_t>(size
);
122 bool WriteFile(const char* filename
, const uint8_t* data
, size_t size
) {
123 FILE* file
= fopen(filename
, "wb");
125 fprintf(stderr
, "Could not open %s for writing", filename
);
128 fwrite(data
, 1, size
, file
);
129 if (fclose(file
) != 0) {
135 int main(int argc
, char* argv
[]) {
138 "Usage: %s <jxl> <exif>\n"
140 " jxl = input JPEG XL image filename\n"
141 " exif = output exif filename\n"
142 "Output files will be overwritten.\n",
147 const char* jxl_filename
= argv
[1];
148 const char* exif_filename
= argv
[2];
150 std::vector
<uint8_t> jxl
;
151 if (!LoadFile(jxl_filename
, &jxl
)) {
152 fprintf(stderr
, "couldn't load %s\n", jxl_filename
);
156 std::vector
<uint8_t> exif
;
157 if (!DecodeJpegXlExif(jxl
.data(), jxl
.size(), &exif
)) {
158 fprintf(stderr
, "Error while decoding the jxl file\n");
162 printf("No exif data present in this image\n");
164 // TODO(lode): the exif box data contains the 4-byte TIFF header at the
165 // beginning, check whether this is desired to be part of the output, or
166 // should be removed.
167 if (!WriteFile(exif_filename
, exif
.data(), exif
.size())) {
168 fprintf(stderr
, "Error while writing the exif file\n");
171 printf("Successfully wrote %s\n", exif_filename
);