Skip to content
Victor Derks edited this page Sep 1, 2024 · 7 revisions

Introduction

CharLS comes with a C API as its primary ABI and 2 C++ classes for encoding and decoding. These C++ classes are header-only classes and will call into the C API functions.

Samples

The CharLS source code package comes with two samples. A sample written in C17 and a sample written C++17. These samples demonstrate how to encode a 24-bit RGB Windows Bitmap file (.bmp) to a standalone JPEG-LS encoded file (.jls).

Interface file

The header file that needs to be included is charls.hpp for C++ applications and charls.h for C applications. All public API functions are documented with the Microsoft XML documentation format. Depending on the used IDE, this API documentation is automatically available as a tooltip.

Pixel data input and output format

Single component image (monochrome)

CharLS can process and can generate native pixel data that uses padding to align the start of a line on a specific address boundary (for example a 32-bit boundary). This information can be provided with the stride parameter. A stride of 0 can be used to indicate that no padding for the alignment is needed.

Multi component image (typical RGB color)

Besides the alignment option, CharLS expects a different input format depending on the selected interleave mode and will generate a different output format depending how the JPEG-LS encoded data is stored in the bit-stream. A different format is needed as the image is encoded / decoded per line in a forward only process. For monochrome images this format requirement is not important as only 1 component is encoded, but for multi-component images, like color images, it is crucial to handle the difference.

The expected format for a RGB image is for example:

interleave mode native format encoded format
none by plane: RRRRGGGGBBBB scan 1:rrr, scan 2:ggg, scan 3: bbb
line by pixel: RGBRGBRGBRGB scan 1: rrrgggbbb
sample by pixel: RGBRGBRGBRGB scan 1: rgbrgbrgb

Note that line and sample use the same native format. Many viewing pipelines can only handle the "by pixel" format and a pre/post processing step may be needed to transform the native input/output format to the "by plane" format to encode it in the interleave mode "none". The included samples demonstrate this step. The interleave mode "none" is in general faster to encode/decode and provides a better compression ratio.

Bit sizes

Pixel samples are always interpreted in the native endian format of the system. In most cases this means Little Endian. This is important for bit sizes larger than 8 bits which require 2 bytes. The least significant bits are used and for bit sizes other then 8 and 16 the not used bits should be set to zero.

API Instructions

The paragraphs below show how to use the C++ CharLS API. The C API is not demonstrated explicitly, but it usages follows the same patterns.

Decoding with the C++ API

#include <charls/charls.hpp>
#include <vector>
#include <tuple>

std::vector<std::byte> decode_simple_8_bit_monochrome(const std::vector<std::byte>& source)
{
    std::vector<std::byte> destination;

    if (const auto [frame_info, _] = charls::jpegls_decoder::decode(source, destination);
        frame_info.component_count != 1 || frame_info.bits_per_sample != 8)
        throw std::runtime_error("Not a 8 bit monochrome image");

    return destination;
}

Decoding JPEG-LS images for which the format is already known is relatively easy. It is more complex to decode unknown JPEG-LS images. In such cases a jpegls_decoder instance can be constructed.

#include <charls/charls.hpp>
#include <vector>

std::vector<std::byte> decode_advanced(const std::vector<std::byte>& source)
{
    charls::jpegls_decoder decoder{source, true};

    // Standalone JPEG-LS files may have a SPIFF header (color space info, etc.)
    if (decoder.spiff_header_has_value() &&
        decoder.spiff_header().color_space != charls::spiff_color_space::grayscale)
        throw std::exception("Not a grayscale image");

    if (decoder.near_lossless() != 0)
    {
        // Handle near-lossless (lossy) images.
    }

    return decoder.decode<std::vector<std::byte>>();
}

Encoding with the C++ API

Encoding lossless monochrome images or color images with the interleave mode "none" to a STL vector container can be done with the static template function encode. This function creates a STL container with the encoded JPEG-LS data that can be saved to a file.

#include <charls/charls.hpp>
#include <vector>

std::vector<std::byte> encode_simple_8_bit_monochrome(const std::vector<std::byte>& source,
                                                      const uint32_t width,
                                                      const uint32_t height)
{
    constexpr auto bits_per_sample{8};
    constexpr auto component_count{1};
    return charls::jpegls_encoder::encode(source,
                                          {width, height, bits_per_sample, component_count});
}

For more advanced options and to create standalone .jls files, the pattern is to create an jpegls_encoder instance, configure it and call encode on the encoder instance.

#include <charls/charls.hpp>
#include <vector>

std::vector<std::byte> encode_advanced_8_bit_monochrome(const std::vector<std::byte>& source,
                                                        const uint32_t width,
                                                        const uint32_t height)
{
    charls::jpegls_encoder encoder;
    encoder.frame_info({width, height, 8, 1})
           .encoding_options(encoding_options::include_version_number);

    std::vector<std::byte> destination(encoder.estimated_destination_size());
    encoder.destination(destination);

    encoder.write_standard_spiff_header(charls::spiff_color_space::grayscale);

    const size_t bytes_written{encoder.encode(source)};
    destination.resize(bytes_written);

    return destination;
}