1

I was trying to use alpha channel to apply transparency on line colors with CustomPaint's Canvas.drawLine().

Problem

However, the color tweaks on alpha channel takes no effect on the results, for example, the following code still gives me 100% opaque white lines


  final gridPaint = Paint()
    ..strokeJoin = StrokeJoin.miter
    ..strokeWidth = 1.0
    ..color = const Color(0xe6ffffff)
    ..style = PaintingStyle.stroke;


  canvas.drawLine(start, end, gridPaint);

Workaround

I have to draw 1-pixel-wide drawRect to get transparent lines.

Question

Is this by design?

kakyo
  • 10,460
  • 14
  • 76
  • 140
  • 2
    Not sure about this but is the result same if you try `fromARGB` like `Color c = const Color.fromARGB(0xe6, 0xff, 0xff, 0xff);` ? referred from [Color docs](https://api.flutter.dev/flutter/dart-ui/Color-class.html) – dev-aentgs Jul 31 '20 at 07:38
  • what are the values for start and end? – pskink Jul 31 '20 at 07:40
  • 1
    @dev-aentgs Wow. That's a surprise. `Color.fromARGB` works! – kakyo Jul 31 '20 at 07:46
  • I don't think that fromARGB would change everything, see it's implementation here https://api.flutter.dev/flutter/dart-ui/Color/Color.fromARGB.html – pskink Jul 31 '20 at 07:57
  • @pskink It actually did. I just tried his suggestion and it works the same way as `withOpacity` – kakyo Jul 31 '20 at 07:59
  • @pskink as for your start/end question, they are vertical lines from `top=0` to `bottom=size.height` – kakyo Jul 31 '20 at 08:02
  • are you suggesting that 0xe6ffffff != 0xe6 << 24 | 0xff << 16 | 0xff << 8 | 0xff ? IMHO it would be a big bug it the dart arithmetics – pskink Jul 31 '20 at 08:07
  • 1
    @pskink Tried your test in DartPad and it's a false. So no bug in arithmetics. It could be a bug in the `Color` or `Paint`, though. For now I have no time digging into this. But might be worth a report to Github later. – kakyo Aug 04 '20 at 05:49
  • see https://paste.ubuntu.com/p/9dgMr28jqb/, green part is done using `drawRect`, red part is done using `drawLine` – pskink Aug 19 '20 at 02:42
  • and? does `drawLine` apply transparency (50% in this particular case) on your device? – pskink Aug 19 '20 at 05:42
  • so change the path to the folder where you have write access (maybe some `/sdcard/` or something?), i used flutter for desktop so i was able to write it in my current folder, or maybe use https://pub.dev/packages/path_provider: "A Flutter plugin for finding commonly used locations on the filesystem. Supports iOS, Android, Linux and MacOS. Not all methods are supported on all platforms." – pskink Aug 19 '20 at 05:59
  • OK, I got it working. Saw in the image written to the card: from the topleft corner a green square with blurry horizontal gradient, from bottomright corner a red one. – kakyo Aug 19 '20 at 06:18
  • @pskink I've added the code and resulting image to an answer: https://stackoverflow.com/a/63481303/987846. Please feel free to complete it with your arguments. From what I can see the leftmost portion of each square doesn't look like transparent, where you assigned `0x80` as alpha, correct? – kakyo Aug 19 '20 at 06:40
  • no, its not blurry - you got the exact same image like me (i posted it in base64 format here https://paste.ubuntu.com/p/9dgMr28jqb/), open it with https://www.gimp.org/ for example, zoom in and you will see 50% transparency – pskink Aug 19 '20 at 06:48
  • @pskink ok, my bad. It's the oversampling of device picture viewer. So the conclusion is that the hex form of the Color value works just fine? – kakyo Aug 19 '20 at 07:00
  • yes, it works just fine - there is no difference if you use `Color(0x80xxxxxx)` or `withOpacity(0.5)` – pskink Aug 19 '20 at 07:03
  • btw, check https://github.com/flutter/flutter/blob/c969b8af7b/packages/flutter/lib/src/material/colors.dart#L244 and other `black*` or `white*` colors – pskink Aug 19 '20 at 07:05

2 Answers2

2

You can use the withOpacity method on the color of your choice.

Colors.green.withOpacity(0.5)

or

Color(0xe6ffffff).withOpacity(0.5)

Set the value to a number from 0 to 1 depending on the level of opacity you wish to achieve.

ambiguous58
  • 1,241
  • 1
  • 9
  • 18
0

On behalf of @pskink, I'm posting his test code and resulting image from my Android device:

    print('devicePixelRatio: ' + MediaQuery.of(context).devicePixelRatio.toString());
    var pr = ui.PictureRecorder();
    var c = Canvas(pr);
    var p = Paint();
    c.drawRect(Rect.fromLTWH(0, 0, 1, 3), p..color = Color(0x8000ff00));
    c.drawRect(Rect.fromLTWH(1.5, 0, 1, 3), p);
    c.drawLine(Offset(3.5, 3.0), Offset(3.5, 6.0), p..color = Color(0x80ff0000));
    c.drawLine(Offset(5.0, 3.0), Offset(5.0, 6.0), p);
    var img = await pr.endRecording().toImage(6, 6);
    var data = await img.toByteData(format: ui.ImageByteFormat.png);
    final imgDir = Platform.isAndroid ?
    (await pathman.getExternalStorageDirectories(type: pathman.StorageDirectory.pictures))[0] :
    (await pathman.getApplicationDocumentsDirectory());
    if (Platform.isAndroid) {
      await Directory(imgDir.path).create(recursive: true);
    }
    final suffix = DateTime.now().toString().replaceAll(RegExp(r'[\:\ \.]+'), '-');
    final filePath = '${imgDir.path}/screenshot-$suffix.png';
    File(filePath).writeAsBytesSync(data.buffer.asInt8List());

Having the above code in my CustomPaint's paint() gives me the tiny image below.

enter image description here

kakyo
  • 10,460
  • 14
  • 76
  • 140