1 /*
2  * Copyright (c) 2022-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_APNG_APNG_IMAGE_PLAYER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_APNG_APNG_IMAGE_PLAYER_H
18 
19 #include <unordered_map>
20 
21 #include "base/memory/ace_type.h"
22 #include "core/animation/animator.h"
23 #include "apng_image_animation.h"
24 #include "core/image/image_source_info.h"
25 #include "core/image/image_provider.h"
26 #include "apng_image_decoder.h"
27 #include "core/pipeline/base/scoped_canvas_state.h"
28 
29 namespace OHOS::Ace {
30 
31 /**
32 Dispose method specifies how the area used by the current frame is to be treated
33 before rendering the next frame on the canvas.
34 */
35 typedef enum {
36     /**
37      No disposal is done on this frame before rendering the next; the contents
38      of the canvas are left as is.
39      */
40     ImageDisposeNone = 0,
41 
42     /**
43      The frame's region of the canvas is to be cleared to fully transparent black
44      before rendering the next frame.
45      */
46     ImageDisposeBackground,
47 
48     /**
49      The frame's region of the canvas is to be reverted to the previous contents
50      before rendering the next frame.
51      */
52     ImageDisposePrevious,
53 } ImageDisposeMethod;
54 
55 /**
56 Blend operation specifies how transparent pixels of the current frame are
57 blended with those of the previous canvas.
58 */
59 typedef enum {
60     /**
61      All color components of the frame, including alpha, overwrite the current
62      contents of the frame's canvas region.
63      */
64     ImageBlendNone = 0,
65 
66     /**
67      The frame should be composited onto the output buffer based on its alpha.
68      */
69     ImageBlendOver,
70 } ImageBlendOperation;
71 
72 /**
73  * Apng Header and frames information
74  */
75 typedef struct {
76     uint32_t index = 0;            ///< sequence number of the animation chunk, starting from 0
77     uint32_t width = 0;            ///< width of the following frame
78     uint32_t height = 0;           ///< height of the following frame
79     uint32_t offsetX = 0;          ///< x position at which to render the following frame
80     uint32_t offsetY = 0;          ///< y position at which to render the following frame
81     float duration = 0.0;
82     ImageDisposeMethod dispose = ImageDisposeNone;
83     ImageBlendOperation blend  = ImageBlendNone;
84     bool isFullSize = false;          ///< Whether frame fill the canvas.
85     uint32_t blendFromIndex = 0;  ///< Blend from frame index to current frame.
86 #ifndef USE_ROSEN_DRAWING
87     sk_sp<SkImage> image = nullptr;
88 #else
89     std::shared_ptr<RSImage> image = nullptr;
90 #endif
91 } APngAnimatedFrameInfo;
92 
93 
94 class APngImagePlayer : public virtual AceType {
95     DECLARE_ACE_TYPE(APngImagePlayer, AceType);
96 
97 public:
98     APngImagePlayer(
99         ImageSourceInfo source,
100         UploadSuccessCallback successCallback,
101         const WeakPtr<PipelineBase>& weakContext,
102         const RefPtr<PNGImageDecoder>& decoder,
103         int32_t dstWidth = -1,
104         int32_t dstHeight = -1);
105 
106     ~APngImagePlayer() override;
107 
108     void Pause();
109 
110     void Resume();
111 
112     void RenderFrame(const int32_t& index);
113 
114     /**
115      * Use for draw each frame image in self
116      **/
117     void Paint(const flutter::Paint& paint, const Offset& offset, const ScopedCanvas& canvas, const Rect& paintRect);
118 
SetTargetSize(int32_t width,int32_t height)119     void SetTargetSize(int32_t width, int32_t height)
120     {
121         dstWidth_ = width;
122         dstHeight_ = height;
123     }
124 
125 private:
126     ImageSourceInfo imageSource_;
127     UploadSuccessCallback successCallback_;
128     WeakPtr<PipelineBase> context_;
129 
130     const RefPtr<PNGImageDecoder> apngDecoder_;
131     int32_t frameCount_;
132     int32_t repetitionCount_;
133     bool needBlend_;
134     int32_t blendFrameIndex_;
135     int32_t width_;  //image source width
136     int32_t height_;
137     std::vector<APngAnimatedFrameInfo> frameInfos_;
138 
139     int32_t dstWidth_ = -1;
140     int32_t dstHeight_ = -1;
141 
142     // used to cache required frame.
143     std::unordered_map<int32_t, std::unique_ptr<APngAnimatedFrameInfo *>> cachedFrame_;
144 
145     // used to cache last required frame. this will be reset during looping.
146     int32_t lastRequiredFrameIndex_ = -1;
147 
148     /**
149      * Use a blank canvas draw each frame to get frame image
150      **/
151 #ifndef USE_ROSEN_DRAWING
152     SkBitmap bitmap_;
153     SkCanvas *blendCanvas_ = nullptr;
154 #else
155     RSBitmap bitmap_;
156     RSCanvas *blendCanvas_ = nullptr;
157 #endif
158     RefPtr<Scheduler> scheduler_;
159     RefPtr<APngImageAnimation> pictureAnimation_;
160 
161     /**
162      * Decode apng image and get all frame head information
163      * but didn't decode image data
164      **/
165     bool GetApngAllFrames();
166 
167     /**
168      * Decode frame image data to SKImage
169      * Before decode frame need decode frame header before
170      **/
171     APngAnimatedFrameInfo *DecodeFrameImage(const int32_t &index);
172 
173     /**
174      * Copy bitmap to a dst bitmap
175      **/
176 #ifndef USE_ROSEN_DRAWING
177     static bool CopyTo(SkBitmap *dst, const SkBitmap &src);
178 #else
179     static bool CopyTo(RSBitmap *dst, const RSBitmap &src);
180 #endif
181 
182     float DelayToSeconds(uint16_t num, uint16_t den);
183 
184 #ifndef USE_ROSEN_DRAWING
185     SkCanvas *CreateBlendCanvas();
186 
187     /**
188      * Get frame image with index or frameinfo
189      **/
190     sk_sp<SkImage> GetImage(const int32_t &index, bool extendToCanvas);
191 
192     sk_sp<SkImage> GetImage(const APngAnimatedFrameInfo *frameInfo);
193 #else
194     RSCanvas *CreateBlendCanvas();
195 
196     /**
197      * Get frame image with index or frameinfo
198      **/
199     std::shared_ptr<RSImage> GetImage(const int32_t &index, bool extendToCanvas);
200 
201     std::shared_ptr<RSImage> GetImage(const APngAnimatedFrameInfo *frameInfo);
202 #endif
203 
204     /**
205      * Before render image in backgroud thread predecode image all frames
206      **/
207     bool PreDecodeAllFrames();
208 
209     void ClearCanvasRect(const APngAnimatedFrameInfo *frameInfo);
210 
211     /**
212      * Use blend role draw frame image to canvas
213      */
214     void BlendImage(const APngAnimatedFrameInfo *frameInfo);
215 
216     /***
217      * Debug function
218      * */
219     void DrawTest();
220 
221 #ifndef USE_ROSEN_DRAWING
222     void DrawTestBorder(SkRect &rect);
223 #else
224     void DrawTestBorder(RSRect &rect);
225 #endif
226 };
227 
228 } // namespace OHOS::Ace
229 
230 
231 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_APNG_APNG_IMAGE_PLAYER_H
232