1 // Copyright (c) Team CharLS.
2 // SPDX-License-Identifier: BSD-3-Clause
3 
4 #pragma once
5 
6 #include "constants.h"
7 #include "util.h"
8 
9 #include <cstdint>
10 
11 namespace charls {
12 
13 // Optimized trait classes for lossless compression of 8 bit color and 8/16 bit monochrome images.
14 // This class assumes MaximumSampleValue correspond to a whole number of bits, and no custom ResetValue is set when encoding.
15 // The point of this is to have the most optimized code for the most common and most demanding scenario.
16 template<typename SampleType, int32_t BitsPerPixel>
17 struct lossless_traits_impl
18 {
19     using sample_type = SampleType;
20 
21     static constexpr int32_t maximum_sample_value{(1U << BitsPerPixel) - 1};
22     static constexpr int32_t near_lossless{};
23     static constexpr int32_t quantized_bits_per_pixel{BitsPerPixel};
24     static constexpr int32_t range{compute_range_parameter(maximum_sample_value, near_lossless)};
25     static constexpr int32_t bits_per_pixel{BitsPerPixel};
26     static constexpr int32_t limit{compute_limit_parameter(BitsPerPixel)};
27     static constexpr int32_t reset_threshold{default_reset_value};
28 
compute_error_valuelossless_traits_impl29     FORCE_INLINE constexpr static int32_t compute_error_value(const int32_t d) noexcept
30     {
31         return modulo_range(d);
32     }
33 
is_nearlossless_traits_impl34     FORCE_INLINE constexpr static bool is_near(const int32_t lhs, const int32_t rhs) noexcept
35     {
36         return lhs == rhs;
37     }
38 
39     FORCE_INLINE constexpr static int32_t
modulo_rangelossless_traits_impl40     modulo_range(const int32_t error_value) noexcept
41     {
42         return (static_cast<int32_t>(static_cast<uint32_t>(error_value) << (int32_t_bit_count - bits_per_pixel))) >>
43                (int32_t_bit_count - bits_per_pixel);
44     }
45 
compute_reconstructed_samplelossless_traits_impl46     FORCE_INLINE static SampleType compute_reconstructed_sample(const int32_t predicted_value,
47                                                                 const int32_t error_value) noexcept
48     {
49         return static_cast<SampleType>(maximum_sample_value & (predicted_value + error_value));
50     }
51 
correct_predictionlossless_traits_impl52     FORCE_INLINE static int32_t correct_prediction(const int32_t predicted) noexcept
53     {
54         if ((predicted & maximum_sample_value) == predicted)
55             return predicted;
56 
57         return (~(predicted >> (int32_t_bit_count - 1))) & maximum_sample_value;
58     }
59 };
60 
61 
62 template<typename PixelType, int32_t BitsPerPixel>
63 struct lossless_traits final : lossless_traits_impl<PixelType, BitsPerPixel>
64 {
65     using pixel_type = PixelType;
66 };
67 
68 
69 template<>
70 struct lossless_traits<uint8_t, 8> final : lossless_traits_impl<uint8_t, 8>
71 {
72     using pixel_type = sample_type;
73 
74     FORCE_INLINE constexpr static signed char mod_range(const int32_t error_value) noexcept
75     {
76         return static_cast<signed char>(error_value);
77     }
78 
79     FORCE_INLINE constexpr static int32_t compute_error_value(const int32_t d) noexcept
80     {
81         return static_cast<signed char>(d);
82     }
83 
84     FORCE_INLINE constexpr static uint8_t compute_reconstructed_sample(const int32_t predicted_value,
85                                                                        const int32_t error_value) noexcept
86     {
87         return static_cast<uint8_t>(predicted_value + error_value);
88     }
89 };
90 
91 
92 template<>
93 struct lossless_traits<uint16_t, 16> final : lossless_traits_impl<uint16_t, 16>
94 {
95     using pixel_type = sample_type;
96 
97     FORCE_INLINE constexpr static short mod_range(const int32_t error_value) noexcept
98     {
99         return static_cast<short>(error_value);
100     }
101 
102     FORCE_INLINE constexpr static int32_t compute_error_value(const int32_t d) noexcept
103     {
104         return static_cast<short>(d);
105     }
106 
107     FORCE_INLINE constexpr static sample_type compute_reconstructed_sample(const int32_t predicted_value,
108                                                                            const int32_t error_value) noexcept
109     {
110         return static_cast<sample_type>(predicted_value + error_value);
111     }
112 };
113 
114 
115 template<typename PixelType, int32_t BitsPerPixel>
116 struct lossless_traits<triplet<PixelType>, BitsPerPixel> final : lossless_traits_impl<PixelType, BitsPerPixel>
117 {
118     using pixel_type = triplet<PixelType>;
119 
120     FORCE_INLINE constexpr static bool is_near(const int32_t lhs, const int32_t rhs) noexcept
121     {
122         return lhs == rhs;
123     }
124 
125     FORCE_INLINE static bool is_near(pixel_type lhs, pixel_type rhs) noexcept
126     {
127         return lhs == rhs;
128     }
129 
130     FORCE_INLINE static PixelType compute_reconstructed_sample(const int32_t predicted_value,
131                                                                const int32_t error_value) noexcept
132     {
133         return static_cast<PixelType>(predicted_value + error_value);
134     }
135 };
136 
137 
138 template<typename PixelType, int32_t BitsPerPixel>
139 struct lossless_traits<quad<PixelType>, BitsPerPixel> final : lossless_traits_impl<PixelType, BitsPerPixel>
140 {
141     using pixel_type = quad<PixelType>;
142 
143     FORCE_INLINE constexpr static bool is_near(const int32_t lhs, const int32_t rhs) noexcept
144     {
145         return lhs == rhs;
146     }
147 
148     FORCE_INLINE static bool is_near(pixel_type lhs, pixel_type rhs) noexcept
149     {
150         return lhs == rhs;
151     }
152 
153     FORCE_INLINE static PixelType compute_reconstructed_sample(const int32_t predicted_value,
154                                                                const int32_t error_value) noexcept
155     {
156         return static_cast<PixelType>(predicted_value + error_value);
157     }
158 };
159 
160 } // namespace charls
161