## Composable pictures

The `(kawa pictures)` library lets you create geometric shapes and images, and combine them in interesting ways. The tutorial gives an introduction.

The easiest way to use and learn the `pictures` library is with a suitable REPL. You can use the old Swing-based console or any DomTerm-based terminal emulator. You can create a suitable window either by starting `kawa` with the `-w` flag, or by running the `kawa` command inside an existing DomTerm-based terminal emulator. The screenshot below is of the latter, using the `qtdomterm` terminal emulator.

After `(import (kawa swing))` you can use `show-picture` to display a picture in a Swing window.

A picture is an object that can be displayed on a screen, web-page, or printed page, and combined with other pictures.

A picture has a method printing itself in a graphical context. It also has various properties.

An important property of a picture is its bounding box. This is a rectangle (with edges parallel to the axes) that surrounds the contents of the picture. Usually the entire visible part of the picture is inside the bounding box, but in some cases part of the picture may stick outside the bounding box. For example when a circle is drawn (stroked) with a “pen”, the bounding box is that of the infinitely-thin mathematical circle, so “ink” from the pen that is outside the circle may be outside the bounding box.

A picture has an origin point corresponding to the (0 0) cordinates. The origin is commonly but not always inside the bounding box. Certain operations (for example `hbox`) combine pictures by putting them “next to” each other, where “next to” is defined in terms of the bounding box and origin point.

### Coordinates - points and dimensions

The library works with a two-dimensional grid, where each position has an x cordinate and y coordinate. Normally, x values increase as you move right on the screen/page, while y values increase as you move down. This convention matches that used by Java 2D, SVG, and many other graphics library. However, note that this is different from the traditional mathematical convention of y values increasing as you go up.

By default, one unit is one “pixel”. (More precisely, it is the `px` unit in the CSS specification.)

Type: `Point`

> A point is a pair consisting of an x and a y coordinate.

Literal: `&P[` ``x`` ``y`` ]

> Construct a point value with the specified `x` and `y` values. Both `x` and `y` are expressions that evaluate to real numbers:

>     &P[(+ old-right 10) baseline]

Type: `Dimension`

> A dimension value is a pair of a width and a height. It is used for the size of pictures in the two dimensions.

> In a context that expects a point, a dimension is treated as an offset relative to some other point.

Literal: `&D[` ``width`` ``height`` ]

> Construct a dimension value with the specified `width` and `height` values, which are both expressions that evaluate to real numbers.

### Shapes

A shape is a collection of lines and curves. Examples include lines, circles, and polygons. A shape can be stroked, which you can think of as being drawn by a very fancy calligraphic pen that follows the lines and curves of the shape.

A closed shape is a shape that is continuous and ends up where it started. This includes circles and polygons. A closed shape can be filled, which means the entire “interior” is painted with some color or texture.

A shape is represented by the Java `java.awt.Shape` interface. The `picture` library only provides relatively simple shapes, but you can use any methods that create a `java.awt.Shape` object.

Shape is effectively a sub-type of picture, though they’re represented using using disjoint classes: If you use a shape where a picture is required, the shape is automatically converted to a picture, as if using the `draw` procedure.

Procedure: `line` `p1` [`p2` `...`]

> In the simple case two points are specified, and the result is a line that goes from point `p1` to `p2`. If `n` points are specied, the result is a polyline: a path consisting of `n-1` line segments, connecting adjacent arguments. (If only a single point is specified, the result is degenerate single-point shape.)

> All of the points except the first can optionally be specified using a dimension, which is treated an an offset from the previous point:

>     (line &P[30 40] &D[10 5] &D[10 -10])

> is the same as:

>     (line &P[30 40] &P[40 45] &P[50 35])

Procedure: `polygon` `p1` [`p2` `...`]

> Constructs a closed shape from line segments. This is the same as calling `line` with the same arguments, with the addition of a final line segment from the last point back to the first point.

Procedure: `rectangle` `p1` [`p2`]

> A rectangle is closed polygon of 4 line segments that are alternatively parallel to the x-axis and the y-axis. I.e. if you rotate a rectangle it is no longer a rectangle by this definition, though of course it still has a rectangular shape. If `p2` is not specified, constructs a rectangle whose upper-left corner is `&P[0 0]` and whose lower-right corner is `p1`. If `p2` is specified, constructs a rectangle whose upper-left corner is `p1` and whose lower-right corner is `p2`. If `p2` is a dimension it is considered a relative offset from `p1`, just like for `polygon`.

Procedure: `circle` `radius` [`center`]

> Creates a circle with the specified `radius`. If the `center` is not specified, it defaults to `&P[0 0]`.

### Colors and paints

A paint is a color pattern used to fill part of the canvas. A paint can be a color, a texture (a replicated pattern), or a gradient (a color that gradually fades to some other color).

A color is defined by red, green, and blue values. It may also have an alpha component, which specifies transparency.

Procedure: `->paint` `value`

> Converts `value` to a color - or more general a paint. Specificlly, the return type is `java.awt.Paint`. The `value` can be any one of:

> - A `java.awt.Paint`, commonly a `java.awt.Color`.

> - A 24-bit integer value is converted to a color. Assume the integer is equal to a hexadecimal literal of the form `#xRRGGBB`. Then `RR` (bits 16-23) is the intensity of the red component; `GG` (bits 8-15) is the intensity of the green component; and `RR` (bits 0-7) is the intensity of the red component.

> - One of the standard HTML/CSS/SVG color names, as a string or symbol. See the table in `gnu/kawa/models/StandardColor.java` source file. Case is ignored, and you can optionally use hyphens to separate words. For example `'hot-pink`, `'hotpink`, and `'hotPink` are all the same sRGB color `#xFF69B4`.

Procedure: `with-paint` `paint` `picture`

> Create a new picture that is the “same” as `picture` but use `paint` as the default paint. For `paint` you can use any valid argument to `->paint`. The default paint (which is the color black if none is specified) is used for both `fill` (paint interior) and `draw` (stroke outline).

>     #|kawa:1|# (! circ1 (circle 20 &P[20 20]))
>     #|kawa:2|# (hbox (fill circ1) (draw circ1))

>     #|kawa:3|# (with-paint 'hot-pink (hbox (fill circ1) (draw circ1)))

> Above we use `with-paint` to create a cloned picture, which is the same as the original `hbox`, except for the default paint, in this case the color `hot-pink`.

>     #|kawa:4|# (! circ2 (hbox (fill circ1) (with-paint 'hot-pink (fill circ1))))
>     #|kawa:5|# circ2

>     #|kawa:6|# (with-paint 'lime-green circ2)

> Here `circ2` is an `hbox` of two filled circles, one that has unspecified paint, and one that is `hot-pink`. Printing `circ2` directly uses black for the circle with unspecified color, but if we wrap `circ2` in another `with-paint` that provides a default that is used for the first circle.

### Filling a shape with a color

Procedure: `fill` `shape`

Procedure: `fill` `paint` `shape`

> Fill the “inside” of `shape`. If no `paint` is specified, uses the current default paint. Otherwise, `(fill `paint` `shape`)` is the same `(with-paint `paint` (file `shape`))`.

### Stroking (outlining) a shape

Procedure: `draw` `option``*` `shape``+`

> Returns a picture that draws the outline of the `shape`. This is called stroking. An `option` may be one of:

> - A `Paint` or `Color` object, which is used to draw the shape.

> - A standard color name, such as `'red` or `'medium-slate-blue`. This is mapped to a `Color`.

> - A join-specifier, which is a symbol specifying how each curve of the shape is connected to the next one. The options are `'miter-join`, `'round-join`, and `'bevel-join`. The default if none is specified is `'miter-join`.

> - A end-cap-specifier, which is a symbol specifying how each end of the shape is terminated. The options are `'square-cap`, `'round-cap`, or `'butt-cap`. The default is `'butt-cap`. (This follows SVG and HTML Canvas. The default in plain Java AWT is a square cap.)

> - A real number specifies the thickness of the stroke.

> - A `java.awt.Stroke` object. This combines join-specifier, end-cap-specifier, thickness, and more in a single object. The `BasicStroke` class can specify dashes, though that is not yet supported for SVG output; only AWT or image output.

> Let us illustrate with a sample line `lin` and a helper macro `show-draw`, which adds a border around a shape, then draws the given shape with some options, and finally re-draws the shape in plain form.

>     #|kawa:10|# (define lin (line &P[0 0] &P[300 40] &P[200 100] &P[50 70]))
>     #|kawa:11|# (define-syntax show-draw
>     #|....:12|#   (syntax-rules ()
>     #|....:13|#     ((_ options ... shape)
>     #|....:14|#      (border 12 'bisque (zbox (draw options ... shape) shape)))))
>     #|....:15|# (show-draw 8 'lime lin)

>     #|....:16|# (show-draw 8 'lime 'round-cap 'round-join lin)

>     #|....:17|# (show-draw 8 'lime 'square-cap 'bevel-join lin)

Notice how the different cap and join styles change the drawing. Also note how the stroke (color lime) extends beyond its bounding box, into the surrounding border (color bisque).

### Affine transforms

A 2D affine transform is a linear mapping from coordinates to coordinates. It generalizes translation, scaling, flipping, shearing, and their composition. An affine transform maps straight parallel lines into other straight parallel lines, so it is only a subset of possible mappings - but a very useful subset.

Procedure: `affine-transform` `xx` `xy` `yx` `yy` `x0` `y0`

Procedure: `affine-transform` `px` `py` `p0`

> Creates a new affine transform. The result of applying `(affine-transform `xx` `xy` `yx` `yy` `x0` `y0`)` to the point `&P[`x` `y`]` is the transformed point

>     &P[(+ (* x xx) (* y yx) x0)
>        (+ (* x xy) (* y yy) y0)]

> If using point arguments, `(affine-transform &P[`xx` `xy`] &P[`yx` `yy`] &P[`x0` `y0`])` is equivalent to: `(affine-transform `xx` `xy` `yx` `yy` `x0` `y0`)`.

Procedure: `with-transform` `transform` `picture`

Procedure: `with-transform` `transform` `shape`

> Creates a transformed picture.

> If the argument is a `shape`, then the result is also a shape.

Procedure: `with-transform` `transform` `point`

> Apply a transform to a single point, yielding a new point.

Procedure: `with-transform` `transform1` `transform2`

> Combine two transforms, yielding the composed transform.

Procedure: `rotate` `angle`

Procedure: `rotate` `angle` `picture`

> The one-argument variant creates a new affine transform that rotates a picture about the origin by the specified `angle`. A positive `angle` yields a clockwise rotation. The `angle` can be either a quantity (with a unit of either `rad` radians, `deg` (degrees), or `grad` (gradians)), or it can be a unit-less real number (which is treated as degrees).

> The two-argument variant applies the resulting transform to the specified picture. It is equivalent to:

>     (with-transform (rotate angle) picture)

Procedure: `scale` `factor`

Procedure: `scale` `factor` `picture`

> Scales the `picture` by the given `factor`. The `factor` can be a real number. The `factor` can also be a point or a dimension, in which case the two cordinates are scaled by a different amount.

> The two-argument variant applies the resulting transform to the specified picture. It is equivalent to:

>     (with-transform (scale factor) picture)

Procedure: `translate` `offset`

Procedure: `translate` `offset` `picture`

> The single-argument variant creates a transform that adds the `offset` to each point. The `offset` can be either a point or a dimension (which are treated quivalently).

> The two-argument variant applies the resulting transform to the specified picture. It is equivalent to:

>     (with-transform (translate offset) picture)

### Combining pictures

Procedure: `hbox` [`spacing`] `picture` `...`

Procedure: `vbox` [`spacing`] `picture` `...`

Procedure: `zbox` `picture` `...`

> Make a combined picture from multiple sub-pictures drawn either “next to” or “on top of” each other.

> The case of `zbox` is simplest: The sub-pictures are drawn in argument order at the same position (origin). The “`z`” refers to the idea that the pictures are stacked on top of each other along the “Z-axis” (the one perpendicular to the screen).

> The `hbox` and `vbox` instead place the sub-pictures next to each other, in a row or column. If `spacing` is specified, if must be a real number. That much extra spacing is added between each sub-picture.

> More precisely: `hbox` shifts each sub-picture except the first so its left-origin control-point (see discussion at `re-center`) has the same position as the right-origin control point of the previous picture `plus` the amount of `spacing`. Similarly, `vbox` shifts each sub-picture except the first so its top-origin control point has the same position as the bottom-origin point of the previous picture, plus `spacing`.

> The bounding box of the result is the smallest rectangle that includes the bounding boxes of the (shifted) sub-pictures. The origin of the result is that of the first picture.

Procedure: `border` [`size` [`paint`]] `picture`

> Return a picture that combines `picture` with a rectangular border (frame) around `picture`’s bounding box. The `size` specifies the thickness of the border: it can be real number, in which it is the thickness on all four sides; it can be a Dimension, in which case the width is the left and right thickness, while the height is the top and bottom thickness; or it can be a Rectangle, in which case it is the new bounding box. If `paint` is specified it is used for the border; otherwise the default paint is used. The border is painted before (below) the `picture` painted. The bounding box of the result is that of the border, while the origin point is that of the original `picture`.

>     #|kawa:2|# (with-paint 'blue (border &D[8 5] (fill 'pink (circle 30))))

Procedure: `padding` `width` [`background`] `picture`

> This is similar to `border`, but it just adds extra space around `picture`, without painting it. The `size` is specified the same way. If `background` is specified, it becomes the background paint for the entire padded rectangle (both `picture` and the extra padding).

>     #|kawa:3|# (define circ1 (fill 'teal (circle 25)))
>     #|kawa:4|# (zbox (line &P[-30 20] &P[150 20])
>     #|kawa:5|#   (hbox circ1 (padding 6 'yellow circ1) (padding 6 circ1)))

> This shows a circle drawn three ways: as-is; with padding and a background color; with padding and a transparent background. A line is drawn before (below) the circles to contrast the yellow vs transparent backgrounds.

Procedure: `re-center` [`xpos`] [`ypos`] `picture`

> Translate the `picture` such that the point specified by `xpos` and `ypos` is the new origin point, adjusting the bounding box to match. If the `picture` is a shape, so is the result.

> The `xpos` can have four possible values, all of which are symbols: `'left` (move the origin to the left edge of the bounding box); `'right` (move the origin to the left edge of the bounding box); `'center` (or `'centre`) (move the origin to halfway between the left and right edges); or `'origin` (don’t change the location along the x-axis). The `ypos` can likewise have four possible values: `'top` (move the origin to the top edge of the bounding box); `'bottom` (move the origin to the bottom edge of the bounding box); `'center` (or `'centre`) (move the origin to halfway between the top and bottom edges); or `'origin` (don’t change the location along the y-axis).

> A single `'center` argument is the same as specifying `'center` for both axis; this is the default. A single `'origin` argument is the same as specifying `'origin` for both axis; this is the same as just `picture`.

> The 16 control points are shown below, relative to a picture’s bounding box and the X- and Y-axes. The abbreviations have the obvious values, for example `LC` means `'left 'center`.

>     LT    OT  CT      RT
>       ┌────┬──────────┐
>       │    │          │
>       │    │          │
>     LC│   OC  C       │RC
>     LO├────O──CO──────┤RO
>       │    │          │
>       └────┴──────────┘
>     LB    OB  CB       RB

> The result of (for example) `(re-center 'left 'center `P`)` is `P` translated so the origin is at control point `LC`.

>     #|kawa:1|# (define D (fill 'light-steel-blue (polygon &P[-20 0] &P[0 -20] &P[60 0] &P[0 40])))
>     #|kawa:2|# (zbox D (draw 'red (circle 5)))

> Above we defined `D` as a vaguely diamond-shaped quadrilateral. A small red circle is added to show the origin point. Below we display 5 versions of `D` in a line (an `hbox`), starting with the original `D` and 4 calls to `re-center`.

>     #|kawa:3|# (zbox (hbox D (re-center 'top D) (re-center 'bottom D)
>     #|....:4|#               (re-center 'center D) (re-center 'origin D))
>     #|....:5|#   (line &P[0 0] &P[300 0]))

> The line at `y=0` shows the effects of `re-center`.

### Images

An image is a picture represented as a rectangular grid of color values. An image file is some encoding (usually compressed) of an image, and mostly commonly has the extensions `png`, `gif`, or `jpg`/`jpeg`.

A “native image” is an instance of `java.awt.image.BufferedImage`, while a “picture image” is an instance of `gnu.kawa.models.DrawImage`. (Both classes implement the `java.awt.image.RenderedImage` interface.) A `BufferedImage` is automatically converted to a `DrawImage` when needed.

Procedure: `image` `bimage`

Procedure: `image` `picture`

Procedure: `image` `src:` `path`

> Creates a picture image, using either an existing native image `bimage`, or an image file specified by `path`.

> Writing `(image src: `path`)` is roughly the same as `(image (read-image `path`))` except that the former has the `path` associated with the resulting picture image. This can make a difference when the image is used or displayed.

> If the argument is a `picture`, it is converted to an image as if by `->image`.

Procedure: `image-read` `path`

> Read an image file from the specified `path`, and returns a native image object (a `BufferedImage`).

>     #|kawa:10|# (define img1 (image-read "http://pics.bothner.com/2013/Cats/06t.jpg"))
>     #|kawa:11|# img1

>     #|kawa:12|# (scale 0.6 (rotate 30 img1))

Note that while `img1` above is a (native) image, the scaled rotated image is not an image object. It is a picture - a more complex value that contains an image.

Procedure: `image-write` `picture` `path`

> The `picture` is converted to an image (as if by using `->image`) and then it is written to the specified `path`. The format used depends on (the lower-cased string value of) the path: A JPG file if the name ends with `".jpg"` or `".jpeg"`; a GIF file if the name ends with `".gif"`; a PNG file if the name ends with `".png"`. (Otherwise, the defalt is PNG, but that might change.)

Procedure: `image-width` `image`

Procedure: `image-height` `image`

> Return the width or height of the given `image`, in pixels.

Procedure: `->image` `picture`

> Convert `picture` to an image (a `RenderedImage`). If the `picture` is an image, return as-is. Otherwise, create an empty image (a `BufferedImage` whose size is the `picture`’s bounding box), and “paint” the `picture` into it.

>     #|kawa:1|# (define c (fill (circle 10)))
>     #|kawa:2|# (scale 3 (hbox c (->image c)))

> Here we take a circle `c`, and convert it to an image. Note how when the image is scaled, the pixel artifacts are very noticable. Also note how the origin of the image is the top-level corner, while the origin of the original circle is its center.

### Compositing - Controlling how pictures are combined

Procedure: `with-composite` [[`compose-op`] `picture`] `...`

> Limited support - SVG and DomTerm output has not been implemented.

### Displaying and exporting pictures

#### Export to SVG

Procedure: `picture-write-svg` `picture` `path` [`headers`]

> Writes the `picture` to the file specified `path`, in SVG (Structered Vector Graphics) format. If `headers` is true (which is the default) first write out the XML and DOCTYPE declarations that should be in a well-formed standaline SVG file. Otherwise, just write of the `<svg>` element. (Modern browers should be able to display a file consisting of just the `<svg>` element, as long as it has extension `.svg`, `.xml`, or `.html`; the latter may add some extra padding.)

Procedure: `picture->svg-node` `picture`

> Returns a SVG representation of `picture`, in the form of an `<svg>` element, similar to those discussed in Creating XML nodes. If you convert the `<svg>` element to a string, you get formatted XML; if you `write` the `<svg>` element you get an XML literal of form `"#<svg>...</svg>"`. If you `display` the `<svg>` element in a DomTerm terminal you get the picture (as a picture). This works because when you display an element in DomTerm it gets inserted into the display.

#### Display in Swing

These procedures require `(import (kawa swing))` in addition to `(import (kawa pictures))`.

The convenience function `show-picture` is useful for displaying a picture in a new (Swing) window.

Procedure: `show-picture` `picture`

> If this is the first call to `show-pictures`, displays `picture` in a new top-level window (using the Swing toolkit). Sequenent calls to `show-picture` will reuse the window.

>     #|kawa:1|# (import (kawa swing) (kawa pictures))
>     #|kawa:2|# (show-picture some-picture)
>     #|kawa:3|# (set-frame-size! &D[200 200]) ; Adjust window size
>     #|kawa:4|# (show-picture some-other-picture)

Procedure: `picture->jpanel` `picture`

> Return a `JPanel` that displays `picture`. You can change the displayed picture by:

>     (set! panel:picture some-other-picture)

Procedure: `set-frame-size!` `size` [`frame`]

> If `frame` is specified, set its size. Otherwise, remember the size for future `show-picture` calls; if there is already a `show-picture` window, adjust its size.

#### Convert to image

You can convert a picture to an image using the `->image` procedure, or write it to a file using the `image-write` procedure.