1 /*
2 * Copyright (c) 2022 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 "core/image/apng/apng_image_player.h"
17
18 #include <cstdlib>
19 #include <cstdio>
20 #include "base/log/log.h"
21 #include "core/image/image_provider.h"
22 #ifndef USE_ROSEN_DRAWING
23 #include "include/codec/SkCodecAnimation.h"
24 #include "include/core/SkPixelRef.h"
25 #endif
26
27 namespace OHOS::Ace {
APngImagePlayer(ImageSourceInfo source,UploadSuccessCallback successCallback,const WeakPtr<PipelineBase> & weakContext,const RefPtr<PNGImageDecoder> & decoder,int32_t dstWidth,int32_t dstHeight)28 APngImagePlayer::APngImagePlayer(
29 ImageSourceInfo source,
30 UploadSuccessCallback successCallback,
31 const WeakPtr<PipelineBase>& weakContext,
32 const RefPtr<PNGImageDecoder>& decoder,
33 int32_t dstWidth,
34 int32_t dstHeight)
35 : imageSource_(source), successCallback_(successCallback), context_(weakContext),
36 apngDecoder_(decoder), dstWidth_(dstWidth), dstHeight_(dstHeight)
37 {
38 auto context = context_.Upgrade();
39 if (context) {
40 // decode apng
41 if (!apngDecoder_ || !apngDecoder_->isApng()) {
42 LOGE("APNG Image Player png decoder error!");
43 return;
44 }
45
46 // get apng all frames, before use decoder need Use GetAllFrames before
47 frameCount_ = apngDecoder_->GetFrameCount();
48 if (!GetApngAllFrames()) {
49 return;
50 }
51
52 auto pictureAnimation = AceType::MakeRefPtr<APngImageAnimation>();
53 float totalFrameDuration = 0.0f;
54
55 for (int32_t index = 0; index < frameCount_; index++) {
56 // if frame duration is 0, set this frame duration as 100ms
57 if (frameInfos_[index].duration <= 0) {
58 frameInfos_[index].duration = 0;
59 }
60
61 totalFrameDuration += frameInfos_[index].duration;
62 }
63
64 for (int32_t index = 0; index < frameCount_; index++) {
65 pictureAnimation->AddPicture(frameInfos_[index].duration, index);
66 }
67
68 pictureAnimation->AddListener([weak = WeakClaim(this)](const int32_t &index) {
69 auto player = weak.Upgrade();
70 if (player) {
71 player->RenderFrame(index);
72 }
73 });
74
75 pictureAnimation_ = pictureAnimation;
76
77 auto &&callback = [weak = AceType::WeakClaim(this)](uint64_t duration) {
78 auto controller = weak.Upgrade();
79 if (!controller) {
80 LOGE("controller is nullptr, skip frame callback.");
81 return;
82 }
83
84 controller->pictureAnimation_->OnNormalizedTimestampChanged(duration, false);
85 };
86
87 scheduler_ = SchedulerBuilder::Build(callback, context);
88 scheduler_->Start();
89 }
90 }
91
~APngImagePlayer()92 APngImagePlayer::~APngImagePlayer()
93 {
94 if (blendCanvas_) {
95 delete blendCanvas_;
96 }
97
98 scheduler_->Stop();
99 }
100
101 /**
102 * convert fraction to double value
103 * @param num
104 * @param den
105 * @return
106 */
107 const float DefaultDen = 100.0;
108 const float SecondToMinSec = 1000;
109
DelayToSeconds(uint16_t num,uint16_t den)110 float APngImagePlayer::DelayToSeconds(uint16_t num, uint16_t den)
111 {
112 if (den == 0) {
113 return num / DefaultDen * SecondToMinSec;
114 } else {
115 return static_cast<float>(num) / static_cast<float>(den) * SecondToMinSec;
116 }
117 }
118
119 /**
120 * decoder apng all frame head information
121 * need use at first
122 */
123
GetApngAllFrames()124 bool APngImagePlayer::GetApngAllFrames()
125 {
126 auto pngInfo = apngDecoder_->GetApngInfo();
127 if (!pngInfo) {
128 return false;
129 }
130
131 bool needBlend = false;
132 uint32_t lastBlendIndex = 0;
133 uint32_t canvasWidth = pngInfo->header.width;
134 uint32_t canvasHeight = pngInfo->header.height;
135 frameInfos_.clear();
136
137 for (uint32_t i = 0; i < pngInfo->apngFrameNum; i++) {
138 APngAnimatedFrameInfo frame;
139 PngFrameInfo *frameInfo = pngInfo->apngFrames + i;
140 frame.index = i;
141 frame.duration = DelayToSeconds(frameInfo->frameControl.delayNum, frameInfo->frameControl.delayDen);
142 frame.width = frameInfo->frameControl.width;
143 frame.height = frameInfo->frameControl.height;
144 frame.offsetX = frameInfo->frameControl.xOffset;
145 frame.offsetY = frameInfo->frameControl.yOffset;
146
147 bool sizeEqualsToCanvas = (frame.width == canvasWidth && frame.height == canvasHeight);
148 bool offsetIsZero = (frameInfo->frameControl.xOffset == 0 && frameInfo->frameControl.yOffset == 0);
149 frame.isFullSize = (sizeEqualsToCanvas && offsetIsZero);
150
151 switch (frameInfo->frameControl.disposeOp) {
152 case PNG_DISPOSE_OP_BACKGROUND: {
153 frame.dispose = ImageDisposeBackground;
154 break;
155 }
156 case PNG_DISPOSE_OP_PREVIOUS: {
157 frame.dispose = ImageDisposePrevious;
158 break;
159 }
160 default: {
161 frame.dispose = ImageDisposeNone;
162 break;
163 }
164 }
165
166 switch (frameInfo->frameControl.blendOp) {
167 case PNG_BLEND_OP_OVER: {
168 frame.blend = ImageBlendOver;
169 break;
170 }
171 default: {
172 frame.blend = ImageBlendNone;
173 break;
174 }
175 }
176
177 if (frame.blend == ImageBlendNone && frame.isFullSize) {
178 frame.blendFromIndex = i;
179 if (frame.dispose != ImageDisposePrevious) {
180 lastBlendIndex = i;
181 }
182 } else {
183 if (frame.dispose == ImageDisposeBackground && frame.isFullSize) {
184 frame.blendFromIndex = lastBlendIndex;
185 lastBlendIndex = i + 1;
186 } else {
187 frame.blendFromIndex = lastBlendIndex;
188 }
189 }
190
191 if (frame.index != frame.blendFromIndex) {
192 needBlend = true;
193 }
194
195 frameInfos_.push_back(frame);
196 }
197
198 repetitionCount_ = pngInfo->apngLoopNum;
199 needBlend_ = needBlend;
200 width_ = canvasWidth;
201 height_ = canvasHeight;
202
203 return true;
204 }
205
Pause()206 void APngImagePlayer::Pause()
207 {
208 if (scheduler_ && scheduler_->IsActive()) {
209 scheduler_->Stop();
210 }
211 }
212
Resume()213 void APngImagePlayer::Resume()
214 {
215 if (scheduler_ && !scheduler_->IsActive()) {
216 scheduler_->Start();
217 }
218 }
219
RenderFrame(const int32_t & index)220 void APngImagePlayer::RenderFrame(const int32_t& index)
221 {
222 auto context = context_.Upgrade();
223 if (!context) {
224 LOGW("Context may be destroyed!");
225 return;
226 }
227
228 auto taskExecutor = context->GetTaskExecutor();
229 taskExecutor->PostTask(
230 [weak = AceType::WeakClaim(this), index, dstWidth = dstWidth_, dstHeight = dstHeight_, taskExecutor] {
231 auto player = weak.Upgrade();
232 if (!player) {
233 return;
234 }
235
236 APngAnimatedFrameInfo* frameInfo = player->DecodeFrameImage(index);
237 if (!frameInfo || !frameInfo->image) {
238 return;
239 }
240
241 #ifndef USE_ROSEN_DRAWING
242 sk_sp<SkImage> skImage = frameInfo->image;
243 if (dstWidth > 0 && dstHeight > 0) {
244 skImage = ImageProvider::ApplySizeToSkImage(skImage, dstWidth, dstHeight);
245 }
246 if (!skImage) {
247 LOGW("animated player cannot get the %{public}d skImage!", index);
248 return;
249 }
250 auto canvasImage = NG::CanvasImage::Create(&skImage);
251 #else
252 std::shared_ptr<RSImage> dImage = frameInfo->image;
253 if (dstWidth > 0 && dstHeight > 0) {
254 dImage = ImageProvider::ApplySizeToDrawingImage(dImage, dstWidth, dstHeight);
255 }
256 if (!dImage) {
257 LOGW("animated player cannot get the %{public}d dImage!", index);
258 return;
259 }
260 auto canvasImage = NG::CanvasImage::Create(&dImage);
261 #endif
262
263 taskExecutor->PostTask([callback = player->successCallback_, canvasImage,
264 source = player->imageSource_] { callback(source, canvasImage); },
265 TaskExecutor::TaskType::UI, "ArkUIImageAPngRenderSuccess");
266 },
267 TaskExecutor::TaskType::IO, "ArkUIImageAPngRenderFrame");
268 }
269
270 /**
271 * Get Frame Image mybe the image need draw in a new canvas
272 * **/
273 #ifndef USE_ROSEN_DRAWING
GetImage(const int32_t & index,bool extendToCanvas)274 sk_sp<SkImage> APngImagePlayer::GetImage(const int32_t& index, bool extendToCanvas)
275 {
276 uint32_t size = 0;
277 if (!apngDecoder_ || !apngDecoder_->isApng()) {
278 return nullptr;
279 }
280
281 uint8_t *frameData = apngDecoder_->GetFrameData(index, &size);
282 if (!frameData || size <= 0) {
283 return nullptr;
284 }
285
286 APngAnimatedFrameInfo *frameInfo = &frameInfos_[index];
287 SkData::ReleaseProc releaseProc = [](const void *ptr, void *context) -> void {
288 if (ptr) {
289 free((void *) ptr);
290 }
291 };
292
293 sk_sp<SkData> skData = SkData::MakeWithProc(frameData, size, releaseProc, nullptr);
294 if (!skData) {
295 return nullptr;
296 }
297
298 auto rawImage = SkImage::MakeFromEncoded(skData);
299 // if extendToCanvas then draw the image to canvas with offset info
300 if (extendToCanvas && rawImage) {
301 SkPictureRecorder recorder;
302 SkCanvas *canvas = recorder.beginRecording(width_, height_);
303 canvas->drawImage(rawImage, frameInfo->offsetX, frameInfo->offsetY, nullptr);
304 rawImage = SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
305 SkISize::Make(width_, height_), nullptr, nullptr,
306 SkImage::BitDepth::kU8,
307 SkColorSpace::MakeSRGB());
308 }
309
310 return rawImage;
311 }
312 #else
313 // Drawing : SkData::MakeWithProc
314 #endif
ClearCanvasRect(const APngAnimatedFrameInfo * frameInfo)315 void APngImagePlayer::ClearCanvasRect(const APngAnimatedFrameInfo *frameInfo)
316 {
317 if (!frameInfo || !blendCanvas_) {
318 return;
319 }
320
321 #ifndef USE_ROSEN_DRAWING
322 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX,
323 frameInfo->offsetY,
324 frameInfo->width,
325 frameInfo->height);
326
327 SkPaint paint;
328 paint.setStyle(SkPaint::kFill_Style);
329 paint.setColor(SK_ColorTRANSPARENT);
330 blendCanvas_->drawRect(unBlendRect, paint);
331 #else
332 RSRect unBlendRect =
333 RSRect(frameInfo->offsetX, frameInfo->offsetY,
334 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
335
336 RSBrush brush;
337 brush.SetColor(RSColor::COLOR_TRANSPARENT);
338 blendCanvas_->AttachBrush(brush);
339 blendCanvas_->DrawRect(unBlendRect);
340 blendCanvas_->DetachBrush();
341 #endif
342 }
343
BlendImage(const APngAnimatedFrameInfo * frameInfo)344 void APngImagePlayer::BlendImage(const APngAnimatedFrameInfo *frameInfo)
345 {
346 #ifndef USE_ROSEN_DRAWING
347 sk_sp<SkImage> image = nullptr;
348
349 if (!frameInfo) {
350 return;
351 }
352
353 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX,
354 frameInfo->offsetY,
355 frameInfo->width,
356 frameInfo->height);
357
358 if (frameInfo->dispose == ImageDisposePrevious) {
359 } else if (frameInfo->dispose == ImageDisposeBackground) {
360 ClearCanvasRect(frameInfo);
361 } else {
362 if (frameInfo->blend == ImageBlendOver) {
363 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
364 if (unblendImage) {
365 blendCanvas_->drawImageRect(unblendImage,
366 unBlendRect,
367 nullptr);
368 }
369 } else {
370 ClearCanvasRect(frameInfo);
371 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
372 if (unblendImage) {
373 blendCanvas_->drawImageRect(unblendImage,
374 unBlendRect,
375 nullptr);
376 }
377 }
378 }
379 #else
380 if (!frameInfo) {
381 return;
382 }
383
384 RSRect unBlendRect =
385 RSRect(frameInfo->offsetX, frameInfo->offsetY,
386 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
387
388 RSSamplingOptions sampling =
389 RSSamplingOptions(RSFilterMode::NEAREST, RSMipmapMode::NEAREST);
390 if (frameInfo->dispose == ImageDisposePrevious) {
391 } else if (frameInfo->dispose == ImageDisposeBackground) {
392 ClearCanvasRect(frameInfo);
393 } else {
394 if (frameInfo->blend == ImageBlendOver) {
395 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
396 if (unblendImage) {
397 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
398 }
399 } else {
400 ClearCanvasRect(frameInfo);
401 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
402 if (unblendImage) {
403 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
404 }
405 }
406 }
407 #endif
408 }
409
410 /**
411 * Debug function
412 */
DrawTest()413 void APngImagePlayer::DrawTest()
414 {
415 const uint32_t TestWidth = 10;
416 const uint32_t TestX = 10;
417 #ifndef USE_ROSEN_DRAWING
418 SkPaint pt;
419 pt.setStyle(SkPaint::kFill_Style);
420 pt.setColor(SK_ColorRED);
421 blendCanvas_->drawRect(SkRect::MakeXYWH(TestX, TestX, TestWidth, TestWidth), pt);
422 #else
423 RSBrush brush;
424 brush.SetColor(RSColor::COLOR_RED);
425 blendCanvas_->AttachBrush(brush);
426 blendCanvas_->DrawRect(RSRect::MakeXYWH(TestX, TestX, TestWidth, TestWidth));
427 blendCanvas_->DetachBrush();
428 #endif
429 }
430
431 #ifndef USE_ROSEN_DRAWING
DrawTestBorder(SkRect & rect)432 void APngImagePlayer::DrawTestBorder(SkRect& rect)
433 {
434 SkPaint pt;
435 pt.setStyle(SkPaint::kStroke_Style);
436 pt.setColor(SK_ColorRED);
437 pt.setStrokeWidth(1);
438 blendCanvas_->drawRect(rect, pt);
439 }
440 #else
DrawTestBorder(RSRect & rect)441 void APngImagePlayer::DrawTestBorder(RSRect& rect)
442 {
443 RSPen pen;
444 pen.SetColor(RSColor::COLOR_RED);
445 pen.SetWidth(1);
446 blendCanvas_->AttachPen(pen);
447 blendCanvas_->DrawRect(rect);
448 blendCanvas_->DetachPen();
449 }
450 #endif
451
452 /**
453 * Get decoded Image with frameinfo
454 * @param frameInfo
455 * @return
456 */
457 #ifndef USE_ROSEN_DRAWING
GetImage(const APngAnimatedFrameInfo * frameInfo)458 sk_sp<SkImage> APngImagePlayer::GetImage(const APngAnimatedFrameInfo *frameInfo)
459 {
460 sk_sp<SkImage> image = nullptr;
461
462 if (!frameInfo) {
463 return nullptr;
464 }
465
466 if (frameInfo->dispose == ImageDisposePrevious) {
467 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX,
468 frameInfo->offsetY,
469 frameInfo->width,
470 frameInfo->height);
471
472 SkBitmap bitmap;
473 CopyTo(&bitmap, bitmap_);
474 sk_sp<SkImage> previousImage = SkImage::MakeFromBitmap(bitmap);
475 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
476
477 if (frameInfo->blend == ImageBlendOver) {
478 if (unblendImage) {
479 blendCanvas_->drawImageRect(unblendImage,
480 unBlendRect,
481 nullptr);
482 }
483
484 SkBitmap bitmap;
485 CopyTo(&bitmap, bitmap_);
486 image = SkImage::MakeFromBitmap(bitmap);
487
488 blendCanvas_->clear(SK_ColorTRANSPARENT);
489 if (previousImage) {
490 blendCanvas_->drawImage(previousImage, 0, 0);
491 }
492 } else {
493 if (unblendImage) {
494 ClearCanvasRect(frameInfo);
495 blendCanvas_->drawImageRect(unblendImage,
496 unBlendRect,
497 nullptr);
498 }
499
500 SkBitmap bitmap;
501 CopyTo(&bitmap, bitmap_);
502 image = SkImage::MakeFromBitmap(bitmap);
503 blendCanvas_->clear(SK_ColorTRANSPARENT);
504 if (previousImage) {
505 blendCanvas_->drawImage(previousImage, 0, 0);
506 }
507 }
508 } else if (frameInfo->dispose == ImageDisposeBackground) {
509 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
510 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX,
511 frameInfo->offsetY,
512 frameInfo->width,
513 frameInfo->height);
514 if (frameInfo->blend == ImageBlendOver) {
515 if (unblendImage) {
516 blendCanvas_->drawImageRect(unblendImage,
517 unBlendRect,
518 nullptr);
519 }
520
521 SkBitmap bitmap;
522 CopyTo(&bitmap, bitmap_);
523 image = SkImage::MakeFromBitmap(bitmap);
524 blendCanvas_->clear(SK_ColorTRANSPARENT);
525 } else {
526 if (unblendImage) {
527 ClearCanvasRect(frameInfo);
528
529 blendCanvas_->drawImageRect(unblendImage,
530 unBlendRect,
531 nullptr);
532 }
533
534 SkBitmap bitmap;
535 CopyTo(&bitmap, bitmap_);
536 image = SkImage::MakeFromBitmap(bitmap);
537 blendCanvas_->clear(SK_ColorTRANSPARENT);
538 }
539 } else {
540 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
541 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX, frameInfo->offsetY, frameInfo->width,
542 frameInfo->height);
543 if (frameInfo->blend == ImageBlendOver) {
544 if (unblendImage) {
545 blendCanvas_->drawImageRect(unblendImage,
546 unBlendRect,
547 nullptr);
548 }
549
550 SkBitmap bitmap;
551 CopyTo(&bitmap, bitmap_);
552 image = SkImage::MakeFromBitmap(bitmap);
553 } else {
554 if (unblendImage) {
555 ClearCanvasRect(frameInfo);
556
557 blendCanvas_->drawImageRect(unblendImage,
558 unBlendRect,
559 nullptr);
560 }
561
562 SkBitmap bitmap;
563 CopyTo(&bitmap, bitmap_);
564 image = SkImage::MakeFromBitmap(bitmap);
565 }
566 }
567
568 return image;
569 }
570 #else
GetImage(const APngAnimatedFrameInfo * frameInfo)571 std::shared_ptr<RSImage> APngImagePlayer::GetImage(const APngAnimatedFrameInfo *frameInfo)
572 {
573 std::shared_ptr<RSImage> image = nullptr;
574 RSSamplingOptions sampling =
575 RSSamplingOptions(RSFilterMode::NEAREST, RSMipmapMode::NEAREST);
576
577 if (!frameInfo) {
578 return nullptr;
579 }
580
581 if (frameInfo->dispose == ImageDisposePrevious) {
582 RSRect unBlendRect =
583 RSRect(frameInfo->offsetX, frameInfo->offsetY,
584 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
585
586 RSBitmap bitmap;
587 CopyTo(&bitmap, bitmap_);
588 auto previousImage = std::make_shared<RSImage> ();
589 previousImage->BuildFromBitmap(bitmap);
590 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
591
592 if (frameInfo->blend == ImageBlendOver) {
593 if (unblendImage) {
594 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
595 }
596
597 RSBitmap bitmap;
598 CopyTo(&bitmap, bitmap_);
599 image->BuildFromBitmap(bitmap);
600
601 blendCanvas_->Clear(RSColor::COLOR_TRANSPARENT);
602 if (previousImage) {
603 blendCanvas_->DrawImage(*previousImage, 0, 0, sampling);
604 }
605 } else {
606 if (unblendImage) {
607 ClearCanvasRect(frameInfo);
608 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
609 }
610
611 RSBitmap bitmap;
612 CopyTo(&bitmap, bitmap_);
613 image->BuildFromBitmap(bitmap);
614 blendCanvas_->Clear(RSColor::COLOR_TRANSPARENT);
615 if (previousImage) {
616 blendCanvas_->DrawImage(*previousImage, 0, 0, sampling);
617 }
618 }
619 } else if (frameInfo->dispose == ImageDisposeBackground) {
620 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
621 RSRect unBlendRect =
622 RSRect(frameInfo->offsetX, frameInfo->offsetY,
623 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
624 if (frameInfo->blend == ImageBlendOver) {
625 if (unblendImage) {
626 blendCanvas_->DrawImageRect(*unblendImage,
627 unBlendRect,
628 sampling);
629 }
630
631 RSBitmap bitmap;
632 CopyTo(&bitmap, bitmap_);
633 image->BuildFromBitmap(bitmap);
634 blendCanvas_->Clear(RSColor::COLOR_TRANSPARENT);
635 } else {
636 if (unblendImage) {
637 ClearCanvasRect(frameInfo);
638
639 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
640 }
641
642 RSBitmap bitmap;
643 CopyTo(&bitmap, bitmap_);
644 image->BuildFromBitmap(bitmap);
645 blendCanvas_->Clear(RSColor::COLOR_TRANSPARENT);
646 }
647 } else {
648 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
649 RSRect unBlendRect = RSRect(frameInfo->offsetX, frameInfo->offsetY,
650 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
651 if (frameInfo->blend == ImageBlendOver) {
652 if (unblendImage) {
653 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
654 }
655
656 RSBitmap bitmap;
657 CopyTo(&bitmap, bitmap_);
658 image->BuildFromBitmap(bitmap);
659 } else {
660 if (unblendImage) {
661 ClearCanvasRect(frameInfo);
662
663 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
664 }
665
666 RSBitmap bitmap;
667 CopyTo(&bitmap, bitmap_);
668 image->BuildFromBitmap(bitmap);
669 }
670 }
671
672 return image;
673 }
674 #endif
675
PreDecodeAllFrames()676 bool APngImagePlayer::PreDecodeAllFrames()
677 {
678 return false;
679 }
680
681 #ifndef USE_ROSEN_DRAWING
CreateBlendCanvas()682 SkCanvas *APngImagePlayer::CreateBlendCanvas()
683 {
684 if (!blendCanvas_) {
685 blendFrameIndex_ = -1;
686 bitmap_.allocN32Pixels(width_, height_);
687 blendCanvas_ = new SkCanvas(bitmap_);
688 }
689
690 return blendCanvas_;
691 }
692 #else
CreateBlendCanvas()693 RSCanvas *APngImagePlayer::CreateBlendCanvas()
694 {
695 if (!blendCanvas_) {
696 blendFrameIndex_ = -1;
697 ImageInfo imageInfo(width_, height_, COLORTYPE_N32, ALPHATYPE_PREMUL);
698 bitmap_.Build(imageInfo);
699 blendCanvas_.Bind(bitmap_);
700 }
701
702 return blendCanvas_;
703 }
704 #endif
705
706
707 /**
708 * 解码一帧,并把解码后的图片缓存在内存
709 * 注: 所有的帧必须顺序进行,apng图片优化后会存在按帧透明叠加形成新的一帧
710 * @param index
711 * @return frameInformation
712 */
DecodeFrameImage(const int32_t & index)713 APngAnimatedFrameInfo *APngImagePlayer::DecodeFrameImage(const int32_t& index)
714 {
715 // first seek in cache
716 auto iterator = cachedFrame_.find(index);
717 if (iterator != cachedFrame_.end() && iterator->second != nullptr) {
718 APngAnimatedFrameInfo *frameInfo = (APngAnimatedFrameInfo *) *iterator->second;
719 return frameInfo;
720 }
721
722 #ifndef USE_ROSEN_DRAWING
723 SkBitmap bitmap;
724 #else
725 RSBitmap bitmap;
726 #endif
727 APngAnimatedFrameInfo *frameInfo = &frameInfos_[index];
728 bool extendToCanvas = true;
729
730 if (frameInfo->image) {
731 return frameInfo;
732 }
733
734 if (!needBlend_) {
735 if (!frameInfo->image) {
736 #ifndef USE_ROSEN_DRAWING
737 sk_sp<SkImage> image = GetImage(index, true);
738 #else
739 std::shared_ptr<RSImage> image = GetImage(index, true);
740 #endif
741 if (!image) {
742 return nullptr;
743 }
744
745 frameInfo->image = image;
746 }
747
748 return frameInfo;
749 }
750
751 // create a canvas
752 if (!CreateBlendCanvas()) {
753 return nullptr;
754 }
755
756 #ifndef USE_ROSEN_DRAWING
757 sk_sp<SkImage> image = nullptr;
758 #else
759 std::shared_ptr<RSImage> image = nullptr;
760 #endif
761
762 if (blendFrameIndex_ + 1 == frameInfo->index) {
763 image = GetImage(frameInfo);
764 blendFrameIndex_ = index;
765 } else {
766 blendFrameIndex_ = -1;
767 #ifndef USE_ROSEN_DRAWING
768 blendCanvas_->clear(SK_ColorTRANSPARENT);
769 #else
770 blendCanvas_->clear(RSColor::COLOR_TRANSPARENT);
771 #endif
772
773 if (frameInfo->blendFromIndex == frameInfo->index) {
774 #ifndef USE_ROSEN_DRAWING
775 SkRect unBlendRect = SkRect::MakeXYWH(frameInfo->offsetX,
776 frameInfo->offsetY,
777 frameInfo->width,
778 frameInfo->height);
779 sk_sp<SkImage> unblendImage = GetImage(frameInfo->index, false);
780 if (unblendImage) {
781 blendCanvas_->drawImageRect(unblendImage,
782 unBlendRect,
783 nullptr);
784 }
785
786 SkBitmap bitmap;
787 CopyTo(&bitmap, bitmap_);
788 image = SkImage::MakeFromBitmap(bitmap);
789
790 if (frameInfo->dispose == ImageDisposeBackground) {
791 SkPaint paint;
792 paint.setStyle(SkPaint::kFill_Style);
793 paint.setColor(SK_ColorTRANSPARENT);
794 blendCanvas_->drawRect(unBlendRect, paint);
795 }
796 #else
797 RSRect unBlendRect = RSRect(frameInfo->offsetX, frameInfo->offsetY,
798 frameInfo->width + frameInfo->offsetX, frameInfo->height + frameInfo->offsetY);
799 RSSamplingOptions sampling = RSSamplingOptions(
800 RSFilterMode::NEAREST, RSMipmapMode::NEAREST);
801 std::shared_ptr<RSImage> unblendImage = GetImage(frameInfo->index, false);
802 if (unblendImage) {
803 blendCanvas_->DrawImageRect(*unblendImage, unBlendRect, sampling);
804 }
805
806 RSBitmap bitmap;
807 CopyTo(&bitmap, bitmap_);
808 image = std::make_shared<RSImage>();
809 image->BuildFromBitmap(bitmap);
810
811 if (frameInfo->dispose == ImageDisposeBackground) {
812 RSBrush brush;
813 brush.SetColor(RSColor::COLOR_TRANSPARENT);
814 blendCanvas_->AttachBrush(brush);
815 blendCanvas_->DrawRect(unBlendRect);
816 blendCanvas_->DetachBrush();
817 }
818 #endif
819
820 blendFrameIndex_ = index;
821 } else { // canvas is not ready
822 for (uint32_t i = (uint32_t) frameInfo->blendFromIndex; i <= (uint32_t) frameInfo->index; i++) {
823 if (i == frameInfo->index) {
824 if (!image) {
825 image = GetImage(frameInfo);
826 }
827 } else {
828 BlendImage(&frameInfos_[i]);
829 }
830 }
831
832 blendFrameIndex_ = index;
833 }
834 }
835
836 if (!image) {
837 return nullptr;
838 }
839
840 // cache image data
841 // if draw frame image in canvas then need modify offset / width / height
842 frameInfo->image = image;
843
844 if (extendToCanvas) {
845 frameInfo->width = width_;
846 frameInfo->height = height_;
847 frameInfo->offsetX = 0;
848 frameInfo->offsetY = 0;
849 frameInfo->dispose = ImageDisposeNone;
850 frameInfo->blend = ImageBlendNone;
851 }
852
853 return frameInfo;
854 }
855
856 /**
857 * copy src bitmap to dest bitmap
858 * @param dst
859 * @param src
860 * @return
861 */
862 #ifndef USE_ROSEN_DRAWING
CopyTo(SkBitmap * dst,const SkBitmap & src)863 bool APngImagePlayer::CopyTo(SkBitmap *dst, const SkBitmap& src)
864 {
865 SkPixmap srcPixmap;
866 if (!src.peekPixels(&srcPixmap)) {
867 return false;
868 }
869
870 SkBitmap tempDstBitmap;
871 SkImageInfo dstInfo = srcPixmap.info();
872 if (!tempDstBitmap.setInfo(dstInfo)) {
873 return false;
874 }
875
876 if (!tempDstBitmap.tryAllocPixels()) {
877 return false;
878 }
879
880 SkPixmap dstPixmap;
881 if (!tempDstBitmap.peekPixels(&dstPixmap)) {
882 return false;
883 }
884
885 if (!srcPixmap.readPixels(dstPixmap)) {
886 return false;
887 }
888
889 dst->swap(tempDstBitmap);
890 return true;
891 }
892 #else
CopyTo(RSBitmap * dst,const RSBitmap & src)893 bool APngImagePlayer::CopyTo(RSBitmap *dst, const RSBitmap &src)
894 {
895 auto info = src.GetImageInfo();
896 dst->Build(info);
897 src.CopyPixels(*dst, 0, 0);
898 return true;
899 }
900 #endif
901
902 /**
903 * back animate render method use for optimization
904 * @param paint
905 * @param offset
906 * @param canvas
907 * @param paintRect
908 */
Paint(const flutter::Paint & paint,const Offset & offset,const ScopedCanvas & canvas,const Rect & paintRect)909 void Paint(const flutter::Paint& paint, const Offset& offset, const ScopedCanvas& canvas, const Rect& paintRect) {}
910 } // namespace OHOS::Ace
911