Bug 1883912: Enable Intl.ListFormat test for "unit" style. r=spidermonkey-reviewers...
[gecko.git] / third_party / jpeg-xl / examples / decode_exif_metadata.cc
blob8ec999e4f4f9ebb7627a4db786a31178c4d4d1ec
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
2 //
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>
12 #include <limits.h>
13 #include <stdint.h>
14 #include <string.h>
16 #include <vector>
18 bool DecodeJpegXlExif(const uint8_t* jxl, size_t size,
19 std::vector<uint8_t>* exif) {
20 auto dec = JxlDecoderMake(nullptr);
22 // We're only interested in the Exif boxes in this example, so don't
23 // subscribe to events related to pixel data.
24 if (JXL_DEC_SUCCESS != JxlDecoderSubscribeEvents(dec.get(), JXL_DEC_BOX)) {
25 fprintf(stderr, "JxlDecoderSubscribeEvents failed\n");
26 return false;
28 bool support_decompression = true;
29 if (JXL_DEC_SUCCESS != JxlDecoderSetDecompressBoxes(dec.get(), JXL_TRUE)) {
30 fprintf(stderr,
31 "NOTE: decompressing brob boxes not supported with the currently "
32 "used jxl library.\n");
33 support_decompression = false;
36 JxlDecoderSetInput(dec.get(), jxl, size);
37 JxlDecoderCloseInput(dec.get());
39 const constexpr size_t kChunkSize = 65536;
40 size_t output_pos = 0;
42 for (;;) {
43 JxlDecoderStatus status = JxlDecoderProcessInput(dec.get());
44 if (status == JXL_DEC_ERROR) {
45 fprintf(stderr, "Decoder error\n");
46 return false;
47 } else if (status == JXL_DEC_NEED_MORE_INPUT) {
48 fprintf(stderr, "Error, already provided all input\n");
49 return false;
50 } else if (status == JXL_DEC_BOX) {
51 if (!exif->empty()) {
52 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
53 exif->resize(exif->size() - remaining);
54 // No need to wait for JXL_DEC_SUCCESS or decode other boxes.
55 return true;
57 JxlBoxType type;
58 if (JXL_DEC_SUCCESS !=
59 JxlDecoderGetBoxType(dec.get(), type, support_decompression)) {
60 fprintf(stderr, "Error, failed to get box type\n");
61 return false;
63 if (!memcmp(type, "Exif", 4)) {
64 exif->resize(kChunkSize);
65 JxlDecoderSetBoxBuffer(dec.get(), exif->data(), exif->size());
67 } else if (status == JXL_DEC_BOX_NEED_MORE_OUTPUT) {
68 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
69 output_pos += kChunkSize - remaining;
70 exif->resize(exif->size() + kChunkSize);
71 JxlDecoderSetBoxBuffer(dec.get(), exif->data() + output_pos,
72 exif->size() - output_pos);
73 } else if (status == JXL_DEC_SUCCESS) {
74 if (!exif->empty()) {
75 size_t remaining = JxlDecoderReleaseBoxBuffer(dec.get());
76 exif->resize(exif->size() - remaining);
77 return true;
79 return true;
80 } else {
81 fprintf(stderr, "Unknown decoder status\n");
82 return false;
87 bool LoadFile(const char* filename, std::vector<uint8_t>* out) {
88 FILE* file = fopen(filename, "rb");
89 if (!file) {
90 return false;
93 if (fseek(file, 0, SEEK_END) != 0) {
94 fclose(file);
95 return false;
98 long size = ftell(file);
99 // Avoid invalid file or directory.
100 if (size >= LONG_MAX || size < 0) {
101 fclose(file);
102 return false;
105 if (fseek(file, 0, SEEK_SET) != 0) {
106 fclose(file);
107 return false;
110 out->resize(size);
111 size_t readsize = fread(out->data(), 1, size, file);
112 if (fclose(file) != 0) {
113 return false;
116 return readsize == static_cast<size_t>(size);
119 bool WriteFile(const char* filename, const uint8_t* data, size_t size) {
120 FILE* file = fopen(filename, "wb");
121 if (!file) {
122 fprintf(stderr, "Could not open %s for writing", filename);
123 return false;
125 fwrite(data, 1, size, file);
126 if (fclose(file) != 0) {
127 return false;
129 return true;
132 int main(int argc, char* argv[]) {
133 if (argc != 3) {
134 fprintf(stderr,
135 "Usage: %s <jxl> <exif>\n"
136 "Where:\n"
137 " jxl = input JPEG XL image filename\n"
138 " exif = output exif filename\n"
139 "Output files will be overwritten.\n",
140 argv[0]);
141 return 1;
144 const char* jxl_filename = argv[1];
145 const char* exif_filename = argv[2];
147 std::vector<uint8_t> jxl;
148 if (!LoadFile(jxl_filename, &jxl)) {
149 fprintf(stderr, "couldn't load %s\n", jxl_filename);
150 return 1;
153 std::vector<uint8_t> exif;
154 if (!DecodeJpegXlExif(jxl.data(), jxl.size(), &exif)) {
155 fprintf(stderr, "Error while decoding the jxl file\n");
156 return 1;
158 if (exif.empty()) {
159 printf("No exif data present in this image\n");
160 } else {
161 // TODO(lode): the exif box data contains the 4-byte TIFF header at the
162 // beginning, check whether this is desired to be part of the output, or
163 // should be removed.
164 if (!WriteFile(exif_filename, exif.data(), exif.size())) {
165 fprintf(stderr, "Error while writing the exif file\n");
166 return 1;
168 printf("Successfully wrote %s\n", exif_filename);
170 return 0;