Flutter绘制指南06-颜色的基本操作

本节目标

[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});
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值