in src/jpeg2000Compression.cpp [48:147]
std::unique_ptr<uint8_t[]> Jpeg2000Compression::writeToMemory(
unsigned int width, unsigned int height,
uint8_t* buffer, size_t* size) {
opj_cparameters_t parameters;
opj_set_default_encoder_parameters(¶meters);
parameters.cp_disto_alloc = 1;
parameters.tcp_numlayers = 1;
parameters.tcp_rates[0] = 0;
parameters.cp_comment = const_cast<char*>("");
// Image sizes below 2^(#resolutions-1) causes
// error: Number of resolutions is too high in comparison to the smallest
// image dimension. See: https://groups.google.com/g/openjpeg/c/Lpw6Ydhf7bA
unsigned int min_dim = std::min<unsigned int>(width, height);
int max_numresolution = static_cast<int>(std::log2(
static_cast<double>(min_dim))) + 1;
max_numresolution = std::min<int>(parameters.numresolution,
max_numresolution);
if (max_numresolution != parameters.numresolution) {
BOOST_LOG_TRIVIAL(warning) << "JPEG 2000: Image size is smaller than 2^("
"numresolution - 1); Changing numresolution "
"from: " << parameters.numresolution <<
" to: " << max_numresolution <<
" to meet encoder requirments.";
parameters.numresolution = max_numresolution;
}
COLOR_SPACE colorspace = OPJ_CLRSPC_SRGB;
opj_image_cmptparm_t componentsParameters[3];
for (size_t i = 0; i < 3; i++) {
memset(&componentsParameters[i], 0, sizeof(opj_image_cmptparm_t));
componentsParameters[i].dx = 1;
componentsParameters[i].dy = 1;
componentsParameters[i].x0 = 0;
componentsParameters[i].y0 = 0;
componentsParameters[i].w = width;
componentsParameters[i].h = height;
componentsParameters[i].prec = 8;
componentsParameters[i].sgnd = 0;
}
opj_image_t* opjImage = opj_image_create(3, &componentsParameters[0],
colorspace);
opjImage->x0 = 0;
opjImage->y0 = 0;
opjImage->x1 = width;
opjImage->y1 = height;
int32_t* red = opjImage->comps[0].data;
int32_t* green = opjImage->comps[1].data;
int32_t* blue = opjImage->comps[2].data;
const uint8_t* pixel = reinterpret_cast<const uint8_t*>(buffer);
const unsigned int pixels_count = height*width*3;
for (unsigned int y = 0; y < pixels_count; y+=3) {
*red = pixel[y];
*green = pixel[y+1];
*blue = pixel[y+2];
red++;
green++;
blue++;
}
opj_codec_t* cinfo = opj_create_compress(OPJ_CODEC_J2K);
// Uncomment to log info, warnings, & errors
//
// opj_set_info_handler(cinfo, openjpeg_info, NULL);
// opj_set_warning_handler(cinfo, openjpeg_warning, NULL);
// opj_set_error_handler(cinfo, openjpeg_error, NULL);
opj_setup_encoder(cinfo, ¶meters, opjImage);
opj_stream_t* cio;
cio = opj_stream_default_create(0);
opj_stream_set_user_data(cio, this, {});
opj_stream_set_write_function(
cio, [](void* buffer, OPJ_SIZE_T size, void* userData) {
Jpeg2000Compression* jpeg2000Compression =
reinterpret_cast<Jpeg2000Compression*>(userData);
jpeg2000Compression->buffer_ = reinterpret_cast<uint8_t*>(buffer);
jpeg2000Compression->size_ = size;
return size;
});
bool result = opj_start_compress(cinfo, opjImage, cio);
if (!result) {
BOOST_LOG_TRIVIAL(error) << "JPEG 2000 Error starting compression";
}
opj_encode(cinfo, cio);
opj_end_compress(cinfo, cio);
std::unique_ptr<uint8_t[]> compressed = std::make_unique<uint8_t[]>(size_);
memcpy(compressed.get(), buffer_, size_);
opj_image_destroy(opjImage);
opj_stream_destroy(cio);
opj_destroy_codec(cinfo);
*size = size_;
return compressed;
}