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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_APNG_PNG_IMAGE_DECODER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_APNG_PNG_IMAGE_DECODER_H
18 
19 #include "base/geometry/size.h"
20 #include "base/memory/ace_type.h"
21 
22 #ifndef USE_ROSEN_DRAWING
23 #include "include/core/SkStream.h"
24 #include "include/core/SkImage.h"
25 #endif
26 
27 namespace OHOS::Ace {
28 /*
29  PNG  spec: http://www.libpng.org/pub/png/spec/1.2/PNG-Structure.html
30  APNG spec: https://wiki.mozilla.org/APNG_Specification
31 
32  ===============================================================================
33  PNG format:
34  header (8): 89 50 4e 47 0d 0a 1a 0a
35  chunk, chunk, chunk, ...
36 
37  ===============================================================================
38  chunk format:
39  length (4): uint32_t big endian
40  fourcc (4): chunk type code
41  data   (length): data
42  crc32  (4): uint32_t big endian crc32(fourcc + data)
43 
44  ===============================================================================
45  PNG chunk define:
46 
47  IHDR (Image Header) required, must appear first, 13 bytes
48  width              (4) pixel count, should not be zero
49  height             (4) pixel count, should not be zero
50  bit depth          (1) expected: 1, 2, 4, 8, 16
51  color type         (1) 1<<0 (palette used), 1<<1 (color used), 1<<2 (alpha channel used)
52  compression method (1) 0 (deflate/inflate)
53  filter method      (1) 0 (adaptive filtering with five basic filter types)
54  interlace method   (1) 0 (no interlace) or 1 (Adam7 interlace)
55 
56  IDAT (Image Data) required, must appear consecutively if there's multiple 'IDAT' chunk
57 
58  IEND (End) required, must appear last, 0 bytes
59 
60  ===============================================================================
61  APNG chunk define:
62 
63  acTL (Animation Control) required, must appear before 'IDAT', 8 bytes
64  num frames     (4) number of frames
65  num plays      (4) number of times to loop, 0 indicates infinite looping
66 
67  fcTL (Frame Control) required, must appear before the 'IDAT' or 'fdAT'
68  chunks of the frame to which it applies, 26 bytes
69  sequence number   (4) sequence number of the animation chunk, starting from 0
70  width             (4) width of the following frame
71  height            (4) height of the following frame
72  x offset          (4) x position at which to render the following frame
73  y offset          (4) y position at which to render the following frame
74  delay num         (2) frame delay fraction numerator
75  delay den         (2) frame delay fraction denominator
76  dispose op        (1) type of frame area disposal to be done after rendering this frame
77                        (0:none, 1:background 2:previous)
78  blend op          (1) type of frame area rendering for this frame (0:source, 1:over)
79 
80  fdAT (Frame Data) required
81  sequence number   (4) sequence number of the animation chunk
82  frame data        (x) frame data for this frame (same as 'IDAT')
83 
84  ===============================================================================
85  `dispose_op` specifies how the output buffer should be changed at the end of the delay
86  (before rendering the next frame).
87 
88  * NONE: no disposal is done on this frame before rendering the next; the contents
89     of the output buffer are left as is.
90  * BACKGROUND: the frame's region of the output buffer is to be cleared to fully
91     transparent black before rendering the next frame.
92  * PREVIOUS: the frame's region of the output buffer is to be reverted to the previous
93     contents before rendering the next frame.
94 
95  `blend_op` specifies whether the frame is to be alpha blended into the current output buffer
96  content, or whether it should completely replace its region in the output buffer.
97 
98  * SOURCE: all color components of the frame, including alpha, overwrite the current contents
99     of the frame's output buffer region.
100  * OVER: the frame should be composited onto the output buffer based on its alpha,
101     using a simple OVER operation as described in the "Alpha Channel Processing" section
102     of the PNG specification
103  */
104 
105 /**
106  * PNG & APNG Alpha type
107  **/
108 typedef enum {
109     PNG_ALPHA_TYPE_PALEETE = 1 << 0,
110     PNG_ALPHA_TYPE_COLOR = 1 << 1,
111     PNG_ALPHA_TYPE_ALPHA = 1 << 2
112 } PngAlphaType;
113 
114 typedef enum {
115     PNG_DISPOSE_OP_NONE = 0,
116     PNG_DISPOSE_OP_BACKGROUND = 1,
117     PNG_DISPOSE_OP_PREVIOUS = 2
118 } PngDisposeOp;
119 
120 /**
121  * APNG image blend mode
122  **/
123 typedef enum {
124     PNG_BLEND_OP_SOURCE = 0,
125     PNG_BLEND_OP_OVER = 1
126 } PngBlendOp;
127 
128 /**
129  * IHDR (Image Header) required, must appear first, 13 bytes
130  * width              (4) pixel count, should not be zero
131  * height             (4) pixel count, should not be zero
132  * bit depth          (1) expected: 1, 2, 4, 8, 16
133  * color type         (1) 1<<0 (palette used), 1<<1 (color used), 1<<2 (alpha channel used)
134  * compression method (1) 0 (deflate/inflate)
135  * filter method      (1) 0 (adaptive filtering with five basic filter types)
136  * interlace method   (1) 0 (no interlace) or 1 (Adam7 interlace)
137  **/
138 typedef struct {
139     uint32_t width = 0;             ///< pixel count, should not be zero
140     uint32_t height = 0;            ///< pixel count, should not be zero
141     uint8_t bitDepth = 0;          ///< expected: 1, 2, 4, 8, 16
142     uint8_t colorType = 0;         ///< see PngAlphaType
143     uint8_t compressionMethod = 0; ///< 0 (deflate/inflate)
144     uint8_t filterMethod = 0;      ///< 0 (adaptive filtering with five basic filter types)
145     uint8_t interlaceMethod = 0;   ///< 0 (no interlace) or 1 (Adam7 interlace)
146 } PngChunkIHDR;
147 
148 /**
149  * fcTL (Frame Control) required, must appear before the 'IDAT' or 'fdAT'
150  * chunks of the frame to which it applies, 26 bytes
151  * sequence number   (4) sequence number of the animation chunk, starting from 0
152  * width             (4) width of the following frame
153  * height            (4) height of the following frame
154  * x offset          (4) x position at which to render the following frame
155  * y offset          (4) y position at which to render the following frame
156  * delay num         (2) frame delay fraction numerator
157  * delay den         (2) frame delay fraction denominator
158  * dispose op        (1) type of frame area disposal to be done after rendering this frame
159  *                       (0:none, 1:background 2:previous)
160  * blend op          (1) type of frame area rendering for this frame (0:source, 1:over)
161  **/
162 typedef struct {
163     uint32_t sequenceNumber = 0;  ///< sequence number of the animation chunk, starting from 0
164     uint32_t width = 0;            ///< width of the following frame
165     uint32_t height = 0;           ///< height of the following frame
166     uint32_t xOffset = 0;         ///< x position at which to render the following frame
167     uint32_t yOffset = 0;         ///< y position at which to render the following frame
168     uint16_t delayNum = 0;        ///< frame delay fraction numerator
169     uint16_t delayDen = 0;        ///< frame delay fraction denominator
170     uint8_t disposeOp = 0;        ///< see PngDisposeOp
171     uint8_t blendOp = 0;          ///< see PngBlendOp
172 } PngChunkfcTL;
173 
174 /**
175  * Chunk information
176  * use for identifier echo chunk data info
177  **/
178 typedef struct {
179     uint32_t offset = 0; ///< chunk offset in PNG data
180     uint32_t fourcc = 0; ///< chunk fourcc
181     uint32_t length = 0; ///< chunk data length
182     uint32_t crc32 = 0;  ///< chunk crc32
183 } PngChunkInfo;
184 
185 /**
186  * APNG frame information
187  * contain current chunk index and size
188  * detail frame info in the fcTL
189  **/
190 typedef struct {
191     uint32_t chunkIndex = 0; ///< the first `fdAT`/`IDAT` chunk index
192     uint32_t chunkNum = 0;   ///< the `fdAT`/`IDAT` chunk count
193     uint32_t chunkSize = 0;  ///< the `fdAT`/`IDAT` chunk bytes
194     PngChunkfcTL frameControl;
195 } PngFrameInfo;
196 
197 /**
198  * PNG & APNG file information
199  * png Header and chunk data
200  * apng frames info
201  **/
202 typedef struct {
203     PngChunkIHDR header;   ///< png header
204     PngChunkInfo *chunks;      ///< chunks
205     uint32_t chunkNum;          ///< count of chunks
206 
207     PngFrameInfo *apngFrames; ///< frame info, NULL if not apng
208     uint32_t apngFrameNum;     ///< 0 if not apng
209     uint32_t apngLoopNum;      ///< 0 indicates infinite looping
210 
211     uint32_t *apngSharedChunkIndexs; ///< shared chunk index
212     uint32_t apngSharedChunkNum;     ///< shared chunk count
213     uint32_t apngSharedChunkSize;    ///< shared chunk bytes
214     uint32_t apngSharedInsertIndex;  ///< shared chunk insert index
215     bool apngFirstFrameIsCover;     ///< the first frame is same as png (cover)
216 } PngInfo;
217 
218 class PNGImageDecoder : public virtual AceType {
219     DECLARE_ACE_TYPE(PNGImageDecoder, AceType);
220 
221 public:
222 #ifndef USE_ROSEN_DRAWING
223     PNGImageDecoder(const sk_sp<SkData> &data);
224 #else
225     PNGImageDecoder(const std::shared_ptr<RSData> &data);
226 #endif
227 
228     ~PNGImageDecoder() override;
229 
230     /**
231      * with image header judge whether is a apng file
232      * use for split png and apng file
233      * @return
234      */
235     bool isApng();
236     Size GetImageSize();
237     uint32_t GetFrameCount();
238 
239     /**
240      * Decode apng image header information
241      * @return
242      */
243     bool DecodeImage();
244 
245     /**
246      * Get apng header info and all frames information
247      * @return
248      */
249     PngInfo *GetApngInfo();
250 
251     /**
252      * Get frame image data
253      * i: undecoded image data
254      * @param index
255      * @param size : return data size
256      * @return
257      */
258     uint8_t *GetFrameData(uint32_t index, uint32_t *size, bool oldWay = false);
259     static bool IsApngSource(const std::string& src);
260 private:
261 #ifndef USE_ROSEN_DRAWING
262     sk_sp<SkData> data_;
263 #else
264     std::shared_ptr<RSData> data_;
265 #endif
266     PngInfo *pngInfo_ = nullptr;
267     bool dataCheck_ = false;
268     bool isApng_ = false;
269 };
270 } // namespace OHOS::Ace
271 
272 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_IMAGE_PNG_IMAGE_DECODER_H
273