in libheif/plugins/decoder_openjpeg.cc [252:390]
struct heif_error openjpeg_decode_image(void* decoder_raw, struct heif_image** out_img)
{
struct openjpeg_decoder* decoder = (struct openjpeg_decoder*) decoder_raw;
OPJ_BOOL success;
opj_dparameters_t decompression_parameters;
opj_codec_t* l_codec;
// Initialize Decoder
opj_set_default_decoder_parameters(&decompression_parameters);
l_codec = opj_create_decompress(OPJ_CODEC_J2K);
success = opj_setup_decoder(l_codec, &decompression_parameters);
if (!success) {
struct heif_error err = {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "opj_setup_decoder()"};
return err;
}
// Create Input Stream
OPJ_BOOL is_read_stream = true;
opj_stream_t* stream = opj_stream_create_default_memory_stream(decoder, is_read_stream);
// Read Codestream Header
opj_image_t* image = NULL;
success = opj_read_header(stream, l_codec, &image);
if (!success) {
struct heif_error err = {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "opj_read_header()"};
return err;
}
else if (image->numcomps != 3 && image->numcomps != 1) {
//TODO - Handle other numbers of components
struct heif_error err = {heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Number of components must be 3 or 1"};
return err;
}
else if ((image->color_space != OPJ_CLRSPC_UNSPECIFIED) && (image->color_space != OPJ_CLRSPC_SRGB)) {
//TODO - Handle other colorspaces
struct heif_error err = {heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Colorspace must be SRGB"};
return err;
}
const int width = (image->x1 - image->x0);
const int height = (image->y1 - image->y0);
/* Get the decoded image */
success = opj_decode(l_codec, stream, image);
if (!success) {
struct heif_error err = {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "opj_decode()"};
return err;
}
success = opj_end_decompress(l_codec, stream);
if (!success) {
struct heif_error err = {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "opj_end_decompress()"};
return err;
}
/* Close the byte stream */
opj_stream_destroy(stream);
heif_colorspace colorspace = heif_colorspace_YCbCr;
heif_chroma chroma = heif_chroma_444; //heif_chroma_interleaved_RGB;
std::vector<heif_channel> channels;
if (image->numcomps == 1) {
colorspace = heif_colorspace_monochrome;
chroma = heif_chroma_monochrome;
channels = {heif_channel_Y};
}
else if (image->numcomps == 3 &&
image->comps[1].dx == 1 &&
image->comps[1].dy == 1) {
colorspace = heif_colorspace_YCbCr;
chroma = heif_chroma_444;
channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
}
else if (image->numcomps == 3 &&
image->comps[1].dx == 2 &&
image->comps[1].dy == 1) {
colorspace = heif_colorspace_YCbCr;
chroma = heif_chroma_422;
channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
}
else if (image->numcomps == 3 &&
image->comps[1].dx == 2 &&
image->comps[1].dy == 2) {
colorspace = heif_colorspace_YCbCr;
chroma = heif_chroma_420;
channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
}
else {
struct heif_error err = {heif_error_Decoder_plugin_error, heif_suberror_Unspecified, "unsupported image format"};
return err;
}
struct heif_error error = heif_image_create(width, height, colorspace, chroma, out_img);
if (error.code) {
return error;
}
for (size_t c = 0; c < image->numcomps; c++) {
const opj_image_comp_t& opj_comp = image->comps[c];
int bit_depth = opj_comp.prec;
int cwidth = opj_comp.w;
int cheight = opj_comp.h;
error = heif_image_add_plane(*out_img, channels[c], cwidth, cheight, bit_depth);
int stride = -1;
uint8_t* p = heif_image_get_plane(*out_img, channels[c], &stride);
// TODO: a SIMD implementation to convert int32 to uint8 would speed this up
// https://stackoverflow.com/questions/63774643/how-to-convert-uint32-to-uint8-using-simd-but-not-avx512
if (stride == cwidth) {
for (int i = 0; i < cwidth * cheight; i++) {
p[i] = (uint8_t) opj_comp.data[i];
}
}
else {
for (int y = 0; y < cheight; y++) {
for (int x = 0; x < cwidth; x++) {
p[y * stride + x] = (uint8_t) opj_comp.data[y * cwidth + x];
}
}
}
}
return heif_error_ok;
}