import 'dart:math';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:ui';
import 'package:collection/collection.dart';
import 'package:convert/convert.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() async {
final rawImageData = [
0x52, 0x49, 0x46, 0x46, 0x28, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, 0x4c,
0x1c, 0x00, 0x00, 0x00, 0x2f, 0x3f, 0xc0, 0x03, 0x00, 0x0f, 0x30, 0xff, 0xf3, 0x1f, 0xf3, 0x1f,
0x0e, 0x04, 0x02, 0x09, 0xc2, 0xfe, 0x96, 0x6b, 0x64, 0x10, 0xd1, 0xff, 0x9c, 0xe3, 0x39, 0x06,
];
WidgetsFlutterBinding.ensureInitialized();
final image = await decodeImageFromList(Uint8List.fromList(rawImageData));
runApp(MaterialApp(home: Scaffold(body: Foo(image))));
}
class Foo extends StatefulWidget {
Foo(this.image);
final ui.Image image;
@override
State<Foo> createState() => _FooState();
}
class _FooState extends State<Foo> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
...FilterQuality.values.map((fq) => FooItem(
image: widget.image,
label: 'drawAtlas, $fq',
drawAtlas: true,
paint: Paint()..filterQuality = fq,
),
),
...FilterQuality.values.map((fq) => FooItem(
image: widget.image,
label: 'drawImage, $fq',
drawAtlas: false,
paint: Paint()..filterQuality = fq,
),
),
],
),
);
}
}
class FooItem extends StatelessWidget {
const FooItem({
required this.image,
required this.label,
required this.drawAtlas,
required this.paint,
});
final ui.Image image;
final String label;
final bool drawAtlas;
final Paint paint;
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox.fromSize(size: const Size(150, 70), child: Text(label)),
Expanded(
child: CustomPaint(
painter: FooPainter(
image: image,
drawAtlas: drawAtlas,
paint: paint,
),
),
),
],
);
}
}
class FooPainter extends CustomPainter {
FooPainter({
required this.image,
required this.drawAtlas,
required Paint paint,
}) : _paint = paint;
final ui.Image image;
final bool drawAtlas;
final Paint _paint;
@override
void paint(Canvas canvas, Size size) {
if (drawAtlas) {
final transforms = [RSTransform.fromComponents(
rotation: pi / 16,
scale: 2,
anchorX: 0,
anchorY: 0,
translateX: 0,
translateY: 0,
)];
final rects = [Offset.zero & Size(64 , 16)];
canvas.drawAtlas(image, transforms, rects, null, null, null, _paint);
} else {
final matrix = composeMatrix(
rotation: pi / 16,
scale: 2,
);
canvas
..save()
..transform(matrix.storage)
..drawImage(image, Offset.zero, _paint)
..restore();
}
}
@override
bool shouldRepaint(FooPainter oldDelegate) => false;
}
Matrix4 composeMatrix({
double scale = 1,
double rotation = 0,
Offset translate = Offset.zero,
Offset anchor = Offset.zero,
}) {
final double c = cos(rotation) * scale;
final double s = sin(rotation) * scale;
final double dx = translate.dx - c * anchor.dx + s * anchor.dy;
final double dy = translate.dy - s * anchor.dx - c * anchor.dy;
return Matrix4(c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, dx, dy, 0, 1);
}
Steps to reproduce
run the attached code
Expected results
image edges should be smooth like when using
Canvas.drawImageActual results
they are always sharp (no matter what FilterQuality` is used)
Code sample
Code sample
Screenshots or Video
Screenshots / Video demonstration
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output