Enrollment 28.2.0
Loading...
Searching...
No Matches
Print.h
Go to the documentation of this file.
1
9
10#pragma once
12#include "enrollment/Export.h"
27#include <algorithm>
28#include <array>
29#include <cstdint>
30#include <memory>
31#include <mutex>
32#include <numeric>
33#include <optional>
34
35// cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes: This is not a
36// problem because we are using them only as read only.
37// cppcoreguidelines-avoid-const-or-ref-data-members: We design te API with const member variables instead of
38// implementing getter methods. This is nicely transformed in C# to properties. Usually our objects are immutable by
39// intention to have no problem in multithreaded applications.
40// NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,cppcoreguidelines-avoid-const-or-ref-data-members)
41namespace inno
42{
46 */
47 class Print final : public Serializable
48 {
49 public:
51 const std::shared_ptr<Image> image;
56
65 */
66 [[nodiscard]] std::shared_ptr<Print> ChangeDpiTo(ImageDpi targetDpi) const
67 {
68 const Image::BicubicImageResampler resampler{ targetDpi };
69 return ChangeDpiTo(resampler);
70 }
71
82 */
83 [[nodiscard]] std::shared_ptr<Print> ChangeDpiTo(const Image::ImageResampler& resampler) const
84 {
85 return Create(image->ChangeDpiTo(resampler), position, printAttributes, exec);
86 }
87
98 */
99 std::vector<uint8_t> ToIsoImage(ImageEncoder& encoder) const
100 {
101 auto isoEncoder = IsoImageEncoder(*this, encoder);
102 return isoEncoder.Encode();
103 }
104
109 */
110 std::vector<uint8_t> ToIsoRawImage() const
111 {
112 IsoImage isoImage(*this);
113 const std::vector<uint8_t> rawGrayscale = image->AsRawGrayscale().Data();
114 return isoImage.FillIsoImage(rawGrayscale);
115 }
116
130 */
131 static std::shared_ptr<Print> FromIsoImage(const std::vector<uint8_t>& isoImage)
132 {
133 static constexpr size_t SizeOfIdentifier = 4UL;
134 static constexpr size_t SizeOfVersion = 4UL;
135 if (isoImage.size() < SizeOfIdentifier + SizeOfVersion)
136 {
137 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (fail to read header)");
138 }
139 if (const std::vector<uint8_t> id = { 'F', 'I', 'R', '\0' };
140 std::search(isoImage.begin(), isoImage.end(), id.begin(), id.end()) == isoImage.end())
141 {
142 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (invalid id)");
143 }
144 static constexpr size_t VersionIndex = SizeOfIdentifier;
145 if (const std::vector<uint8_t> ver = { '0', '2', '0', '\0' };
146 std::search(isoImage.begin() + VersionIndex, isoImage.end(), ver.begin(), ver.end()) == isoImage.end())
147 {
148 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (invalid version)");
149 }
150 static constexpr size_t CertificationFlagIndex = 14UL;
151 static constexpr size_t SizeOfCertificationFlag = 1UL;
152 if (isoImage.size() < (CertificationFlagIndex + SizeOfCertificationFlag))
153 {
155 "Fail to decode print ISO image (fail to read certification flag)");
156 }
157 const auto certificationFlag = isoImage[CertificationFlagIndex];
158 static constexpr size_t DeviceTechnologyId = 29UL;
159 static constexpr size_t SizeOfDeviceTechnologyId = 1UL;
160 if (isoImage.size() < (DeviceTechnologyId + SizeOfDeviceTechnologyId))
161 {
163 "Fail to decode print ISO image (fail to read device technology identifier)");
164 }
165 const auto deviceTechnologyId = isoImage[DeviceTechnologyId];
166 static constexpr size_t DeviceVendorId = 30UL;
167 static constexpr size_t SizeOfDeviceVendorId = 2UL;
168 if (isoImage.size() < (DeviceVendorId + SizeOfDeviceVendorId))
169 {
171 "Fail to decode print ISO image (fail to read device vendor identifier)");
172 }
173 const uint16_t deviceVendorId = (isoImage[DeviceVendorId] << 8U) + isoImage[DeviceVendorId + 1];
174 static constexpr size_t DeviceTypeId = 32UL;
175 static constexpr size_t SizeOfDeviceTypeId = 2UL;
176 if (isoImage.size() < (DeviceTypeId + SizeOfDeviceTypeId))
177 {
179 "Fail to decode print ISO image (fail to read device type identifier)");
180 }
181 const uint16_t deviceTypeId = (isoImage[DeviceTypeId] << 8U) + isoImage[DeviceTypeId + 1];
182 static constexpr size_t QualityBlocksLengthIndex = 34UL;
183 static constexpr size_t SizeOfQualityBlocksLength = 1UL;
184 static constexpr size_t SizeOfQualityBlock = 5UL;
185 if (isoImage.size() < (QualityBlocksLengthIndex + SizeOfQualityBlocksLength))
186 {
188 "Fail to decode print ISO image (fail to read quality blocks count)");
189 }
190 const auto qualityBlocksCount = isoImage[QualityBlocksLengthIndex];
191 const auto qualityBlocksSize = qualityBlocksCount * SizeOfQualityBlock;
192 size_t sizeOfCertificationRecord = 0;
193 if (certificationFlag == 1)
194 {
195 const auto certificationRecordsCountIndex =
196 QualityBlocksLengthIndex + SizeOfQualityBlocksLength + qualityBlocksSize;
197 static constexpr size_t SizeOfCertificationRecordsCount = 1UL;
198 if (isoImage.size() < (certificationRecordsCountIndex + SizeOfCertificationRecordsCount))
199 {
201 "Fail to decode print ISO image (fail to read certification records count)");
202 }
203 static constexpr size_t SizeOfCertificationRecord = 3UL;
204 sizeOfCertificationRecord = isoImage[certificationRecordsCountIndex] * SizeOfCertificationRecord +
205 SizeOfCertificationRecordsCount;
206 }
207 const auto positionIndex =
208 QualityBlocksLengthIndex + SizeOfQualityBlocksLength + qualityBlocksSize + sizeOfCertificationRecord;
209 static constexpr size_t SizeOfPosition = 1UL;
210 if (isoImage.size() < (positionIndex + SizeOfPosition))
211 {
212 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (fail to read position)");
213 }
214 const auto position = isoImage[positionIndex];
215 static constexpr size_t ImpressionOffsetFromPosition = 13UL;
216 static constexpr size_t SizeOfImpression = 1UL;
217 const auto impressionIndex = positionIndex + ImpressionOffsetFromPosition;
218 if (isoImage.size() < (impressionIndex + SizeOfImpression))
219 {
220 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (fail to read impression)");
221 }
222 const auto impression = isoImage[impressionIndex];
223 static constexpr size_t ImageLengthOffsetFromPosition = 18UL;
224 const auto imageLengthIndex = positionIndex + ImageLengthOffsetFromPosition;
225 static constexpr size_t SizeOfImageLength = 4UL;
226 if (isoImage.size() < (imageLengthIndex + SizeOfImageLength))
227 {
228 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (fail to read image length)");
229 }
230 const size_t encodedImageLength = (isoImage[imageLengthIndex] << 24U) +
231 (isoImage[imageLengthIndex + 1] << 16U) +
232 (isoImage[imageLengthIndex + 2] << 8U) + isoImage[imageLengthIndex + 3];
233 const auto imageDataIndex = imageLengthIndex + SizeOfImageLength;
234 if (isoImage.size() < (imageDataIndex + encodedImageLength))
235 {
236 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (fail to read image data)");
237 }
238 std::vector<uint8_t> encodedImageData = std::vector<uint8_t>(
239 std::next(isoImage.begin(), static_cast<ptrdiff_t>(imageDataIndex)),
240 std::next(isoImage.begin(), static_cast<ptrdiff_t>(imageDataIndex + encodedImageLength)));
241
242 static constexpr size_t ImageHorizontalDpiOffsetFromPosition = 7UL;
243 const auto imageHorizontalDpiIndex = positionIndex + ImageHorizontalDpiOffsetFromPosition;
244 const unsigned int imageHorizontalDpi =
245 (isoImage[imageHorizontalDpiIndex] << 8U) + isoImage[imageHorizontalDpiIndex + 1];
246 static constexpr size_t ImageVerticalDpiOffsetFromPosition = 9UL;
247 const auto imageVerticalDpiIndex = positionIndex + ImageVerticalDpiOffsetFromPosition;
248 const unsigned int imageVerticalDpi =
249 (isoImage[imageVerticalDpiIndex] << 8U) + isoImage[imageVerticalDpiIndex + 1];
250 if (imageHorizontalDpi != imageVerticalDpi)
251 {
253 "Fail to decode print ISO image (vertical and horizontal image DPI is different)");
254 }
255 static constexpr size_t ImageScaleUnitOffsetFromPosition = 2UL;
256 const auto imageScaleUnitIndex = positionIndex + ImageScaleUnitOffsetFromPosition;
257 const auto imageScaleUnit = isoImage[imageScaleUnitIndex];
258 static constexpr uint8_t ImageScaleUnitDPI = 1;
259 static constexpr uint8_t ImageScaleUnitDPCM = 2;
260 if (imageScaleUnit != ImageScaleUnitDPI && imageScaleUnit != ImageScaleUnitDPCM)
261 {
262 throw EnrollmentInvalidArgumentException("Fail to decode print ISO image (invalid scale unit)");
263 }
264 auto dpi = ImageDpi{ imageHorizontalDpi };
265 if (imageScaleUnit == ImageScaleUnitDPCM)
266 {
267 dpi = ImageDpi::FromDPCM(imageHorizontalDpi);
268 }
269
271 pa.SetImpression(IsoToPrintImpression(impression));
275 pa.SetCertificationFlag(static_cast<bool>(certificationFlag));
276
277 static constexpr size_t ImageBitDepthOffsetFromPosition = 11UL;
278 const auto imagBitDepthIndex = positionIndex + ImageBitDepthOffsetFromPosition;
279 const auto imageBitDepth = isoImage[imagBitDepthIndex];
280 static constexpr uint8_t SupportedBitsPerPixel = 8;
281
282 static constexpr size_t ImageCompressionOffsetFromPosition = 12UL;
283 const auto imageCompressionIndex = positionIndex + ImageCompressionOffsetFromPosition;
284 const auto imageCompression = isoImage[imageCompressionIndex];
285 static constexpr uint8_t RawNotPackedImage = 0;
286 static constexpr uint8_t RawPackedImage = 1;
287
288 if (imageCompression == RawNotPackedImage || imageCompression == RawPackedImage)
289 {
290 if (imageBitDepth != SupportedBitsPerPixel)
291 {
292 throw NotSupportedException("Fail to decode print ISO image (bit depth is not 8 for raw image)");
293 }
294
295 static constexpr size_t ImageWidthOffsetFromPosition = 14UL;
296 const auto imagWidthIndex = positionIndex + ImageWidthOffsetFromPosition;
297 const ImageWidth imageWidth = (isoImage[imagWidthIndex] << 8U) + isoImage[imagWidthIndex + 1];
298 static constexpr size_t ImageHeightOffsetFromPosition = 16UL;
299 const auto imagHeightIndex = positionIndex + ImageHeightOffsetFromPosition;
300 const ImageHeight imageHeight = (isoImage[imagHeightIndex] << 8U) + isoImage[imagHeightIndex + 1];
301
302 return Print::Create(
304 RawImage{ imageWidth, imageHeight, dpi, RawImage::Type::GRAYSCALE, std::move(encodedImageData) }),
306 pa);
307 }
308
309 return Print::Create(
310 Image::Decode(encodedImageData, static_cast<unsigned int>(dpi)), IsoToPrintPosition(position), pa);
311 }
312
320 */
321 uint8_t CalculatePresence()
322 {
323 const std::scoped_lock lock(presenceMux);
324 if (!presence.has_value())
325 {
326 uint8_t localPresence = 0;
327
328 auto gs = image->AsRawGrayscale();
329 exec->CalculatePresence(gs.width,
330 gs.height,
331 static_cast<unsigned int>(gs.dpi),
332 gs.Data().data(),
333 &localPresence,
334 ThrowOnError{});
335
336 presence = localPresence;
337 }
338 return presence.value();
339 }
340
348 */
349 uint8_t CalculateNFIQ1()
350 {
351 const std::scoped_lock lock(nfiq1Mux);
352 if (!nfiq1.has_value())
353 {
354 uint8_t localNFIQ1 = 0;
355
356 auto gs = image->AsRawGrayscale();
357
358 exec->CalculateNFIQ1(gs.width,
359 gs.height,
360 static_cast<unsigned int>(gs.dpi),
361 gs.Data().data(),
362 &localNFIQ1,
363 ThrowOnError{});
364
365 nfiq1 = localNFIQ1;
366 }
367 return nfiq1.value();
368 }
369
383 */
384 uint8_t CalculateNFIQ2()
385 {
386 const std::scoped_lock lock(nfiq2Mux);
387 log.LogInfo("Calculating NFIQ2 for image %v", image);
388
389 if (!nfiq2.has_value())
390 {
391 if (image->Dpi() != DefaultDpi)
392 {
393 static constexpr const char* Msg = "Image for NFIQ2 quality MUST have 500 DPI";
394 log.LogError("Calculating NFIQ2 for image %v failed '%s'", image, Msg);
396 }
397
398 uint8_t localNFIQ2 = 0;
399
400 auto gs = image->AsRawGrayscale();
401
402 exec->CalculateNFIQ2(gs.width,
403 gs.height,
404 static_cast<unsigned int>(gs.dpi),
405 gs.Data().data(),
406 &localNFIQ2,
407 ThrowOnError{});
408
409 nfiq2 = localNFIQ2;
410 }
411 log.LogInfo("Calculating NFIQ2 for image %v with result %d", image, nfiq2.value());
412 return nfiq2.value();
413 }
414
422 */
423 uint8_t CalculateImageQuality()
424 {
425 const std::scoped_lock lock(imageQualityMux);
426 if (!imageQuality.has_value())
427 {
428 uint8_t quality = 0;
429
430 auto gs = image->AsRawGrayscale();
431
432 exec->CalculateImageQuality(
433 gs.width, gs.height, static_cast<unsigned int>(gs.dpi), gs.Data().data(), &quality, ThrowOnError{});
434
435 imageQuality = quality;
436 }
437 return imageQuality.value();
438 }
439
447 */
448 uint8_t CalculatePlacement()
449 {
450 const std::scoped_lock lock(placementMux);
451 if (!placement.has_value())
452 {
453 uint8_t localPlacement = 0;
454
455 auto gs = image->AsRawGrayscale();
456
457 exec->CalculatePlacement(gs.width,
458 gs.height,
459 static_cast<unsigned int>(gs.dpi),
460 gs.Data().data(),
461 &localPlacement,
462 ThrowOnError{});
463
464 placement = localPlacement;
465 }
466 return placement.value();
467 }
468
473 */
474 static uint8_t CalculateIntensity(const std::shared_ptr<inno::Image>& image,
475 std::shared_ptr<PrintExecutor>& executor)
476 {
477 uint8_t intensity = 0;
478
479 const inno::RawImage rawImage = image->AsRawGrayscale();
480
481 executor->GetImageIntensity(
482 rawImage.width, rawImage.height, rawImage.Data().data(), &intensity, ThrowOnError{});
483
484 return intensity;
485 }
486
494 */
495 uint8_t CalculateIntensity()
496 {
497 const std::scoped_lock lock(intensityMux);
498 if (!intensity.has_value())
499 {
500 intensity = CalculateIntensity(image, exec);
501 }
502 return intensity.value();
503 }
504
510 */
511 [[nodiscard]] std::shared_ptr<Image> DrawMinutiae(const std::vector<std::shared_ptr<Minutia>>& minutiae,
512 const ImageShapeAttributes& attr) const
513 {
514 return image->DrawShape(MinutiaeShape(minutiae, attr));
515 }
516
522 */
523 [[nodiscard]] std::shared_ptr<Image> DrawCriticalPoints(
524 const std::vector<std::shared_ptr<CriticalPoint>>& points,
525 const ImageShapeAttributes& attr) const
526 {
527 return image->DrawShape(CriticalPointsShape(points, attr));
528 }
529
533 */
534 void WriteTo(Writer& writer) const final
535 {
536 writer.Write("i", image);
537 writer.Write("p", static_cast<unsigned int>(position));
538 writer.Write("a", printAttributes);
539
540 const std::scoped_lock lock(presenceMux, nfiq1Mux, nfiq2Mux, imageQualityMux, placementMux, intensityMux);
541
542 if (presence.has_value())
543 {
544 writer.Write("pr", presence.value());
545 }
546 if (nfiq1.has_value())
547 {
548 writer.Write("n1", nfiq1.value());
549 }
550 if (nfiq2.has_value())
551 {
552 writer.Write("n2", nfiq2.value());
553 }
554 if (imageQuality.has_value())
555 {
556 writer.Write("iq", imageQuality.value());
557 }
558 if (placement.has_value())
559 {
560 writer.Write("pl", placement.value());
561 }
562 if (intensity.has_value())
563 {
564 writer.Write("in", intensity.value());
565 }
566 }
567
574 */
575 bool IsSameAs(const Print& print) const
576 {
577 return this == &print;
578 }
579
586 */
587 bool operator==(const Print& f) const
588 {
589 if (this == &f)
590 {
591 return true;
592 }
593
594 return *image == *f.image && position == f.position && printAttributes == f.printAttributes;
595 }
596
603 */
604 bool operator!=(const Print& f) const
605 {
606 return !(*this == f);
607 }
608
609 Print(const Print&) = delete;
610 Print(Print&&) = delete;
611 Print& operator=(const Print&) = delete;
612 Print& operator=(Print&&) = delete;
613 virtual ~Print() = default;
614 Print() = delete;
615
625 */
626 static std::shared_ptr<Print> Create(std::shared_ptr<Image> img,
627 const PrintPosition& position,
628 const PrintAttributes& pa = PrintAttributes(),
629 std::shared_ptr<PrintExecutor> executor = GlobalPrintExecutor::Get())
630 {
631 return std::shared_ptr<Print>(new Print(std::move(img), position, pa, std::move(executor)));
632 }
633
634 private:
635 std::shared_ptr<PrintExecutor> exec;
637 mutable std::mutex presenceMux;
638 mutable std::mutex nfiq1Mux;
639 mutable std::mutex nfiq2Mux;
640 mutable std::mutex imageQualityMux;
641 mutable std::mutex placementMux;
642 mutable std::mutex intensityMux;
643
644 std::optional<uint8_t> presence;
645 std::optional<uint8_t> nfiq1;
646 std::optional<uint8_t> nfiq2;
647 std::optional<uint8_t> imageQuality;
648 std::optional<uint8_t> placement;
649 std::optional<uint8_t> intensity;
650
651 Print(std::shared_ptr<Image> img,
652 const PrintPosition& pos,
654 std::shared_ptr<PrintExecutor> executor)
655 : image(std::move(img))
656 , position(pos)
657 , printAttributes(std::move(pa))
658 , exec(std::move(executor))
659 , log(GlobalLogger::Get())
660 {
661 if (exec == nullptr)
662 {
663 throw NullArgumentException("Could not create Print due to executor can not be null");
664 }
665
666 if (image == nullptr)
667 {
668 throw NullArgumentException("Could not create Print due to image can not be null");
669 }
670 }
671
672 class IsoImage
673 {
674 public:
675 explicit IsoImage(const Print& p)
676 : print(p)
677 {
678 }
679 IsoImage() = delete;
680 ~IsoImage() = default;
681 IsoImage(const IsoImage&) = delete;
682 IsoImage(IsoImage&&) = delete;
683 IsoImage& operator=(const IsoImage&) = delete;
684 IsoImage& operator=(IsoImage&&) = delete;
685
686 void SetCompressionType(uint8_t ct)
687 {
688 compressionType = ct;
689 }
690
691 std::vector<uint8_t> FillIsoImage(const std::vector<uint8_t>& encodedImage)
692 {
693 static constexpr size_t GeneralHeaderLength = 16UL;
694 static constexpr size_t RepresentationHeaderLength = 41UL;
695 static constexpr size_t CertificationBlockSize = 1UL;
696 const size_t representationHeaderLength =
697 RepresentationHeaderLength +
698 (print.printAttributes.GetCertificationFlag() ? CertificationBlockSize : 0UL);
699 static constexpr size_t RepresentationBodyExtraDataLength = 0;
700
701 // Length of encoded image.
702 auto imageLength = encodedImage.size();
703
704 // Representation length including the representation header length.
705 auto representationLength =
706 representationHeaderLength + imageLength + RepresentationBodyExtraDataLength;
707
708 // Record length with image data.
709 auto recordLength = GeneralHeaderLength + representationLength;
710
711 std::vector<uint8_t> isoImage;
712 isoImage.resize(recordLength);
713
714 FillGeneralHeader(isoImage, recordLength);
715 FillRepresentationHeader(isoImage, representationLength, imageLength);
716 FillRepresentationBody(isoImage, encodedImage);
717
718 return isoImage;
719 }
720
721 private:
722 size_t writeIndex = 0;
723
724 static void ThrowWhenValueCannotFitInto4Bytes(size_t recordLength)
725 {
726 if (recordLength > static_cast<size_t>(std::numeric_limits<uint32_t>::max()))
727 {
728 throw EnrollmentRuntimeException("Invalid conversion size");
729 }
730 }
731
740 void FillGeneralHeader(std::vector<uint8_t>& isoImage, const size_t recordLength)
741 {
742 FillFormatIdentifier(isoImage);
743 FillVersionNumber(isoImage);
744 FillLengthOfRecord(isoImage, recordLength);
745 FillNumberOfFingerPalmRepresentations(isoImage);
746 FillCertificationFlag(isoImage);
747 FillNumberOfDistinctFingerPalmPositions(isoImage);
748 }
749
756 void FillFormatIdentifier(std::vector<uint8_t>& isoImage)
757 {
758 // Mandatory fields.
759 isoImage[writeIndex++] = 'F';
760 isoImage[writeIndex++] = 'I';
761 isoImage[writeIndex++] = 'R';
762 isoImage[writeIndex++] = '\0';
763 }
764
774 void FillVersionNumber(std::vector<uint8_t>& isoImage)
775 {
776 // Mandatory fields.
777 isoImage[writeIndex++] = '0';
778 isoImage[writeIndex++] = '2';
779 isoImage[writeIndex++] = '0';
780 isoImage[writeIndex++] = '\0';
781 }
782
792 void FillLengthOfRecord(std::vector<uint8_t>& isoImage, const size_t recordLength)
793 {
794 ThrowWhenValueCannotFitInto4Bytes(recordLength);
795
796 // Mandatory fields.
797 isoImage[writeIndex++] = static_cast<uint8_t>(recordLength >> ThreeBytesBitsCount);
798 isoImage[writeIndex++] = static_cast<uint8_t>((recordLength >> ThreeBytesBitsCount) & ByteMask);
799 isoImage[writeIndex++] = static_cast<uint8_t>((recordLength >> OneByteBitsCount) & ByteMask);
800 isoImage[writeIndex++] = static_cast<uint8_t>(recordLength & ByteMask);
801 }
802
810 void FillNumberOfFingerPalmRepresentations(std::vector<uint8_t>& isoImage)
811 {
812 // Mandatory fields.
813 isoImage[writeIndex++] = 0x00;
814 isoImage[writeIndex++] = 0x01;
815 }
816
825 void FillCertificationFlag(std::vector<uint8_t>& isoImage)
826 {
827 isoImage[writeIndex++] = print.printAttributes.GetCertificationFlag() ? 1 : 0; // Mandatory field.
828 }
829
837 void FillNumberOfDistinctFingerPalmPositions(std::vector<uint8_t>& isoImage)
838 {
839 isoImage[writeIndex++] = 0x01; // Mandatory field.
840 }
841
855 void FillRepresentationHeader(std::vector<uint8_t>& isoImage,
856 size_t representationLength,
857 size_t imageLength)
858 {
859 FillRepresentationLength(isoImage, representationLength);
860 FillCaptureDateTime(isoImage);
861 FillCaptureDeviceTechnologyIdentifier(isoImage);
862 FillCaptureDeviceVendorIdentifier(isoImage);
863 FillCaptureDeviceTypeIdentifier(isoImage);
864 FillNumberOfQualityBlocks(isoImage);
865 FillCaptureDeviceCertifications(isoImage);
866 FillFingerPalmPosition(isoImage);
867 FillRepresentationNumber(isoImage);
868 FillScaleUnits(isoImage);
869 FillCaptureDeviceSpatialHorizontalSamplingRate(isoImage);
870 FillCaptureDeviceSpatialVerticalSamplingRate(isoImage);
871 FillImageSpatialHorizontalSamplingRate(isoImage);
872 FillImageSpatialVerticalSamplingRate(isoImage);
873 FillBitDepth(isoImage);
874 FillImageCompressionAlgorithm(isoImage);
875 FillImpressionType(isoImage);
876 FillHorizontalLineLength(isoImage);
877 FillVerticalLineLength(isoImage);
878 FillImageDataLength(isoImage, imageLength);
879 }
880
889 void FillRepresentationLength(std::vector<uint8_t>& isoImage, size_t representationLength)
890 {
891 ThrowWhenValueCannotFitInto4Bytes(representationLength);
892
893 // Mandatory fields.
894 isoImage[writeIndex++] = static_cast<uint8_t>(representationLength >> ThreeBytesBitsCount);
895 isoImage[writeIndex++] = static_cast<uint8_t>((representationLength >> ThreeBytesBitsCount) & ByteMask);
896 isoImage[writeIndex++] = static_cast<uint8_t>((representationLength >> OneByteBitsCount) & ByteMask);
897 isoImage[writeIndex++] = static_cast<uint8_t>(representationLength & ByteMask);
898 }
899
908 void FillCaptureDateTime(std::vector<uint8_t>& isoImage)
909 {
910 // Mandatory fields.
911 static constexpr uint8_t DummyValue = 0xff;
912 isoImage[writeIndex++] = DummyValue; // year
913 isoImage[writeIndex++] = DummyValue; // year
914 isoImage[writeIndex++] = DummyValue; // month
915 isoImage[writeIndex++] = DummyValue; // day
916 isoImage[writeIndex++] = DummyValue; // hour
917 isoImage[writeIndex++] = DummyValue; // minute
918 isoImage[writeIndex++] = DummyValue; // second
919 isoImage[writeIndex++] = DummyValue; // millisecond
920 isoImage[writeIndex++] = DummyValue; // millisecond
921 }
922
931 void FillCaptureDeviceTechnologyIdentifier(std::vector<uint8_t>& isoImage)
932 {
933 const PrintCaptureDeviceTechnology technology = print.printAttributes.GetCaptureDeviceTechnology();
934 isoImage[writeIndex++] =
935 static_cast<uint8_t>(PrintToIsoCaptureDeviceTechnology(technology)); // Mandatory field.
936 }
937
946 void FillCaptureDeviceVendorIdentifier(std::vector<uint8_t>& isoImage)
947 {
948 // Mandatory fields.
949 const PrintCaptureDeviceVendorID vendor = print.printAttributes.GetCaptureDeviceVendorID();
950 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(vendor) >> OneByteBitsCount);
951 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(vendor) & ByteMask);
952 }
953
961 void FillCaptureDeviceTypeIdentifier(std::vector<uint8_t>& isoImage)
962 {
963 // Mandatory fields.
964 const PrintCaptureDeviceTypeID type = print.printAttributes.GetCaptureDeviceTypeID();
965 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(type) >> OneByteBitsCount);
966 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(type) & ByteMask);
967 }
968
977 void FillNumberOfQualityBlocks(std::vector<uint8_t>& isoImage)
978 {
979 isoImage[writeIndex++] = 0x00; // Mandatory field.
980 }
981
986 void FillQualityBlockData(std::vector<uint8_t>& isoImage)
987 {
988 // Optional fields.
989 FillQualityScore(isoImage);
990 FillQualityAlgorithmVendorId(isoImage);
991 FillQualityAlgorithmId(isoImage);
992 }
993
1003 void FillQualityScore(std::vector<uint8_t>& isoImage)
1004 {
1005 isoImage[writeIndex++] = 0x00; // Optional field.
1006 }
1007
1016 void FillQualityAlgorithmVendorId(std::vector<uint8_t>& isoImage)
1017 {
1018 // Optional fields.
1019 isoImage[writeIndex++] = 0x00;
1020 isoImage[writeIndex++] = 0x00;
1021 }
1022
1032 void FillQualityAlgorithmId(std::vector<uint8_t>& isoImage)
1033 {
1034 // Optional fields.
1035 isoImage[writeIndex++] = 0x00;
1036 isoImage[writeIndex++] = 0x00;
1037 }
1038
1049 void FillCaptureDeviceCertifications(std::vector<uint8_t>& isoImage)
1050 {
1051 FillNumberOfCertificationBlocks(isoImage);
1052 }
1053
1060 void FillNumberOfCertificationBlocks(std::vector<uint8_t>& isoImage)
1061 {
1062 // we are not storing any certification block
1063 if (print.printAttributes.GetCertificationFlag())
1064 {
1065 isoImage[writeIndex++] = 0x00;
1066 }
1067 }
1068
1076 void FillCertificationBlocks(std::vector<uint8_t>& isoImage)
1077 {
1078 // Optional fields.
1079 isoImage[writeIndex++] = 0x00;
1080 isoImage[writeIndex++] = 0x00;
1081 }
1082
1089 void FillCertificationSchemeIdentifier(std::vector<uint8_t>& isoImage)
1090 {
1091 isoImage[writeIndex++] = 0x00; // Optional field.
1092 }
1093
1099 void FillFingerPalmPosition(std::vector<uint8_t>& isoImage)
1100 {
1101 // Mandatory field.
1102 isoImage[writeIndex++] = static_cast<uint8_t>(PrintToIsoPosition(print.position));
1103 }
1104
1111 void FillRepresentationNumber(std::vector<uint8_t>& isoImage)
1112 {
1113 isoImage[writeIndex++] = 0x00; // Mandatory field.
1114 }
1115
1123 void FillScaleUnits(std::vector<uint8_t>& isoImage)
1124 {
1125 isoImage[writeIndex++] = 0x01; // Mandatory field.
1126 }
1127
1135 void FillCaptureDeviceSpatialHorizontalSamplingRate(std::vector<uint8_t>& isoImage)
1136 {
1137 // Mandatory fields.
1138 isoImage[writeIndex++] =
1139 static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) >> OneByteBitsCount);
1140 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) & ByteMask);
1141 }
1142
1150 void FillCaptureDeviceSpatialVerticalSamplingRate(std::vector<uint8_t>& isoImage)
1151 {
1152 // Mandatory fields.
1153 isoImage[writeIndex++] =
1154 static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) >> OneByteBitsCount);
1155 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) & ByteMask);
1156 }
1157
1166 void FillImageSpatialHorizontalSamplingRate(std::vector<uint8_t>& isoImage)
1167 {
1168 // Mandatory fields.
1169 isoImage[writeIndex++] =
1170 static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) >> OneByteBitsCount);
1171 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) & ByteMask);
1172 }
1173
1182 void FillImageSpatialVerticalSamplingRate(std::vector<uint8_t>& isoImage)
1183 {
1184 // Mandatory fields.
1185 isoImage[writeIndex++] =
1186 static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) >> OneByteBitsCount);
1187 isoImage[writeIndex++] = static_cast<uint8_t>(static_cast<unsigned int>(print.image->Dpi()) & ByteMask);
1188 }
1189
1196 void FillBitDepth(std::vector<uint8_t>& isoImage)
1197 {
1198 static constexpr uint8_t BitsPerPixel = 8;
1199 isoImage[writeIndex++] = BitsPerPixel; // Mandatory field.
1200 }
1201
1216 void FillImageCompressionAlgorithm(std::vector<uint8_t>& isoImage)
1217 {
1218 isoImage[writeIndex++] = compressionType; // Mandatory field.
1219 }
1220
1229 void FillImpressionType(std::vector<uint8_t>& isoImage)
1230 {
1231 isoImage[writeIndex++] =
1232 static_cast<uint8_t>(PrintToIsoImpression(print.printAttributes.GetImpression())); // Mandatory field.
1233 }
1234
1241 void FillHorizontalLineLength(std::vector<uint8_t>& isoImage)
1242 {
1243 // Mandatory fields.
1244 isoImage[writeIndex++] = static_cast<uint8_t>(print.image->Width() >> OneByteBitsCount);
1245 isoImage[writeIndex++] = static_cast<uint8_t>(print.image->Width() & ByteMask);
1246 }
1247
1254 void FillVerticalLineLength(std::vector<uint8_t>& isoImage)
1255 {
1256 // Mandatory fields.
1257 isoImage[writeIndex++] = static_cast<uint8_t>(print.image->Height() >> OneByteBitsCount);
1258 isoImage[writeIndex++] = static_cast<uint8_t>(print.image->Height() & ByteMask);
1259 }
1260
1270 void FillImageDataLength(std::vector<uint8_t>& isoImage, size_t imageLength)
1271 {
1272 ThrowWhenValueCannotFitInto4Bytes(imageLength);
1273
1274 // Mandatory fields.
1275 isoImage[writeIndex++] = static_cast<uint8_t>(imageLength >> ThreeBytesBitsCount);
1276 isoImage[writeIndex++] = static_cast<uint8_t>((imageLength >> ThreeBytesBitsCount) & ByteMask);
1277 isoImage[writeIndex++] = static_cast<uint8_t>((imageLength >> OneByteBitsCount) & ByteMask);
1278 isoImage[writeIndex++] = static_cast<uint8_t>(imageLength & ByteMask);
1279 }
1280
1288 void FillRepresentationBody(std::vector<uint8_t>& isoImage, const std::vector<uint8_t>& encodedImage)
1289 {
1290 FillImageData(isoImage, encodedImage);
1291 FillExtendedDataBlocks(isoImage);
1292 }
1293
1301 void FillImageData(std::vector<uint8_t>& isoImage, const std::vector<uint8_t>& encodedImage)
1302 {
1303 std::copy(encodedImage.begin(),
1304 encodedImage.end(),
1305 std::next(isoImage.begin(), static_cast<ptrdiff_t>(writeIndex))); // Mandatory field.
1306 writeIndex += encodedImage.size();
1307 }
1308
1320 void FillExtendedDataBlocks(std::vector<uint8_t>& /* isoImage */)
1321 {
1322 // no extended data are stored
1323 }
1324
1337 void FillTypeIdentificationCode(std::vector<uint8_t>& isoImage)
1338 {
1339 // Optional fields.
1340 isoImage[writeIndex++] = 0x00;
1341 isoImage[writeIndex++] = 0x00;
1342 }
1343
1353 void FillLengthOfData(std::vector<uint8_t>& isoImage)
1354 {
1355 // Optional fields.
1356 isoImage[writeIndex++] = 0x00;
1357 isoImage[writeIndex++] = 0x00;
1358 }
1359
1368 void FillDataSection(std::vector<uint8_t>& isoImage)
1369 {
1370 isoImage[writeIndex++] = 0x00; // Optional field.
1371 }
1372
1373 const Print& print;
1374 static constexpr uint8_t RawCompressionType = 0;
1375 uint8_t compressionType = RawCompressionType;
1376 static constexpr unsigned int OneByteBitsCount = 8U;
1377 static constexpr unsigned int TwoBytesBitsCount = 16U;
1378 static constexpr unsigned int ThreeBytesBitsCount = 24U;
1379 static constexpr unsigned int ByteMask = 0xffU;
1380 };
1381
1382 class IsoImageEncoder : public ImageEncoderVisitor
1383 {
1384 public:
1392 std::vector<uint8_t> Encode()
1393 {
1394 // Get necessary image data for creating iso image.
1395 encoder.Accept(*this);
1396
1397 // Get image data in requested format.
1398 auto encodedImage = print.image->EncodeIn(encoder);
1399
1400 return isoImage.FillIsoImage(encodedImage);
1401 }
1402
1403 void Visit(const WsqImageEncoder& /* encoder */) final
1404 {
1405 // According to table of compression algorithm codes, WSQ has compression code 2.
1406 static constexpr uint8_t WsqCompression = 2;
1407 isoImage.SetCompressionType(WsqCompression);
1408 }
1409
1410 void Visit(const JpgImageEncoder& /* encoder */) final
1411 {
1412 // According to table of compression algorithm codes, JPEG has compression code 3.
1413 static constexpr uint8_t JpgCompression = 3;
1414 isoImage.SetCompressionType(JpgCompression);
1415 }
1416
1417 void Visit(const Jp2ImageEncoder& jp2Encoder) final
1418 {
1419 if (jp2Encoder.IsLossy())
1420 {
1421 // According to table of compression algorithm codes, JPEG 2000 lossy has compression code 4.
1422 static constexpr uint8_t Jp2Lossy = 4;
1423 isoImage.SetCompressionType(Jp2Lossy);
1424 }
1425 else
1426 {
1427 // According to table of compression algorithm codes, JPEG 2000 lossless has compression code 5.
1428 static constexpr uint8_t Jp2Lossless = 5;
1429 isoImage.SetCompressionType(Jp2Lossless);
1430 }
1431 }
1432
1433 void Visit(const PngImageEncoder& /* encoder */) final
1434 {
1435 // According to table of compression algorithm codes, PNG has compression code 6.
1436 static constexpr uint8_t PngCompression = 6;
1437 isoImage.SetCompressionType(PngCompression);
1438 }
1439
1440 void Visit(const IRawImageEncoder& /* encoder */) final
1441 {
1442 throw EnrollmentInvalidArgumentException("Could not create ISO image for IRAW image format");
1443 }
1444
1445 void Visit(const BmpImageEncoder& /* encoder */) final
1446 {
1447 throw EnrollmentInvalidArgumentException("Could not create ISO image for BMP image format");
1448 }
1449
1450 void Visit(const TiffImageEncoder& /* encoder */) final
1451 {
1452 throw EnrollmentInvalidArgumentException("Could not create ISO image for TIFF image format");
1453 }
1454
1455 void Visit(const WebpImageEncoder& /* encoder */) final
1456 {
1457 throw EnrollmentInvalidArgumentException("Could not create ISO image for WEBP image format");
1458 }
1459
1460 // We can use references because this is inner class of Print and we always know the usage.
1461 // The references will be valid in whole class lifetime.
1462 IsoImageEncoder(const Print& p, ImageEncoder& e)
1463 : print(p)
1464 , encoder(e)
1465 , isoImage(IsoImage(p))
1466 {
1467 }
1468 IsoImageEncoder() = delete;
1469 virtual ~IsoImageEncoder() = default;
1470 IsoImageEncoder(const IsoImageEncoder&) = delete;
1471 IsoImageEncoder(IsoImageEncoder&&) = delete;
1472 IsoImageEncoder& operator=(const IsoImageEncoder&) = delete;
1473 IsoImageEncoder& operator=(IsoImageEncoder&&) = delete;
1474
1475 private:
1476 const Print& print;
1477 ImageEncoder& encoder;
1478 IsoImage isoImage;
1479 };
1480 };
1481
1482} // namespace inno
1483// NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes,misc-non-private-member-variables-in-classes,cppcoreguidelines-avoid-const-or-ref-data-members)
constexpr ImageDpi DefaultDpi
Provides default DPI Default DPI is 500.
Definition ImageAttribute.h:107
It draws collection of CriticalPoint into image.
Definition CriticalPoint.h:181
Base exception for all enrollment-sdk invalid argument exceptions.
Definition EnrollmentException.h:96
It provides functions with format specifier to compose and log message via provided Logger.
Definition FormattingLogger.h:601
Holds instance of Logger.
Definition Logger.h:275
static std::shared_ptr< PrintExecutor > Get()
Provides current executor.
Definition PrintExecutor.h:1306
Image DPI.
Definition ImageAttribute.h:47
static ImageDpi FromDPCM(unsigned int dpcm)
Converts dot per centimeter to dot per inch.
Definition ImageAttribute.h:81
Interface for image formatting converting to ImageType.
Definition ImageEncoder.h:106
It holds shape attributes such as color and line width.
Definition ImageShape.h:22
Image resampler for DPI-change operations, including upsampling and downsampling using bicubic interp...
Definition Image.h:584
Image resampler for DPI-change operations, including upsampling and downsampling.
Definition Image.h:530
static std::shared_ptr< Image > DecodeRawImage(const RawImage &raw, std::shared_ptr< ImageEncoder > originalEncoder=nullptr, std::shared_ptr< ImageExecutor > executor=GlobalImageExecutor::Get())
Creates Image from raw data.
Definition Image.h:200
static std::shared_ptr< Image > Decode(const std::vector< uint8_t > &imageData)
Creates Image from image data with 500 DPI.
Definition Image.h:48
Image has wrong format or dimensions or dpi and is not suitable for processing.
Definition EnrollmentException.h:144
It draws Minutia into image.
Definition Minutia.h:188
When user uses not supported functionality.
Definition NotSupportedException.h:23
Null argument is not allowed.
Definition EnrollmentException.h:156
Print attributes Holds the print attributes.
Definition PrintAttributes.h:34
void SetImpression(PrintImpression imp)
Sets impression of print.
Definition PrintAttributes.h:142
void SetCaptureDeviceVendorID(PrintCaptureDeviceVendorID vendor)
Sets capture device vendor ID.
Definition PrintAttributes.h:182
void SetCaptureDeviceTypeID(PrintCaptureDeviceTypeID type)
Sets capture device type ID.
Definition PrintAttributes.h:202
void SetCertificationFlag(bool deviceCertified)
Sets the certification flag.
Definition PrintAttributes.h:224
void SetCaptureDeviceTechnology(PrintCaptureDeviceTechnology technology)
Sets capture device technology.
Definition PrintAttributes.h:162
Capture device type identifier The capture device type identifier shall identify the biometric organi...
Definition PrintCaptureDeviceTypeID.h:24
Capture device vendor identifier The capture device vendor identifier shall identify the biometric or...
Definition PrintCaptureDeviceVendorID.h:24
It holds all functions and data related to print manipulation.
Definition Print.h:47
static std::shared_ptr< Print > FromIsoImage(const std::vector< uint8_t > &isoImage)
Function creates shared pointer of the Print object from ISO image based on ISO/IEC 19794-4 (Finger i...
Definition Print.h:130
uint8_t CalculateNFIQ2()
Function calculates NFIQ2 score (quality score defined by NIST) of the fingerprint image.
Definition Print.h:383
bool IsSameAs(const Print &print) const
Returns true when argument is same object.
Definition Print.h:574
void WriteTo(Writer &writer) const final
Function serializes print via provided Writer.
Definition Print.h:533
uint8_t CalculateNFIQ1()
Function calculates NFIQ score (quality score defined by NIST) of the fingerprint image.
Definition Print.h:348
std::vector< uint8_t > ToIsoRawImage() const
Function creates ISO image based on ISO/IEC 19794-4 (Finger image data) use RawImage.
Definition Print.h:109
bool operator!=(const Print &f) const
Compares if Print is not equal with other one.
Definition Print.h:603
static uint8_t CalculateIntensity(const std::shared_ptr< inno::Image > &image, std::shared_ptr< PrintExecutor > &executor)
Function calculates the image intensity.
Definition Print.h:473
std::shared_ptr< Image > DrawMinutiae(const std::vector< std::shared_ptr< Minutia > > &minutiae, const ImageShapeAttributes &attr) const
Draws minutiae on image.
Definition Print.h:510
std::vector< uint8_t > ToIsoImage(ImageEncoder &encoder) const
Function creates ISO image based on ISO/IEC 19794-4 (Finger image data).
Definition Print.h:98
std::shared_ptr< Print > ChangeDpiTo(const Image::ImageResampler &resampler) const
Create new Print using provided DPI-change configuration.
Definition Print.h:82
uint8_t CalculatePlacement()
Function calculates the finger placement quality of the input fingerprint image.
Definition Print.h:447
uint8_t CalculateImageQuality()
Function calculates Image quality of the input fingerprint image.
Definition Print.h:422
std::shared_ptr< Print > ChangeDpiTo(ImageDpi targetDpi) const
Create new Print with given DPI.
Definition Print.h:65
const PrintPosition position
Provides Print position.
Definition Print.h:52
uint8_t CalculatePresence()
Function calculates fingerprint presence on the fingerprint scanner surface.
Definition Print.h:320
uint8_t CalculateIntensity()
Function calculates the image intensity.
Definition Print.h:494
const std::shared_ptr< Image > image
Provides Print Image.
Definition Print.h:50
const PrintAttributes printAttributes
Provides PrintCapture Image.
Definition Print.h:54
bool operator==(const Print &f) const
Compares if Print is equal with other one.
Definition Print.h:586
std::shared_ptr< Image > DrawCriticalPoints(const std::vector< std::shared_ptr< CriticalPoint > > &points, const ImageShapeAttributes &attr) const
Draws critical points on skeleton image.
Definition Print.h:522
static std::shared_ptr< Print > Create(std::shared_ptr< Image > img, const PrintPosition &position, const PrintAttributes &pa=PrintAttributes(), std::shared_ptr< PrintExecutor > executor=GlobalPrintExecutor::Get())
Constructor creates Print object.
Definition Print.h:625
Contains plain image data.
Definition ImageAttribute.h:135
@ GRAYSCALE
Raw data where image pixels are stored in grayscale format.
Definition ImageAttribute.h:146
Provides interface for serialization of all classes.
Definition Writer.h:164
ImageDimension ImageHeight
Image Height.
Definition ImageAttribute.h:36
ImageDimension ImageWidth
Image Width.
Definition ImageAttribute.h:41
PrintCaptureDeviceTechnology
It shall indicate the class of capture device technology used to acquire the captured biometric sampl...
Definition PrintCaptureDeviceTechnology.h:22
static constexpr PrintPosition IsoToPrintPosition(int isoPosition)
Function converts ISO position to PrintPosition.
Definition PrintPosition.h:138
PrintPosition
It is position of finger on hands.
Definition PrintPosition.h:29
static constexpr PrintImpression IsoToPrintImpression(int isoImpression)
Function converts ISO impression to PrintImpression.
Definition PrintImpression.h:147
static constexpr PrintCaptureDeviceTechnology IsoToPrintCaptureDeviceTechnology(int isoCaptureDeviceTechnology)
Function converts ISO capture technology to PrintCaptureDeviceTechnology.
Definition PrintCaptureDeviceTechnology.h:138
static constexpr int PrintToIsoPosition(PrintPosition position)
Function converts Print position to ISO position.
Definition PrintPosition.h:204
static constexpr int PrintToIsoCaptureDeviceTechnology(PrintCaptureDeviceTechnology printCaptureDeviceTechnology)
Function converts PrintCaptureDeviceTechnology to ISO capture technology.
Definition PrintCaptureDeviceTechnology.h:78
static constexpr int PrintToIsoImpression(PrintImpression printImpression)
Function converts PrintImpression to ISO impression.
Definition PrintImpression.h:91