-
first i create blank canvas then i want to change it's height , weight and color how can i do it if there is any built in functionality then guide me on that
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
If you just want to change the canvas color and size dynamically, you can do it as in the example below: // Dart imports:
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;
// Flutter imports:
import 'package:example/pages/pick_image_example.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:pro_image_editor/models/history/state_history.dart';
// Package imports:
import 'package:pro_image_editor/pro_image_editor.dart';
// Project imports:
import '../utils/example_helper.dart';
import '../utils/pixel_transparent_painter.dart';
import 'reorder_layer_example.dart';
class MoveableBackgroundImageExample extends StatefulWidget {
const MoveableBackgroundImageExample({super.key});
@override
State<MoveableBackgroundImageExample> createState() =>
_MoveableBackgroundImageExampleState();
}
class _MoveableBackgroundImageExampleState
extends State<MoveableBackgroundImageExample>
with ExampleHelperState<MoveableBackgroundImageExample> {
late final ScrollController _bottomBarScrollCtrl;
final _bottomTextStyle = const TextStyle(fontSize: 10.0, color: Colors.white);
@override
void initState() {
_bottomBarScrollCtrl = ScrollController();
super.initState();
}
@override
void dispose() {
_bottomBarScrollCtrl.dispose();
super.dispose();
}
Future<Uint8List> _createCanvas({
color = Colors.amber,
width = 1000,
height = 1000,
}) async {
final recorder = ui.PictureRecorder();
final canvas = Canvas(
recorder, Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()));
final paint = Paint()..color = color;
canvas.drawRect(
Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()), paint);
final picture = recorder.endRecording();
final img = await picture.toImage(width.toInt(), height.toInt());
final pngBytes = await img.toByteData(format: ui.ImageByteFormat.png);
return pngBytes!.buffer.asUint8List();
}
void _replaceBackground() async {
Color getRandomColor() {
final Random random = Random();
return Color.fromARGB(
255,
random.nextInt(256),
random.nextInt(256),
random.nextInt(256),
);
}
var bytes = await _createCanvas(
color: getRandomColor(),
width: Random().nextInt(500) + 800,
height: Random().nextInt(500) + 800,
);
if (!mounted) return;
await precacheImage(MemoryImage(bytes), context);
editorKey.currentState!.editorImage = EditorImage(byteArray: bytes);
await editorKey.currentState!.decodeImage();
/// Force to rebuild everything
int pos = editorKey.currentState!.stateManager.position;
EditorStateHistory oldHistory =
editorKey.currentState!.stateManager.stateHistory[pos];
editorKey.currentState!.stateManager.stateHistory[pos] = EditorStateHistory(
layers: oldHistory.layers,
transformConfigs: oldHistory.transformConfigs,
blur: oldHistory.blur,
filters: [...oldHistory.filters],
);
/// Ensure that in the case the editor generated
/// in the background a screenshot it will generate
/// it again with the new picture.
if (pos > 0) {
editorKey.currentState!.stateManager.screenshots[pos - 1].broken = true;
}
}
@override
Widget build(BuildContext context) {
return ListTile(
onTap: () async {
LoadingDialog loading = LoadingDialog();
await loading.show(
context,
configs: const ProImageEditorConfigs(),
theme: ThemeData.dark(),
);
var backgroundBytes = await _createCanvas(
color: Colors.amber,
width: 1000,
height: 1000,
);
if (context.mounted) {
await loading.hide(context);
}
if (!context.mounted) return;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
LayoutBuilder(builder: (context, constraints) {
return CustomPaint(
size: Size(constraints.maxWidth, constraints.maxHeight),
painter: const PixelTransparentPainter(
primary: Colors.white,
secondary: Color(0xFFE2E2E2),
),
child: ProImageEditor.memory(
backgroundBytes,
key: editorKey,
callbacks: ProImageEditorCallbacks(
onImageEditingStarted: onImageEditingStarted,
onImageEditingComplete: onImageEditingComplete,
onCloseEditor: onCloseEditor,
),
configs: ProImageEditorConfigs(
designMode: platformDesignMode,
imageGenerationConfigs: ImageGeneratioConfigs(
captureOnlyDrawingBounds: true,
captureOnlyBackgroundImageArea: false,
outputFormat: OutputFormat.png,
/// Set the pixel ratio manually. You can also set this value higher than the device pixel ratio for higher quality.
customPixelRatio: max(
2000 / MediaQuery.of(context).size.width,
MediaQuery.of(context).devicePixelRatio),
),
/// Crop-Rotate, Filter and Blur editors are not supported
cropRotateEditorConfigs:
const CropRotateEditorConfigs(enabled: false),
filterEditorConfigs:
const FilterEditorConfigs(enabled: false),
blurEditorConfigs:
const BlurEditorConfigs(enabled: false),
customWidgets: ImageEditorCustomWidgets(
mainEditor: CustomWidgetsMainEditor(
bodyItems: (editor, rebuildStream) {
return [
ReactiveCustomWidget(
stream: rebuildStream,
builder: (_) => editor.selectedLayerIndex >= 0 ||
editor.isSubEditorOpen
? const SizedBox.shrink()
: Positioned(
bottom: 20,
left: 0,
child: Container(
decoration: BoxDecoration(
color: Colors.lightBlue.shade200,
borderRadius: const BorderRadius.only(
topRight: Radius.circular(100),
bottomRight: Radius.circular(100),
),
),
child: IconButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return ReorderLayerSheet(
layers: editor.activeLayers,
onReorder:
(oldIndex, newIndex) {
editor
.moveLayerListPosition(
oldIndex: oldIndex,
newIndex: newIndex,
);
Navigator.pop(context);
},
);
},
);
},
icon: const Icon(
Icons.reorder,
color: Colors.white,
),
),
),
),
),
];
},
bottomBar: (editor, rebuildStream, key) =>
editor.selectedLayerIndex < 0
? ReactiveCustomWidget(
stream: rebuildStream,
key: key,
builder: (_) => _bottomNavigationBar(
editor,
constraints,
),
)
: null,
)),
imageEditorTheme: const ImageEditorTheme(
uiOverlayStyle: SystemUiOverlayStyle(
statusBarColor: Colors.black,
),
background: Colors.transparent,
paintingEditor:
PaintingEditorTheme(background: Colors.transparent),
/// Optionally remove background
/// cropRotateEditor: CropRotateEditorTheme(background: Colors.transparent),
/// filterEditor: FilterEditorTheme(background: Colors.transparent),
/// blurEditor: BlurEditorTheme(background: Colors.transparent),
),
stickerEditorConfigs: StickerEditorConfigs(
enabled: false,
buildStickers: (setLayer, scrollController) {
// Optionally your code to pick layers
return const SizedBox();
},
)),
),
);
}),
),
);
},
leading: const Icon(Icons.pan_tool_alt_outlined),
title: const Text('Movable background image'),
subtitle: const Text('Includes how to add multiple images.'),
trailing: const Icon(Icons.chevron_right),
);
}
Widget _bottomNavigationBar(
ProImageEditorState editor,
BoxConstraints constraints,
) {
return Scrollbar(
controller: _bottomBarScrollCtrl,
scrollbarOrientation: ScrollbarOrientation.top,
thickness: isDesktop ? null : 0,
child: BottomAppBar(
color: Colors.black,
padding: EdgeInsets.zero,
child: Center(
child: SingleChildScrollView(
controller: _bottomBarScrollCtrl,
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: min(constraints.maxWidth, 500),
maxWidth: 500,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
FlatIconTextButton(
label: Text('Change Canvas', style: _bottomTextStyle),
icon: const Icon(
Icons.change_circle_outlined,
size: 22.0,
color: Colors.white,
),
onPressed: _replaceBackground,
),
FlatIconTextButton(
label: Text('Paint', style: _bottomTextStyle),
icon: const Icon(
Icons.edit_rounded,
size: 22.0,
color: Colors.white,
),
onPressed: editor.openPaintingEditor,
),
FlatIconTextButton(
label: Text('Text', style: _bottomTextStyle),
icon: const Icon(
Icons.text_fields,
size: 22.0,
color: Colors.white,
),
onPressed: editor.openTextEditor,
),
FlatIconTextButton(
label: Text('Emoji', style: _bottomTextStyle),
icon: const Icon(
Icons.sentiment_satisfied_alt_rounded,
size: 22.0,
color: Colors.white,
),
onPressed: editor.openEmojiEditor,
),
],
),
),
),
),
),
),
);
}
} |
Beta Was this translation helpful? Give feedback.
-
thank you for answering my question i implement the above logic but there is bug when i update the height and width dynamically the main editor is not update it's state _onSliderWidthValueChanged(
SliderwidthtValueChangedEvent event,
Emitter<AddNewState> emit,
) async {
Uint8List image =
await _createTransparentImage(event.width!, event.height!);
emit(state.copyWith(transparentBytes: image, selectedwidth: event.width));
if (state.editorKey!.currentState != null) {
state.editorKey!.currentState!.editorImage =
EditorImage(byteArray: image);
}
} Screen.Recording.2024-06-30.111723.mp4 |
Beta Was this translation helpful? Give feedback.
If you just want to change the canvas color and size dynamically, you can do it as in the example below: