Files
Alhan 32fb12c210
Build & Release / build-linux (push) Canceled after 0s
Build & Release / build-windows (push) Canceled after 0s
Build & Release / create-release (push) Canceled after 0s
feat: zoom percentage badge at bottom center (v1.7.1)
- Percentage shown between the prev/next buttons, together with the hover
  controls, on a translucent background.
- Value is the on-screen scale relative to the image's real pixel size
  (100% = 1:1); updated on wheel zoom, fill/fit toggle, image change and
  window resize.
- Pixel-size header parsing moved to lib/services/image_header.dart, shared
  with the settings file-properties panel.
- dist: 1.7.1 .deb replaces the tracked 1.7.0 package.
2026-10-25 18:53:59 +03:00

81 lines
2.7 KiB
Dart
Raw Permalink 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:io';
import 'dart:typed_data';
import 'package:flutter/widgets.dart' show Size;
import 'package:image/image.dart' as img;
/// Görüntü dosyasının gerçek piksel boyutu — tam decode yapmadan.
///
/// PNG/GIF/BMP/WebP: boyut ilk 33 baytta → elle parse.
/// JPEG: SOF büyük APP/EXIF segmentlerinin ardından gelebilir → package:image startDecode.
Size? pixelSizeOfFile(String path) {
try {
final file = File(path);
final stat = file.statSync();
const maxHead = 512 * 1024;
final raf = file.openSync();
final header = raf.readSync(stat.size < maxHead ? stat.size : maxHead);
raf.closeSync();
return _headerPixelSize(header);
} catch (_) {}
return null;
}
Size? _headerPixelSize(Uint8List b) {
try {
if (b.length >= 24 && b[0] == 0x89 && b[1] == 0x50) {
// PNG
final w = (b[16] << 24) | (b[17] << 16) | (b[18] << 8) | b[19];
final h = (b[20] << 24) | (b[21] << 16) | (b[22] << 8) | b[23];
return Size(w.toDouble(), h.toDouble());
}
if (b.length >= 10 && b[0] == 0x47 && b[1] == 0x49 && b[2] == 0x46) {
// GIF (WBMP da GIF tabanlı olabilir)
final w = b[6] | (b[7] << 8);
final h = b[8] | (b[9] << 8);
return Size(w.toDouble(), h.toDouble());
}
if (b.length >= 26 && b[0] == 0x42 && b[1] == 0x4D) {
// BMP
final w = b[18] | (b[19] << 8) | (b[20] << 16) | (b[21] << 24);
final h = b[22] | (b[23] << 8) | (b[24] << 16) | (b[25] << 24);
return Size(w.toDouble(), h.abs().toDouble());
}
if (b.length >= 30 &&
b[0] == 0x52 &&
b[1] == 0x49 &&
b[2] == 0x46 &&
b[3] == 0x46 &&
b[8] == 0x57 &&
b[9] == 0x45 &&
b[10] == 0x42 &&
b[11] == 0x50) {
// WebP
if (b[12] == 0x56 && b[13] == 0x50 && b[15] == 0x58) {
// VP8X
final w = b[24] | (b[25] << 8) | (b[26] << 16);
final h = b[27] | (b[28] << 8) | (b[29] << 16);
return Size((w + 1).toDouble(), (h + 1).toDouble());
}
if (b.length >= 25 && b[12] == 0x56 && b[13] == 0x50 && b[15] == 0x4C && b[20] == 0x2F) {
// VP8L
final w = (b[21] & 0x3F) | ((b[22] & 0x0F) << 6);
final h = (b[23] & 0x3F) | ((b[24] & 0x0F) << 6);
return Size((w + 1).toDouble(), (h + 1).toDouble());
}
if (b[12] == 0x56 && b[13] == 0x50 && b[15] == 0x20) {
// VP8 (lossy)
final w = (b[26] | (b[27] << 8)) & 0x3FFF;
final h = (b[28] | (b[29] << 8)) & 0x3FFF;
return Size(w.toDouble(), h.toDouble());
}
}
} catch (_) {}
try {
// JPEG
final info = img.JpegDecoder().startDecode(b);
if (info != null) return Size(info.width.toDouble(), info.height.toDouble());
} catch (_) {}
return null;
}