Quick Start Guide#

This section will explain how to use decoder and encoder APIs in a few quick steps. The API details will be covered in the next section.

Note

Link to nvTIFF Samples: NVIDIA/CUDALibrarySamples

Please note that since the decoding and encoding of TIFF images are two fundamentally different problems the APIs for decoding and encoding are also different and independent.

nvTIFF Decode#

The library reads the file from disk and loads the image data to device memory.

  1. Create instances of the following -

nvtiffStream_t - is used to parse the bitstream and store the bitstream metadata

nvtiffDecoder_t - is used to store the work buffers required for decode

nvtiffStream_t nvtiff_stream;
nvtiffDecoder_t nvtiff_decoder;

nvtiffStreamCreate(&nvtiff_stream);
nvtiffDecoderCreateSimple(&nvtiff_decoder);
  1. Use the nvtiffStreamParseFromFile API to parse the tiff file from disk.

// char *fname, is the tiff file name
nvtiffStatus_t status = nvtiffStreamParseFromFile(fname, nvtiff_stream));
// make sure that nvtiffStreamParseFromFile returns NVTIFF_STATUS_SUCCESS before proceeding to the next step
  1. Extract the tiff file meta data.

nvtiffFileInfo_t file_info;
nvtiffStatus_t status = nvtiffStreamGetFileInfo(tiff_stream, &file_info);
//nvTiff requires all the images (subfiles) in the same file to have the same properties.
  1. Allocate decode output on device.

// allocate device memory for images
unsigned char **image_out = NULL;


const size_t image_size = sizeof(**image_out)*file_info.image_width *
                                              file_info.image_height *
                                              (file_info.bits_per_pixel/8);

// we are decoding all the images in file "fname" from
// subfile no. "frameBeg" to subfile no. "frameEnd"
frame_beg = fmax(frame_beg, 0);
frame_end = fmin(frame_end, file_info.num_images - 1);
const int num_decoded_images = frame_end - frame_beg + 1;


image_out = (unsigned char **)Malloc(sizeof(*image_out)*num_decoded_images);
for(unsigned int i = 0; i < nDecode; i++) {
        CHECK_CUDA(cudaMalloc(image_out + i, image_size));
}
  1. Call nvtiffDecode function to decode the data or range of data from files.

if (!decodeRange) {
        nvtiffStatus_t status = nvtiffDecode(nvtiff_stream, nvtiff_decoder, image_out, stream);
} else {
        nvtiffStatus_t status = nvtiffDecodeRange(nvtiff_stream, nvtiff_decoder, frame_beg, num_decoded_images, image_out, stream);
}
cudaStreamSynchronize(stream);
// cudaStreamSynchronize is requires since the decode APIs are asychronous with respect to the host
  1. Go to step 1 to decode another image. Once all images are decoded, release nvTIFF the library resources by calling the corresponding destroy APIs.

nvTIFF Encode#

Set image info#

Other image info parameters can be set, but the following are absolutely necessary.

nvtiffImageInfo_t info;
info.image_width = 1920;
info.image_height = 1080;
info.samples_per_pixel = 3;
info.bits_per_sample[0] = info.bits_per_sample[1] = info.bits_per_sample[2] = 8;

Basic encode flow#

nvtiffEncoder_t encoder;
nvtiffEncoderCreate(&encoder, nullptr, nullptr, stream);
nvtiffEncodeParams_t params;
nvtiffEncodeParamsCreate(&params);
nvtiffEncodeParamsSetImageInfo(params, &info);
nvtiffEncodeParamsSetInputs(params, images, nImages);
nvtiffEncode(encoder, &params, 1, stream);
nvtiffEncodeFinalize(encoder, &params, 1, stream);
nvtiffWriteTiffFile(encoder, &params, 1, "outFile.tif", stream);
nvtiffEncodeParamsDestroy(params, stream);
nvtiffEncoderDestroy(encoder, stream);

Write TIFF stream to a buffer#

nvtiffEncodeParamsSetImageInfo(params, &info);
nvtiffEncodeParamsSetInputs(params, imageOut_d, num_images);
nvtiffEncode(encoder, &params, 1, stream);
size_t metadata_size = 0, bitstream_size = 0;
nvtiffEncodeFinalize(encoder, &params, 1, stream);
nvtiffGetBitstreamSize(encoder, &params, 1, &metadata_size, &bitstream_size));
std::vector<unsigned char> buf(metadata_size + bitstream_size);
nvtiffWriteTiffBuffer(encoder, &params, 1, buf.data(), buf.size(), stream);

Decode then encode#

nvtiffStream_t tiff_stream;
nvtiffStreamCreate(&tiff_stream);
nvtiffDecoder_t decoder;
nvtiffDecoderCreate(&decoder, nullptr, nullptr, 0);
nvtiffStreamParseFromFile(fname, tiff_stream));
uint32_t num_images = 0;
nvtiffStreamGetNumImages(tiff_stream, &num_images);
nvtiffImageInfo_t info;
nvtiffStreamGetImageInfo(tiff_stream, 0, &info);
unsigned char **imageOut_d = nullptr;
const size_t imageSize = sizeof(**imageOut_d) * info.image_height * info.image_width * (info.bits_per_pixel/8);
imageOut_d = (unsigned char **)malloc(sizeof(*imageOut_d) * num_images);
for(unsigned int i = 0; i < num_images; i++)
    cudaMalloc(imageOut_d+i, imageSize);
nvtiffDecode(tiff_stream, decoder, imageOut_d, stream);

cudaStreamSynchronize(stream));

nvtiffEncoder_t encoder;
nvtiffEncoderCreate(&encoder, nullptr, nullptr, 0);
nvtiffEncodeParams_t params;
nvtiffEncodeParamsCreate(&params);
nvtiffEncodeParamsSetImageInfo(params, &info);
nvtiffEncodeParamsSetInputs(params, imageOut_d, num_images);
nvtiffEncode(encoder, &params, 1, stream);

Geotiff#

const char* citation = "Generated by nvtiff|";
nvtiffEncodeParamsSetGeoKeyASCII(params, NVTIFF_GEOKEY_GT_CITATION, citation,
strlen(citation) + 1));
nvtiffEncodeParamsSetGeoKeySHORT(params, NVTIFF_GEOKEY_GT_MODEL_TYPE, 2, 1);
nvtiffEncodeParamsSetGeoKeySHORT(params, NVTIFF_GEOKEY_GEODETIC_CRS, 4326, 1);
double geotransform[6] = { ... };
double pixelScale[3] = {geotransform[1], std::abs(geotransform[5]), 0.0};
nvtiffEncodeParamsSetTag(params, NVTIFF_TAG_MODEL_PIXEL_SCALE, NVTIFF_TAG_TYPE_DOUBLE, pixelScale, 3);
double tiePoint[6] = {0.0, 0.0, 0.0, geotransform[0], geotransform[3], 0.0};
nvtiffEncodeParamsSetTag(params, NVTIFF_TAG_MODEL_TIE_POINT, NVTIFF_TAG_TYPE_DOUBLE, tiePoint, 6);

Tiff Decode / Encode Demo example#

The binary nvtiff_example provides a complete and detailed usage example for the encoding and decoding capabilities of the nvTIFF library.

Usage:
nvTiff_example [options] -f|--file <TIFF_FILE>

General options:

        -d DEVICE_ID
        --device DEVICE_ID
                Specifies the GPU to use for images decoding/encoding.
                Default: device 0 is used.

        -v
        --verbose
                Prints some information about the decoded TIFF file.

        -h
        --help
                Prints this help

Decoding options:

        -f TIFF_FILE
        --file TIFF_FILE
                Specifies the TIFF file to decode. The code supports both single and multi-image
                tiff files with the following limitations:
                  * color space must be either Grayscale (PhotometricInterp.=1) or RGB (=2)
                  * image data compressed with LZW (Compression=5) or uncompressed
                  * pixel components stored in "chunky" format (RGB..., PlanarConfiguration=1)
                    for RGB images
                  * image data must be organized in Strips, not Tiles
                  * pixels of RGB images must be represented with at most 4 components
                  * each component must be represented exactly with:
                  * 8 bits for LZW compressed images
                  * 8, 16 or 32 bits for uncompressed images
                  * all images in the file must have the same properties

        -b BEG_FRM
        --frame-beg BEG_FRM
                Specifies the image id in the input TIFF file to start decoding from.  The image
                id must be a value between 0 and the total number of images in the file minus 1.
                Values less than 0 are clamped to 0.
                Default: 0

        -e END_FRM
        --frame-end END_FRM
                Specifies the image id in the input TIFF file to stop  decoding  at  (included).
                The image id must be a value between 0 and the total number  of  images  in  the
                file minus 1.  Values greater than num_images-1  are  clamped  to  num_images-1.
                Default:  num_images-1.

        -m
        --memtype TYPE
                Specifies the type of memory used to hold  the  TIFF  file  content:  pinned  or
                pageable.  Pinned memory is used if 'p' is specified. Pageable memory is used if
                'r' is specified.  In case of pinned memory,  file  content  is  not  copied  to
                device memory before the decoding process (with a resulting performance  impact)
                unless the option -c is also specified (see below).
                Defualt: r (pageable)

        -c
        --copyh2d
                Specifies to copy the file data to device memory in case the -m option specifies
                to use pinned memory.  In case of pageable memory this  option  has  no  effect.
                Default: off.

        --decode-out NUM_OUT
                Enables the writing of selected images from the decoded  input  TIFF  file  into
                separate BMP files for inspection.  If no argument is  passed,  only  the  first
                image is written to disk,  otherwise  the  first  NUM_OUT  images  are  written.
                Output files are named outImage_0.bmp, outImage_1.bmp...
                Defualt: disabled.

Encoding options:

        -E
        --encode
                This option enables the encoding of the raster images obtained by  decoding  the
                input TIFF file.  The images are divided into strips, compressed  with  LZW and,
                optionally, written into an output TIFF file.
                Default: disabled.

        --encode-out
                Enables the writing of the compressed  images  to  an  output  TIFF  file named
                outFile.tif.
                This option is ignored if -E is not specified.
                Defualt: disabled.