PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
frame_deflate_codec.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
7
8#include <algorithm>
9#include <cstring>
10
11#ifdef PACS_WITH_ZLIB
12#include <zlib.h>
13#endif
14
16
18 : compression_level_(
19 std::clamp(compression_level,
20 kMinCompressionLevel,
21 kMaxCompressionLevel)) {}
22
24
26frame_deflate_codec& frame_deflate_codec::operator=(frame_deflate_codec&&) noexcept = default;
27
28std::string_view frame_deflate_codec::transfer_syntax_uid() const noexcept {
29 return kTransferSyntaxUID;
30}
31
32std::string_view frame_deflate_codec::name() const noexcept {
33 return "Frame Deflate";
34}
35
36bool frame_deflate_codec::is_lossy() const noexcept {
37 return false;
38}
39
40bool frame_deflate_codec::can_encode(const image_params& params) const noexcept {
41 if (params.width == 0 || params.height == 0) {
42 return false;
43 }
44
45 // Frame Deflate supports grayscale only (optimized for segmentation masks)
46 if (params.samples_per_pixel != 1) {
47 return false;
48 }
49
50 // Support 1-bit through 16-bit
51 if (params.bits_stored < 1 || params.bits_stored > 16) {
52 return false;
53 }
54
55 return true;
56}
57
58bool frame_deflate_codec::can_decode(const image_params& params) const noexcept {
59 return can_encode(params);
60}
61
63 return compression_level_;
64}
65
66#ifdef PACS_WITH_ZLIB
67
69 std::span<const uint8_t> pixel_data,
70 const image_params& params,
71 [[maybe_unused]] const compression_options& options) const {
72
73 if (pixel_data.empty()) {
76 }
77
78 if (params.width == 0 || params.height == 0) {
80 kcenon::pacs::error_codes::compression_error, "Invalid image dimensions");
81 }
82
83 // Calculate expected data size
84 const size_t expected_size = params.frame_size_bytes();
85 if (pixel_data.size() < expected_size) {
88 "Pixel data too small: expected " + std::to_string(expected_size)
89 + " bytes, got " + std::to_string(pixel_data.size()));
90 }
91
92 // Estimate compressed output size (zlib recommends deflateBound)
93 uLong source_len = static_cast<uLong>(expected_size);
94 uLong bound = compressBound(source_len);
95 std::vector<uint8_t> compressed(bound);
96
97 uLong dest_len = bound;
98 int ret = compress2(compressed.data(), &dest_len,
99 pixel_data.data(), source_len,
101
102 if (ret != Z_OK) {
105 "zlib compress2 failed with error code: " + std::to_string(ret));
106 }
107
108 compressed.resize(dest_len);
109
110 return kcenon::pacs::ok<compression_result>(
111 compression_result{std::move(compressed), params});
112}
113
114codec_result frame_deflate_codec::decode(
115 std::span<const uint8_t> compressed_data,
116 const image_params& params) const {
117
118 if (compressed_data.empty()) {
120 kcenon::pacs::error_codes::decompression_error, "Empty compressed data");
121 }
122
123 // Calculate expected decompressed size
124 const size_t expected_size = params.frame_size_bytes();
125 if (expected_size == 0) {
128 "Cannot determine output size from image parameters");
129 }
130
131 std::vector<uint8_t> decompressed(expected_size);
132 uLong dest_len = static_cast<uLong>(expected_size);
133 uLong source_len = static_cast<uLong>(compressed_data.size());
134
135 int ret = uncompress(decompressed.data(), &dest_len,
136 compressed_data.data(), source_len);
137
138 if (ret != Z_OK) {
141 "zlib uncompress failed with error code: " + std::to_string(ret));
142 }
143
144 if (dest_len != expected_size) {
147 "Decompressed size mismatch: expected " + std::to_string(expected_size)
148 + " bytes, got " + std::to_string(dest_len));
149 }
150
151 return kcenon::pacs::ok<compression_result>(
152 compression_result{std::move(decompressed), params});
153}
154
155#else // !PACS_WITH_ZLIB
156
158 [[maybe_unused]] std::span<const uint8_t> pixel_data,
159 [[maybe_unused]] const image_params& params,
160 [[maybe_unused]] const compression_options& options) const {
163 "Frame Deflate codec not available: zlib library not found at build time");
164}
165
167 [[maybe_unused]] std::span<const uint8_t> compressed_data,
168 [[maybe_unused]] const image_params& params) const {
171 "Frame Deflate codec not available: zlib library not found at build time");
172}
173
174#endif // PACS_WITH_ZLIB
175
176} // namespace kcenon::pacs::encoding::compression
Frame-level Deflate codec implementation (Supplement 244).
int compression_level() const noexcept
Gets the current zlib compression level.
frame_deflate_codec(int compression_level=kDefaultCompressionLevel)
Constructs a Frame Deflate codec instance.
bool can_encode(const image_params &params) const noexcept override
Checks if this codec supports the given image parameters.
bool is_lossy() const noexcept override
Checks if this codec produces lossy compression.
std::string_view name() const noexcept override
Returns a human-readable name for the codec.
codec_result encode(std::span< const uint8_t > pixel_data, const image_params &params, const compression_options &options={}) const override
Compresses pixel data using zlib deflate.
bool can_decode(const image_params &params) const noexcept override
Checks if this codec can decode data with given parameters.
codec_result decode(std::span< const uint8_t > compressed_data, const image_params &params) const override
Decompresses deflate-compressed pixel data.
constexpr int compression_error
Definition result.h:78
constexpr int decompression_error
Definition result.h:79
Result< T > pacs_error(int code, const std::string &message, const std::string &details="")
Create a PACS error result with module context.
Definition result.h:234
Result<T> type aliases and helpers for PACS system.
Compression quality settings for lossy codecs.
Parameters describing image pixel data.
uint16_t height
Image height in pixels (Rows - 0028,0010)
size_t frame_size_bytes() const noexcept
Calculates the size of uncompressed pixel data in bytes.
uint16_t width
Image width in pixels (Columns - 0028,0011)