Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ISO19794_5.cs
1using System;
2using System.Diagnostics.CodeAnalysis;
3using System.IO;
4using System.Text;
7
9{
13 public static class ISO19794_5
14 {
21 public static bool TryParse(byte[] Data,
22 [NotNullWhen(true)] out BiometricDataInterchangeRecord? Record)
23 {
24 using MemoryStream StreamData = new(Data);
25 return TryParse(StreamData, out Record);
26 }
27
34 public static bool TryParse(Stream Data,
35 [NotNullWhen(true)] out BiometricDataInterchangeRecord? Record)
36 {
37 long Start = Data.Position;
38 long MaxRecordLength = Data.Length - Start;
39
40 Record = null;
41
42 // General Header
43
44 if (!Data.TryRead(out string? s) || s != "FAC")
45 return false;
46
47 if (!Data.TryRead(out s) || !int.TryParse(s, out int i))
48 return false;
49
50 int Version = i / 10;
51 int Revision = i % 10;
52
53 if (!Data.TryRead(out uint RecordLength) ||
54 RecordLength < 68 || RecordLength > MaxRecordLength)
55 {
56 return false;
57 }
58
59 if (!Data.TryRead(out ushort NrRepresentations) || NrRepresentations == 0)
60 return false;
61
62 if (Version >= 3)
63 {
64 if (!Data.TryRead(out bool Certification))
65 return false;
66
67 if (!Data.TryRead(out ushort TemporalSemantics))
68 return false;
69 }
70
71 // Representations
72
73 ChunkedList<Representation> Representations = [];
74
75 for (int Representation = 0; Representation < NrRepresentations; Representation++)
76 {
77 long RepresentationStart = Data.Position;
78 long MaxRepresentationLength = Data.Length - RepresentationStart;
79
80 // Representation Header
81
82 if (!Data.TryRead(out uint RepresentationLength) ||
83 RepresentationLength < 51 || RepresentationLength > MaxRepresentationLength)
84 {
85 return false;
86 }
87
88 if (Version >= 3)
89 {
90 if (!Data.TryRead(out DateTime CaptureDateAndTime))
91 return false;
92
93 return false; // TODO: Parse version 3 records
94 }
95
96 if (!Data.TryRead(out ushort NrLandmarkPoints))
97 return false;
98
99 if (!Data.TryRead(out byte GenderUntyped) || (GenderUntyped > 2 && GenderUntyped < 0xff) ||
100 !Data.TryRead(out byte EyeColourUntyped) || EyeColourUntyped > 7 ||
101 !Data.TryRead(out byte HairColourUntyped))
102 {
103 return false;
104 }
105
106 Gender Gender = (Gender)GenderUntyped;
107 EyeColour EyeColour = (EyeColour)EyeColourUntyped;
108 HairColour HairColour = (HairColour)HairColourUntyped;
109
110 if (Version >= 3)
111 {
112 if (!Data.TryRead(out byte SubjectHeight))
113 return false;
114 }
115
116 if (!Data.TryRead(3, out uint PropertyMask) ||
117 !Data.TryRead(out ushort ExpressionMask) ||
118 !Data.TryRead(3, out uint PoseAngle) ||
119 !Data.TryRead(3, out uint PoseAngleUncertainty))
120 {
121 return false;
122 }
123
124 if (NrLandmarkPoints > 0)
125 return false; // TODO: Parse landmark points
126
127
128 if (!Data.TryRead(out byte FaceImageTypeRaw) || FaceImageTypeRaw > 3 ||
129 !Data.TryRead(out byte ImageDataTypeRaw) || ImageDataTypeRaw > 3 ||
130 !Data.TryRead(out ushort Width) ||
131 !Data.TryRead(out ushort Height))
132 {
133 return false;
134 }
135
136 FaceImageType FaceImageType = (FaceImageType)FaceImageTypeRaw;
137 ImageDataType ImageDataType = (ImageDataType)ImageDataTypeRaw;
138
139 if (Version < 3 && ImageDataTypeRaw < 2)
140 {
141 ImageDataTypeRaw++;
142 ImageDataType = (ImageDataType)ImageDataTypeRaw;
143 }
144
145 if (Version >= 3)
146 {
147 if (!Data.TryRead(out byte SpatialSamplingRateLevel) ||
148 !Data.TryRead(out byte PostAcquisitionProcessing) ||
149 !Data.TryRead(out byte CrossReference))
150 {
151 return false;
152 }
153 }
154
155 if (!Data.TryRead(out byte ImageColourSpace))
156 return false;
157
158 if (Version < 3)
159 {
160 if (!Data.TryRead(out byte SourceType) ||
161 !Data.TryRead(out ushort DeviceType) ||
162 !Data.TryRead(out ushort Quality))
163 {
164 return false;
165 }
166 }
167
168 int BytesLeft = (int)RepresentationLength - (int)(Data.Position - RepresentationStart);
169 if (BytesLeft < 0)
170 return false;
171
172 if (!Data.TryRead(BytesLeft, out byte[] ImageData))
173 return false;
174
176 Width, Height, ImageData, Gender, EyeColour, HairColour));
177 }
178
179 Record = new BiometricDataInterchangeRecord([.. Representations]);
180
181 return true;
182 }
183
184 private static bool TryRead(this Stream Data, int N, out byte[] Binary)
185 {
186 Binary = new byte[N];
187 return Data.TryReadAll(Binary, 0, N) == N;
188 }
189
190 private static bool TryRead(this Stream Data, out bool Result)
191 {
192 if (!Data.TryRead(out byte b) || b > 1)
193 {
194 Result = false;
195 return false;
196 }
197 else
198 {
199 Result = b != 0;
200 return true;
201 }
202 }
203
204 private static bool TryRead(this Stream Data, out byte Result)
205 {
206 int i = Data.ReadByte();
207
208 if (i < 0)
209 {
210 Result = 0;
211 return false;
212 }
213 else
214 {
215 Result = (byte)i;
216 return true;
217 }
218 }
219
220 private static bool TryRead(this Stream Data, out ushort Result)
221 {
222 Result = 0;
223
224 for (int i = 0; i < 2; i++)
225 {
226 int j = Data.ReadByte();
227 if (j < 0)
228 return false;
229
230 Result <<= 8;
231 Result |= (byte)j;
232 }
233
234 return true;
235 }
236
237 private static bool TryRead(this Stream Data, out uint Result)
238 {
239 return Data.TryRead(4, out Result);
240 }
241
242 private static bool TryRead(this Stream Data, int N, out uint Result)
243 {
244 Result = 0;
245
246 for (int i = 0; i < N; i++)
247 {
248 int j = Data.ReadByte();
249 if (j < 0)
250 return false;
251
252 Result <<= 8;
253 Result |= (byte)j;
254 }
255
256 return true;
257 }
258
259 private static bool TryRead(this Stream Data, [NotNullWhen(true)] out string? Result)
260 {
261 return Data.TryRead(Encoding.ASCII, out Result);
262 }
263
264 private static bool TryRead(this Stream Data, Encoding Encoding,
265 [NotNullWhen(true)] out string? Result)
266 {
267 using MemoryStream Temp = new();
268
269 while (true)
270 {
271 int i = Data.ReadByte();
272 if (i < 0)
273 {
274 Result = null;
275 return false;
276 }
277
278 if (i == 0)
279 {
280 Result = Encoding.GetString(Temp.ToArray());
281 return true;
282 }
283
284 Temp.WriteByte((byte)i);
285 }
286 }
287
288 private static bool TryRead(this Stream Data, out DateTime Result)
289 {
290 if (!Data.TryRead(out ushort Year) || Year < 1800 || Year > 9999 ||
291 !Data.TryRead(out byte Month) || Month < 1 || Month > 12 ||
292 !Data.TryRead(out byte Day) || Day < 1 || Day > DateTime.DaysInMonth(Year, Month) ||
293 !Data.TryRead(out byte Hour) || Hour > 59 ||
294 !Data.TryRead(out byte Minute) || Minute > 59 ||
295 !Data.TryRead(out byte Second) || Second > 59 ||
296 !Data.TryRead(out ushort Millisecond) || Millisecond > 1000)
297 {
298 Result = DateTime.MinValue;
299 return false;
300 }
301 else
302 {
303 Result = new DateTime(Year, Month, Day, Hour, Minute, Second, Millisecond, DateTimeKind.Utc);
304 return true;
305 }
306 }
307 }
308}
ISO 19794-5: Biometric Data interchange formats - Part 5: Face image data.
Definition: ISO19794_5.cs:14
static bool TryParse(byte[] Data, [NotNullWhen(true)] out BiometricDataInterchangeRecord? Record)
Tries to parse biometric data from ISO 19794-5 compliant data.
Definition: ISO19794_5.cs:21
static bool TryParse(Stream Data, [NotNullWhen(true)] out BiometricDataInterchangeRecord? Record)
Tries to parse biometric data from ISO 19794-5 compliant data.
Definition: ISO19794_5.cs:34
Contains a representation of biometric data of a face.
Contains a representation of biometric data.
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
FaceImageType
ICAO 9303 / ISO 19794-5 face image type.
Definition: FaceImageType.cs:7
ImageDataType
ICAO 9303 / ISO 19794-5 image data type.
Definition: ImageDataType.cs:7
HairColour
ISO 19794-5 hair colour enumeration.
Definition: HairColour.cs:7
EyeColour
ISO 19794-5 eye colour enumeration.
Definition: EyeColour.cs:7
Gender
ISO 19794-5 gender enumeration.
Definition: Gender.cs:7