1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "svg_decoder.h"
17
18 #include <sstream>
19 #include <thread>
20 #include "include/core/SkBitmap.h"
21 #include "include/core/SkCanvas.h"
22 #include "include/core/SkImageInfo.h"
23 #include "image_trace.h"
24 #include "image_log.h"
25 #include "image_utils.h"
26 #include "media_errors.h"
27 #include "securec.h"
28 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
29 #include "surface_buffer.h"
30 #endif
31
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
34
35 #undef LOG_TAG
36 #define LOG_TAG "SvgDecoder"
37
38 namespace OHOS {
39 namespace ImagePlugin {
40 using namespace MultimediaPlugin;
41 using namespace Media;
42 namespace {
43 constexpr uint32_t SVG_IMAGE_NUM = 1;
44 constexpr uint32_t SVG_BYTES_PER_PIXEL = 4;
45 constexpr uint32_t SVG_COLOR_ATTR_WIDTH = 6;
46 constexpr uint32_t SVG_COLOR_MASK = 0xFFFFFF;
47 const std::string SVG_FILL_COLOR_ATTR = "fill";
48 const std::string SVG_STROKE_COLOR_ATTR = "stroke";
49 static constexpr uint32_t DEFAULT_RESIZE_PERCENTAGE = 100;
50 static constexpr float FLOAT_HALF = 0.5f;
51
Float2UInt32(float val)52 static inline uint32_t Float2UInt32(float val)
53 {
54 return static_cast<uint32_t>(val + FLOAT_HALF);
55 }
56
57 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
AllocShareBufferInner(DecodeContext & context,uint64_t byteCount)58 bool AllocShareBufferInner(DecodeContext &context, uint64_t byteCount)
59 {
60 uint32_t id = context.pixelmapUniqueId_;
61 std::stringstream sstream;
62 sstream << "SVG RawData, uniqueId: " << std::this_thread::get_id() << '_' << std::to_string(getpid()) <<
63 '_' << std::to_string(id);
64 std::string name = sstream.str();
65 int fd = AshmemCreate(name.c_str(), byteCount);
66 if (fd < 0) {
67 IMAGE_LOGE("[AllocShareBuffer] create fail");
68 return false;
69 }
70
71 int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
72 if (result < 0) {
73 IMAGE_LOGE("[AllocShareBuffer] set fail");
74 ::close(fd);
75 return false;
76 }
77
78 void* ptr = ::mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
79 if (ptr == MAP_FAILED) {
80 IMAGE_LOGE("[AllocShareBuffer] map fail");
81 ::close(fd);
82 return false;
83 }
84
85 context.pixelsBuffer.buffer = ptr;
86 void *fdBuffer = new int32_t();
87 if (fdBuffer == nullptr) {
88 IMAGE_LOGE("[AllocShareBuffer] new fdBuffer fail");
89 ::munmap(ptr, byteCount);
90 ::close(fd);
91 context.pixelsBuffer.buffer = nullptr;
92 return false;
93 }
94
95 *static_cast<int32_t *>(fdBuffer) = fd;
96 context.pixelsBuffer.context = fdBuffer;
97 context.pixelsBuffer.bufferSize = byteCount;
98 context.allocatorType = AllocatorType::SHARE_MEM_ALLOC;
99 context.freeFunc = nullptr;
100
101 IMAGE_LOGD("[AllocShareBuffer] OUT");
102 return true;
103 }
104 #endif
105
AllocShareBuffer(DecodeContext & context,uint64_t byteCount)106 bool AllocShareBuffer(DecodeContext &context, uint64_t byteCount)
107 {
108 IMAGE_LOGD("[AllocShareBuffer] IN byteCount=%{public}llu",
109 static_cast<unsigned long long>(byteCount));
110
111 if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
112 IMAGE_LOGE("[AllocShareBuffer] pixelmap buffer size %{public}llu out of max size",
113 static_cast<unsigned long long>(byteCount));
114 return false;
115 }
116 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
117 return AllocShareBufferInner(context, byteCount);
118 #else
119 IMAGE_LOGE("[AllocShareBuffer] Not support Ashmem!");
120 return false;
121 #endif
122 }
123
AllocDmaBuffer(DecodeContext & context,uint64_t byteCount,SkSize & svgSize)124 bool AllocDmaBuffer(DecodeContext &context, uint64_t byteCount, SkSize &svgSize)
125 {
126 IMAGE_LOGD("[AllocDmaBuffer] IN byteCount=%{public}llu",
127 static_cast<unsigned long long>(byteCount));
128
129 if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
130 IMAGE_LOGE("[AllocDmaBuffer] pixelmap buffer size %{public}llu out of max size",
131 static_cast<unsigned long long>(byteCount));
132 return false;
133 }
134 #if !defined(_WIN32) && !defined(_APPLE) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
135 sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
136 BufferRequestConfig requestConfig = {
137 .width = svgSize.width(),
138 .height = svgSize.height(),
139 .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
140 .format = GRAPHIC_PIXEL_FMT_RGBA_8888, // PixelFormat
141 .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA,
142 .timeout = 0,
143 .colorGamut = GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB,
144 .transform = GraphicTransformType::GRAPHIC_ROTATE_NONE,
145 };
146 GSError ret = sb->Alloc(requestConfig);
147 if (ret != GSERROR_OK) {
148 IMAGE_LOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
149 return false;
150 }
151 void* nativeBuffer = sb.GetRefPtr();
152 int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
153 if (err != OHOS::GSERROR_OK) {
154 IMAGE_LOGE("NativeBufferReference failed");
155 return false;
156 }
157
158 context.pixelsBuffer.buffer = sb->GetVirAddr();
159 context.pixelsBuffer.context = nativeBuffer;
160 context.pixelsBuffer.bufferSize = byteCount;
161 context.allocatorType = AllocatorType::DMA_ALLOC;
162 context.freeFunc = nullptr;
163
164 IMAGE_LOGD("[AllocDmaBuffer] OUT");
165 return true;
166 #else
167 IMAGE_LOGE("[AllocDmaBuffer] Not support dma!");
168 return false;
169 #endif
170 }
171
AllocHeapBuffer(DecodeContext & context,uint64_t byteCount)172 bool AllocHeapBuffer(DecodeContext &context, uint64_t byteCount)
173 {
174 IMAGE_LOGD("[AllocHeapBuffer] IN byteCount=%{public}llu",
175 static_cast<unsigned long long>(byteCount));
176
177 if (byteCount > PIXEL_MAP_MAX_RAM_SIZE) {
178 IMAGE_LOGE("[AllocHeapBuffer] pixelmap buffer size %{public}llu out of max size",
179 static_cast<unsigned long long>(byteCount));
180 return false;
181 }
182
183 auto outputBuffer = malloc(byteCount);
184 if (outputBuffer == nullptr) {
185 IMAGE_LOGE("[AllocHeapBuffer] alloc buffer size:[%{public}llu] failed.",
186 static_cast<unsigned long long>(byteCount));
187 return false;
188 }
189
190 if (memset_s(outputBuffer, byteCount, 0, byteCount) != EOK) {
191 IMAGE_LOGE("[AllocHeapBuffer] memset buffer failed.");
192 free(outputBuffer);
193 outputBuffer = nullptr;
194 return false;
195 }
196
197 context.pixelsBuffer.buffer = outputBuffer;
198 context.pixelsBuffer.bufferSize = byteCount;
199 context.pixelsBuffer.context = nullptr;
200 context.allocatorType = AllocatorType::HEAP_ALLOC;
201 context.freeFunc = nullptr;
202
203 IMAGE_LOGD("[AllocHeapBuffer] OUT");
204 return true;
205 }
206
MakeImageInfo(const PixelDecodeOptions & opts)207 SkImageInfo MakeImageInfo(const PixelDecodeOptions &opts)
208 {
209 int width = opts.desiredSize.width;
210 int height = opts.desiredSize.height;
211 SkColorType colorType = SkColorType::kRGBA_8888_SkColorType;
212 SkAlphaType alphaType = SkAlphaType::kPremul_SkAlphaType;
213 return SkImageInfo::Make(width, height, colorType, alphaType);
214 }
215 } // namespace
216
SvgDecoder()217 SvgDecoder::SvgDecoder()
218 {
219 IMAGE_LOGD("[Create] IN");
220
221 IMAGE_LOGD("[Create] OUT");
222 }
223
~SvgDecoder()224 SvgDecoder::~SvgDecoder()
225 {
226 IMAGE_LOGD("[Release] IN");
227
228 Reset();
229
230 IMAGE_LOGD("[Release] OUT");
231 }
232
SetSource(InputDataStream & sourceStream)233 void SvgDecoder::SetSource(InputDataStream &sourceStream)
234 {
235 IMAGE_LOGD("[SetSource] IN");
236
237 Reset();
238
239 inputStreamPtr_ = &sourceStream;
240 state_ = SvgDecodingState::SOURCE_INITED;
241
242 IMAGE_LOGD("[SetSource] OUT");
243 }
244
Reset()245 void SvgDecoder::Reset()
246 {
247 IMAGE_LOGD("[Reset] IN");
248
249 state_ = SvgDecodingState::UNDECIDED;
250
251 if (svgDom_) {
252 svgDom_->setContainerSize(svgSize_);
253 }
254
255 svgDom_ = nullptr;
256 svgStream_ = nullptr;
257 inputStreamPtr_ = nullptr;
258
259 svgSize_.setEmpty();
260
261 PixelDecodeOptions opts;
262 opts_ = opts;
263
264 IMAGE_LOGD("[Reset] OUT");
265 }
266
SetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)267 uint32_t SvgDecoder::SetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
268 {
269 if (index >= SVG_IMAGE_NUM) {
270 IMAGE_LOGE("[SetDecodeOptions] decode image index[%{public}u], out of range[%{public}u].",
271 index, SVG_IMAGE_NUM);
272 return Media::ERR_IMAGE_INVALID_PARAMETER;
273 }
274
275 IMAGE_LOGD("[SetDecodeOptions] IN index=%{public}u, pixelFormat=%{public}d, alphaType=%{public}d, "
276 "colorSpace=%{public}d, size=(%{public}u, %{public}u), state=%{public}d", index,
277 static_cast<int32_t>(opts.desiredPixelFormat), static_cast<int32_t>(opts.desireAlphaType),
278 static_cast<int32_t>(opts.desiredColorSpace), opts.desiredSize.width, opts.desiredSize.height, state_);
279
280 if (state_ < SvgDecodingState::SOURCE_INITED) {
281 IMAGE_LOGE("[SetDecodeOptions] set decode options failed for state %{public}d.", state_);
282 return Media::ERR_MEDIA_INVALID_OPERATION;
283 }
284
285 if (state_ >= SvgDecodingState::IMAGE_DECODING) {
286 state_ = SvgDecodingState::SOURCE_INITED;
287 }
288
289 if (state_ < SvgDecodingState::BASE_INFO_PARSED) {
290 uint32_t ret = DoDecodeHeader();
291 if (ret != Media::SUCCESS) {
292 IMAGE_LOGE("[SetDecodeOptions] decode header error on set decode options, ret:%{public}u.", ret);
293 state_ = SvgDecodingState::BASE_INFO_PARSING;
294 return ret;
295 }
296
297 state_ = SvgDecodingState::BASE_INFO_PARSED;
298 }
299
300 // only state SvgDecodingState::BASE_INFO_PARSED can go here.
301 uint32_t ret = DoSetDecodeOptions(index, opts, info);
302 if (ret != Media::SUCCESS) {
303 IMAGE_LOGE("[SetDecodeOptions] do set decode options failed, ret:%{public}u.", ret);
304 state_ = SvgDecodingState::BASE_INFO_PARSING;
305 return ret;
306 }
307
308 state_ = SvgDecodingState::IMAGE_DECODING;
309
310 IMAGE_LOGD("[SetDecodeOptions] OUT");
311 return Media::SUCCESS;
312 }
313
Decode(uint32_t index,DecodeContext & context)314 uint32_t SvgDecoder::Decode(uint32_t index, DecodeContext &context)
315 {
316 ImageTrace imageTrace("SvgDecoder::Decode, index:%u", index);
317 if (index >= SVG_IMAGE_NUM) {
318 IMAGE_LOGE("[Decode] decode image index[%{public}u], out of range[%{public}u].",
319 index, SVG_IMAGE_NUM);
320 return Media::ERR_IMAGE_INVALID_PARAMETER;
321 }
322
323 IMAGE_LOGD("[Decode] IN index=%{public}u", index);
324
325 if (state_ < SvgDecodingState::IMAGE_DECODING) {
326 IMAGE_LOGE("[Decode] decode failed for state %{public}d.", state_);
327 return Media::ERR_MEDIA_INVALID_OPERATION;
328 }
329
330 uint32_t ret = DoDecode(index, context);
331 if (ret == Media::SUCCESS) {
332 IMAGE_LOGD("[Decode] success.");
333 state_ = SvgDecodingState::IMAGE_DECODED;
334 } else {
335 IMAGE_LOGE("[Decode] fail, ret=%{public}u", ret);
336 state_ = SvgDecodingState::IMAGE_ERROR;
337 }
338
339 IMAGE_LOGD("[Decode] OUT ret=%{public}u", ret);
340 return ret;
341 }
342
PromoteIncrementalDecode(uint32_t index,ProgDecodeContext & context)343 uint32_t SvgDecoder::PromoteIncrementalDecode(uint32_t index, ProgDecodeContext &context)
344 {
345 // currently not support increment decode
346 return ERR_IMAGE_DATA_UNSUPPORT;
347 }
348
349 // need decode all frame to get total number.
GetTopLevelImageNum(uint32_t & num)350 uint32_t SvgDecoder::GetTopLevelImageNum(uint32_t &num)
351 {
352 num = SVG_IMAGE_NUM;
353 return Media::SUCCESS;
354 }
355
356 // return background size but not specific frame size, cause of frame drawing on background.
GetImageSize(uint32_t index,Size & size)357 uint32_t SvgDecoder::GetImageSize(uint32_t index, Size &size)
358 {
359 if (index >= SVG_IMAGE_NUM) {
360 IMAGE_LOGE("[GetImageSize] decode image index[%{public}u], out of range[%{public}u].",
361 index, SVG_IMAGE_NUM);
362 return Media::ERR_IMAGE_INVALID_PARAMETER;
363 }
364
365 IMAGE_LOGD("[GetImageSize] IN index=%{public}u", index);
366
367 if (state_ < SvgDecodingState::SOURCE_INITED) {
368 IMAGE_LOGE("[GetImageSize] get image size failed for state %{public}d.", state_);
369 return ERR_MEDIA_INVALID_OPERATION;
370 }
371
372 if (state_ >= SvgDecodingState::BASE_INFO_PARSED) {
373 DoGetImageSize(index, size);
374 IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
375 return Media::SUCCESS;
376 }
377
378 // only state SvgDecodingState::SOURCE_INITED and SvgDecodingState::BASE_INFO_PARSING can go here.
379 uint32_t ret = DoDecodeHeader();
380 if (ret != Media::SUCCESS) {
381 IMAGE_LOGE("[GetImageSize] decode header error on get image size, ret:%{public}u.", ret);
382 state_ = SvgDecodingState::BASE_INFO_PARSING;
383 return ret;
384 }
385
386 ret = DoGetImageSize(index, size);
387 if (ret != Media::SUCCESS) {
388 IMAGE_LOGE("[GetImageSize] do get image size failed, ret:%{public}u.", ret);
389 state_ = SvgDecodingState::BASE_INFO_PARSING;
390 return ret;
391 }
392
393 state_ = SvgDecodingState::BASE_INFO_PARSED;
394
395 IMAGE_LOGD("[GetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
396 return Media::SUCCESS;
397 }
398
AllocBuffer(DecodeContext & context)399 bool SvgDecoder::AllocBuffer(DecodeContext &context)
400 {
401 IMAGE_LOGD("[AllocBuffer] IN");
402
403 if (svgDom_ == nullptr) {
404 IMAGE_LOGE("[AllocBuffer] DOM is null.");
405 return false;
406 }
407
408 bool ret = true;
409 if (context.pixelsBuffer.buffer == nullptr) {
410 auto svgSize = svgDom_->containerSize();
411 if (svgSize.isEmpty()) {
412 IMAGE_LOGE("[AllocBuffer] size is empty.");
413 return false;
414 }
415 uint32_t width = Float2UInt32(svgSize.width());
416 uint32_t height = Float2UInt32(svgSize.height());
417 uint64_t byteCount = static_cast<uint64_t>(width) * height * SVG_BYTES_PER_PIXEL;
418 if (context.allocatorType == Media::AllocatorType::SHARE_MEM_ALLOC) {
419 ret = AllocShareBuffer(context, byteCount);
420 } else if (context.allocatorType == Media::AllocatorType::DMA_ALLOC) {
421 ret = AllocDmaBuffer(context, byteCount, svgSize);
422 } else {
423 ret = AllocHeapBuffer(context, byteCount);
424 }
425 }
426
427 IMAGE_LOGD("[AllocBuffer] OUT ret=%{public}d", ret);
428 return ret;
429 }
430
BuildStream()431 bool SvgDecoder::BuildStream()
432 {
433 IMAGE_LOGD("[BuildStream] IN");
434
435 if (inputStreamPtr_ == nullptr) {
436 IMAGE_LOGE("[BuildStream] Stream is null.");
437 return false;
438 }
439
440 auto length = inputStreamPtr_->GetStreamSize();
441 if (inputStreamPtr_->GetStreamType() == ImagePlugin::BUFFER_SOURCE_TYPE) {
442 svgStream_ = std::make_unique<SkMemoryStream>(inputStreamPtr_->GetDataPtr(), length);
443 } else {
444 auto data = std::make_unique<uint8_t[]>(length);
445 uint32_t readSize = 0;
446 if (!inputStreamPtr_->Read(length, data.get(), length, readSize)) {
447 IMAGE_LOGE("[BuildStream] read failed.");
448 return false;
449 }
450 svgStream_ = std::make_unique<SkMemoryStream>(data.get(), length, true);
451 }
452
453 IMAGE_LOGD("[BuildStream] OUT");
454 return true;
455 }
456
SetSVGColor(SkSVGNode * node,std::string color,std::string colorAttr)457 static void SetSVGColor(SkSVGNode* node, std::string color, std::string colorAttr)
458 {
459 if (node == nullptr) {
460 return;
461 }
462 IMAGE_LOGD("[SetSVGColor] node tag %{public}d %{public}s %{public}s.",
463 node->tag(), color.c_str(), colorAttr.c_str());
464 node->setAttribute(colorAttr.c_str(), color.c_str());
465 for (auto childNode : node->getChild()) {
466 SetSVGColor(childNode.get(), color, colorAttr);
467 }
468 }
469
SetSVGColor(SkSVGNode * node,uint32_t color,std::string colorAttr)470 static void SetSVGColor(SkSVGNode* node, uint32_t color, std::string colorAttr)
471 {
472 std::stringstream stream;
473 stream.fill('0');
474 stream.width(SVG_COLOR_ATTR_WIDTH);
475 stream << std::hex << (color & SVG_COLOR_MASK);
476 std::string newValue(stream.str());
477 SetSVGColor(node, "#" + newValue, colorAttr);
478 }
479
BuildDom()480 bool SvgDecoder::BuildDom()
481 {
482 IMAGE_LOGD("[BuildDom] IN");
483
484 if (svgStream_ == nullptr) {
485 IMAGE_LOGE("[BuildDom] Stream is null.");
486 return false;
487 }
488
489 svgDom_ = SkSVGDOM::MakeFromStream(*(svgStream_.get()));
490 if (svgDom_ == nullptr) {
491 IMAGE_LOGE("[BuildDom] DOM is null.");
492 return false;
493 }
494
495 svgSize_ = svgDom_->containerSize();
496 if (svgSize_.isEmpty()) {
497 IMAGE_LOGE("[BuildDom] size is empty.");
498 return false;
499 }
500
501 auto width = Float2UInt32(svgSize_.width());
502 auto height = Float2UInt32(svgSize_.height());
503
504 IMAGE_LOGD("[BuildDom] OUT size=(%{public}u, %{public}u)", width, height);
505 return true;
506 }
507
DoDecodeHeader()508 uint32_t SvgDecoder::DoDecodeHeader()
509 {
510 IMAGE_LOGD("[DoDecodeHeader] IN");
511
512 if (!BuildStream()) {
513 IMAGE_LOGE("[DoDecodeHeader] Build Stream failed");
514 return Media::ERR_IMAGE_TOO_LARGE;
515 }
516
517 if (!BuildDom()) {
518 IMAGE_LOGE("[DoDecodeHeader] Build DOM failed");
519 return Media::ERR_IMAGE_DATA_UNSUPPORT;
520 }
521
522 IMAGE_LOGD("[DoDecodeHeader] OUT");
523 return Media::SUCCESS;
524 }
525
IsSrcRectContainsDistRect(const OHOS::Media::Rect & srcRect,const OHOS::Media::Rect & distRect)526 bool IsSrcRectContainsDistRect(const OHOS::Media::Rect &srcRect, const OHOS::Media::Rect &distRect)
527 {
528 if (srcRect.left < 0 || srcRect.top < 0 || srcRect.width <= 0 || srcRect.height <= 0) {
529 return false;
530 }
531 if (distRect.left < 0 || distRect.top < 0 || distRect.width <= 0 || distRect.height <= 0) {
532 return false;
533 }
534 return srcRect.left <= distRect.left && srcRect.top <= distRect.top &&
535 (srcRect.left + srcRect.width) >= (distRect.left + distRect.width) &&
536 (srcRect.top + srcRect.height) >= (distRect.top + distRect.height);
537 }
538
CheckCropRectValid(const PixelDecodeOptions & opts,const SkSize & svgSize)539 bool CheckCropRectValid(const PixelDecodeOptions &opts, const SkSize &svgSize)
540 {
541 OHOS::Media::Rect srcRect = {0, 0, 0, 0};
542 if (opts.cropAndScaleStrategy == CropAndScaleStrategy::DEFAULT) {
543 return true;
544 }
545 srcRect.width = svgSize.width();
546 srcRect.height = svgSize.height();
547 if (opts.cropAndScaleStrategy == CropAndScaleStrategy::SCALE_FIRST &&
548 (opts.desiredSize.width != 0 || opts.desiredSize.height != 0)) {
549 srcRect.width = opts.desiredSize.width;
550 srcRect.height = opts.desiredSize.height;
551 }
552 return IsSrcRectContainsDistRect(srcRect, opts.CropRect);
553 }
554
DoSetDecodeOptions(uint32_t index,const PixelDecodeOptions & opts,PlImageInfo & info)555 uint32_t SvgDecoder::DoSetDecodeOptions(uint32_t index, const PixelDecodeOptions &opts, PlImageInfo &info)
556 {
557 IMAGE_LOGD("[DoSetDecodeOptions] IN index=%{public}u", index);
558
559 if (svgDom_ == nullptr) {
560 IMAGE_LOGE("[DoSetDecodeOptions] DOM is null.");
561 return Media::ERROR;
562 }
563
564 opts_ = opts;
565
566 auto svgSize = svgDom_->containerSize();
567 if (svgSize.isEmpty()) {
568 IMAGE_LOGE("[DoSetDecodeOptions] size is empty.");
569 return Media::ERROR;
570 }
571 if (!CheckCropRectValid(opts_, svgSize)) {
572 IMAGE_LOGI("crop rect is invalid.");
573 return ERR_MEDIA_INVALID_OPERATION;
574 }
575
576 float scaleFitDesired = 1.0;
577 if (opts_.desiredSize.width && opts_.desiredSize.height &&
578 opts.cropAndScaleStrategy == CropAndScaleStrategy::DEFAULT) {
579 scaleFitDesired = std::min(static_cast<float>(opts_.desiredSize.width) / svgSize.width(),
580 static_cast<float>(opts_.desiredSize.height) / svgSize.height());
581 }
582
583 if (opts_.plSVGResize.isValidPercentage) {
584 svgDom_->setResizePercentage(opts_.plSVGResize.resizePercentage * scaleFitDesired);
585 } else {
586 svgDom_->setResizePercentage(DEFAULT_RESIZE_PERCENTAGE * scaleFitDesired);
587 }
588
589 opts_.desiredSize.width = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().width()));
590 opts_.desiredSize.height = static_cast<int32_t>(Float2UInt32(svgDom_->containerSize().height()));
591
592 info.size.width = opts_.desiredSize.width;
593 info.size.height = opts_.desiredSize.height;
594 info.pixelFormat = PixelFormat::RGBA_8888;
595 info.colorSpace = ColorSpace::UNKNOWN;
596 info.alphaType = AlphaType::IMAGE_ALPHA_TYPE_PREMUL;
597
598 IMAGE_LOGD("[DoSetDecodeOptions] OUT pixelFormat=%{public}d, alphaType=%{public}d, "
599 "colorSpace=%{public}d, size=(%{public}u, %{public}u)",
600 static_cast<int32_t>(info.pixelFormat), static_cast<int32_t>(info.alphaType),
601 static_cast<int32_t>(info.colorSpace), info.size.width, info.size.height);
602 return Media::SUCCESS;
603 }
604
DoGetImageSize(uint32_t index,Size & size)605 uint32_t SvgDecoder::DoGetImageSize(uint32_t index, Size &size)
606 {
607 IMAGE_LOGD("[DoGetImageSize] IN index=%{public}u", index);
608
609 if (svgDom_ == nullptr) {
610 IMAGE_LOGE("[DoGetImageSize] DOM is null.");
611 return Media::ERROR;
612 }
613
614 auto svgSize = svgDom_->containerSize();
615 if (svgSize.isEmpty()) {
616 IMAGE_LOGE("[DoGetImageSize] size is empty.");
617 return Media::ERROR;
618 }
619
620 size.width = static_cast<int32_t>(Float2UInt32(svgSize.width()));
621 size.height = static_cast<int32_t>(Float2UInt32(svgSize.height()));
622
623 IMAGE_LOGD("[DoGetImageSize] OUT size=(%{public}u, %{public}u)", size.width, size.height);
624 return Media::SUCCESS;
625 }
626
DoDecode(uint32_t index,DecodeContext & context)627 uint32_t SvgDecoder::DoDecode(uint32_t index, DecodeContext &context)
628 {
629 IMAGE_LOGD("[DoDecode] IN index=%{public}u", index);
630
631 if (svgDom_ == nullptr) {
632 IMAGE_LOGE("[DoDecode] DOM is null.");
633 return Media::ERROR;
634 }
635
636 if (opts_.plFillColor.isValidColor) {
637 SetSVGColor(svgDom_->getRoot(), opts_.plFillColor.color, SVG_FILL_COLOR_ATTR);
638 }
639
640 if (opts_.plStrokeColor.isValidColor) {
641 SetSVGColor(svgDom_->getRoot(), opts_.plStrokeColor.color, SVG_STROKE_COLOR_ATTR);
642 }
643
644 if (!AllocBuffer(context)) {
645 IMAGE_LOGE("[DoDecode] alloc buffer failed.");
646 return Media::ERR_IMAGE_MALLOC_ABNORMAL;
647 }
648
649 auto imageInfo = MakeImageInfo(opts_);
650 auto rowBytes = static_cast<uint32_t>(opts_.desiredSize.width * SVG_BYTES_PER_PIXEL);
651 auto pixels = context.pixelsBuffer.buffer;
652
653 SkBitmap bitmap;
654 if (!bitmap.installPixels(imageInfo, pixels, rowBytes)) {
655 IMAGE_LOGE("[DoDecode] bitmap install pixels failed.");
656 return Media::ERROR;
657 }
658
659 auto canvas = SkCanvas::MakeRasterDirect(imageInfo, bitmap.getPixels(), bitmap.rowBytes());
660 if (canvas == nullptr) {
661 IMAGE_LOGE("[DoDecode] make canvas failed.");
662 return Media::ERROR;
663 }
664 canvas->clear(SK_ColorTRANSPARENT);
665 svgDom_->render(canvas.get());
666
667 bool result = canvas->readPixels(imageInfo, pixels, rowBytes, 0, 0);
668 if (!result) {
669 IMAGE_LOGE("[DoDecode] read pixels failed.");
670 return Media::ERROR;
671 }
672
673 IMAGE_LOGD("[DoDecode] OUT");
674 ImageUtils::FlushContextSurfaceBuffer(context);
675 return Media::SUCCESS;
676 }
677 } // namespace ImagePlugin
678 } // namespace OHOS