applyFloydSteinberg static method
Image
applyFloydSteinberg(
- Image image
Converte a imagem fornecida para uma imagem preto e branco utilizando o algoritmo de dithering Floyd-Steinberg, que distribui o erro garantindo uma textura de meio-tom (ideal para impressoras térmicas).
Implementation
static img.Image applyFloydSteinberg(img.Image image) {
final width = image.width;
final height = image.height;
// Converte a imagem para uma matriz 2D de luminâncias (escala de cinza 0-255)
final doubleMatrix = List.generate(
height,
(y) => List.filled(width, 0.0),
);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final pixel = image.getPixel(x, y);
// Calcula a luminância perceptiva
final r = pixel.r;
final g = pixel.g;
final b = pixel.b;
double luminance = (0.299 * r) + (0.587 * g) + (0.114 * b);
doubleMatrix[y][x] = luminance;
}
}
// Aplica o espalhamento de erros de Floyd-Steinberg
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
final oldPixel = doubleMatrix[y][x];
// Threshold em 128 para preto (0) ou branco (255)
final newPixel = oldPixel < 128.0 ? 0.0 : 255.0;
doubleMatrix[y][x] = newPixel;
final error = oldPixel - newPixel;
// Distribui o erro pros vizinhos:
// direita (7/16)
if (x + 1 < width) {
doubleMatrix[y][x + 1] += error * 7.0 / 16.0;
}
// baixo-esquerda (3/16)
if (x - 1 >= 0 && y + 1 < height) {
doubleMatrix[y + 1][x - 1] += error * 3.0 / 16.0;
}
// baixo (5/16)
if (y + 1 < height) {
doubleMatrix[y + 1][x] += error * 5.0 / 16.0;
}
// baixo-direita (1/16)
if (x + 1 < width && y + 1 < height) {
doubleMatrix[y + 1][x + 1] += error * 1.0 / 16.0;
}
}
}
// Reconstrói a imagem em P&B com o novo mapa pontilhado
final resultImage = img.Image(width: width, height: height, numChannels: 3);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// Se for 0.0, é preto. Se for 255.0, é branco.
final v = doubleMatrix[y][x] < 128.0 ? 0 : 255;
resultImage.setPixelRgb(x, y, v, v, v);
}
}
return resultImage;
}