first commit
This commit is contained in:
commit
417e54da96
5696 changed files with 900003 additions and 0 deletions
|
@ -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
|
||||
|
Binary file not shown.
|
@ -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()
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue