Files
imajviewer/tool/crop_test.dart
T
Alhan c34a3bfd95
Build & Release / build-linux (push) Has been cancelled
Build & Release / build-windows (push) Has been cancelled
Build & Release / create-release (push) Has been cancelled
fix: crop save always JPEG q93 + save rotated view 1:1 (v1.4.1)
- Output extension is always .jpg regardless of source format (was: PNG in -> PNG out)
- Rotation now saved correctly: viewport grid resampled bilinearly in source
  space (was: unrotated bounding box copy)
- Quality 90 -> 93; l10n strings updated (JPEG 93)
- New: tool/crop_test.dart — pure-Dart end-to-end test (dart run tool/crop_test.dart)
2026-10-11 22:16:25 +03:00

89 lines
3.9 KiB
Dart

import 'dart:io';
import 'package:image/image.dart' as img;
import 'package:imajviewer/services/crop_save_service.dart';
Future<void> main() async {
final tmp = Directory.systemTemp.createTempSync('crop_test');
final srcPath = '${tmp.path}/test.png';
final src = img.Image(width: 100, height: 50);
void fill(int x, int y, int r, int g, int b) {
for (var dy = 0; dy < 5; dy++)
for (var dx = 0; dx < 5; dx++) src.setPixelRgb(x + dx, y + dy, r, g, b);
}
fill(0, 0, 255, 0, 0); // sol-ust: KIRMIZI
fill(95, 0, 0, 255, 0); // sag-ust: YESIL
fill(0, 45, 0, 0, 255); // sol-alt: MAVI
fill(95, 45, 255, 255, 0); // sag-alt: SARI
File(srcPath).writeAsBytesSync(img.encodePng(src)!);
var fails = 0;
void checkPix(String label, (int, int, int) px, int r, int g, int b) {
int d(int a, int c) => (a - c).abs();
final ok = d(px.$1, r) <= 60 && d(px.$2, g) <= 60 && d(px.$3, b) <= 60;
if (!ok) fails++;
print('${ok ? 'OK ' : 'FAIL'} $label: got ${px.$1},${px.$2},${px.$3} want ~$r,$g,$b');
}
// 1) Duz, fit, zoom yok: gorunen = kaynakin kendisi
final outDir1 = '${tmp.path}/a';
Directory(outDir1).createSync();
final f1 = '${outDir1}/src.jpg';
File(f1).writeAsBytesSync(File(srcPath).readAsBytesSync());
final p1 = CropViewParams(w: 100, h: 50, vw: 100, vh: 50, tx: 0, ty: 0, sc: 1,
angleDeg: 0, cx: 50, cy: 25, k: 1, ox: 0, oy: 0);
final path1 = await CropSaveService.saveCrop(srcPath: f1, source: await CropSaveService.load(f1), vp: p1);
final r1 = img.decodeImage(File(path1).readAsBytesSync())!;
print('1) dims ${r1.width}x${r1.height} (100x50 beklenir)');
if (r1.width != 100 || r1.height != 50 || !path1.endsWith('.jpg')) fails++;
checkPix('1) sol-ust', imgPx(r1, 2, 2), 255, 0, 0);
checkPix('1) sag-alt', imgPx(r1, 97, 47), 255, 255, 0);
// 2) 90 derece saat yelkolevi: cikti 50x100, orij sol-alt -> yeni sol-ust
final out2 = '${tmp.path}/b';
Directory(out2).createSync();
final f2 = '$out2/src.jpg';
File(f2).writeAsBytesSync(File(srcPath).readAsBytesSync());
final p2 = CropViewParams(w: 100, h: 50, vw: 50, vh: 100, tx: 0, ty: 0, sc: 1,
angleDeg: 90, cx: 25, cy: 50, k: 1, ox: -25, oy: 25);
final path2 = await CropSaveService.saveCrop(srcPath: f2, source: await CropSaveService.load(f2), vp: p2);
final r2 = img.decodeImage(File(path2).readAsBytesSync())!;
print('2) dims ${r2.width}x${r2.height} (50x100 beklenir)');
if (r2.width != 50 || r2.height != 100) fails++;
checkPix('2) sol-ust (orij sol-alt MAVI)', imgPx(r2, 2, 2), 0, 0, 255);
checkPix('2) sag-ust (orij sol-ust KIRMIZI)', imgPx(r2, 47, 2), 255, 0, 0);
checkPix('2) sol-alt (orij sag-alt SARI)', imgPx(r2, 2, 97), 255, 255, 0);
checkPix('2) sag-alt (orij sag-ust YESIL)', imgPx(r2, 47, 97), 0, 255, 0);
// 3) Zoom x2, 45 derece, fill: orneklenen alan ortada
final out3 = '${tmp.path}/c';
Directory(out3).createSync();
final f3 = '$out3/src.jpg';
File(f3).writeAsBytesSync(File(srcPath).readAsBytesSync());
final p3 = CropViewParams(w: 100, h: 50, vw: 100, vh: 100, tx: 0, ty: 0, sc: 2,
angleDeg: 45, cx: 50, cy: 50, k: 2, ox: 0, oy: -25);
final path3 = await CropSaveService.saveCrop(srcPath: f3, source: await CropSaveService.load(f3), vp: p3);
final r3 = img.decodeImage(File(path3).readAsBytesSync())!;
print('3) dims ${r3.width}x${r3.height} (25x25 beklenir: zoom x2 + fill k=2 -> 4 src px/ekran px)');
if (r3.width != 25 || r3.height != 25) fails++;
tmp.deleteSync(recursive: true);
print(fails == 0 ? 'ALL PASS' : '$fails FAILURES');
exitCode = fails == 0 ? 0 : 1;
}
// jpeg kaybi oldugu icin 5x5 bolge ortalamasi al
(int, int, int) imgPx(img.Image im, int x, int y) {
int avg(int f) {
var s = 0, n = 0;
for (var dy = -2; dy <= 2; dy++)
for (var dx = -2; dx <= 2; dx++) {
final px = im.getPixelClamped(x + dx, y + dy);
s += f == 0 ? px.r.toInt() : (f == 1 ? px.g.toInt() : px.b.toInt());
n++;
}
return s ~/ n;
}
return (avg(0), avg(1), avg(2));
}