in Flutter what's the correct way to change pixel data of an image with ui.Image type without using the Image package ? I was able to update the pixels by using the Image package but I don't want to convert the image multiple times. So I'm trying to explore the possibility to update Uint8List data. Below is the code snippet. However, I got "Exception: Invalid image data" when I tried to update the image with manipulated Uint8List. Wonder what I did wrong ? Appreciate any feedback.
int clamp(int x, int a, int b) {
return (x < a)
? a
: (x > b)
? b
: x;
}
int getColorY(int a, int r, int g, int b ) =>
(clamp(a, 0, 255) << 24) |
(clamp(r, 0, 255) << 16) |
(clamp(g, 0, 255) << 8) |
(clamp(b, 0, 255));
Future<ui.Image> setImageData(ui.Image uiX) async
int w = uiX.width;
int h = uiX.height;
//get byteData
final rgbaImageData =
await uiX.toByteData(format: ui.ImageByteFormat.png);
// convert to Uint32
Uint32List words = Uint32List.view(
rgbaImageData.buffer,
rgbaImageData.offsetInBytes,
rgbaImageData.lengthInBytes ~/ Uint32List.bytesPerElement);
int a = 0;
int r = 0;
int g = 0;
int b = 0;
for (int idx = 0; idx < words.length; idx++) {
Color color = Color(words[idx]);
if (color.red > 128) {
a = 0;
} else {
r = 128;
g = 135;
b = 110;
}
words[idx] = getColorY(a, r, g, b);
}
//convert Uint32List to Uint8List
Uint8List bytes = words.buffer.asUint8List();
final Completer<ui.Image> imageCompleter = new Completer();
ui.decodeImageFromList(bytes, (ui.Image img) {
imageCompleter.complete(img);
});
return imageCompleter.future;
}
You can convert ui.Image
to raw byte data, manipulate it, then convert it back to ui.Image
using ui.imageFromBytes
.
final ui.Image image = ...;
// Convert to raw rgba
final ByteData bytes = image.toByteData(format:
ImageByteFormat.rawRgba,
);
// Set the first pixel of the image to red.
bytes.setUint32(0, 0xFF0000FF);
// Set pixel at (x, y) to green.
final x = 10;
final y = 10;
bytes.setUint32((y * image.width + x) * 4, 0x00FF00FF);
ui.decodeImageFromPixels(
bytes.buffer.asUint8List(),
image.width,
image.height,
ui.PixelFormat.rgba8888,
(ui.Image result) {
// use your result image
},
);
The wrong part in your code is:
final rgbaImageData = await uiX.toByteData(format: ui.ImageByteFormat.png);
As format:
specifies the format of the returned bytes. So, you had to pass ui.ImageByteFormat.rawRgba
.
Also, Color(int)
expects an ARGB format instead of RGBA.