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