UME: 颜色吸管

369 阅读3分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

功能查看

老规矩先看看该功能是什么样的,当拖动中间的放大区域时, 会选取中心区域的色值进行显示, 所以该功能也是分为两个部分,一部分是放大功能的实现, 另一个就是中心点色值的获取,好的功能看完了,接下来我们就开始今天的源码查看

1.gif

源码查看

今天的代码还是在flutter_ume_kit_ui包中,其中有个color_sucker文件夹,关于上方的toolbar和移动手势相关代码就不做过多的解释了, 跟对其标尺中的基本都是一致的,感兴趣的可以去看下对其标尺中是如何实现的

选中区域放大

在color_sucker.dart的第209行我们看到了一个新的组件BackdropFilter那么组件是做什么的,主要有两个功能,一个是做高斯模糊效果,另一个是做矩阵变换,该功能就是通过矩阵变换来实现的

BackdropFilter(
  filter: ui.ImageFilter.matrix(_matrix.storage,
      filterQuality: FilterQuality.none),
)

可是该功能也没有放大功能阿,那放大是怎么实现的,我们再看下ImageFilter.matrix方法

/// Creates an image filter that applies a matrix transformation.
///
/// For example, applying a positive scale matrix (see [Matrix4.diagonal3])
/// when used with [BackdropFilter] would magnify the background image.
factory ImageFilter.matrix(Float64List matrix4,
                   { FilterQuality filterQuality = FilterQuality.low }) {
}

注释的最后一行我发现写了与BackdropFilter会有背景图放大的效果,这不就是我们要的效果么,再来看看_matrix是哪来的

在onPanUpdate手势中,有个Matrix4,通过x,y转换而来

final Matrix4 newMatrix = Matrix4.identity()
  ..translate(newX, newY)
  ..scale(_scale, _scale)
  ..translate(-newX, -newY);
_matrix = newMatrix;

好了放大功能已经实现了,我们再看看色值是如何得来的

色值获取

还是从手势的方法开始看,在上面矩阵转换的代码下有一行色值获取的方法_searchPixel,我们再往里看,

void _calculatePixel(Offset globalPosition) {
  if (_snapshot == null) return;
  double px = globalPosition.dx;
  double py = globalPosition.dy;
  int pixel32 = _snapshot!.getPixelSafe(px.toInt(), py.toInt());
  int hex = _abgrToArgb(pixel32);
  _currentColor = Color(hex);
}

获取到32位色值后转换成hex从而得到color,再看看是怎么通过坐标获取到色值的,继续看_snapshot!.getPixelSafe,方法注释写的很清楚,该方法传入x,y值以后就可以得到Uint32的色值

/// Get the pixel from the given [x], [y] coordinate. Color is encoded in a
/// Uint32 as #AABBGGRR. If the pixel coordinates are out of bounds, 0 is
/// returned.
int getPixelSafe(int x, int y) => boundsSafe(x, y) ? data[y * width + x] : 0;

所以问题到了_snapshot是如何得到的? 在手势开始的时候会判断是否有屏幕的截图,如果没有屏幕的截图,则会截取一张屏幕的截图

Future<void> _captureScreen() async {
  try {
    RenderRepaintBoundary boundary =
        rootKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
    ui.Image image = await boundary.toImage();
    ByteData? byteData =
        await image.toByteData(format: ui.ImageByteFormat.png);
    if (byteData == null) {
      return;
    }
    Uint8List pngBytes = byteData.buffer.asUint8List();
    _snapshot = img.decodeImage(pngBytes);
    _excuting = false;
    image.dispose();
  } catch (e) {
    debugPrint(e.toString());
  }
}

这样就能通过截图得到色值了

好了今天的源码查看就到这了, 作为Flutter届的一个小学生,希望大家多多指教,有问题的地方一起讨论