/* sane - Scanner Access Now Easy. Copyright (C) 2019 Povilas Kanapickas This file is part of the SANE package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef BACKEND_GENESYS_UTILITIES_H #define BACKEND_GENESYS_UTILITIES_H #include "error.h" #include #include #include #include #include namespace genesys { // just like SANE_FIX and SANE_UNFIX except that the conversion is done by a function and argument // precision is handled correctly inline SANE_Word double_to_fixed(double v) { return static_cast(v * (1 << SANE_FIXED_SCALE_SHIFT)); } inline SANE_Word float_to_fixed(float v) { return static_cast(v * (1 << SANE_FIXED_SCALE_SHIFT)); } inline float fixed_to_float(SANE_Word v) { return static_cast(v) / (1 << SANE_FIXED_SCALE_SHIFT); } inline double fixed_to_double(SANE_Word v) { return static_cast(v) / (1 << SANE_FIXED_SCALE_SHIFT); } template inline T abs_diff(T a, T b) { if (a < b) { return b - a; } else { return a - b; } } inline std::uint64_t align_multiple_floor(std::uint64_t x, std::uint64_t multiple) { if (multiple == 0) { return x; } return (x / multiple) * multiple; } inline std::uint64_t align_multiple_ceil(std::uint64_t x, std::uint64_t multiple) { if (multiple == 0) { return x; } return ((x + multiple - 1) / multiple) * multiple; } inline std::uint64_t multiply_by_depth_ceil(std::uint64_t pixels, std::uint64_t depth) { if (depth == 1) { return (pixels / 8) + ((pixels % 8) ? 1 : 0); } else { return pixels * (depth / 8); } } template inline T clamp(const T& value, const T& lo, const T& hi) { if (value < lo) return lo; if (value > hi) return hi; return value; } template void compute_array_percentile_approx(T* result, const T* data, std::size_t line_count, std::size_t elements_per_line, float percentile) { if (line_count == 0) { throw SaneException("invalid line count"); } if (line_count == 1) { std::copy(data, data + elements_per_line, result); return; } std::vector column_elems; column_elems.resize(line_count, 0); std::size_t select_elem = std::min(static_cast(line_count * percentile), line_count - 1); auto select_it = column_elems.begin() + select_elem; for (std::size_t ix = 0; ix < elements_per_line; ++ix) { for (std::size_t iy = 0; iy < line_count; ++iy) { column_elems[iy] = data[iy * elements_per_line + ix]; } std::nth_element(column_elems.begin(), select_it, column_elems.end()); *result++ = *select_it; } } class Ratio { public: Ratio() : multiplier_{1}, divisor_{1} { } Ratio(unsigned multiplier, unsigned divisor) : multiplier_{multiplier}, divisor_{divisor} { } unsigned multiplier() const { return multiplier_; } unsigned divisor() const { return divisor_; } unsigned apply(unsigned arg) const { return static_cast(arg) * multiplier_ / divisor_; } int apply(int arg) const { return static_cast(arg) * multiplier_ / divisor_; } float apply(float arg) const { return arg * multiplier_ / divisor_; } unsigned apply_inverse(unsigned arg) const { return static_cast(arg) * divisor_ / multiplier_; } int apply_inverse(int arg) const { return static_cast(arg) * divisor_ / multiplier_; } float apply_inverse(float arg) const { return arg * divisor_ / multiplier_; } bool operator==(const Ratio& other) const { return multiplier_ == other.multiplier_ && divisor_ == other.divisor_; } private: unsigned multiplier_; unsigned divisor_; template friend void serialize(Stream& str, Ratio& x); }; template void serialize(Stream& str, Ratio& x) { serialize(str, x.multiplier_); serialize(str, x.divisor_); } inline std::ostream& operator<<(std::ostream& out, const Ratio& ratio) { out << ratio.multiplier() << "/" << ratio.divisor(); return out; } template class BasicStreamStateSaver { public: explicit BasicStreamStateSaver(std::basic_ios& stream) : stream_(stream) { flags_ = stream_.flags(); width_ = stream_.width(); precision_ = stream_.precision(); fill_ = stream_.fill(); } ~BasicStreamStateSaver() { stream_.flags(flags_); stream_.width(width_); stream_.precision(precision_); stream_.fill(fill_); } BasicStreamStateSaver(const BasicStreamStateSaver&) = delete; BasicStreamStateSaver& operator=(const BasicStreamStateSaver&) = delete; private: std::basic_ios& stream_; std::ios_base::fmtflags flags_; std::streamsize width_ = 0; std::streamsize precision_ = 0; Char fill_ = ' '; }; using StreamStateSaver = BasicStreamStateSaver>; template std::string format_indent_braced_list(unsigned indent, const T& x) { std::string indent_str(indent, ' '); std::ostringstream out; out << x; auto formatted_str = out.str(); if (formatted_str.empty()) { return formatted_str; } std::string out_str; for (std::size_t i = 0; i < formatted_str.size(); ++i) { out_str += formatted_str[i]; if (formatted_str[i] == '\n' && i < formatted_str.size() - 1 && formatted_str[i + 1] != '\n') { out_str += indent_str; } } return out_str; } template std::string format_vector_unsigned(unsigned indent, const std::vector& arg) { std::ostringstream out; std::string indent_str(indent, ' '); out << "std::vector{ "; for (const auto& el : arg) { out << indent_str << static_cast(el) << "\n"; } out << "}"; return out.str(); } template std::string format_vector_indent_braced(unsigned indent, const char* type, const std::vector& arg) { if (arg.empty()) { return "{}"; } std::string indent_str(indent, ' '); std::stringstream out; out << "std::vector<" << type << ">{\n"; for (const auto& item : arg) { out << indent_str << format_indent_braced_list(indent, item) << '\n'; } out << "}"; return out.str(); } } // namespace genesys #endif // BACKEND_GENESYS_UTILITIES_H