Files
desktop-plugin/test/card_image_test.dart
T
dzc 0a78ff1b58 feat: Windows PavoApi ffi 直打后端(Phase 3 代码完成,待实机验收)
- lib/print/pavo/:PavoApiW_x64.dll 的 dart:ffi 绑定(结构体布局对齐 C#,W 后缀导出名回退兼容)
- pavo_printer.dart:枚举(UTF-8/UTF-16 自动解码)/状态/色带信息/单卡直打/忙碌轮询(3 分钟超时)/LayerHolder 非托管内存管理
- pavo_backend.dart:全部 ffi 调用与像素转换跑在 Isolate.run,主 isolate HTTP 服务零阻塞
- lib/image/card_image.dart:PNG data URL → 纵横比选卡面 → 手动 alpha 铺白底 → BGR24/Gray8 紧凑像素(image 包 compositeImage 对全透明像素非 src-over 语义,改为逐像素混合对齐 C#)
- windows/ 目录:从 Flutter SDK windows.tmpl 手动实例化(mac 上 flutter create 拒绝生成的绕过),窗口标题"饭卡打印助手"
- windows/vendor/:收录 SDK 的 PavoApiW_x64.dll/PavoCardSDK_x64.dll/HeatTB3.dll/heatthcd.bin,CMake POST_BUILD 自动拷到 exe 旁
- backend.dart 工厂接通 Windows 分支;analyze 零问题、单测 12 个全过
2026-09-21 12:19:07 +08:00

99 lines
3.9 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'dart:convert';
import 'dart:typed_data';
import 'package:desktop_plugin/image/card_image.dart';
import 'package:desktop_plugin/print/pavo/pavo_ffi.dart';
import 'package:desktop_plugin/print/pavo/pavo_printer.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:image/image.dart';
String dataUrl(Image img) => 'data:image/png;base64,${base64.encode(encodePng(img))}';
void main() {
group('CardImage 像素层转换', () {
test('横向图缩放到 1014×642,纯红转 BGR 字节序正确', () {
final img = Image(width: 100, height: 50);
fill(img, color: ColorRgb8(255, 0, 0));
final card = CardImage.fromDataUrl(dataUrl(img));
expect(card.isLandscape, isTrue);
expect(card.width, 1014);
expect(card.height, 642);
final bgr = card.toBgr24();
expect(bgr.length, 1014 * 642 * 3);
// 红色像素 → BGR 序 [B=0, G=0, R=255]
expect(bgr[0], 0);
expect(bgr[1], 0);
expect(bgr[2], 255);
// 中间像素一致(无行对齐错位/跨行污染)
final mid = (642 ~/ 2) * 1014 * 3 + (1014 ~/ 2) * 3;
expect(bgr[mid], 0);
expect(bgr[mid + 1], 0);
expect(bgr[mid + 2], 255);
});
test('纵向图缩放到 642×1014,纯蓝转 BGR 正确', () {
final img = Image(width: 50, height: 100);
fill(img, color: ColorRgb8(0, 0, 255));
final card = CardImage.fromDataUrl(dataUrl(img));
expect(card.isLandscape, isFalse);
expect(card.width, 642);
expect(card.height, 1014);
final bgr = card.toBgr24();
// 蓝色像素 → BGR 序 [B=255, G=0, R=0]
expect(bgr[0], 255);
expect(bgr[1], 0);
expect(bgr[2], 0);
});
test('透明像素铺白,避免黑底', () {
// 注意:image v4 的 Image() 默认是 3 通道不透明黑,透明图必须显式 numChannels: 4
final img = Image(width: 100, height: 50, numChannels: 4); // RGBA(0,0,0,0) 全透明
final card = CardImage.fromDataUrl(dataUrl(img));
final bgr = card.toBgr24();
expect(bgr[0], 255);
expect(bgr[1], 255);
expect(bgr[2], 255);
});
test('灰度转换:红 ≈ 76、白 = 255(K 层白底黑字语义)', () {
final red = Image(width: 100, height: 50);
fill(red, color: ColorRgb8(255, 0, 0));
final card = CardImage.fromDataUrl(dataUrl(red));
final gray = card.toGray8();
expect(gray.length, 1014 * 642);
expect(gray[0], 255 * 299 ~/ 1000); // = 76
expect(gray.every((g) => g == 76), isTrue);
final white = Image(width: 100, height: 50);
fill(white, color: ColorRgb8(255, 255, 255));
expect(CardImage.fromDataUrl(dataUrl(white)).toGray8()[0], 255);
});
test('空 data URL 报错', () {
expect(() => CardImage.fromDataUrl(''), throwsArgumentError);
});
});
group('PavoPrinter 纯 Dart 工具', () {
test('decodeAuto 识别 UTF-8 / UTF-16 打印机名', () {
// 纯 ASCII:UTF-8 解码即可正确还原(NUL 计入可打印率,两种编码都可能命中 UTF-8 路径)
final ascii = Uint8List.fromList('HiTi CS-200e'.codeUnits);
expect(PavoPrinter.decodeAuto(ascii).startsWith('HiTi CS-200e'), isTrue);
// 纯中文:UTF-8 解码得乱码(可打印率低),走 UTF-16 路径正确还原
// (ASCII 混中文时 NUL 也计入可打印率,可能仍走 UTF-8 路径——与 C# 行为一致)
final name = '证卡打印机';
final bytes = <int>[];
for (final c in name.codeUnits) {
bytes..add(c & 0xff)..add(c >> 8);
}
expect(PavoPrinter.decodeAuto(Uint8List.fromList(bytes)), name);
});
test('statusTextOf 状态文案', () {
expect(PavoPrinter.statusTextOf(0), '就绪');
expect(PavoPrinter.statusTextOf(PavoApi.dsOutOfRibbon), '色带已用尽,请更换色带');
expect(PavoPrinter.statusTextOf(0x12345678), contains('设备状态异常'));
});
});
}