Bug 1270832 - Activate standard c++ library hardening r=glandium
[gecko.git] / third_party / jpeg-xl / examples / encode_oneshot.cc
blob6c45a70411e630256b544eeb9799ec27916d49a9
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 example encodes a file containing a floating point image to another
7 // file containing JPEG XL image with a single frame.
9 #include <jxl/codestream_header.h>
10 #include <jxl/color_encoding.h>
11 #include <jxl/encode.h>
12 #include <jxl/encode_cxx.h>
13 #include <jxl/thread_parallel_runner.h>
14 #include <jxl/thread_parallel_runner_cxx.h>
15 #include <jxl/types.h>
16 #include <limits.h>
17 #include <string.h>
19 #include <cstdint>
20 #include <cstdio>
21 #include <sstream>
22 #include <string>
23 #include <vector>
25 /**
26 * Reads from .pfm file (Portable FloatMap)
28 * @param filename name of the file to read
29 * @param pixels vector to fill with loaded pixels as 32-bit floating point with
30 * 3-channel RGB
31 * @param xsize set to width of loaded image
32 * @param ysize set to height of loaded image
34 bool ReadPFM(const char* filename, std::vector<float>* pixels, uint32_t* xsize,
35 uint32_t* ysize) {
36 FILE* file = fopen(filename, "rb");
37 if (!file) {
38 fprintf(stderr, "Could not open %s for reading.\n", filename);
39 return false;
41 uint32_t endian_test = 1;
42 uint8_t little_endian_check[4];
43 memcpy(little_endian_check, &endian_test, 4);
44 bool little_endian = (little_endian_check[0] == 1);
46 if (fseek(file, 0, SEEK_END) != 0) {
47 fclose(file);
48 return false;
51 long size = ftell(file); // NOLINT
52 // Avoid invalid file or directory.
53 if (size >= LONG_MAX || size < 0) {
54 fclose(file);
55 return false;
58 if (fseek(file, 0, SEEK_SET) != 0) {
59 fclose(file);
60 return false;
63 std::vector<char> data;
64 data.resize(size);
66 size_t readsize = fread(data.data(), 1, size, file);
67 if (static_cast<long>(readsize) != size) { // NOLINT
68 fclose(file);
69 return false;
71 if (fclose(file) != 0) {
72 return false;
75 std::stringstream datastream;
76 std::string datastream_content(data.data(), data.size());
77 datastream.str(datastream_content);
79 std::string pf_token;
80 getline(datastream, pf_token, '\n');
81 if (pf_token != "PF") {
82 fprintf(stderr,
83 "%s doesn't seem to be a 3 channel Portable FloatMap file (missing "
84 "'PF\\n' "
85 "bytes).\n",
86 filename);
87 return false;
90 std::string xsize_token;
91 getline(datastream, xsize_token, ' ');
92 *xsize = std::stoi(xsize_token);
94 std::string ysize_token;
95 getline(datastream, ysize_token, '\n');
96 *ysize = std::stoi(ysize_token);
98 std::string endianness_token;
99 getline(datastream, endianness_token, '\n');
100 bool input_little_endian;
101 if (endianness_token == "1.0") {
102 input_little_endian = false;
103 } else if (endianness_token == "-1.0") {
104 input_little_endian = true;
105 } else {
106 fprintf(stderr,
107 "%s doesn't seem to be a Portable FloatMap file (endianness token "
108 "isn't '1.0' or '-1.0').\n",
109 filename);
110 return false;
113 size_t offset = pf_token.size() + 1 + xsize_token.size() + 1 +
114 ysize_token.size() + 1 + endianness_token.size() + 1;
116 if (data.size() != *ysize * *xsize * 3 * 4 + offset) {
117 fprintf(stderr,
118 "%s doesn't seem to be a Portable FloatMap file (pixel data bytes "
119 "are %d, but expected %d * %d * 3 * 4 + %d (%d).\n",
120 filename, static_cast<int>(data.size()), static_cast<int>(*ysize),
121 static_cast<int>(*xsize), static_cast<int>(offset),
122 static_cast<int>(*ysize * *xsize * 3 * 4 + offset));
123 return false;
126 if (little_endian != input_little_endian) {
127 fprintf(stderr,
128 "%s has a different endianness than we do, conversion is not "
129 "supported.\n",
130 filename);
131 return false;
134 pixels->resize(*ysize * *xsize * 3);
136 for (int y = *ysize - 1; y >= 0; y--) {
137 for (int x = 0; x < static_cast<int>(*xsize); x++) {
138 for (int c = 0; c < 3; c++) {
139 memcpy(pixels->data() + (y * *xsize + x) * 3 + c, data.data() + offset,
140 sizeof(float));
141 offset += sizeof(float);
146 return true;
150 * Compresses the provided pixels.
152 * @param pixels input pixels
153 * @param xsize width of the input image
154 * @param ysize height of the input image
155 * @param compressed will be populated with the compressed bytes
157 bool EncodeJxlOneshot(const std::vector<float>& pixels, const uint32_t xsize,
158 const uint32_t ysize, std::vector<uint8_t>* compressed) {
159 auto enc = JxlEncoderMake(/*memory_manager=*/nullptr);
160 auto runner = JxlThreadParallelRunnerMake(
161 /*memory_manager=*/nullptr,
162 JxlThreadParallelRunnerDefaultNumWorkerThreads());
163 if (JXL_ENC_SUCCESS != JxlEncoderSetParallelRunner(enc.get(),
164 JxlThreadParallelRunner,
165 runner.get())) {
166 fprintf(stderr, "JxlEncoderSetParallelRunner failed\n");
167 return false;
170 JxlPixelFormat pixel_format = {3, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0};
172 JxlBasicInfo basic_info;
173 JxlEncoderInitBasicInfo(&basic_info);
174 basic_info.xsize = xsize;
175 basic_info.ysize = ysize;
176 basic_info.bits_per_sample = 32;
177 basic_info.exponent_bits_per_sample = 8;
178 basic_info.uses_original_profile = JXL_FALSE;
179 if (JXL_ENC_SUCCESS != JxlEncoderSetBasicInfo(enc.get(), &basic_info)) {
180 fprintf(stderr, "JxlEncoderSetBasicInfo failed\n");
181 return false;
184 JxlColorEncoding color_encoding = {};
185 JXL_BOOL is_gray = TO_JXL_BOOL(pixel_format.num_channels < 3);
186 JxlColorEncodingSetToSRGB(&color_encoding, is_gray);
187 if (JXL_ENC_SUCCESS !=
188 JxlEncoderSetColorEncoding(enc.get(), &color_encoding)) {
189 fprintf(stderr, "JxlEncoderSetColorEncoding failed\n");
190 return false;
193 JxlEncoderFrameSettings* frame_settings =
194 JxlEncoderFrameSettingsCreate(enc.get(), nullptr);
196 if (JXL_ENC_SUCCESS !=
197 JxlEncoderAddImageFrame(frame_settings, &pixel_format,
198 static_cast<const void*>(pixels.data()),
199 sizeof(float) * pixels.size())) {
200 fprintf(stderr, "JxlEncoderAddImageFrame failed\n");
201 return false;
203 JxlEncoderCloseInput(enc.get());
205 compressed->resize(64);
206 uint8_t* next_out = compressed->data();
207 size_t avail_out = compressed->size() - (next_out - compressed->data());
208 JxlEncoderStatus process_result = JXL_ENC_NEED_MORE_OUTPUT;
209 while (process_result == JXL_ENC_NEED_MORE_OUTPUT) {
210 process_result = JxlEncoderProcessOutput(enc.get(), &next_out, &avail_out);
211 if (process_result == JXL_ENC_NEED_MORE_OUTPUT) {
212 size_t offset = next_out - compressed->data();
213 compressed->resize(compressed->size() * 2);
214 next_out = compressed->data() + offset;
215 avail_out = compressed->size() - offset;
218 compressed->resize(next_out - compressed->data());
219 if (JXL_ENC_SUCCESS != process_result) {
220 fprintf(stderr, "JxlEncoderProcessOutput failed\n");
221 return false;
224 return true;
228 * Writes bytes to file.
230 bool WriteFile(const std::vector<uint8_t>& bytes, const char* filename) {
231 FILE* file = fopen(filename, "wb");
232 if (!file) {
233 fprintf(stderr, "Could not open %s for writing\n", filename);
234 return false;
236 if (fwrite(bytes.data(), sizeof(uint8_t), bytes.size(), file) !=
237 bytes.size()) {
238 fprintf(stderr, "Could not write bytes to %s\n", filename);
239 fclose(file);
240 return false;
242 if (fclose(file) != 0) {
243 fprintf(stderr, "Could not close %s\n", filename);
244 return false;
246 return true;
249 int main(int argc, char* argv[]) {
250 if (argc != 3) {
251 fprintf(stderr,
252 "Usage: %s <pfm> <jxl>\n"
253 "Where:\n"
254 " pfm = input Portable FloatMap image filename\n"
255 " jxl = output JPEG XL image filename\n"
256 "Output files will be overwritten.\n",
257 argv[0]);
258 return 1;
261 const char* pfm_filename = argv[1];
262 const char* jxl_filename = argv[2];
264 std::vector<float> pixels;
265 uint32_t xsize;
266 uint32_t ysize;
267 if (!ReadPFM(pfm_filename, &pixels, &xsize, &ysize)) {
268 fprintf(stderr, "Couldn't load %s\n", pfm_filename);
269 return 2;
272 std::vector<uint8_t> compressed;
273 if (!EncodeJxlOneshot(pixels, xsize, ysize, &compressed)) {
274 fprintf(stderr, "Couldn't encode jxl\n");
275 return 3;
278 if (!WriteFile(compressed, jxl_filename)) {
279 fprintf(stderr, "Couldn't write jxl file\n");
280 return 4;
283 return 0;