Skip to content

Commit 48536cc

Browse files
committed
Move Floyd-Steinberg dithering logic to its own class.
1 parent d74634f commit 48536cc

2 files changed

Lines changed: 58 additions & 46 deletions

File tree

src/Commands/Dithering.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace Zpl\Commands;
4+
5+
use GdImage;
6+
7+
class Dithering
8+
{
9+
/**
10+
* Apply Floyd 6Steinberg dithering to the given image in-place.
11+
*/
12+
public static function apply(GdImage $im, int $threshold = 128): void
13+
{
14+
$w = imagesx($im);
15+
$h = imagesy($im);
16+
17+
$gray = [];
18+
for ($y = 0; $y < $h; $y++) {
19+
$base = $y * $w;
20+
for ($x = 0; $x < $w; $x++) {
21+
$rgb = imagecolorat($im, $x, $y);
22+
$r = ($rgb >> 16) & 0xFF;
23+
$g = ($rgb >> 8) & 0xFF;
24+
$b = $rgb & 0xFF;
25+
$gray[$base + $x] = ($r * 299 + $g * 587 + $b * 114) / 1000;
26+
}
27+
}
28+
29+
$fs = [[1, 0, 7 / 16], [-1, 1, 3 / 16], [0, 1, 5 / 16], [1, 1, 1 / 16]];
30+
for ($y = 0; $y < $h; $y++) {
31+
$base = $y * $w;
32+
for ($x = 0; $x < $w; $x++) {
33+
$i = $base + $x;
34+
$old = $gray[$i];
35+
$gray[$i] = $new = $old < $threshold ? 0 : 255;
36+
$error = $old - $new;
37+
foreach ($fs as $m) {
38+
$nx = $x + $m[0];
39+
$ny = $y + $m[1];
40+
if ($nx >= 0 && $nx < $w && $ny < $h) {
41+
$ni = $ny * $w + $nx;
42+
$v = $gray[$ni] + $error * $m[2];
43+
$gray[$ni] = $v <= 0 ? 0 : (min($v, 255));
44+
}
45+
}
46+
}
47+
}
48+
49+
for ($y = 0; $y < $h; $y++) {
50+
$base = $y * $w;
51+
for ($x = 0; $x < $w; $x++) {
52+
$v = (int) $gray[$base + $x];
53+
imagesetpixel($im, $x, $y, ($v << 16) | ($v << 8) | $v);
54+
}
55+
}
56+
}
57+
}

src/Commands/GraphicField.php

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function encodeImage(string $image, int $width, bool $compressData = true
5959

6060
$im = $resized;
6161
if ($dithering) {
62-
$this->applyDithering($im);
62+
Dithering::apply($im);
6363
}
6464

6565
$width = imagesx($im);
@@ -138,49 +138,4 @@ public function setBlackThreshold(int $threshold): void
138138
{
139139
$this->blackThreshold = $threshold;
140140
}
141-
142-
protected function applyDithering(GdImage $im, int $threshold = 128): void
143-
{
144-
$w = imagesx($im);
145-
$h = imagesy($im);
146-
147-
$gray = [];
148-
for ($y = 0; $y < $h; $y++) {
149-
$base = $y * $w;
150-
for ($x = 0; $x < $w; $x++) {
151-
$rgb = imagecolorat($im, $x, $y);
152-
$r = ($rgb >> 16) & 0xFF;
153-
$g = ($rgb >> 8) & 0xFF;
154-
$b = $rgb & 0xFF;
155-
$gray[$base + $x] = ($r * 299 + $g * 587 + $b * 114) / 1000;
156-
}
157-
}
158-
159-
$fs = [[1, 0, 7 / 16], [-1, 1, 3 / 16], [0, 1, 5 / 16], [1, 1, 1 / 16]];
160-
for ($y = 0; $y < $h; $y++) {
161-
$base = $y * $w;
162-
for ($x = 0; $x < $w; $x++) {
163-
$i = $base + $x;
164-
$old = $gray[$i];
165-
$gray[$i] = $new = $old < $threshold ? 0 : 255;
166-
$error = $old - $new;
167-
foreach ($fs as $m) {
168-
$nx = $x + $m[0];
169-
$ny = $y + $m[1];
170-
if ($nx >= 0 && $nx < $w && $ny < $h) {
171-
$ni = $ny * $w + $nx;
172-
$v = $gray[$ni] + $error * $m[2];
173-
$gray[$ni] = $v <= 0 ? 0 : (min($v, 255));
174-
}
175-
}
176-
}
177-
}
178-
for ($y = 0; $y < $h; $y++) {
179-
$base = $y * $w;
180-
for ($x = 0; $x < $w; $x++) {
181-
$v = (int) $gray[$base + $x];
182-
imagesetpixel($im, $x, $y, ($v << 16) | ($v << 8) | $v);
183-
}
184-
}
185-
}
186141
}

0 commit comments

Comments
 (0)