本节目标
[1]. 认识Dart中的颜色表示方式
[2]. 了解颜色,[混合模式]的坐拥1
[3]. 了解如何读取图片中的像素颜色
一. 认识颜色
Color
类在dart.ui
包下,在Dart里面,颜色很简单,核心就是一个颜色的int值。
这代表Color类对应的是四通道32
位的颜色,并没有提供RGBA颜色到HSV颜色互相转换的方法。Color
类中主要有6个成员属性。核心是int类型的value。这个表示用来记录颜色信息。通过get
关键字可以获取该颜色的透明通道alpha
、红色通道red
、绿色通道green
、蓝色通道blue
、透明度opacity
const Color(int value):value=value& 0XFFFFFFFF;
final int value;
int get alpha=>(0XFF000000 & value) >>24
double get opacity=>alpha/0xFF
int getred=>(0XFF0000 & value) >>16
int get green=>(0x0000ff00 & value) >>8
int get blue=>(0x000000ff & value) >>0
2.关于颜色的ARGB表示
颜色的表示大家应该都不陌生。比如
0xffBBE9F7
可以表示一个32位的颜色。它转化位2进制位11111111
1011101
111010011
1110111
,每8个数字都表示一个颜色通道。本质上是ARGB
.
颜色本质上是什么,这个并不好说。毕竟颜色是人类用来描述自然世界的工具
。我们能够去做的就只有表示颜色
。其实0xffbbe9f7
本身也是一个代号而已。只是人为规定它和ARGB
色彩空间的一个颜色对应而已。
通过一个int值表示颜色。可以很方便的通过位运算对颜色进行变换。0xffbbe9f7
可以转化位2进制。
3.关于颜色与图片
一张位图图片本质上是由一个个像素点组成的。每个像素都是一个颜色。也就是说位图是一个颜色集。我对图片的所有操作。本质上都是对图片的变换。
对于图片的滤色。如果说关闭颜色通道。也就是让图片中所有的颜色R值设置为0
二. 绘制颜色阵列
下面是一个红色透明度依次降低的色块。是一个
0xfffff000~0xff0000
共256个颜色的列表绘制而成的图案。在这里想要介绍以下如何通过一维数组取商
和取余
来绘制出类似二维有行列的效果。
三、颜色的混合模式
混合模式在PS中也有这个概念。表现如下:Dart中一共有29种混合模式
1.了解混合模式是什么?
源码中注释为:
Algorithms to use when painting on the canvas
即 在画布商绘制时使用的算法。当在画布上绘制图片或者形状时。BlendMode会决定混合像素时使用的算法。
竟然是混合,那么肯定要两个东西混合在一起,这就是src和dst。src顾名思义是源。dst是目标。
一般dst会被认为是背景。src会被认为是正在绘制的图像。
void drawBlendImage(Canvas canvas){
if(image==null)return;
Paint srcPaint=Paint();
canvas.translate(-step*17, -step*17);
Paint dstPaint=Paint();
BlendMode.values.asMap().forEach((i, value) {
int line=i~/10;
int row=i%10;
canvas.save();
canvas.translate(3.7*step*row, 5.5*step*line);
canvas.drawImageRect(image!,
Rect.fromPoints(Offset.zero, Offset(image!.width*1.0,image!.height*1.0)),
Rect.fromCenter(center: Offset.zero, width: 25*2.0, height: 25*2.0),
dstPaint
);
srcPaint
..color=Color(0xffff0000)
..blendMode=value;
canvas.drawRect(Rect.fromPoints(Offset.zero, Offset(20*2.0,20*2.0)), srcPaint);
_simpleDrawText(canvas,value.toString().split(".")[1],offset: Offset(-10, 50));
canvas.restore();
});
}
void _simpleDrawText(Canvas canvas, String str,
{Offset offset = Offset.zero, Color color = Colors.black}) {
var builder = ui.ParagraphBuilder(ui.ParagraphStyle(
textAlign: TextAlign.left,
fontSize: 11,
textDirection: TextDirection.ltr,
maxLines: 1,
))
..pushStyle(
ui.TextStyle(color: color, textBaseline: ui.TextBaseline.alphabetic),
)
..addText(str);
canvas.drawParagraph(
builder.build()
..layout(ui.ParagraphConstraints(width: 11.0 * str.length)),
offset);
}
四、获取图片中的颜色
我们知道图片是由像素点构成的。每个像素点都存由颜色信息。Flutter本身的Image对象并没有获取相关像素的方法。可以使用第三方的image库进行相关操作。
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as image;
import 'coordinate.dart';
import 'dart:ui' as ui;
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: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
image.Image? _image;
@override
void initState() {
super.initState();
_loadImage();
}
void _loadImage() async {
_image = await loadImageFromAssets('assets/images/wy_300x200.jpg');
setState(() {});
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white, child: CustomPaint(painter: PaperPainter(_image)));
}
//读取 assets 中的图片
Future<image.Image?> loadImageFromAssets(String path) async {
ByteData data = await rootBundle.load(path);
List<int> bytes = data.buffer.asUint8List();
return image.decodeImage(bytes);
}
}
class PaperPainter extends CustomPainter {
late Paint _paint;
final double strokeWidth = 0.5;
final Color color = Colors.blue;
final image.Image? imageSrc;
final Coordinate coordinate = Coordinate();
PaperPainter(this.imageSrc) {
_paint = Paint()
..style = PaintingStyle.fill
..strokeWidth = strokeWidth
..color = color;
}
@override
void paint(Canvas canvas, Size size) {
coordinate.paint(canvas, size);
canvas.translate(size.width / 2, size.height / 2);
_drawImage(canvas);
}
@override
bool shouldRepaint(PaperPainter oldDelegate) =>
imageSrc != oldDelegate.imageSrc;
void _drawImage(Canvas canvas) {
if (imageSrc == null) return;
int colorInt = imageSrc!.getPixel(imageSrc!.width, 0);
var color = Color(colorInt);
canvas.drawCircle(Offset.zero, 10,
_paint..color =
Color.fromARGB(color.alpha, color.blue, color.green, color.red));
}
}
2. 绘制图片像素
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as image;
import 'coordinate.dart';
import 'dart:ui' as ui;
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: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
image.Image? _image;
List<Ball> balls = [];
double d = 20; //复刻的像素边长
@override
void initState() {
super.initState();
_initBalls();
}
void _initBalls() async {
_image = await loadImageFromAssets('assets/images/dartg.png');
if (_image == null) return;
for (int i = 0; i < _image!.width; i++) {
for (int j = 0; j < _image!.height; j++) {
Ball ball = Ball();
ball.x = i * d + d / 2;
ball.y = j * d + d / 2;
ball.r = d / 2;
var color = Color(_image!.getPixel(i, j));
ball.color =
Color.fromARGB(color.alpha, color.blue, color.green, color.red);
balls.add(ball);
}
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: CustomPaint(
painter: PaperPainter(balls),
));
}
//读取 assets 中的图片
Future<image.Image?> loadImageFromAssets(String path) async {
ByteData data = await rootBundle.load(path);
List<int> bytes = data.buffer.asUint8List();
return image.decodeImage(bytes);
}
}
class PaperPainter extends CustomPainter {
late Paint _paint;
final double strokeWidth = 0.5;
final Color color = Colors.blue;
final List<Ball> balls;
final Coordinate coordinate = Coordinate();
PaperPainter(this.balls) {
_paint = Paint()
..style = PaintingStyle.fill
..strokeWidth = strokeWidth
..color = color;
}
@override
void paint(Canvas canvas, Size size) {
coordinate.paint(canvas, size);
canvas.translate(-710, -1000);
_drawImage(canvas);
}
void _drawImage(Canvas canvas) {
balls.forEach((Ball ball) {
canvas.drawCircle(
Offset(ball.x, ball.y), ball.r, _paint..color = ball.color);
});
}
@override
bool shouldRepaint(PaperPainter oldDelegate) => balls != oldDelegate.balls;
}
class Ball {
double x; //点位X
double y; //点位Y
Color color; //颜色
double r; // 半径
Ball({this.x = 0, this.y = 0, this.color = Colors.black, this.r = 5});
}