jpegjpeg2000openslide

got an error on decoding jpeg2000 in c++ with OpenJPEG


I am trying to decode JPEG2000 format with OpenJPEG.
(Decoding just one raw tile buffer from a svs file.)
But I got an error on opj_read_header().
Is there something I forgot to set before calling opj_read_header()?

opj_image_t *image = NULL;
int32_t datalen = tileByteCounts[test_num];
opj_stream_t *stream = opj_stream_create(datalen, true);
struct buffer_state state =
{
    .data = buffer,
    .length = datalen,
};
opj_stream_set_user_data(stream, &state, NULL);
opj_stream_set_user_data_length(stream, datalen);
opj_stream_set_read_function(stream, read_callback);
opj_stream_set_skip_function(stream, skip_callback);
opj_stream_set_seek_function(stream, seek_callback);
opj_codec_t *codec = opj_create_decompress(OPJ_CODEC_JP2);
opj_dparameters_t parameters;
opj_set_default_decoder_parameters(&parameters);
parameters.decod_format = 1;
parameters.cod_format = 2;
parameters.DA_x0 = 0;
parameters.DA_y0 = 0;
parameters.DA_x1 = tileWidth;
parameters.DA_y1 = tileHeight;
opj_setup_decoder(codec, &parameters);
// enable error handlers
opj_set_warning_handler(codec, warning_callback, NULL);
opj_set_error_handler(codec, error_callback, NULL);

// read header
if (!opj_read_header(stream, codec, &image)) // It's calling error_callback !
{
    printf("error on reading header");
    return 1;
}

Solution

  • I would use libvips to read from SVS images. It has a good openslide import operation written by the openslide devs, and handles this kind of thing well. It's free and cross-platform. Most linuxes have it in their package manager.

    At the command-line you can write:

    $ vipsheader CMU-1.svs
    CMU-1.svs: 46000x32914 uchar, 4 bands, rgb, openslideload
    $ time vips crop CMU-1.svs x.jpg 10 10 100 100
    real    0m0.058s
    user    0m0.050s
    sys 0m0.008s
    

    Be aware that jp2k is rather slow to decode. To convert the entire image, I see:

    $ time vips copy CMU-1.svs x.jpg --vips-progress
    vips temp-5: 46000 x 32914 pixels, 8 threads, 128 x 128 tiles, 256 lines in buffer
    vips temp-5: done in 14.6s          
    
    real    0m14.720s
    user    1m10.978s
    sys 0m1.179s
    

    In C++:

    // compile with
    //      g++ crop.cpp `pkg-config vips-cpp --cflags --libs`
    
    #include <vips/vips8>
    
    int
    main (int argc, char **argv)
    {       
            if (VIPS_INIT (argv[0]))
                    vips_error_exit (NULL);
    
            vips::VImage image = vips::VImage::new_from_file (argv[1]);
    
            image.write_to_file (argv[2]);
    }
    

    There are C, Python, Ruby, JavaScript, PHP, C#, Go, Rust etc. bindings too.

    You can write other formats by changing the output filename, or by setting optional arguments in the C++ code. For example, you can run that C++ program with:

    $ ./a.out CMU-1.svs x.tif[compression=jpeg,tile,pyramid]
    

    Or you could change the write_to_file to be:

            image.tiffsave (argv[2], VImage::option()
                    ->set ("compression", "jpeg")
                    ->set ("tile", TRUE)
                    ->set ("pyramid", TRUE));
    

    The docs have all the details.