-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
didder.1
566 lines (566 loc) · 17.4 KB
/
didder.1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
.\" Automatically generated by Pandoc 3.1.9
.\"
.TH "DIDDER" "1" "December 20, 2023" "didder v1.3.0" "User Manual"
.SH NAME
didder \[em] dither images
.SH SYNOPSIS
\f[B]didder\f[R] [global options] command [command options]
[arguments\&...]
.SH DESCRIPTION
Dither images with a variety of algorithms and processing options.
.PP
Images with transparency are supported, and their alpha channel is kept
the way it was to begin with.
.PP
Mandatory global flags are \f[B]--palette\f[R], \f[B]--in\f[R], and
\f[B]--out\f[R], all others are optional.
Each command applies a dithering algorithm or set of algorithms to the
input image(s).
.PP
The most important parts of this manual are highlighted in the
\f[B]TIPS\f[R] section, make sure you check it out!
.PP
Homepage: \c
.UR https://github.com/makeworld-the-better-one/didder
.UE \c
.SH OPTIONS
.TP
\f[B]-i\f[R], \f[B]--in\f[R] \f[I]PATH\f[R]
Set the input file.
This flag can be used multiple times to dither multiple images with the
same palette and method.
A \f[I]PATH\f[R] of \[aq]\f[B]-\f[R]\[cq] stands for standard input.
.RS
.PP
The input file path can also be parsed as a glob.
This will only happen if the path contains an asterisk.
For example \f[B]-i \[aq]*.jpg\[cq]\f[R] will select all the .jpg files
in the current directory as input.
See this page for more info on glob pattern matching: \c
.UR https://golang.org/pkg/path/filepath/#Match
.UE \c
.RE
.TP
\f[B]-o\f[R], \f[B]--out\f[R] \f[I]PATH\f[R]
Set the output file or directory.
A \f[I]PATH\f[R] of \[aq]\f[B]-\f[R]\[cq] stands for standard output.
.RS
.PP
If \f[I]PATH\f[R] is an existing directory, then for each image input,
an output file with the same name (but possibly different extension)
will be created in that directory.
.PP
If \f[I]PATH\f[R] is a file, that ends in .gif (or \f[B]--format
gif\f[R] is set) then multiple input files will be combined into an
animated GIF.
.RE
.TP
\f[B]-p\f[R], \f[B]--palette\f[R] \f[I]COLORS\f[R]
Set the color palette used for dithering.
Colors are entered as a single quoted argument, with each color
separated by a space.
Colors can be formatted as RGB tuples (comma separated), hex codes
(case-insensitive, with or without the `#'), a single number from 0-255
for grayscale, or a color name from the SVG 1.1 spec (aka the HTML or
W3C color names).
All colors are interpreted in the sRGB colorspace.
.RS
.PP
A list of all color names is available at \c
.UR https://www.w3.org/TR/SVG11/types.html#ColorKeywords
.UE \c
.PP
Images are converted to grayscale automatically if the palette is
grayscale.
This produces more correct results.
.PP
Here\[cq]s an example of all color formats being used: \f[B]--palette
\[aq]23,230,100 D24242 135 forestGreen\[cq]\f[R]
.RE
.TP
\f[B]-r\f[R], \f[B]--recolor\f[R] \f[I]COLORS\f[R]
Set the color palette used for replacing the dithered color palette
after dithering.
The argument syntax is the same as \f[B]--palette\f[R], with one
exception.
It also supports RGB\f[I]A\f[R] tuples, so 4 values.
This means you can also choose to change the opacity of a palette color
after dithering.
The values are not premultiplied, so set the RGB to the color you want
as you\[cq]d expect.
.RS
.PP
The \f[B]--recolor\f[R] flag exists because when palettes that are
severely limited in terms of RGB spread are used, accurately
representing the image colors with the desired palette is impossible.
Instead of accuracy of color, the new goal is accuracy of luminance, or
even just accuracy of contrast.
For example, the original Nintendo Game Boy used a solely green palette:
\c
.UR
https://en.wikipedia.org/wiki/List_of_video_game_console_palettes#Game_Boy
.UE \c
\&.
By setting \f[B]--palette\f[R] to shades of gray and then
\f[B]--recolor\f[R]-ing to the desired shades of green, input images
will be converted to grayscale automatically and then dithered in one
dimension (gray), rather than trying to dither a color image (three
dimensions, RGB) into a one dimensional green palette.
This is similar to \[lq]hue shifting\[rq] or \[lq]colorizing\[rq] an
image in image editing software.
.PP
For these situations, \f[B]--recolor\f[R] should usually be a palette
made up of one hue, and \f[B]--palette\f[R] should be the grayscale
version of that palette.
The \f[B]--palette\f[R] could also be just equally spread grayscale
values, which would increase the contrast but make the luminance
inaccurate.
.PP
Recoloring can also be useful for increasing contrast on a strange
palette, like: \f[B]--palette \[aq]black white\[cq] --recolor
\[aq]indigo LimeGreen\[cq]\f[R].
Setting just \f[B]--palette \[aq]indigo LimeGreen\[cq]\f[R] would give
bad (low contrast) results because that palette is not that far apart in
RGB space.
These \[lq]bad results\[rq] are much more pronounced when the input
image is in color, because three dimensions are being reduced.
.RE
.TP
\f[B]-s\f[R], \f[B]--strength\f[R] \f[I]DECIMAL/PERCENT\f[R]
Set the strength of dithering.
This will affect every command except \f[B]random\f[R].
Decimal format is -1.0 to 1.0, and percentage format is -100% or 100%.
The range is not limited.
A zero value will be ignored.
Defaults to 100%, meaning that the dithering is applied at full
strength.
.RS
.PP
Reducing the strength is often visibly similar to reducing contrast.
With the \f[B]edm\f[R] command, \f[B]--strength\f[R] can be used to
reduce noise, when set to a value around 80%.
.PP
When using the \f[B]bayer\f[R] command with a grayscale palette, usually
100% is fine, but for 4x4 matrices or smaller, you may need to reduce
the strength.
For \f[B]bayer\f[R] (and by extension \f[B]odm\f[R]) color palette
images, several sites recommend 64% strength (written as 256/4).
This is often a good default for \f[B]bayer\f[R]/\f[B]odm\f[R] dithering
color images, as 100% will distort colors too much.
Do not use the default of 100% for Bayer dithering color images.
.RE
.TP
\f[B]-j\f[R], \f[B]--threads\f[R] \f[I]NUM\f[R]
Set the number of threads used.
By default a thread will be created for each CPU.
As dithering is a CPU-bound operation, going above this will not improve
performance.
This flag does not affect \f[B]edm\f[R], as error diffusion dithering
cannot be parallelized.
.TP
\f[B]-g\f[R], \f[B]--grayscale\f[R]
Make input image(s) grayscale before dithering.
.TP
\f[B]--saturation\f[R] \f[I]DECIMAL/PERCENT\f[R]
Change input image(s) saturation before dithering.
Decimal range is -1.0 to 1.0, percentage range is -100% or 100%.
Values that exceed the range will be rounded down.
-1.0 or -100% saturation is equivalent to \f[B]--grayscale\f[R].
.TP
\f[B]--brightness\f[R] \f[I]DECIMAL/PERCENT\f[R]
Change input image(s) saturation before dithering.
Decimal range is -1.0 to 1.0, percentage range is -100% or 100%.
Values that exceed the range will be rounded down.
.TP
\f[B]--contrast\f[R] \f[I]DECIMAL/PERCENT\f[R]
Change input image(s) saturation before dithering.
Decimal range is -1.0 to 1.0, percentage range is -100% or 100%.
Values that exceed the range will be rounded down.
.TP
\f[B]--no-exif-rotation\f[R]
Disable using the EXIF rotation flag in image metadata to rotate the
image before processing.
.TP
\f[B]-f\f[R], \f[B]--format\f[R] \f[I]FORMAT\f[R]
Set the output file format.
Valid options are \[aq]png\[cq] and \[aq]gif\[cq].
It will auto detect from filename when possible, so usually this does
not need to be set.
If \f[B]-o\f[R] is \[aq]\f[B]-\f[R]\[cq] or a directory, then PNG files
will be outputted by default.
So this flag can be used to force GIF output instead.
If your output file has an extension that is not .png or .gif the format
will need to be specified.
.TP
\f[B]--no-overwrite\f[R]
Setting this flag means the program will stop before overwriting an
existing file.
Any files written before that one was encountered will stay in place.
.TP
\f[B]-c\f[R], \f[B]--compression\f[R] \f[I]TYPE\f[R]
Set the type of PNG compression.
Options are \[aq]default\[cq], \[aq]no\[cq], \[aq]speed\[cq], and
\[aq]size\[cq].
This flag is ignored for non-PNG output.
.TP
\f[B]--fps\f[R] \f[I]DECIMAL\f[R]
Set frames per second for animated GIF output.
Note that not all FPS values can be represented by the GIF format, and
so the closest possible one will be chosen.
This flag has no default, and is required when animated GIFs are being
outputted.
This flag is ignored for non animated GIF output.
.TP
\f[B]-l\f[R], \f[B]--loop\f[R] \f[I]NUM\f[R]
Set the number of times animated GIF output should loop.
0 is the default, and will loop infinitely.
.TP
\f[B]-x\f[R], \f[B]--width\f[R] \f[I]NUM\f[R]
Set the width the input image(s) will be resized to, before dithering.
Aspect ratio will be maintained if \f[B]--height\f[R] is not specified
as well.
.TP
\f[B]-y\f[R], \f[B]--height\f[R] \f[I]NUM\f[R]
Set the height the input image(s) will be resized to, before dithering.
Aspect ratio will be maintained if \f[B]--width\f[R] is not specified as
well.
.TP
\f[B]-u\f[R], \f[B]--upscale\f[R] \f[I]NUM\f[R]
Scale image up after dithering.
So \[aq]2\[cq] will make the output two times as big as the input (after
\f[B]-x\f[R] and/or \f[B]-y\f[R]).
Only integers are allowed, as scaling up by a non-integer amount would
distort the dithering pattern and introduce artifacts.
.TP
\f[B]-v\f[R], \f[B]--version\f[R]
Get version information.
.SH COMMANDS
.TP
\f[B]random\f[R] \f[I]MIN MAX\f[R] or \f[I]RED_MIN RED_MAX GREEN_MIN GREEN_MAX BLUE_MIN BLUE_MAX\f[R]
Grayscale and RGB random dithering
.RS
.PP
Accepts two arguments (min and max) for RGB or grayscale, or six
(min/max for each channel) to control each RGB channel.
Arguments can be separated by commas or spaces.
.PP
Random dithering adds random noise to the image.
The min and max numbers limit the range of the random noise.
A good default is -0.5,0.5, which means that a middle gray pixel is 50%
likely to become black and 50% likely to become white, assuming a black
and white palette.
So -0.2,2.0 will reduce the noise (20%), while -0.7,0.7 will increase it
(70%).
Values like -0.5,0.7 will bias the noise to one end of the channel(s).
.TP
\f[B]-s\f[R], \f[B]--seed\f[R] \f[I]DECIMAL\f[R]
Set the seed for randomization.
This will also only use one thread, to keep output deterministic.
By default a different seed is chosen each time and multiple threads are
used.
.RE
.TP
\f[B]bayer\f[R] \f[I]X\f[R] \f[I]Y\f[R]
Bayer matrix ordered dithering
.RS
.PP
Requires two arguments, for the X and Y dimension of the matrix.
They can be separated by a space, comma, or \[aq]x\[cq].
Both arguments must be a power of two, with the exception of: 3x5, 5x3,
and 3x3.
.RE
.TP
\f[B]odm\f[R] \f[I]NAME/JSON/FILE\f[R]
Ordered Dithering Matrix
.RS
.PP
Select or provide an ordered dithering matrix.
This only takes one argument, but there a few types available:
.IP \[bu] 2
A preprogrammed matrix name
.PD 0
.P
.PD
.IP \[bu] 2
Inline JSON of a custom matrix
.PD 0
.P
.PD
.IP \[bu] 2
Or a path to JSON for your custom matrix.
\[aq]\f[B]-\f[R]\[cq] means standard input.
.PP
Here are all the built-in ordered dithering matrices.
You can find details on these matrices here: \c
.UR
https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/ordered_ditherers.go
.UE \c
.IP \[bu] 2
ClusteredDot4x4
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotDiagonal8x8
.PD 0
.P
.PD
.IP \[bu] 2
Vertical5x3
.PD 0
.P
.PD
.IP \[bu] 2
Horizontal3x5
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotDiagonal6x6
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotDiagonal8x8_2
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotDiagonal16x16
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDot6x6
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotSpiral5x5
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotHorizontalLine
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotVerticalLine
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDot8x8
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDot6x6_2
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDot6x6_3
.PD 0
.P
.PD
.IP \[bu] 2
ClusteredDotDiagonal8x8_3
.PP
Their names are case-insensitive, and hyphens and underscores are
treated the same.
.PP
The JSON format (whether inline or in a file) looks like the below.
The matrix must be \[lq]rectangular\[rq], meaning each array must have
the same length.
More information how to use a custom matrix can be found here: \c
.UR
https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#OrderedDitherMatrix
.UE \c
.RE
.IP
.EX
{
\[dq]matrix\[dq]: [
[12, 5, 6, 13],
[4, 0, 1, 7],
[11, 3, 2, 8],
[15, 10, 9, 14]
],
\[dq]max\[dq]: 16
}
.EE
.TP
\f[B]edm\f[R] \f[I]NAME/JSON/FILE\f[R]
Error Diffusion Matrix
.RS
.PP
Select or provide an error diffusion matrix.
This only takes one argument, but there a few types available:
.IP \[bu] 2
A preprogrammed matrix name
.PD 0
.P
.PD
.IP \[bu] 2
Inline JSON of a custom matrix
.PD 0
.P
.PD
.IP \[bu] 2
Or a path to JSON for your custom matrix.
\[aq]\f[B]-\f[R]\[cq] means stdin.
.PP
Here are all the built-in error diffusion matrices.
You can find details on these matrices here: \c
.UR
https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/error_diffusers.go
.UE \c
.IP \[bu] 2
Simple2D
.PD 0
.P
.PD
.IP \[bu] 2
FloydSteinberg
.PD 0
.P
.PD
.IP \[bu] 2
FalseFloydSteinberg
.PD 0
.P
.PD
.IP \[bu] 2
JarvisJudiceNinke
.PD 0
.P
.PD
.IP \[bu] 2
Atkinson
.PD 0
.P
.PD
.IP \[bu] 2
Stucki
.PD 0
.P
.PD
.IP \[bu] 2
Burkes
.PD 0
.P
.PD
.IP \[bu] 2
Sierra (or Sierra3)
.PD 0
.P
.PD
.IP \[bu] 2
TwoRowSierra (or Sierra2)
.PD 0
.P
.PD
.IP \[bu] 2
SierraLite (or Sierra2_4A)
.PD 0
.P
.PD
.IP \[bu] 2
StevenPigeon
.PP
Their names are case-insensitive, and hyphens and underscores are
treated the same.
.PP
The JSON format (whether inline or in a file) for a custom matrix is
very simple, just a 2D array.
The matrix must be \[lq]rectangular\[rq], meaning each array must have
the same length.
.TP
\f[B]-s\f[R], \f[B]--serpentine\f[R]
Enable serpentine dithering, which \[lq]snakes\[rq] back and forth when
moving down the image, instead of going left-to-right each time.
This can reduce artifacts or patterns in the noise.
.RE
.SH TIPS
Read about \f[B]--strength\f[R] if you haven\[cq]t already.
.PP
Read about \f[B]--recolor\f[R] if you haven\[cq]t already.
.PP
It\[cq]s easy to mess up a dithered image by scaling it manually.
It\[cq]s best to scale the image to the size you want before dithering
(externally, or with \f[B]--width\f[R] and/or \f[B]--height\f[R]), and
then leave it.
.PP
If you need to scale it up afterward, use \f[B]--upscale\f[R], rather
than another tool.
This will prevent image artifacts and blurring.
.PP
Be wary of environments where you can\[cq]t make sure an image will be
displayed at 100% size, pixel for pixel.
Make sure to at least use nearest-neighbor scaling, do your best to
preserve sharp pixel edges.
.PP
Dithered images must only be encoded in a lossless image format.
This is why the tool only outputs PNG and GIF.
.PP
To increase the dithering artifacts for aesthetic effect, you can
downscale the image before dithering and upscale after.
Like if the image is 1000 pixels tall, your command can look like
\f[B]didder \[en]height 500 \[en]upscale 2 [\&...]\f[R].
Depending on the input image size and what final size you want, you can
of course just upscale as well.
.PP
If your palette (original or recolor) is low-spread \[em] meaning it
doesn\[cq]t span much of the available shades of a single hue or the
entire RGB space \[em] you can use flags like \f[B]--brightness\f[R],
\f[B]--contrast\f[R], and \f[B]--saturation\f[R] to improve the way
dithered images turn out.
For example, if your palette is dark, you can turn up the brightness.
As mentioned above, these flags apply their transformations to the
original image and will not adjust your selected palette colors.
.SH EXAMPLES
.TP
\f[B]didder --palette \[dq]black white\[rq] -i input.jpg -o test.png bayer 16x16\f[R]
This command dithers \f[CR]input.jpg\f[R] using only black and white
(implicitly converting the image to grayscale first), using a 16x16
Bayer matrix.
The result is written to \f[CR]test.png\f[R].
.TP
\f[B]didder --palette \[dq]black white\[rq] -i input.jpg -o test.png odm ClusteredDot4x4\f[R]
Same command as above, but dithering with the preprogrammed ordered
dithering matrix called ClusteredDot4x4.
.TP
\f[B]didder -i david.png -o david_dithered.png --palette \[dq]black white\[rq] --recolor \[dq]black F273FF\[rq] --upscale 2 bayer 4x4\f[R]
This is the command used for the README.
It dithers using a 4x4 Bayer matrix, initially to black and white, which
is then recolored to black and purple.
Dithering to black and purple directly would produce much lower contrast
results.
The dithered image is upscaled to be two times larger, so that the Bayer
dithering artifacts can be seen more clearly.
.TP
\f[B]didder -i input.png -o output.png -p \[dq]1E1E1E CDCDCD EDEDED FFFFFF\[rq] -r \[dq]11161e 116bcd 63b3ed e1efff\[rq] --strength 64% --brightness 20% bayer 32x32\f[R]
This command uses a blue recolor palette, one that is biased to being
darker.
The palette can be viewed at \c
.UR https://colorpeek.com/#11161e,116bcd,63b3ed,e1efff
.UE \c
\&.
The dithering palette is the grayscale version of those colors, to keep
luminance accurate.
Strength is set to 64%, which although usually recommended for Bayer
dithering of color images, works well here.
Alternatively, one could try and increase \f[B]--contrast\f[R].
Finally, the brightness is increased to compensate for the dark palette.
.TP
\f[B]didder -p \[dq]black white\[rq] --recolor \[dq]darkgreen white\[rq] -i frame_01.png -i frame_02.png -o output.gif --fps 1 random -0.5,0.5\f[R]
This command takes two input images and creates an animated GIF,
dithering and recoloring them along the way.
The GIF moves at 1 frame per second, and by default loops infinitely.
Random dithering is used, with recommended default of -0.5,0.5.
.SH REPORTING BUGS
Any bugs can be reported by creating an issue on GitHub: \c
.UR https://github.com/makeworld-the-better-one/didder
.UE \c