- R mirrors the view about the viewport centre and clears the active effects (same reset as double right click); pressing R again restores the original orientation. Pan/zoom are kept. - Image switch, fill/fit toggle and right double click also clear the flip. - Crop save (Ctrl+S) mirrors the output too, so the saved JPEG matches the on-screen view (verified in combination with rotation). - Shortcut lists (tr/en), README and CHANGELOG updated; deb rebuilt as 1.6.0.
121 lines
5.8 KiB
Dart
121 lines
5.8 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++;
|
|
|
|
// 4) Yatay aynalama (flipH): gorunum aynalanir, cikti da aynali olmali
|
|
final out4 = '${tmp.path}/d';
|
|
Directory(out4).createSync();
|
|
final f4 = '$out4/src.jpg';
|
|
File(f4).writeAsBytesSync(File(srcPath).readAsBytesSync());
|
|
final p4 = CropViewParams(w: 100, h: 50, vw: 100, vh: 50, tx: 0, ty: 0, sc: 1,
|
|
angleDeg: 0, flipH: true, cx: 50, cy: 25, k: 1, ox: 0, oy: 0);
|
|
final path4 = await CropSaveService.saveCrop(srcPath: f4, source: await CropSaveService.load(f4), vp: p4);
|
|
final r4 = img.decodeImage(File(path4).readAsBytesSync())!;
|
|
print('4) dims ${r4.width}x${r4.height} (100x50 beklenir)');
|
|
if (r4.width != 100 || r4.height != 50) fails++;
|
|
checkPix('4) sol-ust (orij sag-ust YESIL)', imgPx(r4, 2, 2), 0, 255, 0);
|
|
checkPix('4) sag-ust (orij sol-ust KIRMIZI)', imgPx(r4, 97, 2), 255, 0, 0);
|
|
checkPix('4) sol-alt (orij sag-alt SARI)', imgPx(r4, 2, 47), 255, 255, 0);
|
|
checkPix('4) sag-alt (orij sol-alt MAVI)', imgPx(r4, 97, 47), 0, 0, 255);
|
|
|
|
// 5) Donus + aynalama: 2. senaryonun aynasi
|
|
final out5 = '${tmp.path}/e';
|
|
Directory(out5).createSync();
|
|
final f5 = '$out5/src.jpg';
|
|
File(f5).writeAsBytesSync(File(srcPath).readAsBytesSync());
|
|
final p5 = CropViewParams(w: 100, h: 50, vw: 50, vh: 100, tx: 0, ty: 0, sc: 1,
|
|
angleDeg: 90, flipH: true, cx: 25, cy: 50, k: 1, ox: -25, oy: 25);
|
|
final path5 = await CropSaveService.saveCrop(srcPath: f5, source: await CropSaveService.load(f5), vp: p5);
|
|
final r5 = img.decodeImage(File(path5).readAsBytesSync())!;
|
|
print('5) dims ${r5.width}x${r5.height} (50x100 beklenir)');
|
|
if (r5.width != 50 || r5.height != 100) fails++;
|
|
checkPix('5) sol-ust (orij sol-ust KIRMIZI)', imgPx(r5, 2, 2), 255, 0, 0);
|
|
checkPix('5) sag-ust (orij sol-alt MAVI)', imgPx(r5, 47, 2), 0, 0, 255);
|
|
checkPix('5) sol-alt (orij sag-ust YESIL)', imgPx(r5, 2, 97), 0, 255, 0);
|
|
checkPix('5) sag-alt (orij sag-alt SARI)', imgPx(r5, 47, 97), 255, 255, 0);
|
|
|
|
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));
|
|
}
|