Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add simpler api for creating a dart:ui Image of a given width and height and by setting individual pixel values #148597

Closed
mmcdon20 opened this issue May 18, 2024 · 1 comment
Labels
a: images Loading, displaying, rendering images c: new feature Nothing broken; request for a new capability engine flutter/engine repository. See also e: labels. r: solved Issue is closed as solved team-engine Owned by Engine team

Comments

@mmcdon20
Copy link

mmcdon20 commented May 18, 2024

Use case

Currently in flutter there is not a convenient way to create an Image of a given width and height, and then set individual pixels on said Image before displaying it.

Consider the following example program:

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart' hide Image;

void main() async {
  final Completer<Image> completer = Completer<Image>();

  const int w = 640;
  const int h = 640;
  final Int32List img = Int32List(w * h);

  final Random random = Random();

  double x = 0;
  double y = 0;

  for (int i = 0; i < 200000; i++) {
    double tmpx, tmpy;
    final double r = random.nextDouble();

    if (r <= 0.01) {
      tmpx = 0;
      tmpy = 0.16 * y;
    } else if (r <= 0.08) {
      tmpx = 0.2 * x - 0.26 * y;
      tmpy = 0.23 * x + 0.22 * y + 1.6;
    } else if (r <= 0.15) {
      tmpx = -0.15 * x + 0.28 * y;
      tmpy = 0.26 * x + 0.24 * y + 0.44;
    } else {
      tmpx = 0.85 * x + 0.04 * y;
      tmpy = -0.04 * x + 0.85 * y + 1.6;
    }

    x = tmpx;
    y = tmpy;

    final int col = (w / 2 + x * w / 11).round();
    final int row = (h - y * h / 11).round();

    img[row * w + col] = Colors.green.value;
  }

  decodeImageFromPixels(
    img.buffer.asUint8List(),
    w,
    h,
    PixelFormat.bgra8888,
    completer.complete,
  );

  runApp(RawImage(image: await completer.future));
}

As far as I know, this is the only available api for this in flutter today. It is a bit awkward because you have to use a 1 dimensional array (Int32List), when conceptually an Image is a 2 dimensional array. You want to be able to easily set the value of a pixel at a given x and y coordinate. Also decodeImageFromPixels feels a bit awkward as well, having to use a Completer to retrieve the Image.

You can compare this program to the same program written in many other languages and frameworks: https://rosettacode.org/wiki/Barnsley_fern. In many other languages there is a an api for this along the lines of image = Image(width, height) and image.setPixel(x, y, color), for example the BufferedImage in the Java example.

There aren't any existing packages on pub.dev for this (as far as I can tell), It would be possible to write a package to help with this, but it seems like something that should be in the framework itself.

Proposal

If there was a class for this, lets say we call it ImageBuffer, it's usage might look like the following:

import 'dart:math';
import 'dart:ui';

import 'package:flutter/material.dart';

void main() async {
  final ImageBuffer img = ImageBuffer(640, 640);

  final Random random = Random();

  double x = 0;
  double y = 0;

  for (int i = 0; i < 200000; i++) {
    double tmpx, tmpy;
    final double r = random.nextDouble();

    if (r <= 0.01) {
      tmpx = 0;
      tmpy = 0.16 * y;
    } else if (r <= 0.08) {
      tmpx = 0.2 * x - 0.26 * y;
      tmpy = 0.23 * x + 0.22 * y + 1.6;
    } else if (r <= 0.15) {
      tmpx = -0.15 * x + 0.28 * y;
      tmpy = 0.26 * x + 0.24 * y + 0.44;
    } else {
      tmpx = 0.85 * x + 0.04 * y;
      tmpy = -0.04 * x + 0.85 * y + 1.6;
    }

    x = tmpx;
    y = tmpy;

    img.setPixel(
      (img.width / 2 + x * img.width / 11).round(), // x position
      (img.height - y * img.height / 11).round(),   // y position
      Colors.green.value,                           // color value
    );
  }

  runApp(RawImage(image: await img.decode()));
}
@huycozy huycozy added in triage Presently being triaged by the triage team c: new feature Nothing broken; request for a new capability engine flutter/engine repository. See also e: labels. a: images Loading, displaying, rendering images team-engine Owned by Engine team and removed in triage Presently being triaged by the triage team labels May 20, 2024
@jonahwilliams
Copy link
Member

I think the API you're presenting here could easily be implemented in a package by wrapping the existing interfaces.

@huycozy huycozy added the r: solved Issue is closed as solved label May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: images Loading, displaying, rendering images c: new feature Nothing broken; request for a new capability engine flutter/engine repository. See also e: labels. r: solved Issue is closed as solved team-engine Owned by Engine team
Projects
None yet
Development

No branches or pull requests

3 participants