88 lines
3.2 KiB
Dart
88 lines
3.2 KiB
Dart
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
import 'dart:ui' show Rect, Size;
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:image/image.dart' as img;
|
|
import 'package:pdf/pdf.dart' as pdf;
|
|
import 'package:pdf/widgets.dart' as pw;
|
|
|
|
import 'package:pdf_signature/data/services/export_service.dart';
|
|
|
|
void main() {
|
|
test(
|
|
'exportSignedPdfFromFile overlays signature image (structure/size check)',
|
|
() async {
|
|
// 1) Create a simple 1-page white PDF as the source
|
|
final srcDoc = pw.Document();
|
|
srcDoc.addPage(
|
|
pw.Page(
|
|
pageFormat: pdf.PdfPageFormat.a4,
|
|
build: (_) => pw.Container(color: pdf.PdfColors.white),
|
|
),
|
|
);
|
|
final srcBytes = await srcDoc.save();
|
|
final srcPath =
|
|
'${Directory.systemTemp.path}/export_src_${DateTime.now().millisecondsSinceEpoch}.pdf';
|
|
await File(srcPath).writeAsBytes(srcBytes, flush: true);
|
|
|
|
// 2) Create a small opaque black PNG as the signature image
|
|
final sigW = 60, sigH = 30;
|
|
final sigBitmap = img.Image(width: sigW, height: sigH);
|
|
img.fill(sigBitmap, color: img.ColorRgb8(0, 0, 0));
|
|
final sigPng = Uint8List.fromList(img.encodePng(sigBitmap));
|
|
|
|
// 3) Define signature rect in UI logical space (400x560), centered
|
|
const uiSize = Size(400, 560);
|
|
final r = Rect.fromLTWH(
|
|
uiSize.width / 2 - sigW / 2,
|
|
uiSize.height / 2 - sigH / 2,
|
|
sigW.toDouble(),
|
|
sigH.toDouble(),
|
|
);
|
|
|
|
// 4) Baseline export without signature (no overlay)
|
|
final baselinePath =
|
|
'${Directory.systemTemp.path}/export_baseline_${DateTime.now().millisecondsSinceEpoch}.pdf';
|
|
final svc = ExportService();
|
|
final okBase = await svc.exportSignedPdfFromFile(
|
|
inputPath: srcPath,
|
|
outputPath: baselinePath,
|
|
signedPage: null,
|
|
signatureRectUi: null,
|
|
uiPageSize: uiSize,
|
|
signatureImageBytes: null,
|
|
targetDpi: 144.0,
|
|
);
|
|
expect(okBase, isTrue, reason: 'baseline export should succeed');
|
|
final baseBytes = await File(baselinePath).readAsBytes();
|
|
expect(baseBytes.isNotEmpty, isTrue);
|
|
|
|
// 5) Export with overlay
|
|
final outPath =
|
|
'${Directory.systemTemp.path}/export_out_${DateTime.now().millisecondsSinceEpoch}.pdf';
|
|
final ok = await svc.exportSignedPdfFromFile(
|
|
inputPath: srcPath,
|
|
outputPath: outPath,
|
|
signedPage: 1,
|
|
signatureRectUi: r,
|
|
uiPageSize: uiSize,
|
|
signatureImageBytes: sigPng,
|
|
targetDpi: 144.0,
|
|
);
|
|
expect(ok, isTrue, reason: 'export should succeed');
|
|
final outBytes = await File(outPath).readAsBytes();
|
|
expect(outBytes.isNotEmpty, isTrue);
|
|
|
|
// 6) Heuristic validations without rasterization:
|
|
// - The output with overlay should be larger than the baseline.
|
|
// - The output should contain at least one image object marker.
|
|
expect(outBytes.length, greaterThan(baseBytes.length));
|
|
// Decode as latin1 to preserve byte-to-char mapping, then look for the image marker
|
|
final outText = String.fromCharCodes(outBytes);
|
|
final hasImageMarker = RegExp(r"/Subtype\s*/Image").hasMatch(outText);
|
|
expect(hasImageMarker, isTrue);
|
|
},
|
|
);
|
|
}
|