[Libreoffice-commits] online.git: kit/Watermark.hpp

mert (via logerrit) logerrit at kemper.freedesktop.org
Tue Oct 15 17:26:08 UTC 2019


 kit/Watermark.hpp |  179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 179 insertions(+)

New commits:
commit a1c58c04cc502addd4e1a07215867e44f075f48b
Author:     mert <mert.tumer at collabora.com>
AuthorDate: Tue Oct 15 20:25:26 2019 +0300
Commit:     mert <mert.tumer at collabora.com>
CommitDate: Tue Oct 15 20:25:26 2019 +0300

    Added Watermark.hpp
    
    Change-Id: I3619283031865f59f94157d5b8df14a94ac9327b

diff --git a/kit/Watermark.hpp b/kit/Watermark.hpp
new file mode 100644
index 000000000..830023f43
--- /dev/null
+++ b/kit/Watermark.hpp
@@ -0,0 +1,179 @@
+#ifndef INCLUDED_WATERMARK_HPP
+#define INCLUDED_WATERMARK_HPP
+
+#define LOK_USE_UNSTABLE_API
+#include <LibreOfficeKit/LibreOfficeKitInit.h>
+#include <LibreOfficeKit/LibreOfficeKit.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <vector>
+#include <Log.hpp>
+#include <cstdlib>
+#include <string>
+#include "ChildSession.hpp"
+
+class Watermark
+{
+public:
+    Watermark(const std::shared_ptr<lok::Document>& loKitDoc,
+              const std::shared_ptr<ChildSession> & session)
+        : _loKitDoc(loKitDoc)
+        , _text(session->getWatermarkText())
+        , _font("Liberation Sans")
+        , _width(0)
+        , _height(0)
+        , _alphaLevel(session->getWatermarkOpacity())
+    {
+    }
+
+    ~Watermark()
+    {
+    }
+
+    void blending(unsigned char* tilePixmap,
+                   int offsetX, int offsetY,
+                   int tilesPixmapWidth, int tilesPixmapHeight,
+                   int tileWidth, int tileHeight,
+                   LibreOfficeKitTileMode /*mode*/)
+    {
+        // set requested watermark size a little bit smaller than tile size
+        int width = tileWidth * 0.9;
+        int height = tileHeight * 0.9;
+
+        const std::vector<unsigned char>* pixmap = getPixmap(width, height);
+
+        if (pixmap && tilePixmap)
+        {
+            // center watermark
+            const int maxX = std::min(tileWidth, _width);
+            const int maxY = std::min(tileHeight, _height);
+            offsetX += (tileWidth - maxX) / 2;
+            offsetY += (tileHeight - maxY) / 2;
+
+            alphaBlend(*pixmap, _width, _height, offsetX, offsetY, tilePixmap, tilesPixmapWidth, tilesPixmapHeight);
+        }
+    }
+
+private:
+    /// Alpha blend pixels from 'from' over the 'to'.
+    void alphaBlend(const std::vector<unsigned char>& from, int from_width, int from_height, int from_offset_x, int from_offset_y,
+            unsigned char* to, int to_width, int to_height)
+    {
+        for (int to_y = from_offset_y, from_y = 0; (to_y < to_height) && (from_y < from_height) ; ++to_y, ++from_y)
+            for (int to_x = from_offset_x, from_x = 0; (to_x < to_width) && (from_x < from_width); ++to_x, ++from_x)
+            {
+                const unsigned char* f = from.data() + 4 * (from_y * from_width + from_x);
+                double src_r = f[0];
+                double src_g = f[1];
+                double src_b = f[2];
+                double src_a = f[3] / 255.0;
+
+                unsigned char* t = to + 4 * (to_y * to_width + to_x);
+                double dst_r = t[0];
+                double dst_g = t[1];
+                double dst_b = t[2];
+                double dst_a = t[3] / 255.0;
+
+                double out_a = src_a + dst_a * (1.0 - src_a);
+                unsigned char out_r = src_r + dst_r * (1.0 - src_a);
+                unsigned char out_g = src_g + dst_g * (1.0 - src_a);
+                unsigned char out_b = src_b + dst_b * (1.0 - src_a);
+
+                t[0] = out_r;
+                t[1] = out_g;
+                t[2] = out_b;
+                t[3] = static_cast<unsigned char>(out_a * 255.0);
+            }
+    }
+
+    /// Create bitmap that we later use as the watermark for every tile.
+    const std::vector<unsigned char>* getPixmap(int width, int height)
+    {
+        if (!_pixmap.empty() && width == _width && height == _height)
+            return &_pixmap;
+
+        _pixmap.clear();
+
+        _width = width;
+        _height = height;
+
+        if (!_loKitDoc)
+        {
+            LOG_ERR("Watermark rendering requested without a valid document.");
+            return nullptr;
+        }
+
+        // renderFont returns a buffer based on RGBA mode, where r, g, b
+        // are always set to 0 (black) and the alpha level is 0 everywhere
+        // except on the text area; the alpha level take into account of
+        // performing anti-aliasing over the text edges.
+        unsigned char* textPixels = _loKitDoc->renderFont(_font.c_str(), _text.c_str(), &_width, &_height);
+
+        if (!textPixels)
+        {
+            LOG_ERR("Watermark: rendering failed.");
+        }
+
+        const unsigned int pixel_count = width * height * 4;
+
+        std::vector<unsigned char> text(textPixels, textPixels + pixel_count);
+        // No longer needed.
+        std::free(textPixels);
+
+        _pixmap.reserve(pixel_count);
+
+        // Create the white blurred background
+        // Use box blur, it's enough for our purposes
+        const int r = 2;
+        const double weight = (r+1) * (r+1);
+        for (int y = 0; y < height; ++y)
+        {
+            for (int x = 0; x < width; ++x)
+            {
+                double t = 0;
+                for (int ky = std::max(y - r, 0); ky <= std::min(y + r, height - 1); ++ky)
+                {
+                    for (int kx = std::max(x - r, 0); kx <= std::min(x + r, width - 1); ++kx)
+                    {
+                        // Pre-multiplied alpha; the text is black, so all the
+                        // information is only in the alpha channel
+                        t += text[4 * (ky * width + kx) + 3];
+                    }
+                }
+
+                // Clamp the result.
+                double avg = t / weight;
+                if (avg > 255.0)
+                    avg = 255.0;
+
+                // Pre-multiplied alpha, but use white for the resulting color
+                const double alpha = avg / 255.0;
+                _pixmap[4 * (y * width + x) + 0] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 1] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 2] = 0xff * alpha;
+                _pixmap[4 * (y * width + x) + 3] = avg;
+            }
+        }
+
+        // Now copy the (black) text over the (white) blur
+        alphaBlend(text, _width, _height, 0, 0, _pixmap.data(), _width, _height);
+
+        // Make the resulting pixmap semi-transparent
+        for (unsigned char* p = _pixmap.data(); p < _pixmap.data() + pixel_count; p++)
+        {
+            *p = static_cast<unsigned char>(*p * _alphaLevel);
+        }
+
+        return &_pixmap;
+    }
+
+private:
+    std::shared_ptr<lok::Document> _loKitDoc;
+    std::string _text;
+    std::string _font;
+    int _width;
+    int _height;
+    double _alphaLevel;
+    std::vector<unsigned char> _pixmap;
+};
+
+#endif
\ No newline at end of file


More information about the Libreoffice-commits mailing list