LibreOffice Module vcl (master) 1
writer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <vcl/graph.hxx>
21#include <tools/stream.hxx>
22#include <filter/WebpWriter.hxx>
25#include <sal/log.hxx>
26#include <o3tl/string_view.hxx>
27
28#include <webp/encode.h>
29
30static int writerFunction(const uint8_t* data, size_t size, const WebPPicture* picture)
31{
32 SvStream* stream = static_cast<SvStream*>(picture->custom_ptr);
33 return stream->WriteBytes(data, size) == size ? 1 : 0;
34}
35
36static WebPPreset presetToValue(std::u16string_view preset)
37{
38 if (o3tl::equalsIgnoreAsciiCase(preset, u"picture"))
39 return WEBP_PRESET_PICTURE;
40 if (o3tl::equalsIgnoreAsciiCase(preset, u"photo"))
41 return WEBP_PRESET_PHOTO;
42 if (o3tl::equalsIgnoreAsciiCase(preset, u"drawing"))
43 return WEBP_PRESET_DRAWING;
44 if (o3tl::equalsIgnoreAsciiCase(preset, u"icon"))
45 return WEBP_PRESET_ICON;
46 if (o3tl::equalsIgnoreAsciiCase(preset, u"text"))
47 return WEBP_PRESET_TEXT;
48 return WEBP_PRESET_DEFAULT;
49}
50
51static bool writeWebp(SvStream& rStream, const BitmapEx& bitmapEx, bool lossless,
52 std::u16string_view preset, int quality)
53{
54 WebPConfig config;
55 if (!WebPConfigInit(&config))
56 {
57 SAL_WARN("vcl.filter.webp", "WebPConfigInit() failed");
58 return false;
59 }
60 if (lossless)
61 {
62 if (!WebPConfigLosslessPreset(&config, 6))
63 {
64 SAL_WARN("vcl.filter.webp", "WebPConfigLosslessPreset() failed");
65 return false;
66 }
67 }
68 else
69 {
70 if (!WebPConfigPreset(&config, presetToValue(preset), quality))
71 {
72 SAL_WARN("vcl.filter.webp", "WebPConfigPreset() failed");
73 return false;
74 }
75 }
76 // Here various parts of 'config' can be altered if wanted.
77 assert(WebPValidateConfig(&config));
78
79 const int width = bitmapEx.GetSizePixel().Width();
80 const int height = bitmapEx.GetSizePixel().Height();
81
82 WebPPicture picture;
83 if (!WebPPictureInit(&picture))
84 {
85 SAL_WARN("vcl.filter.webp", "WebPPictureInit() failed");
86 return false;
87 }
88 picture.width = width;
89 picture.height = height;
90 picture.use_argb = lossless ? 1 : 0; // libwebp recommends argb only for lossless
91 comphelper::ScopeGuard freePicture([&picture]() { WebPPictureFree(&picture); });
92
93 // Apparently libwebp needs the entire image data at once in WebPPicture,
94 // so allocate it and copy there.
95 Bitmap bitmap(bitmapEx.GetBitmap());
96 AlphaMask bitmapAlpha;
97 if (bitmapEx.IsAlpha())
98 bitmapAlpha = bitmapEx.GetAlphaMask();
99 Bitmap::ScopedReadAccess access(bitmap);
100 AlphaMask::ScopedReadAccess accessAlpha(bitmapAlpha);
101 bool dataDone = false;
102 if (!access->IsBottomUp() && bitmapAlpha.IsEmpty())
103 {
104 // Try to directly copy the bitmap data.
105 switch (access->GetScanlineFormat())
106 {
108 if (!WebPPictureImportRGB(&picture, access->GetBuffer(), access->GetScanlineSize()))
109 {
110 SAL_WARN("vcl.filter.webp", "WebPPictureImportRGB() failed");
111 return false;
112 }
113 dataDone = true;
114 break;
116 if (!WebPPictureImportBGR(&picture, access->GetBuffer(), access->GetScanlineSize()))
117 {
118 SAL_WARN("vcl.filter.webp", "WebPPictureImportBGR() failed");
119 return false;
120 }
121 dataDone = true;
122 break;
123 // Our argb formats are premultiplied, so can't read directly using libwebp functions.
124 default:
125 break;
126 }
127 }
128 if (!dataDone)
129 {
130 // It would be simpler to convert the bitmap to 32bpp, but our 32bpp support is broken
131 // (it's unspecified whether it's premultiplied or not, for example). So handle this manually.
132 // Special handling for some common cases, generic otherwise.
133 if (!WebPPictureAlloc(&picture))
134 {
135 SAL_WARN("vcl.filter.webp", "WebPPictureAlloc() failed");
136 return false;
137 }
138 std::vector<uint8_t> data;
139 const int bpp = 4;
140 data.resize(width * height * bpp);
141 if (!bitmapAlpha.IsEmpty())
142 {
143 for (tools::Long y = 0; y < access->Height(); ++y)
144 {
145 unsigned char* dst = data.data() + width * bpp * y;
146 const sal_uInt8* srcB = access->GetScanline(y);
147 const sal_uInt8* srcA = accessAlpha->GetScanline(y);
148 for (tools::Long x = 0; x < access->Width(); ++x)
149 {
150 BitmapColor color = access->GetPixelFromData(srcB, x);
151 BitmapColor transparency = accessAlpha->GetPixelFromData(srcA, x);
152 color.SetAlpha(255 - transparency.GetIndex());
153 dst[0] = color.GetRed();
154 dst[1] = color.GetGreen();
155 dst[2] = color.GetBlue();
156 dst[3] = color.GetAlpha();
157 dst += bpp;
158 }
159 }
160 }
161 else
162 {
163 for (tools::Long y = 0; y < access->Height(); ++y)
164 {
165 unsigned char* dst = data.data() + width * bpp * y;
166 const sal_uInt8* src = access->GetScanline(y);
167 for (tools::Long x = 0; x < access->Width(); ++x)
168 {
169 Color color = access->GetPixelFromData(src, x);
170 dst[0] = color.GetRed();
171 dst[1] = color.GetGreen();
172 dst[2] = color.GetBlue();
173 dst[3] = color.GetAlpha();
174 dst += bpp;
175 }
176 }
177 }
178 // And now import from the temporary data. Use the import function rather
179 // than writing the data directly to avoid the need to write the data
180 // in the exact format WebPPicture wants (YUV, etc.).
181 if (!WebPPictureImportRGBA(&picture, data.data(), width * bpp))
182 {
183 SAL_WARN("vcl.filter.webp", "WebPPictureImportRGBA() failed");
184 return false;
185 }
186 }
187
188 picture.writer = writerFunction;
189 picture.custom_ptr = &rStream;
190 return WebPEncode(&config, &picture);
191}
192
193bool ExportWebpGraphic(SvStream& rStream, const Graphic& rGraphic,
194 FilterConfigItem* pFilterConfigItem)
195{
196 BitmapEx bitmap = rGraphic.GetBitmapEx();
197 // If lossless, neither presets nor quality matter.
198 bool lossless = pFilterConfigItem->ReadBool("Lossless", true);
199 // Preset is WebPPreset values.
200 const OUString preset = pFilterConfigItem->ReadString("Preset", "");
201 int quality = pFilterConfigItem->ReadInt32("Quality", 75);
202 return writeWebp(rStream, bitmap, lossless, preset, quality);
203}
204
205/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsEmpty() const
sal_uInt8 GetIndex() const
Definition: BitmapColor.hxx:70
const AlphaMask & GetAlphaMask() const
Definition: bitmapex.hxx:71
bool IsAlpha() const
Definition: BitmapEx.cxx:207
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:217
const Size & GetSizePixel() const
Definition: bitmapex.hxx:73
tools::Long Height() const
tools::Long Width() const
bool IsBottomUp() const
ScanlineFormat GetScanlineFormat() const
sal_uInt32 GetScanlineSize() const
Scanline GetBuffer() const
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
Scanline GetScanline(tools::Long nY) const
OUString ReadString(const OUString &rKey, const OUString &rDefault)
bool ReadBool(const OUString &rKey, bool bDefault)
sal_Int32 ReadInt32(const OUString &rKey, sal_Int32 nDefault)
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
constexpr tools::Long Height() const
constexpr tools::Long Width() const
Reference< XOutputStream > stream
float u
float y
float x
#define SAL_WARN(area, stream)
@ picture
size
config
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
long Long
unsigned char sal_uInt8
static int writerFunction(const uint8_t *data, size_t size, const WebPPicture *picture)
Definition: writer.cxx:30
bool ExportWebpGraphic(SvStream &rStream, const Graphic &rGraphic, FilterConfigItem *pFilterConfigItem)
Definition: writer.cxx:193
static WebPPreset presetToValue(std::u16string_view preset)
Definition: writer.cxx:36
static bool writeWebp(SvStream &rStream, const BitmapEx &bitmapEx, bool lossless, std::u16string_view preset, int quality)
Definition: writer.cxx:51