d3b6026bfd
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common) - Patched Flutter 3.44 / Dart 3.12 compatibility: * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64 * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0 * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64 - Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter - Verified flutter build macos --debug and --release both produce working .app - Verified .dmg installer (27MB arm64) created via hdiutil - Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
134 lines
3.2 KiB
Dart
134 lines
3.2 KiB
Dart
import 'dart:typed_data';
|
|
import 'dart:ui' as ui;
|
|
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
import 'package:flutter_hbb/common.dart';
|
|
|
|
Future<ui.Image?> decodeImageFromPixels(
|
|
Uint8List pixels,
|
|
int width,
|
|
int height,
|
|
ui.PixelFormat format, {
|
|
int? rowBytes,
|
|
int? targetWidth,
|
|
int? targetHeight,
|
|
bool allowUpscaling = true,
|
|
}) async {
|
|
if (targetWidth != null) {
|
|
assert(allowUpscaling || targetWidth <= width);
|
|
if (!(allowUpscaling || targetWidth <= width)) {
|
|
print("not allow upscaling but targetWidth > width");
|
|
return null;
|
|
}
|
|
}
|
|
if (targetHeight != null) {
|
|
assert(allowUpscaling || targetHeight <= height);
|
|
if (!(allowUpscaling || targetHeight <= height)) {
|
|
print("not allow upscaling but targetHeight > height");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
final ui.ImmutableBuffer buffer;
|
|
try {
|
|
buffer = await ui.ImmutableBuffer.fromUint8List(pixels);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
|
|
final ui.ImageDescriptor descriptor;
|
|
try {
|
|
descriptor = ui.ImageDescriptor.raw(
|
|
buffer,
|
|
width: width,
|
|
height: height,
|
|
rowBytes: rowBytes,
|
|
pixelFormat: format,
|
|
);
|
|
if (!allowUpscaling) {
|
|
if (targetWidth != null && targetWidth > descriptor.width) {
|
|
targetWidth = descriptor.width;
|
|
}
|
|
if (targetHeight != null && targetHeight > descriptor.height) {
|
|
targetHeight = descriptor.height;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
print("ImageDescriptor.raw failed: $e");
|
|
buffer.dispose();
|
|
return null;
|
|
}
|
|
|
|
final ui.Codec codec;
|
|
try {
|
|
codec = await descriptor.instantiateCodec(
|
|
targetWidth: targetWidth,
|
|
targetHeight: targetHeight,
|
|
);
|
|
} catch (e) {
|
|
print("instantiateCodec failed: $e");
|
|
buffer.dispose();
|
|
descriptor.dispose();
|
|
return null;
|
|
}
|
|
|
|
final ui.FrameInfo frameInfo;
|
|
try {
|
|
frameInfo = await codec.getNextFrame();
|
|
} catch (e) {
|
|
print("getNextFrame failed: $e");
|
|
codec.dispose();
|
|
buffer.dispose();
|
|
descriptor.dispose();
|
|
return null;
|
|
}
|
|
|
|
codec.dispose();
|
|
buffer.dispose();
|
|
descriptor.dispose();
|
|
return frameInfo.image;
|
|
}
|
|
|
|
class ImagePainter extends CustomPainter {
|
|
ImagePainter({
|
|
required this.image,
|
|
required this.x,
|
|
required this.y,
|
|
required this.scale,
|
|
});
|
|
|
|
ui.Image? image;
|
|
double x;
|
|
double y;
|
|
double scale;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
if (image == null) return;
|
|
if (x.isNaN || y.isNaN) return;
|
|
canvas.scale(scale, scale);
|
|
// https://github.com/flutter/flutter/issues/76187#issuecomment-784628161
|
|
// https://api.flutter-io.cn/flutter/dart-ui/FilterQuality.html
|
|
var paint = Paint();
|
|
if ((scale - 1.0).abs() > 0.001) {
|
|
paint.filterQuality = FilterQuality.medium;
|
|
if (scale > 10.00000) {
|
|
paint.filterQuality = FilterQuality.high;
|
|
}
|
|
}
|
|
// It's strange that if (scale < 0.5 && paint.filterQuality == FilterQuality.medium)
|
|
// The canvas.drawImage will not work on web
|
|
if (isWeb) {
|
|
paint.filterQuality = FilterQuality.high;
|
|
}
|
|
canvas.drawImage(
|
|
image!, Offset(x.toInt().toDouble(), y.toInt().toDouble()), paint);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
return oldDelegate != this;
|
|
}
|
|
}
|