forked from CaiJingLong/dart_image_size_getter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
webp_decoder.dart
133 lines (114 loc) · 3.85 KB
/
webp_decoder.dart
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
import 'package:collection/collection.dart';
import 'package:image_size_getter/image_size_getter.dart';
/// {@template image_size_getter.WebpDecoder}
///
/// [WebpDecoder] is a class for decoding webp image.
///
/// {@endtemplate}
class WebpDecoder extends BaseDecoder {
/// {@macro image_size_getter.WebpDecoder}
const WebpDecoder();
@override
String get decoderName => 'webp';
@override
Size getSize(ImageInput input) {
final chunkHeader = input.getRange(12, 16);
if (_isExtendedFormat(chunkHeader)) {
final widthList = input.getRange(0x18, 0x1b);
final heightList = input.getRange(0x1b, 0x1d);
return _createExtendedFormatSize(widthList, heightList);
} else if (_isLosslessFormat(chunkHeader)) {
final sizeList = input.getRange(0x15, 0x19);
return _createLosslessFormatSize(sizeList);
} else {
final widthList = input.getRange(0x1a, 0x1c);
final heightList = input.getRange(0x1c, 0x1e);
return _createNormalSize(widthList, heightList);
}
}
Size _createNormalSize(List<int> widthList, List<int> heightList) {
final width = convertRadix16ToInt(widthList, reverse: true);
final height = convertRadix16ToInt(heightList, reverse: true);
return Size(width, height);
}
Size _createExtendedFormatSize(List<int> widthList, List<int> heightList) {
final width = convertRadix16ToInt(widthList, reverse: true) + 1;
final height = convertRadix16ToInt(heightList, reverse: true) + 1;
return Size(width, height);
}
Size _createLosslessFormatSize(List<int> sizeList) {
final bits = sizeList
.map(
(i) => i.toRadixString(2).split('').reversed.join().padRight(8, '0'),
)
.join()
.split('');
final width =
(int.tryParse(bits.sublist(0, 14).reversed.join(), radix: 2) ?? 0) + 1;
final height =
(int.tryParse(bits.sublist(14, 28).reversed.join(), radix: 2) ?? 0) + 1;
return Size(width, height);
}
bool _isExtendedFormat(List<int> chunkHeader) {
return ListEquality().equals(chunkHeader, "VP8X".codeUnits);
}
bool _isLosslessFormat(List<int> chunkHeader) {
return ListEquality().equals(chunkHeader, "VP8L".codeUnits);
}
@override
Future<Size> getSizeAsync(AsyncImageInput input) async {
final chunkHeader = await input.getRange(12, 16);
if (_isExtendedFormat(chunkHeader)) {
final widthList = await input.getRange(0x18, 0x1b);
final heightList = await input.getRange(0x1b, 0x1d);
return _createExtendedFormatSize(widthList, heightList);
} else if (_isLosslessFormat(chunkHeader)) {
final sizeList = await input.getRange(0x15, 0x19);
return _createLosslessFormatSize(sizeList);
} else {
final widthList = await input.getRange(0x1a, 0x1c);
final heightList = await input.getRange(0x1c, 0x1e);
return _createNormalSize(widthList, heightList);
}
}
@override
bool isValid(ImageInput input) {
final sizeStart = input.getRange(0, 4);
final sizeEnd = input.getRange(8, 12);
const eq = ListEquality();
if (eq.equals(sizeStart, _WebpHeaders.fileSizeStart) &&
eq.equals(sizeEnd, _WebpHeaders.fileSizeEnd)) {
return true;
}
return false;
}
@override
Future<bool> isValidAsync(AsyncImageInput input) async {
final sizeStart = await input.getRange(0, 4);
final sizeEnd = await input.getRange(8, 12);
const eq = ListEquality();
if (eq.equals(sizeStart, _WebpHeaders.fileSizeStart) &&
eq.equals(sizeEnd, _WebpHeaders.fileSizeEnd)) {
return true;
}
return false;
}
}
class _WebpHeaders with SimpleFileHeaderAndFooter {
static const fileSizeStart = [
0x52,
0x49,
0x46,
0x46,
];
static const fileSizeEnd = [
0x57,
0x45,
0x42,
0x50,
];
@override
List<int> get endBytes => fileSizeEnd;
@override
List<int> get startBytes => fileSizeStart;
}