-
Notifications
You must be signed in to change notification settings - Fork 74
How to use the API
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.
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).
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.
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.
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.
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.
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.
#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 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;
}