-
Notifications
You must be signed in to change notification settings - Fork 71
Expand file tree
/
Copy pathImageDecoder.h
More file actions
370 lines (300 loc) · 12.1 KB
/
ImageDecoder.h
File metadata and controls
370 lines (300 loc) · 12.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
#ifndef UI_IMAGE_IMAGE_DECODER_H_
#define UI_IMAGE_IMAGE_DECODER_H_
#include "duilib/Core/UiTypes.h"
#include "duilib/Core/Callback.h"
#include "duilib/Utils/FilePath.h"
namespace ui
{
/** 位图接口
*/
class IBitmap;
/** 支持多线程解码的接口(底层解码使用,支持延迟解码,可以在多线程中解码,避免在UI线程解码图片导致卡顿)
*/
class UILIB_API IImageDelayDecode
{
public:
virtual ~IImageDelayDecode() = default;
/** 是否支持延迟解码数据
* @return 返回true表示需要解码,返回false表示不需要解码
*/
virtual bool IsDelayDecodeEnabled() const = 0;
/** 延迟解码图片数据是否完成
* @return 延迟解码图片数据操作已经完成
*/
virtual bool IsDelayDecodeFinished() const = 0;
/** 获取当前延迟解码完成的图片帧索引号(从0开始编号)
*/
virtual uint32_t GetDecodedFrameIndex() const = 0;
/** 延迟解码图片数据(可以在多线程中调用)
* @param [in] nMinFrameIndex 至少需要解码到哪一帧(帧索引号,从0开始编号)
* @param [in] IsAborted 解码终止终止测试函数,返回true表示终止,否则表示正常操作
* @param [out] bDecodeError 返回true表示遇到图片解码错误
* @return 返回true表示成功,返回false表示解码失败或者外部终止
*/
virtual bool DelayDecode(uint32_t nMinFrameIndex,
std::function<bool(void)> IsAborted,
bool* bDecodeError) = 0;
/** 合并延迟解码图片数据的结果
*/
virtual bool MergeDelayDecodeData() = 0;
};
/** 支持多线程解码的接口(应用层使用,支持延迟解码,可以在多线程中解码,避免在UI线程解码图片导致卡顿)
*/
class UILIB_API IImageAsyncDecode
{
public:
virtual ~IImageAsyncDecode() = default;
/** 是否需要异步解码图片数据
* @return 返回true表示需要解码,返回false表示不需要解码
*/
virtual bool IsAsyncDecodeEnabled() const = 0;
/** 异步解码图片数据是否完成
* @return 异步解码图片数据操作已经完成
*/
virtual bool IsAsyncDecodeFinished() const = 0;
/** 获取当前异步解码完成的图片帧索引号(从0开始编号)
*/
virtual uint32_t GetDecodedFrameIndex() const = 0;
/** 设置异步解码的任务ID
* @param [in] nTaskId 在子线程中的任务ID
*/
virtual void SetAsyncDecodeTaskId(size_t nTaskId) = 0;
/** 获取异步解码的任务ID
*/
virtual size_t GetAsyncDecodeTaskId() const = 0;
/** 异步解码图片数据(可以在多线程中调用)
* @param [in] nMinFrameIndex 至少需要解码到哪一帧(帧索引号,从0开始编号)
* @param [in] IsAborted 解码终止终止测试函数,返回true表示终止,否则表示正常操作
* @param [out] bDecodeError 返回true表示遇到图片解码错误
* @return 返回true表示成功,返回false表示解码失败或者外部终止
*/
virtual bool AsyncDecode(uint32_t nMinFrameIndex,
std::function<bool(void)> IsAborted,
bool* bDecodeError) = 0;
/** 合并异步解码图片数据的结果
*/
virtual bool MergeAsyncDecodeData() = 0;
};
/** SVG矢量图片接口
*/
class UILIB_API ISvgImage
{
public:
virtual ~ISvgImage() = default;
/** 获取图片宽度
*/
virtual uint32_t GetWidth() const = 0;
/** 获取图片高度
*/
virtual uint32_t GetHeight() const = 0;
/** 原图加载的宽度和高度缩放比例(1.0f表示无缩放)
*/
virtual float GetImageSizeScale() const = 0;
/** 获取指定大小的位图,矢量缩放
* @param [in] szImageSize 代表获取图片的宽度(cx)和高度(cy)
*/
virtual std::shared_ptr<IBitmap> GetBitmap(const UiSize& szImageSize) = 0;
};
/** 单帧位图图片接口
*/
class UILIB_API IBitmapImage : public IImageDelayDecode
{
public:
virtual ~IBitmapImage() = default;
/** 获取图片宽度
*/
virtual uint32_t GetWidth() const = 0;
/** 获取图片高度
*/
virtual uint32_t GetHeight() const = 0;
/** 原图加载的宽度和高度缩放比例(1.0f表示无缩放)
*/
virtual float GetImageSizeScale() const = 0;
/** 获取位图
* @param [out] bDecodeError 返回值代表是否遇到图片解码错误
* @return 返回位图的接口指针,如果返回nullptr并且bDecodeError为false表示图片尚未完成解码(多线程解码的情况下)
* 如果返回nullptr并且bDecodeError为true代表图片解码出现错误
*/
virtual std::shared_ptr<IBitmap> GetBitmap(bool* bDecodeError) = 0;
};
/** 动画图片默认的播放时间间隔(毫秒)
*/
#define IMAGE_ANIMATION_DELAY_MS (100)
/** 动画图片默认的播放时间间隔最小值(毫秒)
*/
#define IMAGE_ANIMATION_DELAY_MS_MIN (20)
/** 动画图片接口
*/
class UILIB_API IAnimationImage: public IImageDelayDecode
{
public:
virtual ~IAnimationImage() = default;
/** 多帧图片的一帧图片数据
*/
class UILIB_API AnimationFrame
{
public:
bool m_bDataPending = false; //数据是否处于待解码状态:true表示待解码,需要等待解码完成后再使用
bool m_bDataError = false; //数据是否出现解码错误
int32_t m_nFrameIndex = -1; //图片帧的索引号
int32_t m_nOffsetX = 0; //该帧图片在绘制区域的X轴偏移值,单位为像素
int32_t m_nOffsetY = 0; //该帧图片在绘制区域的Y轴偏移值,单位为像素
std::shared_ptr<IBitmap> m_pBitmap; //该帧图片的位图数据,用于绘制
/** 设置帧播放持续时间,毫秒
*/
void SetDelayMs(int32_t nDelayMs)
{
if (nDelayMs <= 0) {
//未设置时,设置为默认值
nDelayMs = IMAGE_ANIMATION_DELAY_MS;
}
else if (nDelayMs < IMAGE_ANIMATION_DELAY_MS_MIN) {
//低于最小值时,设置为最小值
nDelayMs = IMAGE_ANIMATION_DELAY_MS_MIN;
}
m_nDelayMs = nDelayMs;
}
/** 获取帧播放持续时间,毫秒
*/
int32_t GetDelayMs() const
{
return m_nDelayMs;
}
private:
int32_t m_nDelayMs = IMAGE_ANIMATION_DELAY_MS; //图片帧的播放持续时间,单位为毫秒
};
public:
/** 获取图片宽度
*/
virtual uint32_t GetWidth() const = 0;
/** 获取图片高度
*/
virtual uint32_t GetHeight() const = 0;
/** 原图加载的宽度和高度缩放比例(1.0f表示无缩放)
*/
virtual float GetImageSizeScale() const = 0;
/** 获取图片的帧数
*/
virtual int32_t GetFrameCount() const = 0;
/** 获取循环播放的次数
* @return 返回循环播放的次数,-1表示一直播放
*/
virtual int32_t GetLoopCount() const = 0;
/** 查询是某帧的图片数据是否有准备完成(多线程解码时,帧数据在后台线程解码)
* @param [in] nFrameIndex 图片帧的索引号,从0开始编号的下标值,取值范围:[0, GetFrameCount())
*/
virtual bool IsFrameDataReady(uint32_t nFrameIndex) = 0;
/** 获取一个图片帧的播放持续时间,单位为毫秒
* @param [in] nFrameIndex 图片帧的索引号,从0开始编号的下标值,取值范围:[0, GetFrameCount())
*/
virtual int32_t GetFrameDelayMs(uint32_t nFrameIndex) = 0;
/** 读取一帧数据
* @param [in] nFrameIndex 图片帧的索引号,从0开始编号的下标值,取值范围:[0, GetFrameCount())
* @param [in] szDestRectSize 目标区域的大小,用于矢量图的缩放
* @param [out] pAnimationFrame 返回该帧的图片位图数据
* @return 成功返回true,失败则返回false
*/
virtual bool ReadFrameData(int32_t nFrameIndex, const UiSize& szDestRectSize, AnimationFrame* pAnimationFrame) = 0;
};
/** AnimationFrame 的智能指针
*/
typedef std::shared_ptr<IAnimationImage::AnimationFrame> AnimationFramePtr;
/** 图片类型
*/
enum class UILIB_API ImageType
{
kImageBitmap, //位图类型,单帧,图片尺寸缩放时是有损缩放,显示效果会变差
kImageSvg, //SVG矢量图,单帧,图片尺寸缩放时是矢量缩放,显示效果较好
kImageAnimation //动画图片,多帧
};
/** 原图加载的宽度和高度缩放比例:无缩放的值
*/
#define IMAGE_SIZE_SCALE_NONE (1.0f)
/** 图片接口
*/
class UILIB_API IImage: public IImageAsyncDecode
{
public:
virtual ~IImage() = default;
public:
/** 获取图片宽度
*/
virtual int32_t GetWidth() const = 0;
/** 获取图片高度
*/
virtual int32_t GetHeight() const = 0;
/** 原图加载的宽度和高度缩放比例(1.0f表示无缩放)
*/
virtual float GetImageSizeScale() const = 0;
/** 获取图片的类型
*/
virtual ImageType GetImageType() const = 0;
/** 获取图片数据
* @return 仅当ImageType==ImageType::kImageBitmap时返回图片数据
*/
virtual std::shared_ptr<IBitmapImage> GetImageBitmap() const { return nullptr; }
/** 获取图片数据
* @return 仅当ImageType==ImageType::kImageSvg时返回图片数据
*/
virtual std::shared_ptr<ISvgImage> GetImageSvg() const { return nullptr; }
/** 获取图片数据
* @return 仅当ImageType==ImageType::kImageAnimation时返回图片数据
*/
virtual std::shared_ptr<IAnimationImage> GetImageAnimation() const { return nullptr; }
};
/** 图片解码的输入参数
*/
struct ImageDecodeParam
{
public:
//文件路径
FilePath m_imageFilePath;
//文件头数据(1KB数据,用于选择图片解码器)
std::vector<uint8_t> m_fileHeaderData;
//文件数据(如果为空表示未加载文件数据,需要根据文件路径去读取文件数据)
std::shared_ptr<std::vector<uint8_t>> m_pFileData;
//目标区域大小,用于优化加载性能
UiSize m_rcMaxDestRectSize;
//请求加载的缩放比例
float m_fImageSizeScale = 1.0f;
//是否支持异步线程解码图片数据
bool m_bAsyncDecode = false;
//图片加载失败时,代码断言的设置(debug编译时启用,用于排查图片加载过程中的错误,尤其时图片数据错误导致加载失败的问题)
bool m_bAssertEnabled = true;
public:
//如果是多帧图片,是否加载所有帧(true表示加载所有帧;false表示只加载第1帧, 按单帧图片加载)
bool m_bLoadAllFrames = true;
//ICO格式,是否按照动画来加载多帧显示(默认情况下,ICO格式是按单帧显示的)
bool m_bIconAsAnimation = false;
//ICO格式,加载图标的大小值
uint32_t m_nIconSize = 0;
//ICO格式,每帧播放时间间隔,毫秒(仅当m_bIconAsAnimation && m_bLoadAllFrames为true时有效)
uint32_t m_nIconFrameDelayMs = 1000;
//PAG格式,解码动画的帧率
float m_fPagMaxFrameRate = 30.0f;
};
/** 图片解码器接口
*/
class IImageDecoder
{
public:
virtual ~IImageDecoder() = default;
/** 获取该解码器支持的格式名称
*/
virtual DString GetFormatName() const = 0;
/** 检查该解码器是否支持给定的文件名
* @param [in] imageFilePath 实体文件名(比如:"File.jpg",可以带路径), 或者虚拟文件名(比如: "icon:1")
*/
virtual bool CanDecode(const DString& imageFilePath) const = 0;
/** 检查该解码器是否支持给定的数据流
* @param [in] data 数据的起始地址
* @param [in] dataLen 数据的长度
*/
virtual bool CanDecode(const uint8_t* data, size_t dataLen) const = 0;
/** 加载解码图片数据,返回解码后的图像数据
@param [in] decodeParam 图片解码的相关参数
*/
virtual std::unique_ptr<IImage> LoadImageData(const ImageDecodeParam& decodeParam) = 0;
};
} //namespace ui
#endif //UI_IMAGE_IMAGE_DECODER_H_