[Libreoffice-commits] online.git: Branch 'distro/collabora/collabora-online-3-0' - kit/Kit.cpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Fri Dec 15 12:31:41 UTC 2017
kit/Kit.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 104 insertions(+), 39 deletions(-)
New commits:
commit e0a0fe823d23efd457ef92ffd167c3c74c803a7b
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Sun Dec 10 21:54:07 2017 -0500
wsd: improve watermark visibility on dark and grey backgrounds
The watermark text is now rendered on a blurred version
of itself, using inverted colors. This makes it
look sharp on light backgrounds, but inverted in
a blurry haze when on dark backgrounds, thereby
being readable on top of any background.
Change-Id: Ia6daf987674c484980f1fdec4f74e579ed87c213
Reviewed-on: https://gerrit.libreoffice.org/46491
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
Reviewed-on: https://gerrit.libreoffice.org/46526
Reviewed-by: Jan Holesovsky <kendy at collabora.com>
Tested-by: Jan Holesovsky <kendy at collabora.com>
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index 5c6eb920..5cb82801 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -489,7 +489,6 @@ public:
, _font("Liberation Sans")
, _width(0)
, _height(0)
- , _color{64, 64, 64}
, _alphaLevel(0.2)
, _pixmap(nullptr)
{
@@ -505,7 +504,7 @@ public:
int offsetX, int offsetY,
int tilesPixmapWidth, int tilesPixmapHeight,
int tileWidth, int tileHeight,
- LibreOfficeKitTileMode mode)
+ LibreOfficeKitTileMode /*mode*/)
{
// set requested watermark size a little bit smaller than tile size
int width = tileWidth * 0.9;
@@ -515,42 +514,48 @@ public:
if (pixmap && tilePixmap)
{
- unsigned int pixmapSize = tilesPixmapWidth * tilesPixmapHeight * 4;
- int maxX = std::min(tileWidth, _width);
- int maxY = std::min(tileHeight, _height);
-
// center watermark
+ const int maxX = std::min(tileWidth, _width);
+ const int maxY = std::min(tileHeight, _height);
offsetX += (tileWidth - maxX) / 2;
offsetY += (tileHeight - maxY) / 2;
- for (int y = 0; y < maxY; ++y)
- {
- for (int x = 0; x < maxX; ++x)
- {
- unsigned int i = (y * _width + x) * 4;
- unsigned int alpha = pixmap[i + 3];
- if (alpha)
- {
- for (int h = 0; h < 3; ++h)
- {
- unsigned int j = ((y + offsetY) * tilesPixmapWidth + (x + offsetX)) * 4 + h;
- if (j < pixmapSize)
- {
- unsigned int color = (mode == LOK_TILEMODE_BGRA) ? _color[2 - h] : _color[h];
-
- // original alpha blending for smoothing text edges
- color = ((color * alpha) + tilePixmap[j] * (255 - alpha)) / 255;
- // blending between document tile and watermark
- tilePixmap[j] = color * _alphaLevel + tilePixmap[j] * (1 - _alphaLevel);
- }
- }
- }
- }
- }
+ alphaBlend(pixmap, _width, _height, offsetX, offsetY, tilePixmap, tilesPixmapWidth, tilesPixmapHeight);
}
}
private:
+ /// Alpha blend 'pixel_count' pixels from 'from' over the 'to'.
+ void alphaBlend(const 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 + 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);
+ }
+ }
+
const unsigned char* getPixmap(int width, int height)
{
if (_pixmap && width == _width && height == _height)
@@ -572,13 +577,74 @@ private:
// 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.
- _pixmap = _loKitDoc->renderFont(_font.c_str(), _text.c_str(), &_width, &_height);
+ unsigned char* text = _loKitDoc->renderFont(_font.c_str(), _text.c_str(), &_width, &_height);
- if (!_pixmap)
+ if (!text)
{
LOG_ERR("Watermark: rendering failed.");
}
+ const unsigned int pixel_count = width * height * 4;
+
+ // Create the blurred background; first a white text
+ _pixmap = static_cast<unsigned char*>(malloc(pixel_count));
+ unsigned char* from = text;
+ unsigned char* to = _pixmap;
+ for (; to < _pixmap + pixel_count; from += 4, to += 4)
+ {
+ // Pre-multiplied alpha!
+ const double alpha = from[3] / 255.0;
+ to[0] = 0xff * alpha;
+ to[1] = 0xff * alpha;
+ to[2] = 0xff * alpha;
+ to[3] = from[3];
+ }
+
+ // Use box blur, which is fast, though crude.
+ unsigned char* buffer = static_cast<unsigned char*>(malloc(pixel_count));
+ memcpy(buffer, _pixmap, pixel_count);
+
+ // Repeat an even number of times to smooth out.
+ const int r = 2;
+ const double weight = (r+1) * (r+1);
+ for (int y = r; y < height - r; ++y)
+ {
+ for (int x = r; x < width - r; ++x)
+ {
+ double t = 0;
+ for (int ky = y - r; ky <= y + r; ++ky)
+ {
+ for (int kx = x - r; kx <= x + r; ++kx)
+ {
+ t += buffer[4 * (ky * width + kx) + 3];
+ }
+ }
+
+ // Clamp the result.
+ double avg = t / weight;
+ if (avg > 255.0)
+ avg = 255.0;
+ 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] = static_cast<unsigned char>(avg < 255.0 ? avg : 255);
+ }
+ }
+
+ // Now copy text over the blur
+ alphaBlend(text, _width, _height, 0, 0, _pixmap, _width, _height);
+
+ // No longer needed.
+ std::free(buffer);
+ std::free(text);
+
+ // Make the resulting pixmap semi-transparent
+ for (unsigned char* p = _pixmap; p < _pixmap + pixel_count; p++)
+ {
+ *p = static_cast<unsigned char>(*p * _alphaLevel);
+ }
+
return _pixmap;
}
@@ -588,7 +654,6 @@ private:
std::string _font;
int _width;
int _height;
- unsigned char _color[3];
double _alphaLevel;
unsigned char* _pixmap;
};
@@ -918,7 +983,10 @@ public:
const auto pixelWidth = tileCombined.getWidth();
const auto pixelHeight = tileCombined.getHeight();
- const uint64_t hash = Png::hashSubBuffer(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight,
+ const int offsetX = positionX * pixelWidth;
+ const int offsetY = positionY * pixelHeight;
+
+ const uint64_t hash = Png::hashSubBuffer(pixmap.data(), offsetX, offsetY,
pixelWidth, pixelHeight, pixmapWidth, pixmapHeight);
TileWireId wireId = _pngCache.hashToWireId(hash);
@@ -932,16 +1000,13 @@ public:
continue;
}
- int offsetX = positionX * pixelWidth;
- int offsetY = positionY * pixelHeight;
-
if (_docWatermark)
_docWatermark->blending(pixmap.data(), offsetX, offsetY,
pixmapWidth, pixmapHeight,
- tileCombined.getWidth(), tileCombined.getHeight(),
+ pixelWidth, pixelHeight,
mode);
- if (!_pngCache.encodeSubBufferToPNG(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight,
+ if (!_pngCache.encodeSubBufferToPNG(pixmap.data(), offsetX, offsetY,
pixelWidth, pixelHeight, pixmapWidth, pixmapHeight, output, mode,
hash, wireId, oldWireId))
{
More information about the Libreoffice-commits
mailing list