From ec4a8b7b455ec005d7ec40ca9a8f60733507c978 Mon Sep 17 00:00:00 2001 From: wanpat anantapan Date: Mon, 19 Jan 2026 09:06:22 +0700 Subject: [PATCH 1/2] add function transformMatrix --- example/ios/Podfile.lock | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 8 ++--- .../xcshareddata/xcschemes/Runner.xcscheme | 4 +-- .../widgets/preview/awesome_preview_fit.dart | 30 ++++++++++++++++--- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index a619d635..7a6a8c0a 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -148,7 +148,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: camerawesome: a961fa32dafc00d2f093d824311c84f849586b58 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 google_mlkit_barcode_scanning: 8f5987f244a43fe1167689c548342a5174108159 google_mlkit_commons: 2abe6a70e1824e431d16a51085cb475b672c8aab google_mlkit_face_detection: 754da2113a1952f063c7c5dc347ac6ae8934fb77 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index bb268500..e03d7c50 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 54; + objectVersion = 60; objects = { /* Begin PBXBuildFile section */ @@ -245,7 +245,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -775,7 +775,7 @@ CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = Q8N2T428YG; + DEVELOPMENT_TEAM = RDYY3LBWQM; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -826,7 +826,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index f12603cc..8c8f8629 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,7 +1,7 @@ + version = "1.7"> @@ -69,7 +69,7 @@ { } } +typedef FuncTransformMatrix = Matrix4 Function(PreviewSize size, double scale); + class PreviewFitWidget extends StatelessWidget { final Alignment alignment; final BoxConstraints constraints; @@ -131,8 +133,25 @@ class PreviewFitWidget extends StatelessWidget { final double scale; final Size maxSize; final EdgeInsets? previewPadding; - - const PreviewFitWidget({ + // ignore: prefer_function_declarations_over_variables + final FuncTransformMatrix? transformMatrix = + (PreviewSize size, double scale) { + double h = (size.width * 4.0) / 3.0; + double diff = size.height - h; + if (diff <= 0) { + debugPrint('A diff w:${size.width} h:${size.height} diff:${diff} '); + return Matrix4.identity()..scale(scale); + } + double imageHeightDivided = size.height / 2.0; + double localX = imageHeightDivided - ((imageHeightDivided * 3.0) / 4.0); + //double diffTop = (diff * scale) / 2.0; + debugPrint('B w:${size.width} h:${size.height} localX:${localX}'); + return Matrix4.identity() + ..scale(scale) + ..translate(0.0, -(localX)); + }; + + PreviewFitWidget({ super.key, required this.alignment, required this.constraints, @@ -146,8 +165,11 @@ class PreviewFitWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final transformController = TransformationController() - ..value = (Matrix4.identity()..scale(scale)); + var mx = Matrix4.identity()..scale(scale); + if (transformMatrix != null) { + mx = transformMatrix!(previewSize, scale); + } + final transformController = TransformationController()..value = (mx); return Align( alignment: alignment, From 2aaedaaee275e632cd3b6cd203f856b9891c84c5 Mon Sep 17 00:00:00 2001 From: wanpat anantapan Date: Mon, 19 Jan 2026 11:55:02 +0700 Subject: [PATCH 2/2] add transformMatrix --- lib/src/widgets/camera_awesome_builder.dart | 59 +++++++++++-------- .../awesome_camera_floating_preview.dart | 3 + .../preview/awesome_camera_preview.dart | 4 ++ .../widgets/preview/awesome_preview_fit.dart | 26 +++----- 4 files changed, 50 insertions(+), 42 deletions(-) diff --git a/lib/src/widgets/camera_awesome_builder.dart b/lib/src/widgets/camera_awesome_builder.dart index e614f4da..c9474b39 100644 --- a/lib/src/widgets/camera_awesome_builder.dart +++ b/lib/src/widgets/camera_awesome_builder.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:camerawesome/camerawesome_plugin.dart'; import 'package:camerawesome/pigeon.dart'; import 'package:camerawesome/src/orchestrator/camera_context.dart'; +import 'package:camerawesome/src/widgets/preview/awesome_preview_fit.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -118,6 +119,8 @@ class CameraAwesomeBuilder extends StatefulWidget { /// You can use it to do whatever you want once a media has been saved final OnMediaCaptureEvent? onMediaCaptureEvent; + final FuncTransformMatrix? transformMatrix; + const CameraAwesomeBuilder._({ required this.sensorConfig, required this.enablePhysicalButton, @@ -127,6 +130,7 @@ class CameraAwesomeBuilder extends StatefulWidget { required this.builder, required this.previewFit, required this.defaultFilter, + required this.transformMatrix, this.onImageForAnalysis, this.imageAnalysisConfig, this.onPreviewTapBuilder, @@ -162,29 +166,30 @@ class CameraAwesomeBuilder extends StatefulWidget { /// If you want to do image analysis (for AI for instance), you can set the /// [imageAnaysisConfig] and listen to the stream of images with /// [onImageForAnalysis]. - CameraAwesomeBuilder.awesome( - {SensorConfig? sensorConfig, - bool enablePhysicalButton = false, - Widget? progressIndicator, - required SaveConfig saveConfig, - Function(MediaCapture)? onMediaTap, - OnImageForAnalysis? onImageForAnalysis, - AnalysisConfig? imageAnalysisConfig, - OnPreviewTap Function(CameraState)? onPreviewTapBuilder, - OnPreviewScale Function(CameraState)? onPreviewScaleBuilder, - CameraPreviewFit? previewFit, - CameraLayoutBuilder? previewDecoratorBuilder, - AwesomeTheme? theme, - Widget Function(CameraState state)? topActionsBuilder, - Widget Function(CameraState state)? bottomActionsBuilder, - Widget Function(CameraState state)? middleContentBuilder, - EdgeInsets previewPadding = EdgeInsets.zero, - Alignment previewAlignment = Alignment.center, - PictureInPictureConfigBuilder? pictureInPictureConfigBuilder, - AwesomeFilter? defaultFilter, - List? availableFilters, - OnMediaCaptureEvent? onMediaCaptureEvent}) - : this._( + CameraAwesomeBuilder.awesome({ + SensorConfig? sensorConfig, + bool enablePhysicalButton = false, + Widget? progressIndicator, + required SaveConfig saveConfig, + Function(MediaCapture)? onMediaTap, + OnImageForAnalysis? onImageForAnalysis, + AnalysisConfig? imageAnalysisConfig, + OnPreviewTap Function(CameraState)? onPreviewTapBuilder, + OnPreviewScale Function(CameraState)? onPreviewScaleBuilder, + CameraPreviewFit? previewFit, + CameraLayoutBuilder? previewDecoratorBuilder, + AwesomeTheme? theme, + Widget Function(CameraState state)? topActionsBuilder, + Widget Function(CameraState state)? bottomActionsBuilder, + Widget Function(CameraState state)? middleContentBuilder, + EdgeInsets previewPadding = EdgeInsets.zero, + Alignment previewAlignment = Alignment.center, + PictureInPictureConfigBuilder? pictureInPictureConfigBuilder, + AwesomeFilter? defaultFilter, + List? availableFilters, + OnMediaCaptureEvent? onMediaCaptureEvent, + FuncTransformMatrix? transformMatrix, + }) : this._( sensorConfig: sensorConfig ?? SensorConfig.single( sensor: Sensor.position(SensorPosition.back), @@ -215,6 +220,7 @@ class CameraAwesomeBuilder extends StatefulWidget { defaultFilter: defaultFilter, availableFilters: availableFilters ?? awesomePresetFiltersList, onMediaCaptureEvent: onMediaCaptureEvent, + transformMatrix: transformMatrix, ); /// 🚧 Experimental @@ -239,6 +245,7 @@ class CameraAwesomeBuilder extends StatefulWidget { PictureInPictureConfigBuilder? pictureInPictureConfigBuilder, List? filters, OnMediaCaptureEvent? onMediaCaptureEvent, + FuncTransformMatrix? transformMatrix, }) : this._( sensorConfig: sensorConfig ?? SensorConfig.single( @@ -262,6 +269,7 @@ class CameraAwesomeBuilder extends StatefulWidget { pictureInPictureConfigBuilder: pictureInPictureConfigBuilder, availableFilters: filters, onMediaCaptureEvent: onMediaCaptureEvent, + transformMatrix: transformMatrix, ); /// Use this constructor when you don't want to take pictures or record videos. @@ -279,6 +287,7 @@ class CameraAwesomeBuilder extends StatefulWidget { EdgeInsets previewPadding = EdgeInsets.zero, Alignment previewAlignment = Alignment.center, PictureInPictureConfigBuilder? pictureInPictureConfigBuilder, + FuncTransformMatrix? transformMatrix, }) : this._( sensorConfig: sensorConfig ?? SensorConfig.single(sensor: Sensor.position(SensorPosition.back)), @@ -298,6 +307,7 @@ class CameraAwesomeBuilder extends StatefulWidget { previewPadding: previewPadding, previewAlignment: previewAlignment, pictureInPictureConfigBuilder: pictureInPictureConfigBuilder, + transformMatrix: transformMatrix, ); /// Use this constructor when you only want to do image analysis. @@ -314,6 +324,7 @@ class CameraAwesomeBuilder extends StatefulWidget { required CameraLayoutBuilder builder, required OnImageForAnalysis onImageForAnalysis, AnalysisConfig? imageAnalysisConfig, + FuncTransformMatrix? transformMatrix, }) : this._( sensorConfig: sensorConfig ?? SensorConfig.single(sensor: Sensor.position(SensorPosition.back)), @@ -334,6 +345,7 @@ class CameraAwesomeBuilder extends StatefulWidget { previewAlignment: Alignment.center, showPreview: false, pictureInPictureConfigBuilder: null, + transformMatrix: transformMatrix, ); @override @@ -446,6 +458,7 @@ class _CameraWidgetBuilder extends State state: snapshot.requireData, padding: widget.previewPadding, alignment: widget.previewAlignment, + transformMatrix: widget.transformMatrix, onPreviewTap: widget.onPreviewTapBuilder ?.call(snapshot.requireData) ?? OnPreviewTap( diff --git a/lib/src/widgets/preview/awesome_camera_floating_preview.dart b/lib/src/widgets/preview/awesome_camera_floating_preview.dart index de1bbb54..c2a55e44 100644 --- a/lib/src/widgets/preview/awesome_camera_floating_preview.dart +++ b/lib/src/widgets/preview/awesome_camera_floating_preview.dart @@ -10,6 +10,7 @@ class AwesomeCameraFloatingPreview extends StatefulWidget { final double aspectRatio; final Sensor sensor; final PictureInPictureConfig pictureInPictureConfig; + final FuncTransformMatrix? transformMatrix; AwesomeCameraFloatingPreview({ super.key, @@ -17,6 +18,7 @@ class AwesomeCameraFloatingPreview extends StatefulWidget { required this.sensor, required this.texture, required this.aspectRatio, + required this.transformMatrix, PictureInPictureConfig? pictureInPictureConfig, }) : pictureInPictureConfig = pictureInPictureConfig ?? PictureInPictureConfig(sensor: sensor); @@ -58,6 +60,7 @@ class _AwesomeCameraFloatingPreviewState : null, child: widget.pictureInPictureConfig.pictureInPictureBuilder( AnimatedPreviewFit( + transformMatrix: widget.transformMatrix, previewFit: CameraPreviewFit.cover, previewSize: PreviewSize( width: 1000, diff --git a/lib/src/widgets/preview/awesome_camera_preview.dart b/lib/src/widgets/preview/awesome_camera_preview.dart index 0fac6711..4f73c12a 100644 --- a/lib/src/widgets/preview/awesome_camera_preview.dart +++ b/lib/src/widgets/preview/awesome_camera_preview.dart @@ -28,6 +28,7 @@ class AwesomeCameraPreview extends StatefulWidget { final EdgeInsets padding; final Alignment alignment; final PictureInPictureConfigBuilder? pictureInPictureConfigBuilder; + final FuncTransformMatrix? transformMatrix; const AwesomeCameraPreview({ super.key, @@ -40,6 +41,7 @@ class AwesomeCameraPreview extends StatefulWidget { this.previewDecoratorBuilder, required this.padding, required this.alignment, + required this.transformMatrix, this.pictureInPictureConfigBuilder, }); @@ -161,6 +163,7 @@ class AwesomeCameraPreviewState extends State { children: [ Positioned.fill( child: AnimatedPreviewFit( + transformMatrix: widget.transformMatrix, alignment: widget.alignment, previewFit: widget.previewFit, previewSize: _previewSize!, @@ -246,6 +249,7 @@ class AwesomeCameraPreviewState extends State { final texture = _textures[i]; final sensor = sensors[kDebugMode ? 0 : i]; final frame = AwesomeCameraFloatingPreview( + transformMatrix: widget.transformMatrix, index: i, sensor: sensor, texture: texture, diff --git a/lib/src/widgets/preview/awesome_preview_fit.dart b/lib/src/widgets/preview/awesome_preview_fit.dart index 4a2ea79d..e8c491c6 100644 --- a/lib/src/widgets/preview/awesome_preview_fit.dart +++ b/lib/src/widgets/preview/awesome_preview_fit.dart @@ -17,6 +17,7 @@ class AnimatedPreviewFit extends StatefulWidget { final Widget child; final OnPreviewCalculated? onPreviewCalculated; final Sensor sensor; + final FuncTransformMatrix? transformMatrix; const AnimatedPreviewFit({ super.key, @@ -26,6 +27,7 @@ class AnimatedPreviewFit extends StatefulWidget { required this.constraints, required this.sensor, required this.child, + required this.transformMatrix, this.onPreviewCalculated, this.previewPadding, }); @@ -108,6 +110,7 @@ class _AnimatedPreviewFitState extends State { constraints: widget.constraints, previewFit: widget.previewFit, previewSize: widget.previewSize, + transformMatrix: widget.transformMatrix, scale: ratio, maxSize: maxSize!, previewPadding: widget.previewPadding, @@ -133,25 +136,9 @@ class PreviewFitWidget extends StatelessWidget { final double scale; final Size maxSize; final EdgeInsets? previewPadding; - // ignore: prefer_function_declarations_over_variables - final FuncTransformMatrix? transformMatrix = - (PreviewSize size, double scale) { - double h = (size.width * 4.0) / 3.0; - double diff = size.height - h; - if (diff <= 0) { - debugPrint('A diff w:${size.width} h:${size.height} diff:${diff} '); - return Matrix4.identity()..scale(scale); - } - double imageHeightDivided = size.height / 2.0; - double localX = imageHeightDivided - ((imageHeightDivided * 3.0) / 4.0); - //double diffTop = (diff * scale) / 2.0; - debugPrint('B w:${size.width} h:${size.height} localX:${localX}'); - return Matrix4.identity() - ..scale(scale) - ..translate(0.0, -(localX)); - }; - - PreviewFitWidget({ + final FuncTransformMatrix? transformMatrix; + + const PreviewFitWidget({ super.key, required this.alignment, required this.constraints, @@ -160,6 +147,7 @@ class PreviewFitWidget extends StatelessWidget { required this.child, required this.scale, required this.maxSize, + required this.transformMatrix, this.previewPadding, });