LCOV - code coverage report
Current view: top level - core/bitmap - SPBitmap.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 181 198 91.4 %
Date: 2024-05-12 00:16:13 Functions: 43 44 97.7 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
       3             : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       4             : 
       5             : Permission is hereby granted, free of charge, to any person obtaining a copy
       6             : of this software and associated documentation files (the "Software"), to deal
       7             : in the Software without restriction, including without limitation the rights
       8             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       9             : copies of the Software, and to permit persons to whom the Software is
      10             : furnished to do so, subject to the following conditions:
      11             : 
      12             : The above copyright notice and this permission notice shall be included in
      13             : all copies or substantial portions of the Software.
      14             : 
      15             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      16             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      17             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      18             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      19             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      20             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      21             : THE SOFTWARE.
      22             : **/
      23             : 
      24             : #ifndef STAPPLER_BITMAP_SPBITMAP_H_
      25             : #define STAPPLER_BITMAP_SPBITMAP_H_
      26             : 
      27             : #include "SPBitmapFormat.h"
      28             : #include "SPFilepath.h"
      29             : #include "SPLog.h" // for SPASSERT
      30             : 
      31             : namespace STAPPLER_VERSIONIZED stappler::bitmap {
      32             : 
      33             : enum class ResampleFilter {
      34             :         Box, // "box"
      35             :         Tent, // "tent"
      36             :         Bell, // "bell"
      37             :         BSpline, // "b-spline"
      38             :         Mitchell, // "mitchell"
      39             :         Lanczos3, // "lanczos3"
      40             :         Blackman, // "blackman"
      41             :         Lanczos4, // "Lanczos4"
      42             :         Lanczos6, // "lanczos6"
      43             :         Lanczos12, // "lanczos12"
      44             :         Kaiser, // "kaiser"
      45             :         Gaussian, // "gaussian"
      46             :         Catmullrom, // "catmullrom"
      47             :         QuadInterp, // "quadratic_interp"
      48             :         QuadApprox, // "quadratic_approx"
      49             :         QuadMix, // "quadratic_mix"
      50             : 
      51             :         Default = Lanczos4,
      52             : };
      53             : 
      54             : template <typename Interface>
      55             : class BitmapTemplate : public Interface::AllocBaseType {
      56             : public:
      57             :         BitmapTemplate();
      58             : 
      59             :         // init with jpeg, png or another formatted data
      60             :         BitmapTemplate(BytesView, const StrideFn &strideFn = nullptr);
      61             : 
      62             :         BitmapTemplate(const uint8_t *, size_t, const StrideFn &strideFn = nullptr);
      63             : 
      64             :         // init with raw data
      65             :         BitmapTemplate(const uint8_t *d, uint32_t width, uint32_t height,
      66             :                         PixelFormat c = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Premultiplied, uint32_t stride = 0);
      67             : 
      68             :         BitmapTemplate(BytesView d, uint32_t width, uint32_t height,
      69             :                         PixelFormat c = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Premultiplied, uint32_t stride = 0);
      70             : 
      71             :         BitmapTemplate(typename Interface::BytesType &&d, uint32_t width, uint32_t height,
      72             :                         PixelFormat c = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Premultiplied, uint32_t stride = 0);
      73             : 
      74             :         BitmapTemplate(const BitmapTemplate &) = delete;
      75             :         BitmapTemplate &operator =(const BitmapTemplate &) = delete;
      76             : 
      77             :         BitmapTemplate(BitmapTemplate &&);
      78             :         BitmapTemplate &operator =(BitmapTemplate &&);
      79             : 
      80    88767247 :         uint32_t width() const { return _width; }
      81      150622 :         uint32_t height() const { return _height; }
      82        5303 :         uint32_t stride() const { return _stride; }
      83             : 
      84             :         bool hasStrideOffset() const { return _width * getBytesPerPixel(_color) < _stride; }
      85             : 
      86        3485 :         AlphaFormat alpha() const { return _alpha; }
      87        4403 :         PixelFormat format() const { return _color; }
      88             : 
      89         354 :         BytesView data() const { return _data; }
      90             : 
      91        1271 :         uint8_t *dataPtr() { return _data.data(); }
      92         975 :         const uint8_t *dataPtr() const { return _data.data(); }
      93             : 
      94             :         bool updateStride(const StrideFn &strideFn);
      95             :         bool convert(PixelFormat, const StrideFn &strideFn = nullptr);
      96             :         bool truncate(PixelFormat, const StrideFn &strideFn = nullptr);
      97             : 
      98             :         // target should be large enough
      99             :         bool convertWithTarget(uint8_t *target, PixelFormat, const StrideFn &strideFn = nullptr) const;
     100             : 
     101             :         // init with jpeg or png data
     102             :         bool loadData(const uint8_t * data, size_t dataLen, const StrideFn &strideFn = nullptr);
     103             :         bool loadData(BytesView, const StrideFn &strideFn = nullptr);
     104             : 
     105             :         // init with raw data
     106             :         void loadBitmap(const uint8_t *d, uint32_t w, uint32_t h,
     107             :                         PixelFormat = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Unpremultiplied, uint32_t stride = 0);
     108             :         void loadBitmap(BytesView d, uint32_t w, uint32_t h,
     109             :                         PixelFormat = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Unpremultiplied, uint32_t stride = 0);
     110             :         void loadBitmap(typename Interface::BytesType &&d, uint32_t w, uint32_t h,
     111             :                         PixelFormat = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Unpremultiplied, uint32_t stride = 0);
     112             : 
     113             :         void alloc(uint32_t w, uint32_t h,
     114             :                         PixelFormat = PixelFormat::RGBA8888, AlphaFormat a = AlphaFormat::Unpremultiplied, uint32_t stride = 0);
     115             : 
     116         150 :         explicit operator bool () const { return _data.size() != 0; }
     117             : 
     118             :         void clear() { _data.clear(); }
     119         975 :         bool empty() const { return _data.empty(); }
     120             :         size_t size() const { return _data.size(); }
     121             : 
     122         250 :         FileFormat getOriginalFormat() const { return _originalFormat; }
     123          25 :         StringView getOriginalFormatName() const { return _originalFormatName; }
     124             : 
     125             :         bool save(StringView, bool invert = false);
     126             :         bool save(FileFormat, StringView, bool invert = false);
     127             :         bool save(StringView name, StringView path, bool invert = false);
     128             : 
     129             :         auto write(FileFormat = FileFormat::Png, bool invert = false) -> typename Interface::BytesType;
     130             :         auto write(StringView name, bool invert = false) -> typename Interface::BytesType;
     131             : 
     132             :         // resample with default filter (usually Lanczos4)
     133             :         BitmapTemplate resample(uint32_t width, uint32_t height, uint32_t stride = 0) const;
     134             : 
     135             :         BitmapTemplate resample(ResampleFilter, uint32_t width, uint32_t height, uint32_t stride = 0) const;
     136             : 
     137             : protected:
     138             :         void setInfo(uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a = AlphaFormat::Unpremultiplied, uint32_t stride = 0);
     139             : 
     140             :         PixelFormat _color = PixelFormat::RGBA8888;
     141             :         AlphaFormat _alpha = AlphaFormat::Opaque;
     142             : 
     143             :         uint32_t _width = 0;
     144             :         uint32_t _height = 0;
     145             :         uint32_t _stride = 0; // in bytes
     146             :         typename Interface::BytesType _data;
     147             : 
     148             :         FileFormat _originalFormat = FileFormat::Custom;
     149             :         StringView _originalFormatName;
     150             : };
     151             : 
     152             : 
     153             : template <typename Interface>
     154         967 : BitmapTemplate<Interface>::BitmapTemplate() { }
     155             : 
     156             : template <typename Interface>
     157        1152 : BitmapTemplate<Interface>::BitmapTemplate(BytesView data, const StrideFn &strideFn)
     158        1152 : : BitmapTemplate(data.data(), data.size(), strideFn) { }
     159             : 
     160             : 
     161             : template <typename Interface>
     162        1177 : BitmapTemplate<Interface>::BitmapTemplate(const uint8_t *data, size_t size, const StrideFn &strideFn) {
     163        1177 :         if (!loadData(data, size, strideFn)) {
     164           0 :                 _data.clear();
     165             :         }
     166        1177 : }
     167             : 
     168             : template <typename Interface>
     169          16 : BitmapTemplate<Interface>::BitmapTemplate(const uint8_t *d, uint32_t width, uint32_t height,
     170             :                 PixelFormat c, AlphaFormat a, uint32_t stride)
     171          16 : : _color(c), _alpha(a), _width(width), _height(height)
     172          16 : , _stride(max(stride, width * getBytesPerPixel(c))), _data(d, d + _stride * height) {
     173          16 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     174          16 : }
     175             : 
     176             : template <typename Interface>
     177             : BitmapTemplate<Interface>::BitmapTemplate(BytesView d, uint32_t width, uint32_t height,
     178             :                 PixelFormat c, AlphaFormat a, uint32_t stride)
     179             : : _color(c), _alpha(a), _width(width), _height(height)
     180             : , _stride(max(stride, width * getBytesPerPixel(c))), _data(d.bytes<Interface>()) {
     181             :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     182             : }
     183             : 
     184             : template <typename Interface>
     185             : BitmapTemplate<Interface>::BitmapTemplate(typename Interface::BytesType &&d, uint32_t width, uint32_t height,
     186             :                 PixelFormat c, AlphaFormat a, uint32_t stride)
     187             : : _color(c), _alpha(a), _width(width), _height(height)
     188             : , _stride(max(stride, width * getBytesPerPixel(c))), _data(std::move(d)) {
     189             :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     190             : }
     191             : 
     192             : template <typename Interface>
     193          25 : BitmapTemplate<Interface>::BitmapTemplate(BitmapTemplate &&other)
     194          25 : : _color(other._color), _alpha(other._alpha)
     195          25 : , _width(other._width), _height(other._height), _stride(other._stride)
     196          25 : , _data(std::move(other._data))
     197          25 : , _originalFormat(other._originalFormat)
     198          25 : , _originalFormatName(move(other._originalFormatName)) {
     199          25 :         other._data.clear();
     200          25 : }
     201             : 
     202             : template <typename Interface>
     203         350 : auto BitmapTemplate<Interface>::operator =(BitmapTemplate &&other) -> BitmapTemplate & {
     204         350 :         _alpha = other._alpha;
     205         350 :         _color = other._color;
     206         350 :         _width = other._width;
     207         350 :         _height = other._height;
     208         350 :         _stride = other._stride;
     209         350 :         _data = std::move(other._data);
     210         350 :         _originalFormat = other._originalFormat;
     211         350 :         _originalFormatName = move(other._originalFormatName);
     212         350 :         other._data.clear();
     213         350 :         return *this;
     214             : }
     215             : 
     216             : template <typename Interface>
     217          25 : void BitmapTemplate<Interface>::loadBitmap(const uint8_t *d, uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a, uint32_t stride) {
     218          25 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     219          25 :         setInfo(w, h, c, a, stride);
     220          25 :         _data.clear();
     221          25 :         _data.resize(_stride * h);
     222          25 :         memcpy(_data.data(), d, _data.size());
     223          25 :         _originalFormat = FileFormat::Custom;
     224          25 :         _originalFormatName.clear();
     225          25 : }
     226             : 
     227             : template <typename Interface>
     228          25 : void BitmapTemplate<Interface>::loadBitmap(BytesView d, uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a, uint32_t stride) {
     229          25 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     230          25 :         setInfo(w, h, c, a, stride);
     231          25 :         _data = d.bytes<Interface>();
     232          25 :         _originalFormat = FileFormat::Custom;
     233          25 :         _originalFormatName.clear();
     234          25 : }
     235             : 
     236             : template <typename Interface>
     237          25 : void BitmapTemplate<Interface>::loadBitmap(typename Interface::BytesType &&d, uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a, uint32_t stride) {
     238          25 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     239          25 :         setInfo(w, h, c, a, stride);
     240          25 :         _data = std::move(d);
     241          25 :         _originalFormat = FileFormat::Custom;
     242          25 :         _originalFormatName.clear();
     243          25 : }
     244             : 
     245             : template <typename Interface>
     246         967 : void BitmapTemplate<Interface>::alloc(uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a, uint32_t stride) {
     247         967 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     248         967 :         setInfo(w, h, c, a, stride);
     249         967 :         _data.clear();
     250         967 :         _data.resize(_stride * h);
     251         967 :         _originalFormat = FileFormat::Custom;
     252         967 :         _originalFormatName.clear();
     253         967 : }
     254             : 
     255             : template <typename Interface>
     256        1050 : void BitmapTemplate<Interface>::setInfo(uint32_t w, uint32_t h, PixelFormat c, AlphaFormat a, uint32_t stride) {
     257        1050 :         SPASSERT(c != PixelFormat::Auto, "Bitmap: Format::Auto should not be used with Bitmap directly");
     258        1050 :         _width = w;
     259        1050 :         _height = h;
     260        1050 :         _stride = max(stride, w * getBytesPerPixel(c));
     261        1050 :         _color = c;
     262        1050 :         _alpha = a;
     263        1050 : }
     264             : 
     265             : template <typename Interface>
     266         274 : bool BitmapTemplate<Interface>::updateStride(const StrideFn &strideFn) {
     267         274 :         uint32_t outStride = (strideFn != nullptr) ? max(strideFn(_color, _width), _width * getBytesPerPixel(_color)):_width * getBytesPerPixel(_color);
     268         274 :         if (outStride != _stride) {
     269          25 :                 typename Interface::BytesType out;
     270          25 :                 out.resize(_height * outStride);
     271          25 :                 size_t minStride = _width * getBytesPerPixel(_color);
     272        7550 :                 for (size_t j = 0; j < _height; j ++) {
     273        7525 :                         memcpy(out.data() + j * outStride, _data.data() + j * _stride, minStride);
     274             :                 }
     275          25 :                 _data = std::move(out);
     276          25 :                 _stride = outStride;
     277          25 :                 return true;
     278          25 :         }
     279         249 :         return true;
     280             : }
     281             : 
     282             : template <typename Interface>
     283        1230 : bool BitmapTemplate<Interface>::convert(PixelFormat color, const StrideFn &strideFn) {
     284        1230 :         if (color == PixelFormat::Auto) {
     285           0 :                 color = _color;
     286             :         }
     287        1230 :         if (_color == color) {
     288         201 :                 return updateStride(strideFn);
     289             :         }
     290             : 
     291        1029 :         bool ret = false;
     292        1029 :         typename Interface::BytesType out;
     293        1029 :         uint32_t outStride = (strideFn != nullptr) ? max(strideFn(color, _width), _width * getBytesPerPixel(color)) : _width * getBytesPerPixel(color);
     294        1029 :         out.resize(_height * outStride);
     295             : 
     296        1029 :         ret = convertWithTarget(out.data(), color, strideFn);
     297             : 
     298        1029 :         if (ret) {
     299        1029 :                 _color = color;
     300        1029 :                 _data = std::move(out);
     301        1029 :                 _stride = outStride;
     302             :         }
     303             : 
     304        1029 :         return ret;
     305        1029 : }
     306             : 
     307             : template <typename Interface>
     308          96 : bool BitmapTemplate<Interface>::truncate(PixelFormat color, const StrideFn &strideFn) {
     309          96 :         if (color == PixelFormat::Auto) {
     310           0 :                 color = _color;
     311             :         }
     312          96 :         if (_color == color) {
     313          48 :                 return updateStride(strideFn);
     314             :         }
     315             : 
     316          48 :         if (getBytesPerPixel(color) == getBytesPerPixel(_color)) {
     317           0 :                 _color = color;
     318           0 :                 return true;
     319             :         }
     320             : 
     321          48 :         auto height = _height;
     322          48 :         auto data = _data.data();
     323          48 :         auto bppIn = getBytesPerPixel(_color);
     324             : 
     325          48 :         typename Interface::BytesType out;
     326          48 :         uint32_t outStride = (strideFn != nullptr) ? max(strideFn(color, _width), _width * getBytesPerPixel(color)) : _width * getBytesPerPixel(color);
     327          48 :         out.resize(height * outStride);
     328          48 :         auto bppOut = getBytesPerPixel(color);
     329             : 
     330          48 :         auto fillBytes = min(bppIn, bppOut);
     331          48 :         auto clearBytes = bppOut - fillBytes;
     332             : 
     333        4144 :         for (size_t j = 0; j < height; j ++) {
     334        4096 :                 auto inData = data + _stride * j;
     335        4096 :                 auto outData = out.data() + outStride * j;
     336      364544 :             for (size_t i = 0; i < _stride; i += bppIn) {
     337     1441792 :                 for (uint8_t k = 0; k < fillBytes; ++ k) {
     338     1081344 :                         *outData++ = inData[i * bppIn + k];
     339             :                 }
     340      360448 :                 for (uint8_t k = 0; k < clearBytes; ++ k) {
     341           0 :                         *outData++ = 0;
     342             :                 }
     343             :             }
     344             :         }
     345             : 
     346          48 :         _color = color;
     347          48 :         _data = std::move(out);
     348          48 :         _stride = outStride;
     349             : 
     350          48 :         return true;
     351          48 : }
     352             : 
     353             : template <typename Interface>
     354        1257 : bool BitmapTemplate<Interface>::convertWithTarget(uint8_t *target, PixelFormat color, const StrideFn &strideFn) const {
     355        1257 :         bool ret = false;
     356        1257 :         uint32_t outStride = (strideFn != nullptr) ? max(strideFn(color, _width), _width * getBytesPerPixel(color)) : _width * getBytesPerPixel(color);
     357        1257 :         BytesView out(target, _height * outStride);
     358             : 
     359        1257 :         switch (_color) {
     360         100 :         case PixelFormat::A8:
     361             :                 switch (color) {
     362           0 :                 case PixelFormat::A8: return true; break;
     363          25 :                 case PixelFormat::I8: return true; break;
     364          25 :                 case PixelFormat::IA88: ret = convertData<PixelFormat::A8, PixelFormat::IA88>(_data, out, _stride, outStride); break;
     365          25 :                 case PixelFormat::RGB888: ret = convertData<PixelFormat::A8, PixelFormat::RGB888>(_data, out, _stride, outStride); break;
     366          25 :                 case PixelFormat::RGBA8888: ret = convertData<PixelFormat::A8, PixelFormat::RGBA8888>(_data, out, _stride, outStride); break;
     367           0 :                 case PixelFormat::Auto: return false; break;
     368             :                 }
     369          75 :                 break;
     370         208 :         case PixelFormat::I8:
     371             :                 switch (color) {
     372          19 :                 case PixelFormat::A8: return true; break;
     373           0 :                 case PixelFormat::I8: return true; break;
     374          63 :                 case PixelFormat::IA88: ret = convertData<PixelFormat::I8, PixelFormat::IA88>(_data, out, _stride, outStride); break;
     375          63 :                 case PixelFormat::RGB888: ret = convertData<PixelFormat::I8, PixelFormat::RGB888>(_data, out, _stride, outStride); break;
     376          63 :                 case PixelFormat::RGBA8888: ret = convertData<PixelFormat::I8, PixelFormat::RGBA8888>(_data, out, _stride, outStride); break;
     377           0 :                 case PixelFormat::Auto: return false; break;
     378             :                 }
     379         189 :                 break;
     380         214 :         case PixelFormat::IA88:
     381             :                 switch (color) {
     382          63 :                 case PixelFormat::A8: ret = convertData<PixelFormat::IA88, PixelFormat::A8>(_data, out, _stride, outStride); break;
     383          25 :                 case PixelFormat::I8: ret = convertData<PixelFormat::IA88, PixelFormat::I8>(_data, out, _stride, outStride); break;
     384           0 :                 case PixelFormat::IA88: return true; break;
     385          63 :                 case PixelFormat::RGB888: ret = convertData<PixelFormat::IA88, PixelFormat::RGB888>(_data, out, _stride, outStride); break;
     386          63 :                 case PixelFormat::RGBA8888: ret = convertData<PixelFormat::IA88, PixelFormat::RGBA8888>(_data, out, _stride, outStride); break;
     387           0 :                 case PixelFormat::Auto: return false; break;
     388             :                 }
     389         214 :                 break;
     390         214 :         case PixelFormat::RGB888:
     391             :                 switch (color) {
     392          44 :                 case PixelFormat::A8: ret = convertData<PixelFormat::RGB888, PixelFormat::A8>(_data, out, _stride, outStride); break;
     393          44 :                 case PixelFormat::I8: ret = convertData<PixelFormat::RGB888, PixelFormat::I8>(_data, out, _stride, outStride); break;
     394          63 :                 case PixelFormat::IA88: ret = convertData<PixelFormat::RGB888, PixelFormat::IA88>(_data, out, _stride, outStride); break;
     395           0 :                 case PixelFormat::RGB888: return true; break;
     396          63 :                 case PixelFormat::RGBA8888: ret = convertData<PixelFormat::RGB888, PixelFormat::RGBA8888>(_data, out, _stride, outStride); break;
     397           0 :                 case PixelFormat::Auto: return false; break;
     398             :                 }
     399         214 :                 break;
     400         521 :         case PixelFormat::RGBA8888:
     401             :                 switch (color) {
     402         157 :                 case PixelFormat::A8: ret = convertData<PixelFormat::RGBA8888, PixelFormat::A8>(_data, out, _stride, outStride); break;
     403          50 :                 case PixelFormat::I8: ret = convertData<PixelFormat::RGBA8888, PixelFormat::I8>(_data, out, _stride, outStride); break;
     404         157 :                 case PixelFormat::IA88: ret = convertData<PixelFormat::RGBA8888, PixelFormat::IA88>(_data, out, _stride, outStride); break;
     405         157 :                 case PixelFormat::RGB888: ret = convertData<PixelFormat::RGBA8888, PixelFormat::RGB888>(_data, out, _stride, outStride); break;
     406           0 :                 case PixelFormat::RGBA8888: return true; break;
     407           0 :                 case PixelFormat::Auto: return false; break;
     408             :                 }
     409         521 :                 break;
     410           0 :         case PixelFormat::Auto: return false; break;
     411             :         }
     412             : 
     413        1213 :         return ret;
     414             : }
     415             : 
     416             : template <typename Interface>
     417          75 : bool BitmapTemplate<Interface>::save(StringView path, bool invert) {
     418          75 :         FileFormat fmt = FileFormat::Png;
     419          75 :         auto ext = filepath::lastExtension(path);
     420          75 :         if (ext == "png") {
     421          25 :                 fmt = FileFormat::Png;
     422          50 :         } else if (ext == "jpeg" || ext == "jpg") {
     423          25 :                 fmt = FileFormat::Jpeg;
     424          25 :         } else if (ext == "webp") {
     425          25 :                 fmt = FileFormat::WebpLossless;
     426             :         }
     427         150 :         return save(fmt, path, invert);
     428             : }
     429             : 
     430             : template <typename Interface>
     431             : bool BitmapTemplate<Interface>::loadData(BytesView d, const StrideFn &strideFn) {
     432             :         return loadData(d.data(), d.size(), strideFn);
     433             : }
     434             : 
     435             : }
     436             : 
     437             : namespace STAPPLER_VERSIONIZED stappler::mem_std {
     438             : 
     439             : using Bitmap = bitmap::BitmapTemplate<memory::StandartInterface>;
     440             : 
     441             : }
     442             : 
     443             : namespace STAPPLER_VERSIONIZED stappler::mem_pool {
     444             : 
     445             : using Bitmap = bitmap::BitmapTemplate<memory::PoolInterface>;
     446             : 
     447             : }
     448             : 
     449             : #endif /* STAPPLER_BITMAP_SPBITMAP_H_ */

Generated by: LCOV version 1.14