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