Flutter ClipRect and Align : how to compute the Alignment values - flutter

I want to display part of an image (a rectangle of 128 * 128 inside this image which is 512 * 512) in a rectangle in Flutter app.
Like this:
I want to select a specific zone in the source image, here from x=115, y=12 with width=128,height=128.
So here's my Flutter code to do this:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
var myWidth = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: myWidth,
height: myWidth,
color: Colors.yellow,
child: FittedBox(
fit: BoxFit.fill,
child: ClipRect(
child: Align(
alignment: Alignment(2.0*115.0 / 512.0 - 1, 2.0*12.0 / 512.0 -1.0),
widthFactor: 0.25,
heightFactor: 0.25,
child: Image.network(
"https://homepages.cae.wisc.edu/~ece533/images/baboon.png"),
),
),
)));
}
}
I suppose that the widthFactor and heightFactor represent the percentage of the original image I want to display - so here, because I want to display 128 pixels, it's 25% of the original width/height.
However, I just can't figure out out to calculate the values for the alignment.
First I tried for x :
alignment: Alignment(2.0*115.0 / 512.0 - 1, 2.0*12.0 / 512.0 -1.0),
Which almost gives the desired result, but not quite, see below:
I tried many other combinations to calculate the Alignment values and read all I could find with the help of Google... Is this even possible to accomplish this with a ClipRect and an Align?
Any help is welcome ;-)
NOTE : I don't want to crop the original image (and hence produce a new image), I want to keep it as downloaded to avoid having N copies of the same bitmap in memory. What I want is a specific view on the image - something that is absolutely trivial to do with OpenGL/DirectX and UV coordinates for example, but not so with Flutter.

Based on pskink comment, provided a working solution in the original post.
import 'package:flutter/material.dart';
import 'package:network_to_file_image/image_for_canvas.dart';
import 'package:network_to_file_image/network_to_file_image.dart';
import 'dart:ui' as ui;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var myWidth = MediaQuery.of(context).size.width;
User user = User(
filename: null,
url: "https://homepages.cae.wisc.edu/~ece533/images/baboon.png",
);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
width: myWidth,
height: myWidth,
color: Colors.yellow,
child: CustomPaint(
painter: ImagePainter(user, loadCallback: (_, __, ___) {
setState(() {});
})),
));
}
}
class ImagePainter extends CustomPainter {
final User user;
final LoadCallback<User> loadCallback;
ImagePainter(
this.user, {
required this.loadCallback,
});
#override
void paint(Canvas canvas, Size size) {
canvas.save();
canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height),
Paint()..color = Colors.lightGreenAccent);
canvas.restore();
var imageForCanvas = _imageForCanvas();
ui.Image? image = imageForCanvas.image(user);
if (image != null) {
canvas.save();
canvas.drawImageRect(
image,
Rect.fromLTWH(
12,
12,
256,
256,
),
Rect.fromLTWH(
0,
0,
size.width,
size.height,
),
Paint()..imageFilter = ui.ImageFilter.blur(sigmaX: .5, sigmaY: .5),
);
canvas.restore();
}
}
ImageForCanvas<User> _imageForCanvas() => ImageForCanvas<User>(
imageProviderSupplier: (User user) => NetworkToFileImage(
file: null,
url: user.url,
),
keySupplier: (User user) => user.url!,
loadCallback: loadCallback,
);
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
class User {
final String? filename;
final String? url;
User({
this.filename,
this.url,
});
}

Related

Draw a Image on Website using Image_picker

i want to upload a image with image_picker_web to my flutter website.
This works without problems.
Than i need to edit the image (for example grayscale or draw on it) with the image_class from pub_dev and after that i want to display it on my flutter website.
But all my attempts not working. I have problem to convert the img.image class Image back to Uint8List for displaying in Image.memory .
Can anybody help me with a little code snippet?
Ronny
This is my code:
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
import 'package:image_picker/image_picker.dart';
import 'package:image_picker_web/image_picker_web.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Draw Picture Homepage'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late Uint8List pickedImage;
bool imageAvailable = false;
#override
void initState() {
super.initState();
}
getImageWeb() async {
final fromPicker = await ImagePickerWeb.getImageAsBytes();
/* // Fill it with a solid color (blue)
img.fill(test, img.getColor(0, 0, 255));
// Draw some text using 24pt arial font
img.drawString(test, img.arial_24, 0, 0, 'Hello World');
// Draw a line
img.drawLine(test, 0, 0, 320, 240, img.getColor(255, 0, 0), thickness: 3);
// Blur the image
img.gaussianBlur(test, 10); */
setState(() {
pickedImage = fromPicker!;
imageAvailable = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: () => getImageWeb(),
child: Text('Select Image'),
),
Container(
width: 300,
child: imageAvailable ? Image.memory(pickedImage) : const SizedBox(height: 10),
),
const Text('Test'
),
],
),
),
);
}
}
This works. But i am not able to convert the edited Image (which is img.Image after editing) back to Uint8List to show it on the Website.

Flutter - Custom Animation Using CustomPaint

I created a CustomPaint widget and I want to change the heigth from zero to end of screen with smooth animation as shown in the image.
You can use Flutter's AnimationController to drive explicit CustomPaint animation as follows (DartPad):
class AnimatedHeightCustomPaint extends StatefulWidget {
final AnimationController controller;
final Size size;
final Color color;
final Curve curve;
const AnimatedHeightCustomPaint({Key? key,
required this.controller,
required this.size,
required this.color,
this.curve = Curves.linear}) : super(key: key);
#override
State<StatefulWidget> createState() => AnimatedHeightCustomPaintState();
}
class AnimatedHeightCustomPaintState extends State<AnimatedHeightCustomPaint> {
#override
void initState() {
super.initState();
// Listen to the animation progress and update the custom paint (height in this case)
widget.controller.addListener(() => setState(() { }));
}
#override
Widget build(BuildContext context) => CustomPaint(
painter: AnimatedHeightPainter(
// Here we can apply some fancy animation progress like bounce in
heightProps: widget.curve.transform(widget.controller.value),
color: widget.color,
),
// Since you want to change the height, you need to provide a size
size: widget.size,
);
}
class AnimatedHeightPainter extends CustomPainter
{
// Progress of the animation, i.e. between 0.0 and 1.0
final double heightProps;
final Color color;
AnimatedHeightPainter({required this.heightProps, required this.color});
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(Offset(0.0, size.height * (1 - heightProps)) & Size(size.width, size.height * heightProps),
Paint()..color = color,
);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
As a complete sample,
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
// Flutter's AnimationController
late AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this, // the SingleTickerProviderStateMixin
duration: const Duration(seconds: 2),
);
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: AnimatedHeightCustomPaint(
controller: _animationController,
size: MediaQuery.of(context).size,
color: Colors.red,
curve: Curves.bounceInOut,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// In Parent widget, you can control the animation (back and forth here)
if(_animationController.isCompleted) {
_animationController.reverse();
}else if(_animationController.isDismissed) {
_animationController.forward();
}
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class AnimatedHeightCustomPaint extends StatefulWidget {
final AnimationController controller;
final Size size;
final Color color;
final Curve curve;
const AnimatedHeightCustomPaint({Key? key,
required this.controller,
required this.size,
required this.color,
this.curve = Curves.linear}) : super(key: key);
#override
State<StatefulWidget> createState() => AnimatedHeightCustomPaintState();
}
class AnimatedHeightCustomPaintState extends State<AnimatedHeightCustomPaint> {
#override
void initState() {
super.initState();
// Listen to the animation progress and update the custom paint (height in this case)
widget.controller.addListener(() => setState(() { }));
}
#override
Widget build(BuildContext context) => CustomPaint(
painter: AnimatedHeightPainter(
// Here we can apply some fancy animation progress like bounce in
heightProps: widget.curve.transform(widget.controller.value),
color: widget.color,
),
// Since you want to change the height, you need to provide a size
size: widget.size,
);
}
class AnimatedHeightPainter extends CustomPainter
{
// Progress of the animation, i.e. between 0.0 and 1.0
final double heightProps;
final Color color;
AnimatedHeightPainter({required this.heightProps, required this.color});
#override
void paint(Canvas canvas, Size size) {
canvas.drawRect(Offset(0.0, size.height * (1 - heightProps)) & Size(size.width, size.height * heightProps),
Paint()..color = color,
);
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
Perhaps You can even use AnimatedContainer if there is no specific reason to use CustomPaint widget (DartPad):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
// Flutter's AnimationController
bool isExpanded = true;
#override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stack(
children: [
Align(
alignment: Alignment.bottomCenter,
child: AnimatedContainer(
curve: Curves.bounceInOut,
width: screenSize.width,
height: screenSize.height * (isExpanded ? 1: 0),
duration: const Duration(seconds: 2),
color: Colors.red,
),
),
],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() => isExpanded = !isExpanded);
},
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}

Masked Blur for Image

I would like to implement the effect shown below in which most parts of an image are blurred and only the interesting part of the image is shown crisp (with a border).
I am not sure how to implement the effect and would like to consider your ideas. Blurring the image is not the problem (i am doing it as described here), but leaving a part of the image non-blurred is quite a challenge. I thought about layering two images (one blurred and one non-blurred) over each other. However that will not work because then the blurred image will cast a shadow over the cutout section.
I also tried to use a CustomPainter, however i failed to get the blur working.
This is how you can do it , The idea is to make CustomClipper to invert the behavior of the BackDropFilter.
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
height: 250,
child: Stack(
children: <Widget>[
Center(
child: Image.network(
'https://cdn-prod.medicalnewstoday.com/content/images/articles/322/322736/elephant-from-the-front.jpg')),
Center(
child: ClipPath(
clipper: InvertedRect(),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
child: Container(
color: Colors.transparent,
),
),
),
),
],
),
),
);
}
}
class InvertedRect extends CustomClipper<Path> {
#override
getClip(Size size) {
print(size);
return Path()
..addRect(Rect.fromLTWH(0.0, 0.0, size.width, size.height))
..addRect(Rect.fromLTWH(100.0, 40.0, 100, 100))
..fillType = PathFillType.evenOdd;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}

How to make Custom thumb of seekbar with flutter?

I'm trying to make seekbar like below image, but unable to made.
I followed Seekbar Package plugin.
Using flutter_xlider plugin makes this a breeze.
Here is a small example from their docs:
FlutterSlider(
...
handler: FlutterSliderHandler(
decoration: BoxDecoration(),
child: Material(
type: MaterialType.canvas,
color: Colors.orange,
elevation: 3,
child: Container(
padding: EdgeInsets.all(5),
child: Icon(Icons.adjust, size: 25,)),
),
),
)
Their slider is very well documented, check it out.
if you are trying to create a custom Thumb design,
then you can extend your choice of Existing thumb class and override the drawing to get the shape you want.
check out this code in dart pad it will help you get started.
Update:
Here is the source code for the same in case the link goes offline:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom Slider Thumb Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: SliderTheme(
child: RangeSlider(
min: 0,
max: 100,
divisions: 10,
onChanged: (RangeValues value) {
if (value.end - value.start <= 10) return;
print('current progress: $value');
},
values: RangeValues(0, 100),
),
data: SliderThemeData(
// change size here to customize the thumb
rangeThumbShape: SliderThumbShape(thumbSize: 15.0),
),
),
),
);
}
}
class SliderThumbShape extends RangeSliderThumbShape {
final double thumbSize;
const SliderThumbShape({this.thumbSize = 10.0});
#override
Size getPreferredSize(bool isEnabled, bool isDiscrete) {
return Size.fromWidth(thumbSize);
}
#override
void paint(
PaintingContext context,
Offset center, {
Animation<double> activationAnimation,
#required Animation<double> enableAnimation,
bool isDiscrete,
bool isEnabled,
bool isOnTop,
TextDirection textDirection,
SliderThemeData sliderTheme,
Thumb thumb,
}) {
assert(context != null);
assert(center != null);
assert(enableAnimation != null);
assert(sliderTheme != null);
assert(sliderTheme.disabledThumbColor != null);
assert(sliderTheme.thumbColor != null);
final Canvas canvas = context.canvas;
final ColorTween colorTween = ColorTween(
begin: sliderTheme.disabledThumbColor,
end: sliderTheme.thumbColor,
);
canvas.drawRect(
Rect.fromCenter(center: center, height: thumbSize/2, width: thumbSize),
Paint()..color = colorTween.evaluate(enableAnimation),
);
}
}

How to bind a callback function in a statefull widget properly in Flutter?

I'm new in Flutter development,
Here is the problem:
The Controlpad is not working well when the setState() method is called in my function.
I am using ControlPad GitHub
My dependincies:
control_pad: ^1.0.0+2
When I comment out the setState() line the ControlPad works fine but the widget is not updating, othervise ControlPad is not working well.
Summary:
I want to bind _move method with onDirectionChanged function
import 'package:flutter/material.dart';
import 'package:control_pad/control_pad.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.lightBlue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title, this.test}) : super(key: key);
final String title;
final String test;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
double _x= 50;
double _y= 50;
void _move(double _degrees, double _distance) {
print('Degree:'+_degrees.toString()+' Distance:'+_distance.toString());
//setState(() {
_x += 1;
_y += 1;
//});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: Container(
child: Stack(
children: <Widget>[
Container( //FullScreen
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.grey,
),
Positioned(
bottom: _x ,
left: _y,
height: 50,
width: 50,
child: Container(
color: Colors.purple,
child: null,
),
),
Positioned(
bottom: 10 ,
left: 10,
child: JoystickView(
opacity: 0.9,
size: MediaQuery.of(context).size.width/4,
showArrows: false,
onDirectionChanged: (double degrees, double distance)=> _move(degrees,distance),
),
),
],
)
),
);
}
}
I don't know what is wrong with this code.
Any help is apriciated.
modify your constructor to:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title, this.test, this.onTap}) : super(key: key);
final String title;
final String test;
VoidCallback onTap;
#override
_MyHomePageState createState() => _MyHomePageState();
}
then call it like that:
MyHomePage(
title: '',
'test': '',
(){}
);
my answer is based on your title, it seems you look for different thing in question detail