image_quality_gate 0.1.0
image_quality_gate: ^0.1.0 copied to clipboard
Reject blurry, dark, overexposed, glary, low-contrast or undersized photos before OCR, upload or document scanning, with typed reasons and messages.
// Evaluates a photo passed on the command line, or a generated test page.
//
// dart run example/main.dart path/to/photo.jpg [receipt|idCard|document|photo] [en|fr|ar]
import 'dart:io';
import 'dart:typed_data';
import 'package:image/image.dart' as img;
import 'package:image_quality_gate/image_quality_gate_io.dart';
Future<void> main(List<String> args) async {
final Uint8List bytes;
if (args.isNotEmpty) {
bytes = File(args[0]).readAsBytesSync();
} else {
// A light page with dark "text" lines, blurred to show a rejection.
final page = img.Image(width: 1200, height: 1600);
img.fill(page, color: img.ColorRgb8(220, 220, 220));
for (var y = 40; y < 1550; y += 24) {
img.fillRect(page,
x1: 40, y1: y, x2: 1160, y2: y + 7, color: img.ColorRgb8(10, 10, 10));
}
bytes = Uint8List.fromList(
img.encodeJpg(img.gaussianBlur(page, radius: 10), quality: 90));
}
final config = switch (args.length > 1 ? args[1] : 'receipt') {
'idCard' => QualityConfig.idCard,
'document' => QualityConfig.document,
'photo' => QualityConfig.photo,
_ => QualityConfig.receipt,
};
final messages = QualityMessages.forLocale(args.length > 2 ? args[2] : 'en');
final report = await evaluateInIsolate(bytes, config);
print(report.passed ? 'Accepted.' : 'Rejected.');
for (final issue in report.issues) {
print('- [${issue.severity.name}] ${messages.forIssue(issue)}');
print(' ${issue.metric} = ${issue.value.toStringAsFixed(3)}, '
'${issue.kind.name} ${issue.threshold}');
}
print('Metrics: ${report.metrics.toMap()}');
}