in tensorflow_io/core/kernels/image_jpeg2k_kernels.cc [94:244]
void Compute(OpKernelContext* context) override {
const Tensor& contents_tensor = context->input(0);
OP_REQUIRES(context, TensorShapeUtils::IsScalar(contents_tensor.shape()),
errors::InvalidArgument("contents must be scalar, got shape ",
contents_tensor.shape().DebugString()));
auto contents = contents_tensor.scalar<tstring>()();
OPJ_CODEC_FORMAT format = OPJ_CODEC_JP2;
std::unique_ptr<opj_image_t, void (*)(opj_image_t*)> l_image(
nullptr, [](opj_image_t* p) {
if (p != nullptr) {
opj_image_destroy(p);
}
});
std::unique_ptr<opj_codec_t, void (*)(opj_codec_t*)> l_codec(
opj_create_decompress(format), [](opj_codec_t* p) {
if (p != nullptr) {
opj_destroy_codec(p);
}
});
OpjMsgCallback msg;
opj_set_info_handler(l_codec.get(), OpjMsgCallback::InfoCallback, &msg);
opj_set_warning_handler(l_codec.get(), OpjMsgCallback::WarningCallback,
&msg);
opj_set_error_handler(l_codec.get(), OpjMsgCallback::ErrorCallback, &msg);
std::unique_ptr<opj_stream_t, void (*)(opj_stream_t*)> l_stream(
opj_stream_default_create(OPJ_TRUE), [](opj_stream_t* p) {
if (p != nullptr) {
opj_stream_destroy(p);
}
});
OP_REQUIRES(context, (l_stream.get() != nullptr),
errors::InvalidArgument("unable to create stream"));
OpjStreamCallback data(contents.data(), contents.size());
opj_stream_set_user_data(l_stream.get(), &data,
OpjStreamCallback::OpjStreamFreeUserDataFn);
opj_stream_set_user_data_length(l_stream.get(), contents.size());
opj_stream_set_read_function(l_stream.get(), OpjStreamCallback::ReadFn);
opj_stream_set_skip_function(l_stream.get(), OpjStreamCallback::SkipFn);
opj_stream_set_seek_function(l_stream.get(), OpjStreamCallback::SeekFn);
opj_dparameters_t l_param;
opj_set_default_decoder_parameters(&l_param);
// TODO: adjust additional parameter with:
// do not use layer decoding limitations
// l_param.cp_layer = 0;
// do not use resolutions reductions
// l_param.cp_reduce = 0;
OPJ_BOOL status;
status = opj_setup_decoder(l_codec.get(), &l_param);
OP_REQUIRES(
context, (status),
errors::InvalidArgument("unable to setup decoder: ", msg.error_));
opj_image_t* p_image = nullptr;
status = opj_read_header(l_stream.get(), l_codec.get(), &p_image);
OP_REQUIRES(context, (status),
errors::InvalidArgument("unable to read header: ", msg.error_));
l_image.reset(p_image);
OP_REQUIRES(context, ((p_image->numcomps * p_image->x1 * p_image->y1) != 0),
errors::InvalidArgument("invalid raw image parameters"));
int prec = 0;
for (int i = 0; i < p_image->numcomps; i++) {
if (prec == 0) {
prec = p_image->comps[i].prec;
}
OP_REQUIRES(
context, (prec == p_image->comps[i].prec),
errors::InvalidArgument("precision mismatch for component ", i, ": ",
prec, " vs. ", p_image->comps[i].prec));
switch (prec) {
case 8:
case 16:
break;
default:
OP_REQUIRES(
context, false,
errors::InvalidArgument(
"only 8 and 16 bit images supported, received component ", i,
" = ", prec));
}
}
switch (p_image->numcomps) {
case 1:
case 3:
case 4:
break;
default:
OP_REQUIRES(
context, false,
errors::InvalidArgument("only images with 3 or 4 channels are "
"currently supported, received ",
p_image->numcomps));
}
OP_REQUIRES(context, (p_image->x1 != 0 && p_image->y1 != 0),
errors::InvalidArgument(
"image grid (x1, y1) cannot be zero, received (",
p_image->x1, ", ", p_image->y1, ")"));
for (int i = 0; i < p_image->numcomps; i++) {
OP_REQUIRES(
context,
(p_image->comps[i].w == p_image->x1) &&
(p_image->comps[i].h == p_image->y1),
errors::InvalidArgument("channel (", i, ") does not match image: ",
p_image->comps[i].h, "x", p_image->comps[i].w,
" vs. ", p_image->y1, "x", p_image->x1));
}
int64 width = p_image->x1;
int64 height = p_image->y1;
int64 channels = p_image->numcomps;
long signed_offsets[4] = {0, 0, 0, 0};
for (int i = 0; i < p_image->numcomps; i++) {
if (p_image->comps[i].sgnd) {
signed_offsets[i] = 1 << (p_image->comps[i].prec - 1);
}
}
status = opj_decode(l_codec.get(), l_stream.get(), p_image);
OP_REQUIRES(
context, (status),
errors::InvalidArgument("unable to decode_image: ", msg.error_));
Tensor* image_tensor = nullptr;
OP_REQUIRES_OK(
context, context->allocate_output(
0, TensorShape({height, width, channels}), &image_tensor));
switch (prec) {
case 8:
FillTensor<uint8>(image_tensor, p_image, height, width, channels,
signed_offsets);
break;
case 16:
FillTensor<uint16>(image_tensor, p_image, height, width, channels,
signed_offsets);
break;
}
}