first commit

This commit is contained in:
Yura 2024-09-15 15:12:16 +03:00
commit 417e54da96
5696 changed files with 900003 additions and 0 deletions

View file

@ -0,0 +1,148 @@
Generating the image test suite
-------------------------------
On Linux/unix systems, you can use the `imagemagick-testsuite.sh` script
to create an image test suite using the `convert` command line utility. You
must have ImageMagick installed ("apt install imagemagick" on debian
derivatives). There is also a rule in the Makefile, `make image-testsuite`.
A more comprehensive test suite can be generated using Gimp (tested on
version 2.8.18). To install the plugin, copy `gimp28-testsuite.py` to your
gimp plugins directory, on linux/unix systems usually `~/.gimp-2.8/plug-ins`.
You can find the plugin location via the Gimp menu `Edit` - `Preferences` -
`Folders` - `Plug-Ins`. Once installed, the plugin should appear in "Tools"
menu, named "Kivy image testsuite".
Test images must be saved in the `kivy/tests/image-testsuite` directory,
after this you can run the test. It is (currently) preferable to run it
directly as a script, instead of via `make test`, since the latter won't
give you useful debug output.
cd kivy/tests
python test_imageloader.py | less
or to get only the summary report:
python test_imageloader.py | grep REPORT | less
Kivy ImageLoader testsuite
--------------------------
These tools generate a wide range of images for testing Kivy's ImageLoaders.
The pixel data is encoded in the file name, and reproduced "from the sideline"
in order to verify the pixel data loaded from file. This is used to expose
issues in the Kivy core and underlying provider libraries.
The filenames consist of sections separated by an underscore `_`:
v0_ <W> x <H> _ <pat> _ <alpha> _ <fmt> _ <testname> _ <encoder> . <ext>
Variables are enclosed in pointy brackets. The leading `v0_` indicates that
it conforms to version 0 of the test protocol (described in this document)
and must be present.
v0_5x1_rgb_FF_PNG24_OPAQUE_magick.png
This is a 5x1 image, pattern is "rgb", alpha is "FF". `PNG24` is the internal
file format name (ImageMagick-specific), and `OPAQUE` is the test we are
performing (drawing opaque pixels only), see test names below.
* <pattern> indicates the pixel colors (in order), as they are drawn in the
image file.
* <alpha> is the global alpha from 00-FF (2 bytes, ascii) which is applied to
all pixels except 't' (transparent) which have fixed alpha at 00
* <fmt> (aka fmtinfo) is an encoder-specific string with information about the
format or process that generated the file. For example, if the same image
is saved with and without interlacing, it will contain "I1" and "I0" to
distinguish the files.
* ImageMagick test suite generator uses magick format name, such as `PNG24`
* The Gimp generator plugin adds information about the layer that was
exported to form the image:
* BPP1G = 1 byte per pixel, gray
* BPP2GA = 2 bytes per pixel, gray + alpha
* BPP3 = 3 bytes per pixel, rgb
* BPP4 = 4 bytes per pixel, rgba
* IX = indexed, IXA = indexed+alpha
* Note: Indexed images are drawn in RGB or GRAY images (with alpha if
needed), and converted to indexed before export. These values
represent the layer type at time of export, it affects the parameters
used for encoding the output data.
* <testname> is a special string that indicates what type of data is expected
in the file. Options are OPAQUE, BINARY, ALPHA and repeated for grayscale,
GRAY-OPAQUE, GRAY-BINARY, GRAY-ALPHA. We expect BINARY and ALPHA tests to
result in an alpha channel (details below)
* <encoder> identifies the software that created the file, "magick", "gimp" ..
* <ext> is the extension, must be lowercase and match the extensions
supported by Kivy image loaders (or they will be ignored)
Test names
----------
* `OPAQUE` tests opaque pixels (normal RGB) (lossless formats)
* `BINARY` tests opaque + fully transparent pixels (GIF etc)
* `ALPHA` tests semi-transparent pixels (normal RGBA) (PNG32 etc)
* `GRAY-OPAQUE` tests opaque grayscale only (various PNG, tga, )
* `GRAY-BINARY` tests opaque grayscale + fully transparent pixels (PNGs)
* `GRAY-ALPHA` tests semi-transparent grayscale pixels (TGA, XCF)
Patterns must conform to the specific test. For example, the pattern "rgb" has
undefined behavior for a grayscale test, since r/g/b can't be represented
in grayscale. So all grayscale formats must use 0-9A-F only, and optionally
't' for transparent pixels in GRAY-BINARY/GRAY-ALPHA.
| Test name | Valid pattern characters |
| -----------: | :---------------------------------------------------------- |
| OPAQUE | `wxrgbcyp`, and full grayscale\*\* |
| GRAY-OPAQUE | `0123456789ABCDEF` (full grayscale) |
| BINARY | `t` REQUIRED + `wrgbcyp`, limited grayscale (no 0/x!!!) |
| GRAY-BINARY | `t` REQUIRED + limited grayscale (no 0/x!!!) |
| ALPHA | `t`, `wxrbgcyp` and full grayscale\*\* |
| GRAY-ALPHA | `t`, `0123456789ABCDEF` (full grayscale) |
* `**`: While grayscale is supported here, it is generally better to use
colors, since all the bytes in a grayscale pixel represented as rgb are
identical. For example, 'A' or \xAA\xAA\xAA will pass despite a byte
order problem.
* `!!!`: In some cases, black color is used for binary transparency. So
if you use "0" (or "x"), test_imageloader will expect #000000FF in RGBA,
but the pixel becomes transparent (a=00) and test fails. All BINARY tests
**MUST** include at least one "t" pixel to ensure that the image is
saved with an alpha channel.
Pixel values
------------
Each character in the pattern represents the color of a single pixel. It is
important that you include only the correct type of pixel values for the
different test types (see table above). Individual pixel values get their
alpha from global setting (<alpha> in filename), but 't' pixels always have
alpha = 0x00 regardless of the test's alpha setting.
OPAQUE, BINARY, ALPHA (lowercase)
-----------------------------------------
"w" White (#fff) "x" Black (#000)!!!
"r" Red (#f00) "g" Green (#0f0)
"b" Blue (#00f) "y" Yellow (#ff0)
"c" Cyan (#0ff) "p" Purple (#f0f)
GRAY-OPAQUE, GRAY-BINARY, GRAY-ALPHA (uppercase)
------------------------------------------------
"0" #000!!! "1" #111 "2" #222 "3" #333
"4" #444 "5" #555 "6" #666 "7" #777
"8" #888 "9" #999 "A" #AAA "B" #BBB
"C" #CCC "D" #DDD "E" #EEE "F" #FFF
!!! See warnings above regarding BINARY tests

View file

@ -0,0 +1,329 @@
#!/usr/bin/env python
# flake8: noqa
import os
import re
import random
from gimpfu import *
# Test suite configuration - key is test name, values are:
#
# alpha....: global alpha, used for all pixels except 't'
# patterns.: allowed v0 pattern characters (+ force include and exclude)
# *_IMAGE..: gimp layer types to export for this test, w/target extensions
TESTSUITE_CONFIG = {
'OPAQUE': {
'alpha': [255],
'patterns': ('wxrgbcyp', None, None),
RGB_IMAGE: ['xcf', 'png', 'tga', 'tiff', 'ppm',
'sgi', 'pcx', 'fits', 'ras'],
INDEXED_IMAGE: ['xcf', 'png', 'tga', 'tiff', 'ppm', 'gif', 'ras'],
},
'GRAY-OPAQUE': {
'alpha': [255],
'patterns': ('0123456789ABCDEF', None, None),
GRAY_IMAGE: ['xcf', 'png', 'tga', 'tiff',
'pgm', 'sgi', 'fits', 'ras'],
INDEXED_IMAGE: ['xcf', 'png', 'tga', 'tiff', 'pgm', 'fits', 'ras'],
},
'BINARY': {
'alpha': [255],
'patterns': ('twrgbcyp', 't', None),
RGBA_IMAGE: ['xcf', 'png', 'tga', 'ico', 'sgi'],
INDEXEDA_IMAGE: ['xcf', 'png', 'tga', 'gif'],
},
'GRAY-BINARY': {
'alpha': [255],
'patterns': ('t123456789ABCDEF', 't', None),
GRAYA_IMAGE: ['xcf', 'tga', 'png', 'sgi'],
INDEXEDA_IMAGE: ['xcf', 'tga', 'png'],
},
"ALPHA": {
'alpha': [0x7F, 0xF0],
'patterns': ('twxrgbcyp', None, None),
RGBA_IMAGE: ['xcf', 'png', 'tga', 'sgi'],
},
'GRAY-ALPHA': {
'alpha': [0x7F, 0xF0],
'patterns': ('t0123456789ABCDEF', None, None),
GRAYA_IMAGE: ['xcf', 'png', 'tga', 'sgi'],
},
}
# kivy image test protocol v0 data: key is pattern char, value is pixel w/o a
v0_PIXELS = {
'w': [0xFF, 0xFF, 0xFF], 'x': [0x00, 0x00, 0x00], 'r': [0xFF, 0x00, 0x00],
'g': [0x00, 0xFF, 0x00], 'b': [0x00, 0x00, 0xFF], 'y': [0xFF, 0xFF, 0x00],
'c': [0x00, 0xFF, 0xFF], 'p': [0xFF, 0x00, 0xFF], '0': [0x00, 0x00, 0x00],
'1': [0x11, 0x11, 0x11], '2': [0x22, 0x22, 0x22], '3': [0x33, 0x33, 0x33],
'4': [0x44, 0x44, 0x44], '5': [0x55, 0x55, 0x55], '6': [0x66, 0x66, 0x66],
'7': [0x77, 0x77, 0x77], '8': [0x88, 0x88, 0x88], '9': [0x99, 0x99, 0x99],
'A': [0xAA, 0xAA, 0xAA], 'B': [0xBB, 0xBB, 0xBB], 'C': [0xCC, 0xCC, 0xCC],
'D': [0xDD, 0xDD, 0xDD], 'E': [0xEE, 0xEE, 0xEE], 'F': [0xFF, 0xFF, 0xFF]}
# kivy image test protocol v0: return pixel data for given pattern char
def v0_pattern_pixel(char, alpha, fmt):
if fmt == 'rgba':
if char == 't':
return [0, 0, 0, 0]
return v0_PIXELS[char] + [alpha]
if fmt == 'rgb':
if char == 't':
return [0, 0, 0]
return v0_PIXELS[char]
if fmt == 'gray':
assert char in '0123456789ABCDEF'
return [v0_PIXELS[char][0]]
if fmt == 'graya':
assert char in 't0123456789ABCDEF'
if char == 't':
return [0, 0]
return [v0_PIXELS[char][0]] + [alpha]
raise Exception('v0_pattern_pixel: unknown format {}'.format(fmt))
# kivy image test protocol v0: filename
def v0_filename(w, h, pat, alpha, fmtinfo, testname, ext):
return 'v0_{}x{}_{}_{:02X}_{}_{}_gimp.{}'.format(
w, h, pat, alpha, fmtinfo, testname, ext)
# Saves an image to one or more files. We can't specify these details when
# saving by extension. (This declaration is PEP8 compliant, 's all good)
def save_image(dirname, img, lyr, w, h, pat, alpha, v0_fmtinfo, testname, ext):
def filename(fmtinfo_in=None):
fmtinfo = fmtinfo_in and v0_fmtinfo + '-' + fmtinfo_in or v0_fmtinfo
return v0_filename(w, h, pat, alpha, fmtinfo, testname, ext)
def savepath(fn):
return os.path.join(dirname, fn)
if ext in ('ppm', 'pgm', 'pbm', 'pnm', 'pam'):
fn = filename('ASCII')
pdb.file_pnm_save(img, lyr, savepath(fn), fn, 0)
fn = filename('RAW')
pdb.file_pnm_save(img, lyr, savepath(fn), fn, 1)
elif ext == 'tga':
# FIXME: Last argument to file_tga_save is undocumented, not sure what
fn = filename('RAW')
pdb.file_tga_save(img, lyr, savepath(fn), fn, 0, 0)
fn = filename('RLE')
pdb.file_tga_save(img, lyr, savepath(fn), fn, 1, 0)
elif ext == 'gif':
fn = filename('I0')
pdb.file_gif_save(img, lyr, savepath(fn), fn, 0, 0, 0, 0)
fn = filename('I1')
pdb.file_gif_save(img, lyr, savepath(fn), fn, 1, 0, 0, 0)
elif ext == 'png':
bits = [0, 1]
# interlaced, bkgd block, gama block
for i, b, g in [(i, b, g) for i in bits for b in bits for g in bits]:
fn = filename('I{}B{}G{}'.format(i, b, g))
pdb.file_png_save(img, lyr, savepath(fn), fn, i, 9, b, g, 1, 1, 1)
elif ext == 'sgi':
fn = filename('RAW')
pdb.file_sgi_save(img, lyr, savepath(fn), fn, 0)
fn = filename('RLE')
pdb.file_sgi_save(img, lyr, savepath(fn), fn, 1)
fn = filename('ARLE')
pdb.file_sgi_save(img, lyr, savepath(fn), fn, 2)
elif ext == 'tiff':
fn = filename('RAW')
pdb.file_tiff_save(img, lyr, savepath(fn), fn, 0)
fn = filename('LZW')
pdb.file_tiff_save(img, lyr, savepath(fn), fn, 1)
fn = filename('PACKBITS')
pdb.file_tiff_save(img, lyr, savepath(fn), fn, 2)
fn = filename('DEFLATE')
pdb.file_tiff_save(img, lyr, savepath(fn), fn, 3)
elif ext == 'ras':
fn = filename('RAW')
pdb.file_sunras_save(img, lyr, savepath(fn), fn, 0)
fn = filename('RLE')
pdb.file_sunras_save(img, lyr, savepath(fn), fn, 1)
else:
fn = filename()
pdb.gimp_file_save(img, lyr, savepath(fn), fn)
# Draw pattern on layer, helper for make_images() below
def draw_pattern(lyr, pat, alpha, direction, pixelgetter):
assert 0 <= alpha <= 255
assert re.match('[twxrgbycp0-9A-F]+$', pat)
assert direction in ('x', 'y', 'width', 'height')
dirx = direction in ('x', 'width')
for i in range(0, len(pat)):
pixel = pixelgetter(pat[i], alpha)
if dirx:
pdb.gimp_drawable_set_pixel(lyr, i, 0, len(pixel), pixel)
else:
pdb.gimp_drawable_set_pixel(lyr, 0, i, len(pixel), pixel)
# Create an image from the given pattern, with the specified layertype_in*,
# draw the pattern with given alpha, and save to the given extensions. Gimp
# adjust the encoder accordingly.
# * cheat for indexed formats: draw in RGB(A) and let gimp make palette
def make_images(testname, pattern, alpha, layertype_in, extensions, dirname):
assert testname.upper() == testname
assert len(pattern) > 0
assert len(extensions) > 0
assert isinstance(extensions, (list, tuple))
assert re.match('[wxtrgbcypA-F0-9]+$', pattern)
test_alpha = 'ALPHA' in testname or 'BINARY' in testname
grayscale = 'GRAY' in testname
# Indexed layer types are drawn in RGB/RGBA, and converted later
imgtype, v0_fmtinfo = {
GRAY_IMAGE: (GRAY, 'BPP1G'),
GRAYA_IMAGE: (GRAY, 'BPP2GA'),
RGB_IMAGE: (RGB, 'BPP3'),
RGBA_IMAGE: (RGB, 'BPP4'),
INDEXED_IMAGE: (grayscale and GRAY or RGB, 'IX'),
INDEXEDA_IMAGE: (grayscale and GRAY or RGB, 'IXA'),
}[layertype_in]
# We need to supply pixels of the format of the layer
PP = v0_pattern_pixel
pixelgetter = {
GRAY_IMAGE: lambda c, a: PP(c, a, 'gray'),
GRAYA_IMAGE: lambda c, a: PP(c, a, 'graya'),
RGB_IMAGE: lambda c, a: PP(c, a, 'rgb'),
RGBA_IMAGE: lambda c, a: PP(c, a, 'rgba'),
INDEXED_IMAGE: lambda c, a: PP(c, a, grayscale and 'gray' or 'rgb'),
INDEXEDA_IMAGE: lambda c, a: PP(c, a, grayscale and 'graya' or 'rgba'),
}[layertype_in]
# Pick the correct layer type for indexed formats
layertype = {
INDEXED_IMAGE: grayscale and GRAY_IMAGE or RGB_IMAGE,
INDEXEDA_IMAGE: grayscale and GRAYA_IMAGE or RGBA_IMAGE,
}.get(layertype_in, layertype_in)
# Draw pattern Nx1 and 1xN variations
for direction in 'xy':
# Create the gimp image, and the layer we will draw on
w, h = (direction == 'x') and (len(pattern), 1) or (1, len(pattern))
img = pdb.gimp_image_new(w, h, imgtype)
lyr = pdb.gimp_layer_new(img, w, h, layertype, 'P', 100, NORMAL_MODE)
# Add alpha layer if we are planning on encoding alpha information
if test_alpha:
pdb.gimp_layer_add_alpha(lyr)
pdb.gimp_drawable_fill(lyr, TRANSPARENT_FILL)
pdb.gimp_image_add_layer(img, lyr, 0)
# Draw it
draw_pattern(lyr, pattern, alpha, direction, pixelgetter)
# Convert to indexed before saving, if needed
if layertype_in in (INDEXED_IMAGE, INDEXEDA_IMAGE):
colors = len(set(pattern)) + (test_alpha and 1 or 0)
pdb.gimp_convert_indexed(img, 0, 0, colors, 0, 0, "ignored")
# Save each individual extension
for ext in extensions:
save_image(dirname, img, lyr,
w, h, pattern, alpha, v0_fmtinfo, testname, ext)
# FIXME: this fails?
# pdb.gimp_image_delete(img)
# FIXME: pattern generation needs thought, this sucks..
def makepatterns(allow, include=None, exclude=None):
src = set()
src.update([x for x in allow])
src.update([allow[:i] for i in range(1, len(allow) + 1)])
for i in range(len(allow)):
pick1, pick2 = random.choice(allow), random.choice(allow)
src.update([pick1 + pick2])
for i in range(3, 11) + range(14, 18) + range(31, 34):
src.update([''.join([random.choice(allow) for k in range(i)])])
out = []
for srcpat in src:
if exclude and exclude in srcpat:
continue
if include and include not in srcpat:
out.append(include + srcpat[1:])
continue
out.append(srcpat)
return list(set(out))
def plugin_main(dirname, do_opaque, do_binary, do_alpha):
if not dirname:
pdb.gimp_message("No output directory selected, aborting")
return
if not os.path.isdir(dirname) or not os.access(dirname, os.W_OK):
pdb.gimp_message("Invalid / non-writeable output directory, aborting")
return
tests = []
tests.extend({
0: ['OPAQUE', 'GRAY-OPAQUE'],
2: ['OPAQUE'],
3: ['GRAY-OPAQUE'],
}.get(do_opaque, []))
tests.extend({
0: ['BINARY', 'GRAY-BINARY'],
2: ['BINARY'],
3: ['GRAY-BINARY'],
}.get(do_binary, []))
tests.extend({
0: ['ALPHA', 'GRAY-ALPHA'],
2: ['ALPHA'],
3: ['GRAY-ALPHA'],
}.get(do_alpha, []))
suite_cfg = dict(TESTSUITE_CONFIG)
for testname, cfg in suite_cfg.items():
if testname not in tests:
continue
pchars, inc, exc = cfg.pop('patterns')
if not pchars:
continue
patterns = makepatterns(pchars, inc, exc)
for alpha in cfg.pop('alpha', [255]):
for layertype, exts in cfg.items():
if not exts:
continue
for p in patterns:
make_images(testname, p, alpha, layertype, exts, dirname)
register(
proc_name="kivy_image_testsuite",
help="Creates image test suite for Kivy ImageLoader",
blurb=("Creates image test suite for Kivy ImageLoader. "
"Warning: This will create thousands of images"),
author="For kivy.org, Terje Skjaeveland",
copyright="Copyright 2017 kivy.org (MIT license)",
date="2017",
imagetypes="",
params=[
(PF_DIRNAME, "outputdir", "Output directory:", 0),
(PF_OPTION, "opaque", "OPAQUE tests?", 0,
["All", "None", "OPAQUE", "GRAY-OPAQUE"]),
(PF_OPTION, "binary", "BINARY tests?", 0,
["All", "None", "BINARY", "GRAY-BINARY"]),
(PF_OPTION, "alpha", "ALPHA tests?", 0,
["All", "None", "ALPHA", "GRAY-ALPHA"]),
],
results=[],
function=plugin_main,
menu="<Image>/Tools/_Kivy image testsuite...",
label="Generate images...")
main()

View file

@ -0,0 +1,238 @@
#!/usr/bin/env sh
# ImageMagickFormat:extension
FMT_OPAQUE="TIFF:tiff BMP:bmp BMP3:bmp PNG:png GIF87:gif CUR:cur \
PPM:ppm FITS:fits RAS:ras"
FMT_BINARY="BMP:bmp GIF:gif PNG8:png PNG24:png PNG48:png ICO:ico"
FMT_ALPHA="PNG32:png PNG64:png TGA:tga SGI:sgi DPX:dpx"
# FIXME: Magick output is not completely predictable. Some images
# become gray+alpha, some palette, some bitonal, and it's not obvious
# how/if this can be controlled better
#FMT_BITONAL=""
FMT_GRAY_OPAQUE="PGM:pgm FITS:fits RAS:ras"
FMT_GRAY_BINARY="PNG8:png"
FMT_GRAY_ALPHA="PNG:png TGA:tga"
# Pixel values used for different tests
PIX_alpha="twxrgbcyp48A"
PIX_opaque="wxrgbcyp48A"
PIX_binary="twrgbcyp48A"
PIX_gray_opaque="0123456789ABCDEF"
PIX_gray_binary="t123456789ABCDEF"
PIX_gray_alpha="t0123456789ABCDEF"
usage() { cat <<EOM
Usage: $0 <target-directory>
Creates test images in many formats using ImageMagick 'convert'
utility. The pixel values are encoded in the filename, so they
can be reconstructed and verified independently. This system
is referred to as the image test protocol (version 0).
More info: kivy/tools/image-testsuite/README.md
EOM
}
# Outputs command line arguments for convert to draw pixels from the
# specified pattern in the specified direction. It is always 1 in w or h.
draw_pattern() {
pattern=$1
direction="${2:-x}"
pos=0
for char in $(echo $pattern | fold -w1); do
case $char in
t) fill="#00000000" ;;
w) fill="#FFFFFF${TESTALPHA}" ;;
x) fill="#000000${TESTALPHA}" ;;
r) fill="#FF0000${TESTALPHA}" ;;
g) fill="#00FF00${TESTALPHA}" ;;
b) fill="#0000FF${TESTALPHA}" ;;
y) fill="#FFFF00${TESTALPHA}" ;;
c) fill="#00FFFF${TESTALPHA}" ;;
p) fill="#FF00FF${TESTALPHA}" ;;
0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)
fill="#${char}${char}${char}${char}${char}${char}${TESTALPHA}"
;;
*) (>&2 echo "Error: Invalid pattern char: $char"); exit 100 ;;
esac
case $direction in
y|height) echo -n "-draw 'fill $fill color 0, $pos point' " ;;
x|width) echo -n "-draw 'fill $fill color $pos, 0 point' " ;;
esac
pos=$((pos+1))
done
}
# Creates 1xN and Nx1 test images from the given pattern, in the given
# format. Only use alpha != FF if you are actually testing alpha.
make_images() {
pattern=$1
len=${#pattern}
if [ -z $pattern ] || [ -z $TESTFMT ] || [ -z $TESTEXT ]; then
(>&2 echo "make_images() missing required arguments/environment")
exit 101
fi
if [ ${#TESTALPHA} != 2 ]; then
(>&2 echo "make_images() invalid TESTALPHA: $TESTALPHA")
exit 102
fi
# Nx1
ending="${TESTALPHA}_${TESTFMT}_${TESTNAME}_magick.${TESTEXT}"
outfile="v0_${len}x1_${pattern}_${ending}"
eval convert -size ${len}x1 xc:none -quality 100% $TESTARGS \
$(draw_pattern "$pattern" "x") \
${convert_args} \
"${TESTFMT}:$destdir/$outfile"
# 1xN - don't create duplicates for single pixel
if [ $len -ne 1 ]; then
outfile="v0_1x${len}_${pattern}_${ending}"
eval convert -size 1x${len} xc:none -quality 100% $TESTARGS \
$(draw_pattern "$pattern" "y") \
"${TESTFMT}:$destdir/$outfile"
fi
}
# Make a random pattern from given characters $1 at length $2
# FIXME: portability?
mkpattern() {
< /dev/urandom LC_ALL=C tr -dc "$1" | head -c $2
}
# Makes simple permutations and random patterns, optionally with
# prefix and postfix (args are pattern, prefix, postfix)
permutepattern() {
if [ -z "$1" ]; then
(>&2 echo "permutepattern() missing required argument")
exit 200
fi
# Individual pixel values + poor permutation FIXME
for char in $(echo $1 | fold -w1); do
echo -n "$2${char}$3 "
if [ ! -z $p1 ]; then echo -n "$2${char}${p1}$3 "; fi
# Uncomment for more data
# if [ ! -z $p2 ]; then echo -n "$2${char}${p1}${p2}$3 "; fi
# if [ ! -z $p3 ]; then echo -n "$2${char}${p1}${p2}${p3}$3 "; fi
# if [ ! -z $p4 ]; then echo -n "$2${char}${p1}${p2}${p3}${p4}$3 "; fi
p4=$p3 ; p3=$p2 ; p2=$p1 ; p1=$char
done
# Random
for i in $(seq 3 9) $(seq 14 17) $(seq 31 33); do
echo -n "$2$(mkpattern "$1" "$i")$3 "
done
}
# ------------------------------------------------------------
# Main
# ------------------------------------------------------------
if [ "$#" -ne 1 ] || [ -z "$1" ]; then
echo "Usage: $0 <target-directory> (or -h for help)"
exit 1
fi
case $1 in
-h|--help) usage; exit 1 ;;
esac
if [ ! -d "$1" ]; then
(>&2 echo "Error: Destination directory '$1' does not exist")
exit 2
elif [ ! -w "$1" ]; then
(>&2 echo "Error: Destination directory '$1' not writeable")
exit 2
fi
destdir=$(cd "$1"; echo $(pwd))
if [ ! -x "$(command -v convert)" ]; then
(2>&1 echo "Required ImageMagick 'convert' not found in path")
exit 3
fi
# - Opaque patterns only include solid colors, alpha is fixed at FF
# - Binary patterns MUST include 't' pixels and MUST NOT include 'x' or '0'
# - Alpha can combine any pixel value and use alpha != FF
PAT_opaque=$(permutepattern "$PIX_opaque")
PAT_binary=$(permutepattern "$PIX_binary" "t")
PAT_alpha="${PAT_binary} $(permutepattern "$PIX_alpha")"
# Grayscale patterns use only grayscale pixel values + 't' and alpha,
# ie #000 #111 #222 .. #EEE #FFF (0 1 2 .. E F in patterns)
PAT_gray_opaque=$(permutepattern "$PIX_gray_opaque")
PAT_gray_binary=$(permutepattern "$PIX_gray_binary" "t")
PAT_gray_alpha="${PAT_gray_binary} $(permutepattern "$PIX_gray_alpha")"
start() {
TESTNAME="$1"
TESTARGS="$2"
TESTALPHA="FF"
TESTFMT=""
TESTEXT=""
}
inform() {
echo "[${TESTNAME}] Creating ${TESTFMT} (.${TESTEXT}) test images..."
}
# OPAQUE / GRAY_OPAQUE
start "OPAQUE" "-alpha off"
for rawfmt in $FMT_OPAQUE $FMT_BINARY $FMT_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for pat in $PAT_opaque; do
make_images "$pat"
done
done
start "GRAY-OPAQUE" "-alpha off -colorspace Gray"
for rawfmt in $FMT_GRAY_OPAQUE $FMT_GRAY_BINARY $FMT_GRAY_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for pat in $PAT_gray_opaque; do
make_images "$pat"
done
done
# BINARY / GRAY_BINARY
start "BINARY" "-alpha on"
for rawfmt in $FMT_BINARY $FMT_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for pat in $PAT_binary; do
make_images "$pat"
done
done
start "GRAY-BINARY" "-alpha on -colorspace Gray"
for rawfmt in $FMT_GRAY_BINARY $FMT_GRAY_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for pat in $PAT_gray_binary; do
make_images "$pat"
done
done
# ALPHA / GRAY_ALPHA
start "ALPHA" "-alpha on"
for rawfmt in $FMT_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for alpha in 7F F0; do
TESTALPHA=$alpha
for pat in $PAT_alpha; do
make_images "$pat"
done
done
done
start "GRAY-ALPHA" "-alpha on -colorspace Gray"
for rawfmt in $FMT_GRAY_ALPHA; do
TESTFMT=${rawfmt%:*}; TESTEXT=${rawfmt#*:}; inform
for alpha in 7F F0; do
TESTALPHA=$alpha
for pat in $PAT_gray_alpha; do
make_images "$pat"
done
done
done