First attempt at man page

This commit is contained in:
makeworld
2021-04-30 18:56:22 -04:00
parent 4da4049227
commit 6a487d55ad
6 changed files with 1147 additions and 142 deletions

392
MANPAGE.md Normal file
View File

@@ -0,0 +1,392 @@
<!-- DO NOT EDIT, AUTOMATICALLY GENERATED, EDIT dither.1.md INSTEAD -->
# NAME
didder - dither images
# SYNOPSIS
**didder** \[global options\] command \[command options\]
\[arguments\...\]
# DESCRIPTION
Dither images with a variety of algorithms and processing options.
Mandatory global flags are **\--palette**, **\--in**, and **\--out**,
all others are optional. Each command represents a dithering algorithm
or set of algorithms to apply to the input image(s).
Homepage: \<https://github.com/makeworld-the-better-one/didder\>
# GLOBAL OPTIONS
**-i**, **\--in** *PATH*
Set the input file. This flag can be used multiple times to dither
multiple images with the same palette and method. A *PATH* of
\'**-**' stands for standard input.
The input file path can also be parsed as a glob. This will only
happen if the path contains an asterisk. For example **-i
\'\*.jpg'** will select all the .jpg files in the current directory
as input. See this page for more info on glob pattern matching:
\<https://golang.org/pkg/path/filepath/\#Match\>
**-o**, **\--out** *PATH*
Set the output file or directory. A *PATH* of \'**-**' stands for
standard output.
If *PATH* 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.
If *PATH* is a file, that ends in .gif (or **\--format** gif is set)
then multiple input files will be combined into an animated GIF.
**-p**, **\--palette** *COLORS*
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.
A list of all color names is available at
\<https://www.w3.org/TR/SVG11/types.html\#ColorKeywords\>
Images are converted to grayscale automatically if the palette is
grayscale. This produces more correct results.
**-r**, **\--recolor** *COLORS*
Set the color palette used for replacing the dithered color palette
after dithering. The argument syntax is the same as **\--palette**.
The **\--recolor** 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:
\<https://en.wikipedia.org/wiki/List_of_video_game_console_palettes\#Game_Boy\>.
By setting **\--palette** to shades of gray and then
**\--recolor**-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 "hue shifting" or "colorizing" an image in image editing
software.
For these situations, **\--recolor** should usually be a palette
made up of one hue, and **\--palette** should be the grayscale
version of that palette. The **\--palette** could also be just
equally spread grayscale values, which would increase the contrast
but make the luminance inaccurate.
Recoloring can also be useful for increasing contrast on a strange
palette, like: **\--palette \'black white' \--recolor** \'indigo
LimeGreen'. Setting just **\--palette \'indigo LimeGreen'** would
give bad (low contrast) results because that palette is not that far
apart in RGB space. These "bad results" are much more pronounced
when the input image is in color, because three dimensions are being
reduced.
**-s**, **\--strength** *DECIMAL/PERCENT*
Set the strength of dithering. This will affect every command except
**random**. 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.
Reducing the strength is often visibly similar to reducing contrast.
With the **edm** command, **\--strength** can be used to reduce
noise, when set to a value around 80%.
When using the **bayer** command with a grayscale palette, usually
100% is fine, but for 4x4 matrices or smaller, you may need to
reduce the strength. For **bayer** (and by extension **odm**) color
palette images, several sites recommend 64% strength (written as
256/4). This is often a good default for **bayer**/**odm** dithering
color images, as 100% will distort colors too much. Do not use the
default of 100% for Bayer dithering color images.
**-j**, **\--threads** *NUM*
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
**edm**, as error diffusion dithering cannot be parallelized.
**-g**, **\--grayscale**
Make input image(s) grayscale before dithering.
**\--saturation** *DECIMAL/PERCENT*
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 **\--grayscale**.
**\--brightness** *DECIMAL/PERCENT*
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.
**\--contrast** *DECIMAL/PERCENT*
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.
**\--no-exif-rotation**
Disable using the EXIF rotation flag in image metadata to rotate the
image before processing.
**-f**, **\--format** *FORMAT*
Set the output file format. Valid options are \'png' and \'gif'. It
will auto detect from filename when possible, so usually this does
not need to be set. If **-o** is \'**-**' 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.
**\--no-overwrite**
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.
**-c**, **\--compression** *TYPE*
Set the type of PNG compression. Options are \'default', \'no',
\'speed', and \'size'. This flag is ignored for non-PNG output.
**\--fps** *DECIMAL*
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.
**-l**, **\--loop** *NUM*
Set the number of times animated GIF output should loop. 0 is the
default, and means infinite looping.
**-x**, **\--width** *NUM*
Set the width the input image(s) will be resized to, before
dithering. Aspect ratio will be maintained if **\--height** is not
specified as well.
**-y**, **\--height** *NUM*
Set the height the input image(s) will be resized to, before
dithering. Aspect ratio will be maintained if **\--width** is not
specified as well.
**-u**, **\--upscale** *NUM*
Scale image up after dithering. So \'2' will make the output two
times as big as the input (after **-x** and/or **-y**). Only
integers are allowed, as scaling up by a non-integer amount would
distort the dithering pattern and introduce artifacts.
**-v**, **\--version**
Get version information.
# COMMANDS
**random**
\- grayscale and RGB random dithering
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.
-0.5,0.5 is a good default.
**-s**, **\--seed** *DECIMAL*
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.
**bayer**
\- Bayer matrix ordered dithering
Requires two arguments, for the X and Y dimension of the matrix.
They can be separated by a space, comma, or \'x'. Both arguments
must be a power of two, with the exception of: 3x5, 5x3, and 3x3.
**odm**
\- Ordered Dither Matrix
Select or provide an ordered dithering matrix. This only takes one
argument, but there a few types available:
- A preprogrammed matrix name
- Inline JSON of a custom matrix
- Or a path to JSON for your custom matrix. \'**-**' means
standard input.
Here are all the built-in ordered dithering matrices. You can find
details on these matrices here:
\<https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/ordered_ditherers.go\>
- ClusteredDot4x4
- ClusteredDotDiagonal8x8
- Vertical5x3
- Horizontal3x5
- ClusteredDotDiagonal6x6
- ClusteredDotDiagonal8x8_2
- ClusteredDotDiagonal16x16
- ClusteredDot6x6
- ClusteredDotSpiral5x5
- ClusteredDotHorizontalLine
- ClusteredDotVerticalLine
- ClusteredDot8x8
- ClusteredDot6x6_2
- ClusteredDot6x6_3
- ClusteredDotDiagonal8x8_3
Their names are case-insensitive, and hyphens and underscores are
treated the same.
The JSON format (whether inline or in a file) looks like the below.
The matrix must be "rectangular", meaning each array must have the
same length. More information how to use a custom matrix can be
found here:
\<https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2\#OrderedDitherMatrix\>
{
"matrix": [
[12, 5, 6, 13],
[4, 0, 1, 7],
[11, 3, 2, 8],
[15, 10, 9, 14]
],
"max": 16
}
**edm**
\- Error Diffusion Matrix
Select or provide an error diffusion matrix. This only takes one
argument, but there a few types available:
- A preprogrammed matrix name
- Inline JSON of a custom matrix
- Or a path to JSON for your custom matrix. \'**-**' means stdin.
Here are all the built-in error diffusion matrices. You can find
details on these matrices here:
\<https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/error_diffusers.go\>
- Simple2D
- FloydSteinberg
- FalseFloydSteinberg
- JarvisJudiceNinke
- Atkinson
- Stucki
- Burkes
- Sierra (or Sierra3)
- TwoRowSierra (or Sierra2)
- SierraLite (or Sierra2_4A)
- StevenPigeon
Their names are case-insensitive, and hyphens and underscores are
treated the same.
The JSON format (whether inline or in a file) for a custom matrix is
very simple, just a 2D array. The matrix must be "rectangular",
meaning each array must have the same length.
**-s**, **\--serpentine**
Enable serpentine dithering, which "snakes" 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.
# TIPS
Read about **\--strength** if you haven't already.
Read about **\--recolor** if you haven't already.
It's easy to mess up a dithered image by scaling it manually. It's best
to scale the image to the size you want before dithering (externally, or
with **\--width** and/or **\--height**), and then leave it
If you need to scale it up afterward, use **\--upscale**, rather than
another tool. This will prevent image artifacts or blurring.
Be wary of environments where you can't make sure an image will be
displayed at 100% size, pixel for pixel. Make sure nearest-neighbor
scaling is being used at least.
Dithered images must only be encoded in a lossless image format. This is
why the tool only outputs PNG or GIF.
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 **didder --height
500 --upscale 2 \[\...\]**. Depending on the input image size and what
final size you want, you can of course just upscale as well.
# EXAMPLES
**didder --palette \`black white\' -i input.jpg -o test.png bayer 16x16**
This command dithers `input.jpg` to just use black and white
(implicitly converting to grayscale first), using a 16x16 Bayer
matrix. The result is written to `test.png`.
TODO
# REPORTING BUGS
Any bugs can be reported by creating an issue on GitHub:
\<https://github.com/makeworld-the-better-one/didder\>

View File

@@ -1,16 +1,22 @@
GITV != git describe --tags
GITC != git rev-parse --verify HEAD
SRC != find . -type f -name '*.go' ! -name '*_test.go'
TEST != find . -type f -name '*_test.go'
GITV != git describe --tags
GITC != git rev-parse --verify HEAD
SRC != find . -type f -name '*.go' ! -name '*_test.go'
TEST != find . -type f -name '*_test.go'
DATEC != date +'%B %d, %Y'
PREFIX ?= /usr/local
VERSION ?= $(GITV)
COMMIT ?= $(GITC)
BUILDER ?= Makefile
DATE ?= $(DATEC)
GO := go
INSTALL := install
RM := rm
SED := sed
PANDOC := pandoc
GZIP := gzip
MANDB := mandb
didder: go.mod go.sum $(SRC)
GO111MODULE=on CGO_ENABLED=0 $(GO) build -o $@ -ldflags="-s -w -X main.version=$(VERSION) -X main.commit=$(COMMIT) -X main.builtBy=$(BUILDER)"
@@ -19,10 +25,22 @@ didder: go.mod go.sum $(SRC)
clean:
$(RM) -f didder
.PHONY: man
man:
$(PANDOC) didder.1.md -s -t man -o didder.1
$(SED) -i 's/VERSION/$(VERSION)/g' didder.1
$(SED) -i 's/DATE/$(DATE)/g' didder.1
$(PANDOC) -f man didder.1 -o MANPAGE.md
$(SED) -i '1s/^/<!-- DO NOT EDIT, AUTOMATICALLY GENERATED, EDIT dither.1.md INSTEAD -->\n/' MANPAGE.md
$(SED) -i 's/: //g' MANPAGE.md
$(SED) -i 's/ //g' MANPAGE.md
.PHONY: install
install: dither
install: didder
$(INSTALL) -d $(PREFIX)/bin/
$(INSTALL) -m 755 didder $(PREFIX)/bin/didder
$(GZIP) -c didder.1 > /usr/share/man/man1/didder.1.gz
mandb
.PHONY: uninstall
uninstall:

View File

@@ -82,8 +82,9 @@ sudo make install # If you want to install the binary for all users
didder [global options] command [command options] [arguments...]
```
Run `didder` to see some info, and the global options and commands. Run `didder help cmd` or `didder cmd --help` to see information and opions for a specific command.
Each command represents a different dithering algorithm, or set of algorithms.
The best place to learn about how to use didder is the manual. Run `man didder`, or look at the [MANPAGE.md](./MANPAGE.md) file. If you only read about one flag, read about `--strength`. It's especially important for `bayer` dithering of color images.
You can also run `didder` to see the global options and commands. Each command represents a different dithering algorithm, or set of algorithms. You can see the options for each command with `didder help cmd` or `didder cmd --help`.
Here's a fully working command as an example:
```shell
@@ -119,39 +120,6 @@ The main reason for using any other dithering algorithm would be
If you want to see examples of the different dithering algorithms, you can look at [this directory](https://github.com/makeworld-the-better-one/dither/tree/master/images/output). Or try them out yourself!
## Avoid these mistakes
- It's easy to mess up a dithered image by scaling it manually. It's best to scale the image to the size you want before dithering (externally, or with `--width` and/or `--height`), and then leave it
- If you need to scale it up afterward, use `--upscale`, rather than another tool. This will prevent image artifacts or blurring.
- Be wary of environments where you can't make sure an image will be displayed at 100% size, pixel for pixel. Make sure nearest-neighbor scaling is being used at least.
- Dithered images must only be encoded in a lossless image format. This is why the tool only outputs PNG or GIF.
See [here](https://github.com/makeworld-the-better-one/dither#scaling-images) for more information on these points.
## Strength
The `--strength` flag applies to every command except `random`. By default it is set to 100%, meaning that the dithering is applied at full strength.
Reducing the strength is often visibly similar to reducing contrast. With `edm`, this can be used to reduce noise, when set to a value around 80%.
For `bayer` grayscale palette images, usually 100% is fine, but for 4x4 matrices or smaller, you may need to reduce the strength. For `bayer` (and by extension `odm`) color palette images, several sites recommend 64% strength (written as 256/4). This is often a good default for `bayer`/`odm` dithering color images, as 100% will distort colors too much.
## When to use `--recolor`
The `--recolor` 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](https://en.wikipedia.org/wiki/List_of_video_game_console_palettes#Game_Boy). By setting `--palette` to shades of gray and then `--recolor`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 "hue shifting" or "colorizing" an image in image editing software.
For these situations, `--recolor` should usually be a palette made up of one hue, and `--palette` should be the grayscale version of that palette. The `--palette` could also be just equally spread grayscale values, which would increase the contrast but make the luminance inaccurate.
Recoloring can also be useful for increasing contrast on a strange palette, like: `--palette 'black white' --recolor 'indigo LimeGreen'`. Setting just `--palette 'indigo LimeGreen'` would give bad (low contrast) results because that palette is not that far apart in RGB space. These "bad results" are much more pronounced when the input image is in color, because three dimensions are being reduced.
Another usage of `--recolor` would be to invert the image colors, by providing `--palette` in reverse. But this is the same as providing the inverted image beforehand.
If you have found other uses for `--recolor`, let me know!
## Other info
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 `didder --height 500 --upscale 2 [...]`. Depending on the input image size and what final size you want, you can of course just upscale as well.
## License
This project is licensed under the GPL v3.0. See the [LICENSE](./LICENSE) file for details.

494
didder.1 Normal file
View File

@@ -0,0 +1,494 @@
.\" Automatically generated by Pandoc 2.13
.\"
.TH "DIDDER" "1" "April 30, 2021" "didder " "User Manual"
.hy
.SH NAME
.PP
didder - dither images
.SH SYNOPSIS
.PP
\f[B]didder\f[R] [global options] command [command options]
[arguments\&...]
.SH DESCRIPTION
.PP
Dither images with a variety of algorithms and processing options.
.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 represents a dithering algorithm or set of algorithms to
apply to the input image(s).
.PP
Homepage: <https://github.com/makeworld-the-better-one/didder>
.SH GLOBAL 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:
<https://golang.org/pkg/path/filepath/#Match>
.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
<https://www.w3.org/TR/SVG11/types.html#ColorKeywords>
.PP
Images are converted to grayscale automatically if the palette is
grayscale.
This produces more correct results.
.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].
.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:
<https://en.wikipedia.org/wiki/List_of_video_game_console_palettes#Game_Boy>.
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 means infinite looping.
.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]
- 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
-0.5,0.5 is a good default.
.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.
.RE
.TP
\f[B]bayer\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]
- Ordered Dither 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:
<https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/ordered_ditherers.go>
.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:
<https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#OrderedDitherMatrix>
.RE
.IP
.nf
\f[C]
{
\[dq]matrix\[dq]: [
[12, 5, 6, 13],
[4, 0, 1, 7],
[11, 3, 2, 8],
[15, 10, 9, 14]
],
\[dq]max\[dq]: 16
}
\f[R]
.fi
.TP
\f[B]edm\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:
<https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/error_diffusers.go>
.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
.PP
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 or 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 nearest-neighbor scaling is being used at least.
.PP
Dithered images must only be encoded in a lossless image format.
This is why the tool only outputs PNG or 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.
.SH EXAMPLES
.TP
\f[B]didder \[en]palette `black white' -i input.jpg -o test.png bayer 16x16\f[R]
This command dithers \f[C]input.jpg\f[R] to just use black and white
(implicitly converting to grayscale first), using a 16x16 Bayer matrix.
The result is written to \f[C]test.png\f[R].
.PP
TODO
.SH REPORTING BUGS
.PP
Any bugs can be reported by creating an issue on GitHub:
<https://github.com/makeworld-the-better-one/didder>

220
didder.1.md Normal file
View File

@@ -0,0 +1,220 @@
---
title: DIDDER
section: 1
header: User Manual
footer: didder VERSION
date: DATE
---
# NAME
didder - dither images
# SYNOPSIS
**didder** \[global options] command [command options] [arguments...]
# DESCRIPTION
Dither images with a variety of algorithms and processing options.
Mandatory global flags are **\--palette**, **\--in**, and **\--out**, all others are optional. Each command represents a dithering algorithm or set of algorithms to apply to the input image(s).
Homepage: <https://github.com/makeworld-the-better-one/didder>
# GLOBAL OPTIONS
**-i**, **\--in** *PATH*
: Set the input file. This flag can be used multiple times to dither multiple images with the same palette and method. A *PATH* of \'**\-**' stands for standard input.
The input file path can also be parsed as a glob. This will only happen if the path contains an asterisk. For example **\-i \'\*.jpg'** will select all the .jpg files in the current directory as input. See this page for more info on glob pattern matching: <https://golang.org/pkg/path/filepath/#Match>
**-o**, **\--out** *PATH*
: Set the output file or directory. A *PATH* of \'**\-**' stands for standard output.
If *PATH* 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.
If *PATH* is a file, that ends in .gif (or **\--format gif** is set) then multiple input files will be combined into an animated GIF.
**-p**, **\--palette** *COLORS*
: 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.
A list of all color names is available at <https://www.w3.org/TR/SVG11/types.html#ColorKeywords>
Images are converted to grayscale automatically if the palette is grayscale. This produces more correct results.
**-r**, **\--recolor** *COLORS*
: Set the color palette used for replacing the dithered color palette after dithering. The argument syntax is the same as **\--palette**.
The **\--recolor** 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: <https://en.wikipedia.org/wiki/List_of_video_game_console_palettes#Game_Boy>. By setting **\--palette** to shades of gray and then **\--recolor**-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 "hue shifting" or "colorizing" an image in image editing software.
For these situations, **\--recolor** should usually be a palette made up of one hue, and **\--palette** should be the grayscale version of that palette. The **\--palette** could also be just equally spread grayscale values, which would increase the contrast but make the luminance inaccurate.
Recoloring can also be useful for increasing contrast on a strange palette, like: **\--palette \'black white' \--recolor \'indigo LimeGreen'**. Setting just **\--palette \'indigo LimeGreen'** would give bad (low contrast) results because that palette is not that far apart in RGB space. These "bad results" are much more pronounced when the input image is in color, because three dimensions are being reduced.
**-s**, **\--strength** *DECIMAL/PERCENT*
: Set the strength of dithering. This will affect every command except **random**. 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.
Reducing the strength is often visibly similar to reducing contrast. With the **edm** command, **\--strength** can be used to reduce noise, when set to a value around 80%.
When using the **bayer** command with a grayscale palette, usually 100% is fine, but for 4x4 matrices or smaller, you may need to reduce the strength. For **bayer** (and by extension **odm**) color palette images, several sites recommend 64% strength (written as 256/4). This is often a good default for **bayer**/**odm** dithering color images, as 100% will distort colors too much. Do not use the default of 100% for Bayer dithering color images.
**-j**, **\--threads** *NUM*
: 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 **edm**, as error diffusion dithering cannot be parallelized.
**-g**, **\--grayscale**
: Make input image(s) grayscale before dithering.
**\--saturation** *DECIMAL/PERCENT*
: 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 **\--grayscale**.
**\--brightness** *DECIMAL/PERCENT*
: 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.
**\--contrast** *DECIMAL/PERCENT*
: 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.
**\--no-exif-rotation**
: Disable using the EXIF rotation flag in image metadata to rotate the image before processing.
**-f**, **\--format** *FORMAT*
: Set the output file format. Valid options are \'png' and \'gif'. It will auto detect from filename when possible, so usually this does not need to be set. If **-o** is \'**-**' 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.
**\--no-overwrite**
: 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.
**-c**, **\--compression** *TYPE*
: Set the type of PNG compression. Options are \'default', \'no', \'speed', and \'size'. This flag is ignored for non-PNG output.
**\--fps** *DECIMAL*
: 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.
**-l**, **\--loop** *NUM*
: Set the number of times animated GIF output should loop. 0 is the default, and means infinite looping.
**-x**, **\--width** *NUM*
: Set the width the input image(s) will be resized to, before dithering. Aspect ratio will be maintained if **\--height** is not specified as well.
**-y**, **\--height** *NUM*
: Set the height the input image(s) will be resized to, before dithering. Aspect ratio will be maintained if **\--width** is not specified as well.
**-u**, **\--upscale** *NUM*
: Scale image up after dithering. So \'2' will make the output two times as big as the input (after **-x** and/or **-y**). Only integers are allowed, as scaling up by a non-integer amount would distort the dithering pattern and introduce artifacts.
**-v**, **\--version**
: Get version information.
# COMMANDS
**random**
: \- grayscale and RGB random dithering
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.
-0.5,0.5 is a good default.
**-s**, **\--seed** *DECIMAL*
: 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.
**bayer**
: \- Bayer matrix ordered dithering
Requires two arguments, for the X and Y dimension of the matrix. They can be separated by a space, comma, or \'x'. Both arguments must be a power of two, with the exception of: 3x5, 5x3, and 3x3.
**odm**
: \- Ordered Dither Matrix
Select or provide an ordered dithering matrix. This only takes one argument, but there a few types available:
- A preprogrammed matrix name\
- Inline JSON of a custom matrix\
- Or a path to JSON for your custom matrix. \'**-**' means standard input.
Here are all the built-in ordered dithering matrices. You can find details on these matrices here: <https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/ordered_ditherers.go>
- ClusteredDot4x4\
- ClusteredDotDiagonal8x8\
- Vertical5x3\
- Horizontal3x5\
- ClusteredDotDiagonal6x6\
- ClusteredDotDiagonal8x8_2\
- ClusteredDotDiagonal16x16\
- ClusteredDot6x6\
- ClusteredDotSpiral5x5\
- ClusteredDotHorizontalLine\
- ClusteredDotVerticalLine\
- ClusteredDot8x8\
- ClusteredDot6x6_2\
- ClusteredDot6x6_3\
- ClusteredDotDiagonal8x8_3
Their names are case-insensitive, and hyphens and underscores are treated the same.
The JSON format (whether inline or in a file) looks like the below. The matrix must be "rectangular", meaning each array must have the same length. More information how to use a custom matrix can be found here: <https://pkg.go.dev/github.com/makeworld-the-better-one/dither/v2#OrderedDitherMatrix>
```json
{
"matrix": [
[12, 5, 6, 13],
[4, 0, 1, 7],
[11, 3, 2, 8],
[15, 10, 9, 14]
],
"max": 16
}
```
**edm**
: \- Error Diffusion Matrix
Select or provide an error diffusion matrix. This only takes one argument, but there a few types available:
- A preprogrammed matrix name\
- Inline JSON of a custom matrix\
- Or a path to JSON for your custom matrix. \'**-**' means stdin.
Here are all the built-in error diffusion matrices. You can find details on these matrices here: <https://github.com/makeworld-the-better-one/dither/blob/v2.0.0/error_diffusers.go>
- Simple2D\
- FloydSteinberg\
- FalseFloydSteinberg\
- JarvisJudiceNinke\
- Atkinson\
- Stucki\
- Burkes\
- Sierra (or Sierra3)\
- TwoRowSierra (or Sierra2)\
- SierraLite (or Sierra2_4A)\
- StevenPigeon
Their names are case-insensitive, and hyphens and underscores are treated the same.
The JSON format (whether inline or in a file) for a custom matrix is very simple, just a 2D array. The matrix must be "rectangular", meaning each array must have the same length.
**-s**, **\--serpentine**
: Enable serpentine dithering, which "snakes" 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.
# TIPS
Read about **\--strength** if you haven't already.
Read about **\--recolor** if you haven't already.
It's easy to mess up a dithered image by scaling it manually. It's best to scale the image to the size you want before dithering (externally, or with **\--width** and/or **\--height**), and then leave it
If you need to scale it up afterward, use **\--upscale**, rather than another tool. This will prevent image artifacts or blurring.
Be wary of environments where you can't make sure an image will be displayed at 100% size, pixel for pixel. Make sure nearest-neighbor scaling is being used at least.
Dithered images must only be encoded in a lossless image format. This is why the tool only outputs PNG or GIF.
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 **didder --height 500 --upscale 2 [...]**. Depending on the input image size and what final size you want, you can of course just upscale as well.
# EXAMPLES
**didder --palette 'black white' -i input.jpg -o test.png bayer 16x16**
: This command dithers `input.jpg` to just use black and white (implicitly converting to grayscale first), using a 16x16 Bayer matrix. The result is written to `test.png`.
TODO
# REPORTING BUGS
Any bugs can be reported by creating an issue on GitHub: <https://github.com/makeworld-the-better-one/didder>

117
main.go
View File

@@ -17,153 +17,102 @@ var (
)
func main() {
var (
matrixTypesDesc = "This only takes one argument, but there a few types available:\n" +
helpList(1,
"A preprogrammed matrix name",
"Inline JSON of a custom matrix",
"Or a path to JSON for your custom matrix. '-' means stdin.",
) + "\n"
decimalOrPercent = ", using a decimal or percentage."
caseInsensitiveNames = "\nTheir names are case-insensitive, and hyphens and underscores are treated the same."
description = `
Colors (for --palette and --recolor) are entered as a single quoted argument.
They can be separated by spaces and commas. Colors can be formatted as RGB tuples,
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.
Color names: https://www.w3.org/TR/SVG11/types.html#ColorKeywords
Images are converted to grayscale automatically if the palette is grayscale.
This produces more correct results.
Decimal range is -1.0 to 1.0. Percentage range is -100% or 100%.
The input file path can also be parsed as a glob. This will only happen if the
path contains an asterisk. For example -i '*.jpg' will select all the .jpg
files in the current directory as input. See this page for more info on glob
pattern matching: https://golang.org/pkg/path/filepath/#Match`
)
app := &cli.App{
Name: "didder",
Usage: "dither images with a variety of algorithms and processing options.",
Description: description,
Description: "didder dithers images.\n\nRun `man didder` for more information, or view the manual online:\nhttps://github.com/makeworld-the-better-one/didder/blob/main/MANPAGE.md",
UseShortOptionHandling: true,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "strength",
Aliases: []string{"s"},
Usage: "set strength of dithering" + decimalOrPercent + " Exceeding the range will work. A zero value will be ignored.",
},
&cli.UintFlag{
Name: "threads",
Aliases: []string{"j"},
Usage: "set number of threads for ordered dithering",
},
&cli.StringFlag{
Name: "palette",
Aliases: []string{"p"},
Usage: "set color palette used for dithering",
Required: true,
},
&cli.BoolFlag{
Name: "grayscale",
Usage: "make input image(s) grayscale before dithering",
Name: "grayscale",
Aliases: []string{"g"},
},
&cli.StringFlag{
Name: "saturation",
Usage: "change input image(s) saturation before dithering" + decimalOrPercent,
Name: "saturation",
},
&cli.StringFlag{
Name: "brightness",
Usage: "change input image(s) brightness before dithering" + decimalOrPercent,
Name: "brightness",
},
&cli.StringFlag{
Name: "contrast",
Usage: "change input image(s) contrast before dithering" + decimalOrPercent,
Name: "contrast",
},
&cli.StringFlag{
Name: "recolor",
Aliases: []string{"r"},
Usage: "set color palette used for replacing the dithered color palette after dithering",
},
&cli.BoolFlag{
Name: "no-exif-rotation",
Usage: "disable using the EXIF rotation flag to rotate the image before processing",
Name: "no-exif-rotation",
},
&cli.StringFlag{
Name: "format",
Aliases: []string{"f"},
Usage: "set output file format. Valid options are png and gif. It will auto detect from filename when possible.",
Value: "png",
},
&cli.StringFlag{
Name: "out",
Aliases: []string{"o"},
Usage: "set output file or directory, '-' for stdout",
Required: true,
},
&cli.StringSliceFlag{
Name: "in",
Aliases: []string{"i"},
Usage: "set input file; can be used multiple times; '-' for stdin",
Required: true,
},
&cli.BoolFlag{
Name: "no-overwrite",
Usage: "the command will stop before overwriting an existing file. Files written before this one was encountered will stay in place.",
Name: "no-overwrite",
},
&cli.StringFlag{
Name: "compression",
Aliases: []string{"c"},
Usage: "PNG compression type. Options: 'default', 'no', 'speed', 'size'",
Value: "default",
},
&cli.Float64Flag{
Name: "fps",
Usage: "set frames per second for animated GIF output",
Name: "fps",
},
&cli.UintFlag{
Name: "loop",
Usage: "number of times the animated GIF output should loop, 0 is infinite",
Name: "loop",
Aliases: []string{"l"},
},
&cli.UintFlag{
Name: "width",
Aliases: []string{"x"},
Usage: "set the width the input image(s) will be resized to, BEFORE dithering. Aspect ratio will be maintained if --height is not specified",
},
&cli.UintFlag{
Name: "height",
Aliases: []string{"y"},
Usage: "set the height the input image(s) will be resized to, BEFORE dithering. Aspect ratio will be maintained if --width is not specified",
},
&cli.UintFlag{
Name: "upscale",
Aliases: []string{"u"},
Usage: "scale image up AFTER dithering. So '2' will make the output 2 times as big as the input. Integer only.",
Value: 1,
},
&cli.BoolFlag{
Name: "version",
Aliases: []string{"v"},
Usage: "get version info",
},
},
Commands: []*cli.Command{
{
Name: "random",
Usage: "grayscale and RGB random dithering",
Description: "Specify two arguments (min and max) for RGB or grayscale, or 6 (min/max for each channel) to control each RGB channel.\nArguments can be separated by commas or spaces. -0.5,0.5 is a good default.",
Name: "random",
Usage: "grayscale and RGB random dithering",
Flags: []cli.Flag{
&cli.Int64Flag{
Name: "seed",
Aliases: []string{"s"},
Usage: "set the seed for randomization. This will also only use one thread, to keep output deterministic",
},
},
UseShortOptionHandling: true,
@@ -173,58 +122,22 @@ pattern matching: https://golang.org/pkg/path/filepath/#Match`
{
Name: "bayer",
Usage: "Bayer matrix ordered dithering",
Description: "Two arguments, for the X and Y dimension of the matrix. They can be separated by a space, comma, or 'x'.\nBoth arguments must be a power of two, with the exception of: 3x5, 5x3, and 3x3.",
UseShortOptionHandling: true,
Action: bayer,
},
{
Name: "odm",
Usage: "Ordered Dither Matrix",
Description: "Select or provide an ordered dithering matrix. " + matrixTypesDesc +
"Here are all the built-in ordered dithering matrices. You can find details on these matrices here:\nhttps://github.com/makeworld-the-better-one/dither/blob/v2.0.0/ordered_ditherers.go\n\n" +
helpList(1,
"ClusteredDot4x4",
"ClusteredDotDiagonal8x8",
"Vertical5x3",
"Horizontal3x5",
"ClusteredDotDiagonal6x6",
"ClusteredDotDiagonal8x8_2",
"ClusteredDotDiagonal16x16",
"ClusteredDot6x6",
"ClusteredDotSpiral5x5",
"ClusteredDotHorizontalLine",
"ClusteredDotVerticalLine",
"ClusteredDot8x8",
"ClusteredDot6x6_2",
"ClusteredDot6x6_3",
"ClusteredDotDiagonal8x8_3",
) + caseInsensitiveNames,
Name: "odm",
Usage: "Ordered Dither Matrix",
UseShortOptionHandling: true,
Action: odm,
},
{
Name: "edm",
Usage: "Error Diffusion Matrix",
Description: "Select or provide an error diffusion matrix. " + matrixTypesDesc +
"Here are all the built-in error diffusion matrices. You can find details on these matrices here:\nhttps://github.com/makeworld-the-better-one/dither/blob/v2.0.0/error_diffusers.go\n\n" +
helpList(1,
"Simple2D",
"FloydSteinberg",
"FalseFloydSteinberg",
"JarvisJudiceNinke",
"Atkinson",
"Stucki",
"Burkes",
"Sierra (or Sierra3)",
"TwoRowSierra (or Sierra2)",
"SierraLite (or Sierra2_4A)",
"StevenPigeon",
) + caseInsensitiveNames,
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "serpentine",
Aliases: []string{"s"},
Usage: "enable serpentine dithering",
},
},
UseShortOptionHandling: true,