A bit on the design.
====================

My plan is to implement only the bare functionality at the C level,
with a multitude of simple commands, and each command handling only a
specific image type, or combination of types. The proper API to the
functions is then done in Tcl, making changes to option processing,
automatic selection of a function, etc. easy to code, and change.

See http://wiki.tcl.tk/2520 (A critical mindset about policy), which
summarizes to "No poli-C, please", or, slightly longer, "Policy issues
must be scripted".

As a simple example, consider the operation ot invert images.

	We will have one command for each image type supporting the
	operation. Currently we have three, one each for rgb, rgba,
	and grey8. The API is then a single invert procedure which
	queries the type of its argument and then dispatches to the
	proper low-level command, or throws an error with a nice
	message.

	Now any changes to the error message can be done by easy
	editing of the Tcl layer, without having to recompile the C
	level.

Similarly for importing from and exporting to files/channels/tk,
conversion between types (where sensible or possible), etc.

Side note:
	Writing the Tcl layer should become easier the more uniform
	the syntax of the underlying group of commands.


Operations done and under consideration
=======================================

[]	write - Export a crimp image to other formats.

	[]	write_grey16_tk
	[]	write_grey32_tk
	[done]	write_grey8_tk
	[done]	write_rgb_tk
	[done]	write_rgba_tk

[]	read  - Import crimp images from other formats.

	[done]	read_tk
	[done]	read_tcl	(list of list of grey)

[]	convert - convert between the various crimp image types.

	[]	convert_hsv_grey16
	[]	convert_hsv_grey32
	[]	convert_hsv_grey8
	[done]	convert_hsv_rgb
	[done]	convert_hsv_rgba	- see the notes on rgb_rgba below. essentially apply here as well.

	[]	convert_rgb_grey16
	[]	convert_rgb_grey32
	[done]	convert_rgb_grey8
	[done]	convert_rgb_hsv
	[]	convert_rgb_rgba	- set opaque alpha, or transparent, or via grey image ?
					- could be done as split/join

	[]	convert_rgba_grey16   - Like grey8, or should we expand to cover whole range ?
	[]	convert_rgba_grey32   - S.a.
	[done]	convert_rgba_grey8    - Standard luma transform (ITU-R 601-2)
	[done]	convert_rgba_hsv
	[]	convert_rgba_rgb

[]	invert - invert colors

	[]	invert_grey16
	[]	invert_grey32
	[done]	invert_grey8
	[]	invert_hsv	- How is inversion defined in this colorspace ? (*)
	[done]	invert_rgb
	[done]	invert_rgba

	(*)	I am speculating that the HUE would rotate by 180 degrees.
		I have no idea if VALUE or SAT should change as well,
		in a similar manner.

[]	split - split the input image into its channels, i.e.
		RGBA into 4 images, one each for R, G, B, and A.
		Etc. for the other types.

	[done]	split_rgba
	[done]	split_rgb
	[done]	split_hsv

[]	join - join multiple grey scale images into a multi-channel
	       (colorized) image. Complementary to split.

	[done]	join_hsv
	[done]	join_rgb
	[done]	join_rgba

[]	blank - blank (black, possibly transparent) image of a given size.

	[done]	blank_grey8
	[]	blank_grey16
	[]	blank_grey32
	[]	blank_hsv
	[done]	blank_rgb
	[done]	blank_rgba

[]	over

	Blending foreground and background, based on the foreground's
	alpha.

		Z = TOP*(1-alpha(TOP))+BOTTOM*alpha(TOP) - alpha from top image.

	[done]	alpha_over_rgba_rgba
	[done]	alpha_over_rgba_rgb

[]	blend

	Blending foreground and background, based on a scalar alpha
	value.

		Z = BACK*(1-alpha)+FORE*alpha   - alpha is scalar


	[done]	alpha_blend_grey8_grey8
	[]	alpha_blend_grey8_rgb  - which channel ? luma ?
	[]	alpha_blend_grey8_rgba - which channel ? luma ?
	[done]	alpha_blend_rgb_grey8
	[done]	alpha_blend_rgb_rgb
	[done]	alpha_blend_rgb_rgba
	[done]	alpha_blend_rgba_grey8
	[done]	alpha_blend_rgba_rgb
	[done]	alpha_blend_rgba_rgba

[]	Blending foreground and background, based on an alpha mask
	image.

	This is not a primitive. Can be had by combining 'over' above
	with an operator to set an image's alpha channel.

		compose FORE BACK MASK =
			over [setalpha FORE MASK] BACK

[]	Set/Replace/Extend/Copy an image's alpha channel from a second
	image.

	setalpha

	[done]	setalpha_rgb_grey8
	[done]	setalpha_rgb_rgba
	[done]	setalpha_rgba_grey8
	[done]	setalpha_rgba_rgba

[]
	[done]	lighter	       Z = max(A,B)
	[done]	darker	       Z = min(A,B)
	[done]	difference     Z = |A-B|
	[done]	multiply       Z = (A*B)/255
	[done]	screen	       Z = 1-((1-A)*(1-B))
	[done]	add	       Z = A+B
	[done]	subtract       Z = A-B

	// The above is a group of composition/merge operations

	stencil - apply a mask - could be 'set alpha channel'
			       - but also 'set black outside mask'
			       (blue/green screen techniques)
		=> combination of setalpha, blend, and some blank image.

[]	crop, cut, expand (various border types), solarize
	flip/mirror v/h/, transpose, transverse

	[done]


--- leptonica - look for algorithms ---
--- bit blit (block ops)

## offset (x, y) - shift by (x,y) pixels [torus wrap around].

## enhance: color, brightness, contrast, sharpness

## filter:  blur, contour, detail, edge_enhance, edge_enhance_more, emboss, find_edges, smooth, smooth_more, and sharpen.
## filter:  kernel3, kernel5, rank n, size/ min, max, median, mode(most common)
##         (scale/offset - default: sum kernel/0)

## autocontrast (max contrast, cutoff (%)) => image

## colorize (grayscale, black-color, white-color) => image

## deform - see transform (as basis)
## equalize (image) of hist - non-linear map to create unform distribution of grayscale values.
## posterize (image,bits) - reduce colors to max bits.

## cmyk and back, hsv revers

## stat (image ?mask?) - statistics
##  extrema min/max per channel
##  count - #pixels
##  sum - sum of pixels
## sum2 - squared sum, mean, median, root-mean-square, variance, stddev

## eval (image f) - f applied to each pixel, each channel.
##                  f called at most once per value => at most 255 times.
##                  generators, random-ness not possible

## point table|f -> f converted to table
##                  256 values in table per channel.
##                  table of f => replicated 3x
## (non-)linear mapping.
##
## putalpha -: make data in specified channel the alpha
##
## bbox - region of non-zero pixels.
## getcolors -> dict (color -> count)
## getextrema (per channel) min/max pixel values
## histogram (?mask?) - (per channel) dict (pixel -> count)

## resize (filter), rotate(angle,expand=0,filter)
## filters = interpolation = nearest (default), bilinear 2x2, bicubic 4x4, antialias

## transform extent sz rect (4-tuple)        - crop, stretch, shrink /rectangle to square
##          |affine sz 2x3-matrix (6-tuple)  - scale, translate, rotate, and shear
##          |quad   sz 4-points (8-tuple)    - arbitrary deformation
##          |mesh   sz list of (rect, quads) - s.a.
# quad(rilateral)
# transpose - flip_left_right, flip_top_bottom, rotate_90, rotate_180, or rotate_270


RGB [0..1] --> CIE XYZ [0..1] (Y = luminosity)

|X|      1      |0.49    0.31    0.2    |   |R|
|Y| = ------- * |0.17697 0.81240 0.01063| * |G|
|Z|   0.17697   |0       0.01    0.99   |   |B|

ITU-R BT.709 is different
|X|             |0.412453 0.357580 0.180423|   |R|
|Y| =           |0.212671 0.715160 0.072169| * |G|
|Z|             |0.019334 0.119193 0.950227|   |B|

While the official definition of the CIE XYZ standard has the matrix
normalized so that the Y value corresponding to pure red is 1, a more
commonly used form is to omit the leading fraction, so that the second
row sums up to one, i.e., the RGB triplet (1, 1, 1) maps to a Y value
of 1.

Chromacity:	S = X+y+Z, x=X/S, y=Y/S, z=Z/S

Yxz - Represent luminosity and chromacity.


L*a*b*

L* = 116 * f (Y/Yn)			| scale 0..100
a* = 500 * (f (X/Xn) - f (Y/Yn))	| s.a.
b* = 200 * (f (Y/Yn) - f (Z/Zn))	| s.a.

f(x) = x**(1/3)                   , x > delta**3
       x/(3*delta**2) + 2*delta/3 , else
       delta = 6/29

f = cube root, approximated with finite slope

(Xn,Yn,Zn) = white point

L*u*v*

The BT.709 system uses the daylight illuminant D65 as its reference
white
