#include "ImageDecoder.h" #include "BoostLog.h" #include #include std::optional ImageDecoder::extractJpegYComponent(const std::string &filename) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); FILE *infile = fopen(filename.c_str(), "rb"); if (infile == nullptr) { LOG(error) << "cannot open " << filename; return std::nullopt; } ImageDecoder::Image ret; jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); // 1 LOG(info) << "jpeg color space: " << cinfo.jpeg_color_space; if (cinfo.jpeg_color_space == JCS_YCbCr) { cinfo.out_color_space = JCS_YCbCr; // We want YCbCr color space jpeg_start_decompress(&cinfo); int row_stride = cinfo.output_width * cinfo.output_components; JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); ret.width = cinfo.output_width; ret.height = cinfo.output_height; ret.data.resize(ret.width * ret.height); while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); for (unsigned int i = 0; i < cinfo.output_width; ++i) { ret.data[(cinfo.output_scanline - 1) * cinfo.output_width + i] = buffer[0][i * 3]; // Y component is the first byte in YCbCr } } jpeg_finish_decompress(&cinfo); } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { cinfo.out_color_space = JCS_GRAYSCALE; // We want grayscale color space jpeg_start_decompress(&cinfo); int row_stride = cinfo.output_width * cinfo.output_components; JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1); ret.width = cinfo.output_width; ret.height = cinfo.output_height; ret.data.resize(ret.width * ret.height); while (cinfo.output_scanline < cinfo.output_height) { (void)jpeg_read_scanlines(&cinfo, buffer, 1); memcpy(ret.data.data() + (cinfo.output_scanline - 1) * row_stride, buffer[0], row_stride); } } else { LOG(warning) << "jpeg color space(" << cinfo.jpeg_color_space << ") not supported."; } jpeg_destroy_decompress(&cinfo); fclose(infile); return std::make_optional(ret); }