2024-07-15 17:47:19 +08:00
|
|
|
#include "ImageDecoder.h"
|
|
|
|
#include "BoostLog.h"
|
|
|
|
#include <jpeglib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
std::optional<ImageDecoder::Image> 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");
|
2024-08-31 11:37:20 +08:00
|
|
|
if (infile == nullptr) {
|
2024-07-15 17:47:19 +08:00
|
|
|
LOG(error) << "cannot open " << filename;
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
ImageDecoder::Image ret;
|
|
|
|
jpeg_stdio_src(&cinfo, infile);
|
2024-08-31 11:37:20 +08:00
|
|
|
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);
|
2024-07-15 17:47:19 +08:00
|
|
|
|
2024-08-31 11:37:20 +08:00
|
|
|
int row_stride = cinfo.output_width * cinfo.output_components;
|
|
|
|
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
|
2024-07-15 17:47:19 +08:00
|
|
|
|
2024-08-31 11:37:20 +08:00
|
|
|
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
|
|
|
|
}
|
2024-07-15 17:47:19 +08:00
|
|
|
}
|
2024-08-31 11:37:20 +08:00
|
|
|
|
|
|
|
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.";
|
2024-07-15 17:47:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
jpeg_destroy_decompress(&cinfo);
|
|
|
|
fclose(infile);
|
|
|
|
return std::make_optional(ret);
|
|
|
|
}
|