1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt>
4
5 This file is part of the SANE package.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
19
20 As a special exception, the authors of SANE give permission for
21 additional uses of the libraries contained in this release of SANE.
22
23 The exception is that, if you link a SANE library with other files
24 to produce an executable, this does not by itself cause the
25 resulting executable to be covered by the GNU General Public
26 License. Your use of that executable is in no way restricted on
27 account of linking the SANE library code into it.
28
29 This exception does not, however, invalidate any other reasons why
30 the executable file might be covered by the GNU General Public
31 License.
32
33 If you submit changes to SANE to the maintainers to be included in
34 a subsequent release, you agree by submitting the changes that
35 those changes may be distributed with this exception intact.
36
37 If you write modifications of your own for SANE, it is your choice
38 whether to permit this exception to apply to your modifications.
39 If you do not wish that, delete this exception notice.
40 */
41
42 #ifndef BACKEND_GENESYS_UTILITIES_H
43 #define BACKEND_GENESYS_UTILITIES_H
44
45 #include "error.h"
46 #include <algorithm>
47 #include <cstdint>
48 #include <iostream>
49 #include <sstream>
50 #include <vector>
51
52
53 namespace genesys {
54
55 // just like SANE_FIX and SANE_UNFIX except that the conversion is done by a function and argument
56 // precision is handled correctly
double_to_fixed(double v)57 inline SANE_Word double_to_fixed(double v)
58 {
59 return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
60 }
61
float_to_fixed(float v)62 inline SANE_Word float_to_fixed(float v)
63 {
64 return static_cast<SANE_Word>(v * (1 << SANE_FIXED_SCALE_SHIFT));
65 }
66
fixed_to_float(SANE_Word v)67 inline float fixed_to_float(SANE_Word v)
68 {
69 return static_cast<float>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
70 }
71
fixed_to_double(SANE_Word v)72 inline double fixed_to_double(SANE_Word v)
73 {
74 return static_cast<double>(v) / (1 << SANE_FIXED_SCALE_SHIFT);
75 }
76
77 template<class T>
abs_diff(T a,T b)78 inline T abs_diff(T a, T b)
79 {
80 if (a < b) {
81 return b - a;
82 } else {
83 return a - b;
84 }
85 }
86
align_multiple_floor(std::uint64_t x,std::uint64_t multiple)87 inline std::uint64_t align_multiple_floor(std::uint64_t x, std::uint64_t multiple)
88 {
89 if (multiple == 0) {
90 return x;
91 }
92 return (x / multiple) * multiple;
93 }
94
align_multiple_ceil(std::uint64_t x,std::uint64_t multiple)95 inline std::uint64_t align_multiple_ceil(std::uint64_t x, std::uint64_t multiple)
96 {
97 if (multiple == 0) {
98 return x;
99 }
100 return ((x + multiple - 1) / multiple) * multiple;
101 }
102
multiply_by_depth_ceil(std::uint64_t pixels,std::uint64_t depth)103 inline std::uint64_t multiply_by_depth_ceil(std::uint64_t pixels, std::uint64_t depth)
104 {
105 if (depth == 1) {
106 return (pixels / 8) + ((pixels % 8) ? 1 : 0);
107 } else {
108 return pixels * (depth / 8);
109 }
110 }
111
112 template<class T>
clamp(const T & value,const T & lo,const T & hi)113 inline T clamp(const T& value, const T& lo, const T& hi)
114 {
115 if (value < lo)
116 return lo;
117 if (value > hi)
118 return hi;
119 return value;
120 }
121
122 template<class T>
compute_array_percentile_approx(T * result,const T * data,std::size_t line_count,std::size_t elements_per_line,float percentile)123 void compute_array_percentile_approx(T* result, const T* data,
124 std::size_t line_count, std::size_t elements_per_line,
125 float percentile)
126 {
127 if (line_count == 0) {
128 throw SaneException("invalid line count");
129 }
130
131 if (line_count == 1) {
132 std::copy(data, data + elements_per_line, result);
133 return;
134 }
135
136 std::vector<T> column_elems;
137 column_elems.resize(line_count, 0);
138
139 std::size_t select_elem = std::min(static_cast<std::size_t>(line_count * percentile),
140 line_count - 1);
141
142 auto select_it = column_elems.begin() + select_elem;
143
144 for (std::size_t ix = 0; ix < elements_per_line; ++ix) {
145 for (std::size_t iy = 0; iy < line_count; ++iy) {
146 column_elems[iy] = data[iy * elements_per_line + ix];
147 }
148
149 std::nth_element(column_elems.begin(), select_it, column_elems.end());
150
151 *result++ = *select_it;
152 }
153 }
154
155 class Ratio
156 {
157 public:
Ratio()158 Ratio() : multiplier_{1}, divisor_{1}
159 {
160 }
161
Ratio(unsigned multiplier,unsigned divisor)162 Ratio(unsigned multiplier, unsigned divisor) : multiplier_{multiplier}, divisor_{divisor}
163 {
164 }
165
multiplier()166 unsigned multiplier() const { return multiplier_; }
divisor()167 unsigned divisor() const { return divisor_; }
168
apply(unsigned arg)169 unsigned apply(unsigned arg) const
170 {
171 return static_cast<std::uint64_t>(arg) * multiplier_ / divisor_;
172 }
173
apply(int arg)174 int apply(int arg) const
175 {
176 return static_cast<std::int64_t>(arg) * multiplier_ / divisor_;
177 }
178
apply(float arg)179 float apply(float arg) const
180 {
181 return arg * multiplier_ / divisor_;
182 }
183
apply_inverse(unsigned arg)184 unsigned apply_inverse(unsigned arg) const
185 {
186 return static_cast<std::uint64_t>(arg) * divisor_ / multiplier_;
187 }
188
apply_inverse(int arg)189 int apply_inverse(int arg) const
190 {
191 return static_cast<std::int64_t>(arg) * divisor_ / multiplier_;
192 }
193
apply_inverse(float arg)194 float apply_inverse(float arg) const
195 {
196 return arg * divisor_ / multiplier_;
197 }
198
199 bool operator==(const Ratio& other) const
200 {
201 return multiplier_ == other.multiplier_ && divisor_ == other.divisor_;
202 }
203 private:
204 unsigned multiplier_;
205 unsigned divisor_;
206
207 template<class Stream>
208 friend void serialize(Stream& str, Ratio& x);
209 };
210
211 template<class Stream>
serialize(Stream & str,Ratio & x)212 void serialize(Stream& str, Ratio& x)
213 {
214 serialize(str, x.multiplier_);
215 serialize(str, x.divisor_);
216 }
217
218 inline std::ostream& operator<<(std::ostream& out, const Ratio& ratio)
219 {
220 out << ratio.multiplier() << "/" << ratio.divisor();
221 return out;
222 }
223
224 template<class Char, class Traits>
225 class BasicStreamStateSaver
226 {
227 public:
BasicStreamStateSaver(std::basic_ios<Char,Traits> & stream)228 explicit BasicStreamStateSaver(std::basic_ios<Char, Traits>& stream) :
229 stream_{stream}
230 {
231 flags_ = stream_.flags();
232 width_ = stream_.width();
233 precision_ = stream_.precision();
234 fill_ = stream_.fill();
235 }
236
~BasicStreamStateSaver()237 ~BasicStreamStateSaver()
238 {
239 stream_.flags(flags_);
240 stream_.width(width_);
241 stream_.precision(precision_);
242 stream_.fill(fill_);
243 }
244
245 BasicStreamStateSaver(const BasicStreamStateSaver&) = delete;
246 BasicStreamStateSaver& operator=(const BasicStreamStateSaver&) = delete;
247
248 private:
249 std::basic_ios<Char, Traits>& stream_;
250 std::ios_base::fmtflags flags_;
251 std::streamsize width_ = 0;
252 std::streamsize precision_ = 0;
253 Char fill_ = ' ';
254 };
255
256 using StreamStateSaver = BasicStreamStateSaver<char, std::char_traits<char>>;
257
258 template<class T>
format_indent_braced_list(unsigned indent,const T & x)259 std::string format_indent_braced_list(unsigned indent, const T& x)
260 {
261 std::string indent_str(indent, ' ');
262 std::ostringstream out;
263 out << x;
264 auto formatted_str = out.str();
265 if (formatted_str.empty()) {
266 return formatted_str;
267 }
268
269 std::string out_str;
270 for (std::size_t i = 0; i < formatted_str.size(); ++i) {
271 out_str += formatted_str[i];
272
273 if (formatted_str[i] == '\n' &&
274 i < formatted_str.size() - 1 &&
275 formatted_str[i + 1] != '\n')
276 {
277 out_str += indent_str;
278 }
279 }
280 return out_str;
281 }
282
283 template<class T>
format_vector_unsigned(unsigned indent,const std::vector<T> & arg)284 std::string format_vector_unsigned(unsigned indent, const std::vector<T>& arg)
285 {
286 std::ostringstream out;
287 std::string indent_str(indent, ' ');
288
289 out << "std::vector<T>{ ";
290 for (const auto& el : arg) {
291 out << indent_str << static_cast<unsigned>(el) << "\n";
292 }
293 out << "}";
294 return out.str();
295 }
296
297 template<class T>
format_vector_indent_braced(unsigned indent,const char * type,const std::vector<T> & arg)298 std::string format_vector_indent_braced(unsigned indent, const char* type,
299 const std::vector<T>& arg)
300 {
301 if (arg.empty()) {
302 return "{}";
303 }
304 std::string indent_str(indent, ' ');
305 std::stringstream out;
306 out << "std::vector<" << type << ">{\n";
307 for (const auto& item : arg) {
308 out << indent_str << format_indent_braced_list(indent, item) << '\n';
309 }
310 out << "}";
311 return out.str();
312 }
313
314 } // namespace genesys
315
316 #endif // BACKEND_GENESYS_UTILITIES_H
317