Rahiche / explore_blur_effect

20 stars 2 forks source link

is it possible to make Blur brush? #1

Open Ansh-Rathod opened 6 months ago

Ansh-Rathod commented 6 months ago

Hey! been using these examples to explore the blur fragments and it works very well. but i lack the knowledge of writing shaders, is it possible in Flutter to use blur like this?

https://github.com/Rahiche/explore_blur_effect/assets/67627096/05a5cbe4-5e2a-4601-8c12-7a815b40724d

here is the prebuild drawing example if you wanna try out:

// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:ui';

import 'package:flutter/material.dart';

void main() async {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      home: const PhotoEditor(),
    );
  }
}

class PhotoEditor extends StatefulWidget {
  const PhotoEditor({super.key});

  @override
  State<PhotoEditor> createState() => _PhotoEditorState();
}

class _PhotoEditorState extends State<PhotoEditor> {
  List<Offset> offsets = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onPanStart: (d) {
          setState(() {
            offsets.add(d.globalPosition);
          });
        },
        onPanUpdate: (d) {
          setState(() {
            offsets.add(d.globalPosition);
          });
        },
        onPanEnd: (d) {},
        child: SizedBox(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          child: Stack(
            children: [
              Image.network(
                "https://images.unsplash.com/photo-1575936123452-b67c3203c357?q=80&w=2940&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D",
                fit: BoxFit.cover,
              ),
              CustomPaint(
                painter: SketchPainter(offsets: offsets),
              )
            ],
          ),
        ),
      ),
    );
  }
}

class SketchPainter extends CustomPainter {
  final List<Offset> offsets;
  SketchPainter({
    required this.offsets,
  });
  @override
  void paint(Canvas canvas, Size size) {
    Path path = Path();

    final paint = Paint()
      ..color = Colors.white
      ..strokeWidth = 30
      ..strokeCap = StrokeCap.butt
      ..strokeJoin = StrokeJoin.round;

    for (var i = 0; i < offsets.length; i++) {
      if (i + 1 != offsets.length) {
        canvas.drawLine(offsets[i], offsets[i + 1], paint);
      } else {
        canvas.drawPoints(PointMode.points, [offsets[i]], paint);
      }
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }
}
Rahiche commented 6 months ago

Yes, it can be done using a shader but it also can be done using the usual flutter blur:

https://zapp.run/edit/zzyu06ggzyv0?theme=dark&lazy=false

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: ImageBrushPage(),
    );
  }
}

class ImageBrushPage extends StatefulWidget {
  @override
  _ImageBrushPageState createState() => _ImageBrushPageState();
}

class _ImageBrushPageState extends State<ImageBrushPage> {
  List<Offset?> points = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        onPanUpdate: (details) {
          setState(() {
            RenderBox object = context.findRenderObject() as RenderBox;
            Offset _localPosition =
                object.globalToLocal(details.globalPosition);
            points.add(_localPosition);
          });
        },
        onPanEnd: (details) {
          points.add(null);
        },
        child: Stack(
          children: <Widget>[

            Image.network(
              'https://i.imgur.com/nYxw0ES.png',
            ),
             ClipPath(
              clipper: MyClipper(points),
              child: ImageFiltered(
                imageFilter: ui.ImageFilter.blur(sigmaX: 5, sigmaY: 5),
                child: Image.network('https://i.imgur.com/nYxw0ES.png',
                    fit: BoxFit.cover), // Replace with your image path
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class MyClipper extends CustomClipper<Path> {
  MyClipper(this.points, {this.strokeWidth = 15.0});
  final List<Offset?> points;
  final double strokeWidth;

  @override
  Path getClip(Size size) {
    var path = Path();

    if (points.isEmpty) {
      return path; // Return an empty path if there are no points
    }

    for (int i = 0; i < points.length - 1; i++) {
      if (points[i] != null && points[i + 1] != null) {
        // Create a stroke between two consecutive points
        path.addOval(Rect.fromCircle(
          center: points[i]!,
          radius: strokeWidth / 2,
        ));
        path.addOval(Rect.fromCircle(
          center: points[i + 1]!,
          radius: strokeWidth / 2,
        ));
        path.addRect(Rect.fromPoints(points[i]!, points[i + 1]!));
      }
    }

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
Rahiche commented 6 months ago

I tried doing the shader one before I might give another try this week @Ansh-Rathod

Ansh-Rathod commented 6 months ago

I solved it too using the same approach a few minutes ago. lol, I just spent time researching on converting open paths to closed paths. you can say "strokeToFill" but it's not necessary at all.

Ansh-Rathod commented 6 months ago

Would love to see the shader implementation.