在 Flutter 中,如何在不使用 Image 包的情况下逐个像素地操作 ui.Image?
In Flutter, how to manipulate pixel by pixel of an ui.Image without using the Image package?
在 Flutter 中,在不使用 Image 包的情况下更改具有 ui.Image 类型的图像像素数据的正确方法是什么?我可以使用 Image 包更新像素,但我不想多次转换图像。所以我试图探索更新 Uint8List 数据的可能性。下面是代码片段。但是,当我尝试使用操纵的 Uint8List 更新图像时,出现“异常:图像数据无效”。想知道我做错了什么吗?感谢任何反馈。
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;
}
您可以将 ui.Image
转换为原始字节数据,对其进行操作,然后使用 ui.imageFromBytes
.
将其转换回 ui.Image
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
},
);
您的代码中错误的部分是:
final rgbaImageData = await uiX.toByteData(format: ui.ImageByteFormat.png);
As format:
指定返回字节的格式。所以,你必须通过 ui.ImageByteFormat.rawRgba
.
此外,Color(int)
需要 ARGB 格式而不是 RGBA。
在 Flutter 中,在不使用 Image 包的情况下更改具有 ui.Image 类型的图像像素数据的正确方法是什么?我可以使用 Image 包更新像素,但我不想多次转换图像。所以我试图探索更新 Uint8List 数据的可能性。下面是代码片段。但是,当我尝试使用操纵的 Uint8List 更新图像时,出现“异常:图像数据无效”。想知道我做错了什么吗?感谢任何反馈。
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;
}
您可以将 ui.Image
转换为原始字节数据,对其进行操作,然后使用 ui.imageFromBytes
.
ui.Image
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
},
);
您的代码中错误的部分是:
final rgbaImageData = await uiX.toByteData(format: ui.ImageByteFormat.png);
As format:
指定返回字节的格式。所以,你必须通过 ui.ImageByteFormat.rawRgba
.
此外,Color(int)
需要 ARGB 格式而不是 RGBA。