Package Version
12.4.8
Flutter Version
3.44.0
Platforms
iOS
How to reproduce?
When opening ProImageEditor with the crop/rotate editor configured for an oval crop at a 1:1 aspect ratio, the main editor displays the oval overlay stretched to the full image bounds (an ellipse for any non-square image) and the exported result is an ellipse, not a circle.
initAspectRatio is only applied inside the crop/rotate sub-editor (crop_rotate_editor.dart:438). The main editor initializes its history with an empty transform and only the crop mode:
// features/main_editor/main_editor.dart:560
transformConfigs: TransformConfigs.empty().copyWith(
cropMode: cropRotateEditorConfigs.initialCropMode,
),
So initAspectRatio is never consulted for the initial state. The overlay painter then falls back to the full image aspect ratio:
// shared/widgets/layer/layer_stack.dart:131
final imgRatio = _transformConfigs?.cropRect.size.aspectRatio ??
transformHelper.mainImageSize.aspectRatio; // <- portrait/landscape ratio
If the user exports without first entering the crop sub-editor, CutOutsideArea clips with the empty-config branch (full image), producing an ellipse:
// shared/widgets/transform/transformed_content_generator.dart:220
if (configs.isEmpty && cropMode == CropMode.oval) {
cropRect = Rect.fromLTWH(0, 0, size.width, size.height);
}
Steps to reproduce
Open ProImageEditor.memory with a non-square image.
Use the config below.
Observe the main editor: oval overlay fills the whole image (ellipse).
Tap done without entering Crop/Rotate → exported image is an ellipse, not a circle.
ProImageEditor.memory(
imageBytes,
callbacks: ProImageEditorCallbacks(
onImageEditingComplete: (bytes) async => Navigator.pop(context, bytes),
),
configs: ProImageEditorConfigs(
cropRotateEditor: CropRotateEditorConfigs(
initialCropMode: CropMode.oval,
initAspectRatio: 1.0,
tools: [CropRotateTool.flip, CropRotateTool.rotate],
),
),
);
Expected
With initAspectRatio: 1.0 + initialCropMode: CropMode.oval, the main editor's initial crop should be a centered square, so the overlay and export are a circle without requiring the user to open the crop sub-editor.
Actual
Overlay and exported image are an ellipse spanning the full image bounds. initAspectRatio has no effect on the main editor's initial state.
Workaround
Use the standalone CropRotateEditor.memory instead of the full ProImageEditor. There initAspectRatio: 1.0 is honored → calcCropRect produces a square cropRect → ClipOval over a square = circle.
Environment
Platform: iOS 26.x (iPhone 17 Pro Max simulator), Xcode 26.3
Example code (optional)
ProImageEditor.memory(
imageBytes,
callbacks: ProImageEditorCallbacks(
onImageEditingComplete: (bytes) async => Navigator.pop(context, bytes),
),
configs: ProImageEditorConfigs(
cropRotateEditor: CropRotateEditorConfigs(
initialCropMode: CropMode.oval,
initAspectRatio: 1.0,
tools: [CropRotateTool.flip, CropRotateTool.rotate],
),
),
);
Device Model (optional)
No response
Package Version
12.4.8
Flutter Version
3.44.0
Platforms
iOS
How to reproduce?
When opening ProImageEditor with the crop/rotate editor configured for an oval crop at a 1:1 aspect ratio, the main editor displays the oval overlay stretched to the full image bounds (an ellipse for any non-square image) and the exported result is an ellipse, not a circle.
initAspectRatio is only applied inside the crop/rotate sub-editor (crop_rotate_editor.dart:438). The main editor initializes its history with an empty transform and only the crop mode:
// features/main_editor/main_editor.dart:560
transformConfigs: TransformConfigs.empty().copyWith(
cropMode: cropRotateEditorConfigs.initialCropMode,
),
So initAspectRatio is never consulted for the initial state. The overlay painter then falls back to the full image aspect ratio:
// shared/widgets/layer/layer_stack.dart:131
final imgRatio = _transformConfigs?.cropRect.size.aspectRatio ??
transformHelper.mainImageSize.aspectRatio; // <- portrait/landscape ratio
If the user exports without first entering the crop sub-editor, CutOutsideArea clips with the empty-config branch (full image), producing an ellipse:
// shared/widgets/transform/transformed_content_generator.dart:220
if (configs.isEmpty && cropMode == CropMode.oval) {
cropRect = Rect.fromLTWH(0, 0, size.width, size.height);
}
Steps to reproduce
Open ProImageEditor.memory with a non-square image.
Use the config below.
Observe the main editor: oval overlay fills the whole image (ellipse).
Tap done without entering Crop/Rotate → exported image is an ellipse, not a circle.
ProImageEditor.memory(
imageBytes,
callbacks: ProImageEditorCallbacks(
onImageEditingComplete: (bytes) async => Navigator.pop(context, bytes),
),
configs: ProImageEditorConfigs(
cropRotateEditor: CropRotateEditorConfigs(
initialCropMode: CropMode.oval,
initAspectRatio: 1.0,
tools: [CropRotateTool.flip, CropRotateTool.rotate],
),
),
);
Expected
With initAspectRatio: 1.0 + initialCropMode: CropMode.oval, the main editor's initial crop should be a centered square, so the overlay and export are a circle without requiring the user to open the crop sub-editor.
Actual
Overlay and exported image are an ellipse spanning the full image bounds. initAspectRatio has no effect on the main editor's initial state.
Workaround
Use the standalone CropRotateEditor.memory instead of the full ProImageEditor. There initAspectRatio: 1.0 is honored → calcCropRect produces a square cropRect → ClipOval over a square = circle.
Environment
Platform: iOS 26.x (iPhone 17 Pro Max simulator), Xcode 26.3
Example code (optional)
Device Model (optional)
No response