12#ifdef PACS_WITH_JPEGLS_CODEC
13#include <charls/charls.h>
20#ifdef PACS_WITH_JPEGLS_CODEC
27[[nodiscard]] charls::interleave_mode get_interleave_mode(
const image_params& params) {
28 if (params.samples_per_pixel == 1) {
29 return charls::interleave_mode::none;
32 return (params.planar_configuration == 0)
33 ? charls::interleave_mode::sample
34 : charls::interleave_mode::line;
40[[nodiscard]] charls::color_transformation get_color_transform(
const image_params& params) {
41 if (params.samples_per_pixel == 1) {
42 return charls::color_transformation::none;
46 return charls::color_transformation::none;
91#ifndef PACS_WITH_JPEGLS_CODEC
96 "JPEG-LS codec not available: CharLS library not found at build time");
99 if (pixel_data.empty()) {
109 bool use_lossless =
lossless_ || options.lossless;
113 }
else if (!
lossless_ && options.quality > 0 && options.quality <= 100) {
117 effective_near =
static_cast<int>((100 - options.quality) * 10 / 100);
118 effective_near = std::clamp(effective_near, 0,
kMaxNearValue);
123 charls::jpegls_encoder encoder;
126 charls::frame_info frame_info{};
127 frame_info.width = params.
width;
128 frame_info.height = params.
height;
132 encoder.frame_info(frame_info);
135 encoder.interleave_mode(get_interleave_mode(params));
138 encoder.near_lossless(effective_near);
141 encoder.color_transformation(get_color_transform(params));
146 size_t estimated_size = encoder.estimated_destination_size();
147 size_t safe_size = (std::max)({
149 pixel_data.size() + pixel_data.size() / 5,
150 pixel_data.size() + 1024
152 std::vector<uint8_t> destination(safe_size);
155 encoder.destination(destination);
156 size_t bytes_written = encoder.encode(pixel_data);
159 destination.resize(bytes_written);
161 return kcenon::pacs::ok<compression_result>(
compression_result{std::move(destination), params});
163 }
catch (
const charls::jpegls_error& e) {
165 std::string(
"JPEG-LS encoding failed: ") + e.what());
166 }
catch (
const std::exception& e) {
168 std::string(
"JPEG-LS encoding failed: ") + e.what());
175#ifndef PACS_WITH_JPEGLS_CODEC
176 (void)compressed_data;
179 "JPEG-LS codec not available: CharLS library not found at build time");
181 if (compressed_data.empty()) {
187 charls::jpegls_decoder decoder;
188 decoder.source(compressed_data);
191 decoder.read_header();
194 const charls::frame_info& frame_info = decoder.frame_info();
198 output_params.
width =
static_cast<uint16_t
>(frame_info.width);
199 output_params.
height =
static_cast<uint16_t
>(frame_info.height);
200 output_params.
bits_stored =
static_cast<uint16_t
>(frame_info.bits_per_sample);
201 output_params.
bits_allocated = (frame_info.bits_per_sample <= 8) ? 8 : 16;
203 output_params.
samples_per_pixel =
static_cast<uint16_t
>(frame_info.component_count);
206 if (frame_info.component_count == 1) {
208 }
else if (frame_info.component_count == 3) {
215 std::to_string(params.
width) +
", got " +
216 std::to_string(output_params.
width));
220 std::to_string(params.
height) +
", got " +
221 std::to_string(output_params.
height));
225 size_t destination_size = decoder.destination_size();
226 std::vector<uint8_t> destination(destination_size);
229 decoder.decode(destination);
234 return kcenon::pacs::ok<compression_result>(
compression_result{std::move(destination), output_params});
236 }
catch (
const charls::jpegls_error& e) {
238 std::string(
"JPEG-LS decoding failed: ") + e.what());
239 }
catch (
const std::exception& e) {
241 std::string(
"JPEG-LS decoding failed: ") + e.what());
254 : impl_(std::make_unique<
impl>(lossless, near_value)) {}
262 return impl_->
is_lossless_mode() ? kTransferSyntaxUIDLossless : kTransferSyntaxUIDNearLossless;
275 if (params.bits_stored < 2 || params.bits_stored > 16) {
280 if (params.bits_allocated != 8 && params.bits_allocated != 16) {
285 if (params.samples_per_pixel != 1 && params.samples_per_pixel != 3) {
290 if (params.width == 0 || params.height == 0) {
295 if (params.width > 65535 || params.height > 65535) {
305 if (params.samples_per_pixel != 0 &&
306 params.samples_per_pixel != 1 &&
307 params.samples_per_pixel != 3) {
PIMPL implementation for jpeg_ls_codec.
codec_result decode(std::span< const uint8_t > compressed_data, const image_params ¶ms) const
int near_value() const noexcept
codec_result encode(std::span< const uint8_t > pixel_data, const image_params ¶ms, const compression_options &options) const
impl(bool lossless, int near_value)
bool is_lossless_mode() const noexcept
JPEG-LS codec implementation supporting both lossless and near-lossless modes.
~jpeg_ls_codec() override
bool is_lossless_mode() const noexcept
Checks if this codec is configured for lossless mode.
static constexpr int kMaxNearValue
Maximum NEAR parameter value (higher = more compression, more loss)
jpeg_ls_codec(bool lossless=true, int near_value=kAutoNearValue)
Constructs a JPEG-LS codec instance.
static constexpr int kLosslessNearValue
NEAR parameter for lossless mode.
codec_result encode(std::span< const uint8_t > pixel_data, const image_params ¶ms, const compression_options &options={}) const override
Compresses pixel data to JPEG-LS format.
static constexpr int kDefaultNearLosslessValue
Default NEAR parameter for near-lossless mode (visually lossless quality)
int near_value() const noexcept
Gets the NEAR parameter value.
codec_result decode(std::span< const uint8_t > compressed_data, const image_params ¶ms) const override
Decompresses JPEG-LS data.
std::string_view name() const noexcept override
Returns a human-readable name for the codec.
std::unique_ptr< impl > impl_
static constexpr int kAutoNearValue
Sentinel value indicating "auto-determine NEAR based on mode".
bool is_lossy() const noexcept override
Checks if this codec produces lossy compression.
bool can_encode(const image_params ¶ms) const noexcept override
Checks if this codec supports the given image parameters.
bool can_decode(const image_params ¶ms) const noexcept override
Checks if this codec can decode data with given parameters.
@ monochrome2
Minimum pixel value displayed as black.
@ rgb
Red, Green, Blue color model.
constexpr int decompression_error
Result< T > pacs_error(int code, const std::string &message, const std::string &details="")
Create a PACS error result with module context.
Result<T> type aliases and helpers for PACS system.
Compression quality settings for lossy codecs.
Successful result of a compression/decompression operation.
Parameters describing image pixel data.
uint16_t samples_per_pixel
Number of samples per pixel (0028,0002) 1 for grayscale, 3 for color.
uint16_t bits_allocated
Bits allocated per pixel sample (0028,0100) Valid values: 8, 16.
uint16_t height
Image height in pixels (Rows - 0028,0010)
photometric_interpretation photometric
Photometric interpretation (0028,0004)
uint16_t planar_configuration
Planar configuration (0028,0006) 0 = interleaved (R1G1B1R2G2B2...), 1 = separate planes (RRR....
uint16_t width
Image width in pixels (Columns - 0028,0011)
uint16_t bits_stored
Bits stored per pixel sample (0028,0101) Must be <= bits_allocated.
uint16_t high_bit
High bit position (0028,0102) Typically bits_stored - 1.