2#include <ufo/io/jpeg.hpp>
19void jpeg_error_throw(j_common_ptr p_cinfo)
21 if (p_cinfo->is_decompressor) {
22 jpeg_destroy_decompress(
reinterpret_cast<jpeg_decompress_struct*
>(p_cinfo));
24 jpeg_destroy_compress(
reinterpret_cast<jpeg_compress_struct*
>(p_cinfo));
27 char buffer[JMSG_LENGTH_MAX];
28 (*p_cinfo->err->format_message)(p_cinfo, buffer);
29 throw std::runtime_error(buffer);
32bool readJPEG(FileHandler fp, std::uint8_t* image)
34 jpeg_decompress_struct cinfo;
39 cinfo.err = jpeg_std_error(&jerr);
40 jerr.error_exit = jpeg_error_throw;
41 jpeg_create_decompress(&cinfo);
42 jpeg_stdio_src(&cinfo, fp.get());
43 jpeg_read_header(&cinfo, TRUE);
46 int num_of_channels = 3;
47 int bytes_per_channel = 1;
48 switch (cinfo.jpeg_color_space) {
51 cinfo.out_color_space = JCS_RGB;
52 cinfo.out_color_components = 3;
56 cinfo.jpeg_color_space = JCS_GRAYSCALE;
57 cinfo.out_color_components = 1;
63 std::println(stderr,
"[UFO | Read JPEG] Color space not supported");
64 jpeg_destroy_decompress(&cinfo);
69 jpeg_start_decompress(&cinfo);
70 int row_stride = cinfo.output_width * cinfo.output_components;
71 buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
72 while (cinfo.output_scanline < cinfo.output_height) {
73 jpeg_read_scanlines(&cinfo, buffer, 1);
74 std::memcpy(image, buffer[0], row_stride);
77 jpeg_finish_decompress(&cinfo);
78 jpeg_destroy_decompress(&cinfo);
81 }
catch (std::runtime_error
const& err) {
82 std::println(stderr,
"[UFO | Read JPEG] libjpeg error: {}", err.what());
88bool writeJPEG(FileHandler& fp, std::uint8_t
const* image, std::uint32_t width,
89 std::uint32_t height,
int num_channels,
int quality)
91 jpeg_compress_struct cinfo;
93 JSAMPROW row_pointer[1];
96 cinfo.err = jpeg_std_error(&jerr);
97 jerr.error_exit = jpeg_error_throw;
99 jpeg_create_compress(&cinfo);
100 jpeg_stdio_dest(&cinfo, fp.get());
102 cinfo.image_width = width;
103 cinfo.image_height = height;
104 cinfo.input_components = num_channels;
105 cinfo.in_color_space = 1 == num_channels ? JCS_GRAYSCALE : JCS_RGB;
107 jpeg_set_defaults(&cinfo);
108 jpeg_set_quality(&cinfo, quality, TRUE);
109 jpeg_start_compress(&cinfo, TRUE);
111 int row_stride = width * num_channels;
112 std::vector<std::uint8_t> buffer(row_stride);
113 while (cinfo.next_scanline < cinfo.image_height) {
114 std::memcpy(buffer.data(), image, row_stride);
115 row_pointer[0] = buffer.data();
116 jpeg_write_scanlines(&cinfo, row_pointer, 1);
120 jpeg_finish_compress(&cinfo);
122 jpeg_destroy_compress(&cinfo);
125 }
catch (std::runtime_error
const& err) {
126 std::println(stderr,
"[UFO | Write JPEG] Error: {}", err.what());
134ImageProperties imagePropertiesJPEG(std::filesystem::path
const& file)
136 FileHandler fp(file.c_str(),
"rb");
139 throw std::runtime_error(std::format(
140 "[UFO | Image Properties JPEG] Failed to open file: {}", file.string()));
143 jpeg_decompress_struct cinfo;
147 cinfo.err = jpeg_std_error(&jerr);
148 jerr.error_exit = detail::jpeg_error_throw;
149 jpeg_create_decompress(&cinfo);
150 jpeg_stdio_src(&cinfo, fp.get());
151 jpeg_read_header(&cinfo, TRUE);
152 }
catch (std::runtime_error
const& err) {
153 throw std::runtime_error(
154 std::format(
"[UFO | Read JPEG] libjpeg error: {}", err.what()));
158 if (JCS_GRAYSCALE != cinfo.jpeg_color_space && JCS_RGB != cinfo.jpeg_color_space &&
159 JCS_YCbCr != cinfo.jpeg_color_space) {
160 jpeg_destroy_decompress(&cinfo);
162 throw std::runtime_error(
"[UFO | Read JPEG] Color space not supported");
165 ImageProperties prop;
166 prop.width = cinfo.image_width;
167 prop.height = cinfo.image_height;
170 prop.grayscale = cinfo.jpeg_color_space == JCS_GRAYSCALE;
172 jpeg_destroy_decompress(&cinfo);
All vision-related classes and functions.