Skip to content

Commit

Permalink
release 2.9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
cormullion committed Feb 18, 2021
1 parent 1a20cf3 commit 86b59a9
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 39 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

## [v2.9.x] - forthcoming
## [v2.9.0] - 2021-02-18

### Added

Expand All @@ -16,6 +16,7 @@
calculated, allowing for various xadvance values. So there
may be a few instances where text is positioned a few
pixels further left compared with earlier Luxor versions.
- BASE64 added (thanks @fonsp!)

### Removed

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@

## Luxor

Luxor is a Julia package for drawing simple static vector graphics. It provides basic drawing functions and utilities for working with simple 2D graphics. Think of it as a high-level easier to use interface to [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. In Luxor, the emphasis is on simplicity and ease of use.
Luxor is a Julia package for drawing simple 2D vector graphics. Think of it as a high-level easier to use interface to [Cairo.jl](https://github.com/JuliaLang/Cairo.jl), with shorter names, fewer underscores, default contexts, and simplified functions. In Luxor, the emphasis is on simplicity and ease of use.

!["luxor gallery"](docs/src/assets/figures/luxorgallery.png)

Luxor is thoroughly procedural and static: your code issues a sequence of simple graphics 'commands' until you've completed a drawing, then the results are saved into a PDF, PNG, SVG, or EPS file.

A short tutorial can be found in the documentation. There are some Luxor-related videos on [YouTube](https://www.youtube.com/channel/UCfd52kTA5JpzOEItSqXLQxg), and some Luxor-related blog posts at [cormullion.github.io/](https://cormullion.github.io/).

Luxor is designed primarily for drawing static 2D images. If you want to build animations, use [Javis.jl](https://github.com/Wikunia/Javis.jl/issues).
Luxor is designed primarily for drawing static pictures. If you want to build animations, use [Javis.jl](https://github.com/Wikunia/Javis.jl/issues).

Luxor isn't interactive: for building interactivity, look at [Gtk.jl](https://github.com/JuliaGraphics/Gtk.jl), [GLVisualize](https://github.com/JuliaGL/GLVisualize.jl), [Makie](https://github.com/JuliaPlots/Makie.jl), and [Pluto.jl](https://github.com/fonsp/Pluto.jl).
Luxor isn't interactive: for building interactivity, look at [Pluto.jl](https://github.com/fonsp/Pluto.jl) and [Makie](https://github.com/JuliaPlots/Makie.jl), and [Pluto.jl](https://github.com/fonsp/Pluto.jl).

## How can you contribute?

Expand Down
21 changes: 10 additions & 11 deletions docs/src/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ DocTestSetup = quote

# The basics

The underlying drawing model is that you make shapes, and add points to paths, and these are filled and/or stroked, using the current *graphics state*, which specifies colors, line thicknesses, and opacity. You can modify the current graphics state by transforming/rotating/scaling it, and setting style parameters, and so on. Subsequent graphics use the new state, but the graphics you've already drawn are unchanged.
The underlying drawing model is that you make shapes, and add points to paths, and these are filled and/or stroked, using the current *graphics state*, which specifies colors, line thicknesses, scale, orientation, opacity, and so on. You can modify the current graphics state by transforming/rotating/scaling it, and setting style parameters, and so on. Subsequent graphics use the new state, but the graphics you've already drawn are unchanged. The `gsave()` and `grestore()` functions (or the `@layer .... ` macro) let you create new temporary graphics states,

You can specify points on the drawing surface using `Point(x, y)`. The default origin is at the top left of the drawing area, but you can reposition it at any time. Many of the drawing functions have an *action* argument. This can be `:none`, `:fill`, `:stroke`, `:fillstroke`, `:fillpreserve`, `:strokepreserve`, `:clip`, or `:path`. The default is `:none`.

Y coordinates increase downwards, so `Point(0, 100)` is below `Point(0, 0)`. This is the preferred coordinate system for computer graphics software, but mathematicians and scientists may well be used to the y-axis increasing upwards...
Y coordinates increase downwards, so `Point(0, 100)` is below `Point(0, 0)`. This is the preferred coordinate system for most computer graphics software, but mathematicians and scientists may well be used to the other convention, where the y-axis increasing up the page...

The main types you'll encounter in Luxor are:

Expand Down Expand Up @@ -56,7 +56,7 @@ julia> P + Q
Luxor.Point(16.0, 18.0)
```

You can add or multiply Points and scalars:
You can add and multiply Points and scalars:

```julia
julia> 10P
Expand Down Expand Up @@ -106,7 +106,7 @@ nothing # hide

![point example](assets/figures/point-ex.png)

Angles are usually supplied in radians, measured starting at the positive x-axis turning towards the positive y-axis (which usually points 'down' the page or canvas, so 'clockwise'). (The main exception is for turtle graphics, which conventionally let you supply angles in degrees.)
Angles are usually supplied in radians, measured starting at the positive x-axis turning towards the positive y-axis (which usually points 'down' the page or canvas). So rotations are ‘clockwise. (The main exception is for turtle graphics, which conventionally let you supply angles in degrees.)

Coordinates are interpreted as PostScript points, where a point is 1/72 of an inch.

Expand Down Expand Up @@ -172,7 +172,7 @@ finish()
preview()
```

They're short-cuts - designed to save typing. You can omit the width and height (defaulting to 600 by 600, except for `@imagematrix`), and you don't have to specify a filename (you'll get time-stamped files in the current working directory). For multiple lines, use either:
They're short-cuts - designed to save a bit of typing. You can omit the width and height (defaulting to 600 by 600, except for `@imagematrix`), and you don't have to specify a filename (you'll get time-stamped files in the current working directory). For multiple lines, use either:

```julia
@svg begin
Expand All @@ -191,7 +191,7 @@ or (less nicely):
)
```

The `@draw` macro creates an in-memory drawing. You should see it displayed if you're working in a capable environment (Juno, VSCode, Jupyter, Pluto).
The `@draw` macro creates a drawing in-memory (not saved in a file). You should see it displayed if you're working in a suitable environment (Juno, VSCode, Jupyter, Pluto).

```@docs
@svg
Expand All @@ -206,7 +206,7 @@ If you don't specify a size, the defaults are 600 by 600. If you don't specify a
@svg juliacircles(150) 400 400 "test" # saves in "test.svg"
```

If you want to create drawings with transparent backgrounds, or located other than in the center, use the longer form rather than the macros:
If you want to create drawings with transparent backgrounds, or use variables to specify filenames, use the longer form, rather than the macros:

```julia
Drawing()
Expand Down Expand Up @@ -348,7 +348,7 @@ origin

## Save and restore

`gsave()` saves a copy of the current graphics settings (current axis rotation, position, scale, line and text settings, color, and so on). When the next `grestore()` is called, all changes you've made to the graphics settings will be discarded, and the previous settings are restored, so things return to how they were when you last used `gsave()`. `gsave()` and `grestore()` should always be balanced in pairs.
`gsave()` saves a copy of the current graphics settings (current axis rotation, position, scale, line and text settings, color, and so on). When the next `grestore()` is called, all changes you've made to the graphics settings will be discarded, and the previous settings are restored, so things return to how they were when you last used `gsave()`. `gsave()` and `grestore()` should always be balanced in pairs, enclosing the functions.

The `@layer` macro is a synonym for a `gsave()`...`grestore()` pair.

Expand Down Expand Up @@ -389,10 +389,9 @@ currentdrawing

## Drawing as image matrix

While drawing, you can copy the current graphics as a
matrix of pixels, using the `image_as_matrix()` function.
While drawing, you can copy the current graphics in a drawing as a matrix of pixels, using the `image_as_matrix()` function.

`image_as_matrix()` returns a array of ARGB32 values. Each ARGB value encodes the Red, Green, Blue, and Alpha values of a pixel.
`image_as_matrix()` returns a array of ARGB32 values. Each ARGB value encodes the Red, Green, Blue, and Alpha values of a pixel into a single 32 bit integer.

The following example draws a red rectangle, then copies the drawing into a matrix called `mat1`. Then it adds a blue triangle, and copies the updated drawing into `mat2`. In the second drawing, values from the two matrices are tested, and table cells are randomly colored depending on the corresponding values ... this is a primitive Boolean operation.

Expand Down
12 changes: 6 additions & 6 deletions docs/src/colors-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ For color definitions and conversions, you can use [Colors.jl](https://github.co

`setmesh()` will apply a color mesh to new graphics.

The difference between the `setcolor()` and `sethue()` functions is that `sethue()` is independent of alpha opacity, so you can change the hue without changing the current opacity value.
The difference between the `setcolor()` and `sethue()` functions is that `sethue()` doesn't change alpha opacity (transparency), so you can change the hue without changing the current alpha opacity (transparency) value.

Named colors, such as "gold", or "lavender", can be found in Colors.color_names.
Named colors, such as "gold", or "lavender", can be found in `Colors.color_names` dictionary.

```@example
using Luxor, Colors # hide
Expand Down Expand Up @@ -62,7 +62,7 @@ setantialias

## Line styles

There are `set-` functions for controlling subsequent lines' width, end shapes, join behavior, and dash patterns:
There are `set-` functions for controlling subsequent lines' width, end shape, join behavior, and dash pattern:

```@example
using Luxor # hide
Expand Down Expand Up @@ -115,7 +115,7 @@ nothing # hide

![dashes](assets/figures/dashes.png)

To define more complicated dash patterns in Luxor, supply a vector to `setdash()`.
To define more complicated dash patterns in Luxor, pass a vector to `setdash()`.

```julia
dashes = [50.0, # ink
Expand Down Expand Up @@ -349,7 +349,7 @@ blendadjust

## Blending (compositing) operators

Graphics software provides ways to modify how the virtual "ink" is applied to existing graphic elements. In PhotoShop and other software products the compositing process is done using [blend modes](https://en.wikipedia.org/wiki/Blend_modes).
Graphics software provides ways to modify how the virtual "ink" is applied to previously-drawn graphic elements. In PhotoShop and other software, the compositing process is done using [blend modes](https://en.wikipedia.org/wiki/Blend_modes).

Use `setmode()` to set the blending mode of subsequent graphics.

Expand Down Expand Up @@ -401,7 +401,7 @@ nothing # hide

Notice in this example that clipping was used to restrict the area affected by the blending process.

In Cairo these blend modes are called *operators*. A source for a more detailed explanation can be found [here](https://www.cairographics.org/operators/).
In Cairo, these blend modes are called *operators*. For a more detailed explanation, refer to [the Cairo documentation](https://www.cairographics.org/operators/).

You can access the list of modes with the unexported symbol `Luxor.blendingmodes`.

Expand Down
25 changes: 13 additions & 12 deletions docs/src/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ finish()
preview()
```

`Drawing(1000, 1000, "hello-world.png")` defines the width, height, location, and type of the finished image. `origin()` moves the 0/0 point to the centre of the drawing surface (by default it's at the top left corner). Thanks to `Colors.jl` we can specify colors by name as well as by numeric value: `background("black")` defines the color of the background of the drawing. `text("helloworld")` draws the text. It's placed at the current 0/0 point and left-justified if you don't specify otherwise. `finish()` completes the drawing and saves the PNG image in the file. `preview()` tries to open the saved file using some other application (eg Preview on macOS).
`Drawing(1000, 1000, "hello-world.png")` defines the width, height, location, and type of the finished image. `origin()` moves the 0/0 point to the centre of the drawing surface (by default it's at the top left corner). Thanks to `Colors.jl` we can specify colors by name as well as by numeric value: `background("black")` defines the color of the background of the drawing. `text("helloworld")` draws the text. It's placed at the current 0/0 point and left-justified if you don't specify otherwise. `finish()` completes the drawing and saves the PNG image in the file. `preview()` tries to display the saved file, perhaps using another application (eg Preview on macOS).

The macros `@png`, `@svg`, `@pdf`, `@draw`, and `@imagematrix` provide shortcuts for making and previewing graphics without having to provide the usual set-up and finish instructions:
The macros `@png`, `@svg`, `@pdf`, `@draw`, and `@imagematrix` provide shortcuts for making and previewing graphics without you having to provide the usual set-up and finish instructions:

```julia
# using Luxor
Expand Down Expand Up @@ -53,9 +53,9 @@ end

The `@draw` macro is useful if you work in Juno/VS Code IDEs
or a notebook environment such as Jupyter or Pluto and
don't need to save work in files. It creates a PNG format
don't need to always save your work in files. It creates a PNG format
drawing in memory, rather than saved in a file. It's
displayed in the plot pane or the next cell.
displayed in the plot pane or in the next cell.

```julia
@draw begin
Expand All @@ -82,13 +82,13 @@ using Luxor
Drawing(600, 400, "assets/figures/julia-logos.png")
origin()
background("white")
for θ in range(0, step=π/8, length=16)
gsave()
scale(0.25)
scale(0.2)
rotate(θ)
translate(250, 0)
randomhue()
julialogo(action=:fill, color=false)
translate(350, 0)
julialogo(action=:fill, bodycolor=randomhue())
grestore()
end
Expand All @@ -97,19 +97,20 @@ scale(0.3)
juliacircles()
grestore()
translate(200, -150)
translate(150, -150)
scale(0.3)
julialogo()
finish()
# preview()
nothing # hide
```

![background](assets/figures/julia-logos.png)

The `gsave()` function saves the current drawing parameters, and any subsequent changes such as the `scale()` and `rotate()` operations are discarded by the next `grestore()` function.
The `gsave()` function saves the current drawing environment temporarily, and any subsequent changes such as the `scale()` and `rotate()` operations are discarded when you call the next `grestore()` function.

Use the extension to specify the format: for example change `julia-logos.png` to `julia-logos.svg` or `julia-logos.pdf` or `julia-logos.eps` to produce SVG, PDF, or EPS format output.
Use the extension to specify the format: for example, change `julia-logos.png` to `julia-logos.svg` or `julia-logos.pdf` or `julia-logos.eps` to produce SVG, PDF, or EPS format output.

## Something a bit more complicated: a Sierpinski triangle

Expand Down Expand Up @@ -177,7 +178,7 @@ You can use an environment such as a Jupyter or Pluto notebook or the Juno or VS

## Images as matrices

With the `@imagematrix` macro, you can create your drawing with vector graphics in the usual way, but the result is returned as a matrix. This example processes the ampersand in Images.jl.
With the `@imagematrix` macro, you can create your drawing with vector graphics in the usual way, but the result is returned as a matrix. This example processes an ampersand in Images.jl.

```
using Luxor, Colors, Images, ImageFiltering
Expand Down
8 changes: 4 additions & 4 deletions docs/src/images.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ DocTestSetup = quote

## Placing images

Luxor lets you place PNG and SVG images on the drawing. First, load an image from a file:
Luxor lets you place PNG and SVG images on the drawing. First, load an image:

- for PNG images, use `readpng(filename)`
- for SVG images, use `readsvg(filename)` or `readsvg(string)`

(JPEGs aren't supported.)

Then use `placeimage()` to place the image by its top left corner at point `pt`. Access the image's dimensions with `.width` and `.height`.
Then use `placeimage()` to place the image by its top left corner at point `pt`, or use the `centered=true` keyword to place the image's center point there. Access the image's dimensions with `.width` and `.height`. You can use the `centered=true` keyword.

```@example
using Luxor # hide
Expand Down Expand Up @@ -114,7 +114,7 @@ finish()

## Transforming images

You can transform images by setting the current matrix, either with `scale()` and `rotate()` and similar, or by modifying it directly. This code skews an image made in an earlier chapter of this document and scales and rotates it in a circle:
You can transform images by setting the current matrix, either with `scale()` and `rotate()` and similar, or by modifying it directly. This code scales and rotates an image made in an earlier chapter of this document around in a circle:

```@example
using Luxor # hide
Expand Down Expand Up @@ -194,7 +194,7 @@ nothing # hide
### Adding text to transformed images

The above approach works well, but suppose you want to locate the working origin
at the lower left of the image, ie you want all coordinates to be relative to the
at the lower left of the image, i.e. you want all coordinates to be relative to the
bottom left corner of the image?

To do this, use `translate()` and `transform()` to modify the drawing space:
Expand Down
4 changes: 2 additions & 2 deletions docs/src/transforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ DocTestSetup = quote

For basic transformations of the drawing space, use `scale(sx, sy)`, `rotate(a)`, and `translate(tx, ty)`.

`translate()` shifts the current axes by the specified amounts in x and y. It's relative and cumulative, rather than absolute:
`translate(pos)` (or `translate(x, y)`) shifts the current axes to `pos` (or by the specified amounts in x and y). It's relative and cumulative, rather than absolute:

```@example
using Luxor, Colors, Random # hide
Expand Down Expand Up @@ -77,7 +77,7 @@ nothing # hide

To return home after many changes, you can use `setmatrix([1, 0, 0, 1, 0, 0])` to reset the matrix to the default. `origin()` resets the matrix then moves the origin to the center of the page.

`rescale()` is a convenient utility function for linear interpolation, also called a "lerp".
`rescale()` is a convenient utility function for linear interpolation (also called a "lerp").

```@docs
scale
Expand Down

0 comments on commit 86b59a9

Please sign in to comment.