Simple drawing package written in Julia
MIT License
This is a lightweight self-contained package that attempts to provide efficient drawing methods for some simple shapes. So far, in this package, all the shapes and drawing algorithms are integer-based, and all the drawing algorithms are single-threaded.
Background
Point
Line
ThickLine
Triangle
FilledTriangle
Rectangle
FilledRectangle
ThickRectangle
Circle
FilledCircle
ThickCircle
Bitmap
Image
Character
TextLine
import SimpleDraw as SD
# create a canvas (could be any AbstractMatrix)
image = falses(32, 32) # (height, width)
# create the shape
shape = SD.Line(SD.Point(9, 5), SD.Point(14, 19))
# we will draw on the boolean image with the "color" true
color = true
# draw the shape on image
SD.draw!(image, shape, color)
# print the boolean image using Unicode block characters
SD.visualize(image)
The following types are part of the API.
AbstractShape
TERMINUS_16_8
, TERMINUS_BOLD_16_8
, TERMINUS_24_12
, TERMINUS_BOLD_24_12
, TERMINUS_32_16
, TERMINUS_BOLD_32_16
.The following functions are part of the API:
draw!
is_valid
get_i_min
get_i_max
get_j_min
get_j_max
get_i_extrema
get_j_extrema
get_height
get_width
get_position
move_i
move_j
move
visualize
Everything else should be considered internal for now.
draw!
Being able to draw broadly requires three things:
image
: A canvas to draw on. It could be any AbstractMatrix
.shape
: The geometric shape to be drawn. Note that primitive shape
s can easily be composed to create more complex shape
s. For example,
struct MyComplexShape{I <: Integer} <: SD.AbstractShape
line::SD.Line{I}
circle::SD.Circle{I}
end
color
: The color to draw the shape with. This is what fills up the entries of the image
matrix at appropriate positions, thereby drawing the geometric shape.With this in mind, this package provides the draw!
function, which is commonly invoked as follows:
SD.draw!(image, shape, color)
Under the hood, it calls internal _draw!
methods that automatically take care of some basic optimizations (see Drawing optimizations). Then there are _draw!
methods of the form SD._draw!(f, image, shape, color)
that are heavily used internally. Here, f
can roughly be thought of as a drawing function applied to every pixel of the shape. This offers a lot of flexibility with the "brush-stroke" and significantly decreases code duplication. At the same time, it does not adversely affect performance. Most users will not need to use these methods directly, but in case you do, please look up the source code as their usage is not very well documented as of now.
By default, the draw!
function is safe, that is, it draws only those pixels of the shape that lie within the bounds of the image. So you don't have to worry about your program breaking even if it tries to draw something outside the bounds of the image
. That being said, certain basic optimizations are already enabled for drawing most shapes. See Drawing optimizations.
DrawingOptimizationStyle
is trait whose subtypes are used to define generic draw!
methods with different levels of optimization for drawing shapes:
PUT_PIXEL
: Iterate through all the positions needed to draw the shape. For each position, if it lies within the bounds of the image, put a pixel at that position else don't do anything.CHECK_BOUNDS
: If the shape lies completely outside the bounds of the image, simply return nothing
. If it lies completely inside the bounds of the image, then draw each pixel of the shape without any further bounds checking. If it is neither of the previous cases, fall back to the slow but safe method of drawing each pixel of the shape only if it lies within the bounds of the image.CLIP
: Some shapes like VerticalLine
, HorizontalLine
, FilledRectangle
can be direcly clipped into shapes that completely lie within the bounds of the image. In such cases, perform the clipping and draw the clipped shape without any further bounds checking.PUT_PIXEL_INBOUNDS
: Iterate through all the positions needed to draw the shape. For each position, put a pixel at that position assuming without any bounds checking image.Use get_drawing_optimization_style(shape)
to get the default drawing optimization style for a shape. Shapes which do not fall within the above will implement custom draw!
methods with relevant optimizations.
The visualize
function helps in visualizing a boolean image directly inside the terminal. This is a quick and effective tool to verify whether a shape is being drawn as expected. This is extremely handy when you want to know about the exact coordinates of the pixels that are being drawn for a shape.
It uses Unicode block characters to represent a pixel. This works well for low resolution images. To visualize slightly higher resolution images, you can maximize your terminal window and reduce its font size.
Below are the benchmarks for v0.5.0
of this package:
julia> versioninfo()
Julia Version 1.8.5
Commit 17cfb8e65ea (2023-01-08 06:45 UTC)
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 12 × AMD Ryzen 5 6600H with Radeon Graphics
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-13.0.1 (ORCJIT, znver3)
Threads: 1 on 12 virtual cores
julia>
Timestamp: 2023_01_11_03_20_28 (yyyy_mm_dd_HH_MM_SS)
Shapes are drawn on an image of type Matrix{UInt32}
with a color of type UInt32
shape type | image height | image width | median time | memory | shape |
---|---|---|---|---|---|
Background | 64 | 64 | 121.069 ns | 0 bytes | SimpleDraw.Background() |
Background | 256 | 256 | 2.140 μs | 0 bytes | SimpleDraw.Background() |
Background | 1024 | 1024 | 59.781 μs | 0 bytes | SimpleDraw.Background() |
Point | 64 | 64 | 2.585 ns | 0 bytes | SimpleDraw.Point{Int64}(33, 33) |
Point | 256 | 256 | 2.334 ns | 0 bytes | SimpleDraw.Point{Int64}(129, 129) |
Point | 1024 | 1024 | 2.585 ns | 0 bytes | SimpleDraw.Point{Int64}(513, 513) |
Line | 64 | 64 | 70.601 ns | 0 bytes | SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(9, 2), SimpleDraw.Point{Int64}(56, 63)) |
Line | 256 | 256 | 342.824 ns | 0 bytes | SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(33, 2), SimpleDraw.Point{Int64}(224, 255)) |
Line | 1024 | 1024 | 1.470 μs | 0 bytes | SimpleDraw.Line{Int64}(SimpleDraw.Point{Int64}(129, 2), SimpleDraw.Point{Int64}(896, 1023)) |
ThickLine | 64 | 64 | 834.514 ns | 0 bytes | SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(9, 9), SimpleDraw.Point{Int64}(56, 56), 7) |
ThickLine | 256 | 256 | 49.472 μs | 0 bytes | SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(33, 33), SimpleDraw.Point{Int64}(224, 224), 31) |
ThickLine | 1024 | 1024 | 1.273 ms | 0 bytes | SimpleDraw.ThickLine{Int64}(SimpleDraw.Point{Int64}(129, 129), SimpleDraw.Point{Int64}(896, 896), 127) |
Triangle | 64 | 64 | 185.163 ns | 0 bytes | SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(63, 32), SimpleDraw.Point{Int64}(32, 63)) |
Triangle | 256 | 256 | 749.029 ns | 0 bytes | SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(255, 128), SimpleDraw.Point{Int64}(128, 255)) |
Triangle | 1024 | 1024 | 4.349 μs | 0 bytes | SimpleDraw.Triangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(1023, 512), SimpleDraw.Point{Int64}(512, 1023)) |
FilledTriangle | 64 | 64 | 433.065 ns | 0 bytes | SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(63, 32), SimpleDraw.Point{Int64}(32, 63)) |
FilledTriangle | 256 | 256 | 2.377 μs | 0 bytes | SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(255, 128), SimpleDraw.Point{Int64}(128, 255)) |
FilledTriangle | 1024 | 1024 | 28.884 μs | 0 bytes | SimpleDraw.FilledTriangle{Int64}(SimpleDraw.Point{Int64}(2, 2), SimpleDraw.Point{Int64}(1023, 512), SimpleDraw.Point{Int64}(512, 1023)) |
Rectangle | 64 | 64 | 56.104 ns | 0 bytes | SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63) |
Rectangle | 256 | 256 | 908.600 ns | 0 bytes | SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255) |
Rectangle | 1024 | 1024 | 9.859 μs | 0 bytes | SimpleDraw.Rectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023) |
FilledRectangle | 64 | 64 | 518.203 ns | 0 bytes | SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63) |
FilledRectangle | 256 | 256 | 3.588 μs | 0 bytes | SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255) |
FilledRectangle | 1024 | 1024 | 49.322 μs | 0 bytes | SimpleDraw.FilledRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023) |
ThickRectangle | 64 | 64 | 841.000 ns | 0 bytes | SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 63, 63, 16) |
ThickRectangle | 256 | 256 | 3.241 μs | 0 bytes | SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 255, 255, 64) |
ThickRectangle | 1024 | 1024 | 53.329 μs | 0 bytes | SimpleDraw.ThickRectangle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1023, 1023, 256) |
Circle | 64 | 64 | 95.229 ns | 0 bytes | SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62) |
Circle | 256 | 256 | 366.939 ns | 0 bytes | SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254) |
Circle | 1024 | 1024 | 3.228 μs | 0 bytes | SimpleDraw.Circle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022) |
FilledCircle | 64 | 64 | 608.218 ns | 0 bytes | SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62) |
FilledCircle | 256 | 256 | 3.966 μs | 0 bytes | SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254) |
FilledCircle | 1024 | 1024 | 52.016 μs | 0 bytes | SimpleDraw.FilledCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022) |
ThickCircle | 64 | 64 | 923.326 ns | 0 bytes | SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 62, 16) |
ThickCircle | 256 | 256 | 24.506 μs | 0 bytes | SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 254, 64) |
ThickCircle | 1024 | 1024 | 1.730 ms | 0 bytes | SimpleDraw.ThickCircle{Int64}(SimpleDraw.Point{Int64}(2, 2), 1022, 256) |
Bitmap | 64 | 64 | 4.490 μs | 0 bytes | SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1]) |
Bitmap | 256 | 256 | 71.583 μs | 0 bytes | SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1]) |
Bitmap | 1024 | 1024 | 1.181 ms | 0 bytes | SimpleDraw.Bitmap{Int64, BitMatrix}(SimpleDraw.Point{Int64}(2, 2), Bool[1 0 … 1 0; 0 1 … 0 1; … ; 1 0 … 1 0; 0 1 … 0 1]) |
Image | 64 | 64 | 2.285 μs | 0 bytes | SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001]) |
Image | 256 | 256 | 38.742 μs | 0 bytes | SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001]) |
Image | 1024 | 1024 | 814.004 μs | 0 bytes | SimpleDraw.Image{Int64, Matrix{UInt32}}(SimpleDraw.Point{Int64}(2, 2), UInt32[0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001; … ; 0x00000001 0x00000000 … 0x00000001 0x00000000; 0x00000000 0x00000001 … 0x00000000 0x00000001]) |
Character | 64 | 64 | 873.814 ns | 0 bytes | SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
Character | 256 | 256 | 874.355 ns | 0 bytes | SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
Character | 1024 | 1024 | 881.478 ns | 0 bytes | SimpleDraw.Character{Int64, Char, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(2, 2), 'A', SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
TextLine | 64 | 64 | 3.548 μs | 0 bytes | SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "BUDB", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
TextLine | 256 | 256 | 14.377 μs | 0 bytes | SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "ZZPEKEEOUGIIHKGY", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
TextLine | 1024 | 1024 | 58.398 μs | 0 bytes | SimpleDraw.TextLine{Int64, String, SimpleDraw.MonospaceBitmapASCIIFont}(SimpleDraw.Point{Int64}(1, 1), "ZBXMZBNLSOTGROCLZJTOONNIEIFUOLCSLIUTYUGDMIEWKIWMYJLOPHGYPLTWBIDF", SimpleDraw.MonospaceBitmapASCIIFont([0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; … ;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0;;; 0 0 … 0 0; 0 0 … 0 0; … ; 0 0 … 0 0; 0 0 … 0 0])) |
Follow these steps to generate benchmarks. Take care to double-check the version of the package you are benchmarking:
Clone the project
$ git clone https://github.com/Sid-Bhatia-0/SimpleDraw.jl.git
Start the julia REPL inside the /benchmark
directory
benchmark $ julia
Activate and instantiate the project
julia> import Pkg; Pkg.activate("."); Pkg.instantiate()
Exit the REP and run generate_benchmarks.jl
with the Project.toml
and Manifest.toml
files in this directory
benchmark $ julia --project=. generate_benchmarks.jl
This will print a bunch of outputs and produce a markdown file named with a timestamp containing the final benchmarks. Using a timestamp in the name helps ensure that running generate_benchmarks.jl
multiple times does not overwrite the same file.
Background
struct Background <: AbstractShape end
Point
struct Point{I <: Integer} <: AbstractShape
i::I
j::I
end
Line
struct Line{I <: Integer} <: AbstractLine
point1::Point{I}
point2::Point{I}
end
Line(point1, point2)
will draw the same thing as Line(point2, point1)
as they are always sorted internally. But note that the visual representation of the line may not symmetric with respect to the end points in general.
ThickLine
struct ThickLine{I <: Integer} <: AbstractLine
point1::Point{I}
point2::Point{I}
thickness::I
end
An instance of ThickLine
is considered valid only if the following conditions hold true:
thickness > 0
Triangle
struct Triangle{I <: Integer} <: AbstractTriangle
point1::Point{I}
point2::Point{I}
point3::Point{I}
end
FilledTriangle
struct FilledTriangle{I <: Integer} <: AbstractTriangle
point1::Point{I}
point2::Point{I}
point3::Point{I}
end
Rectangle
struct Rectangle{I <: Integer} <: AbstractRectangle
position::Point{I}
height::I
width::I
end
An instance of Rectangle
is considered valid only if the following conditions hold true:
height > 0
width > 0
FilledRectangle
struct FilledRectangle{I <: Integer} <: AbstractRectangle
position::Point{I}
height::I
width::I
end
An instance of FilledRectangle
is considered valid only if the following conditions hold true:
height > 0
width > 0
ThickRectangle
struct ThickRectangle{I <: Integer} <: AbstractRectangle
position::Point{I}
height::I
width::I
thickness::I
end
An instance of ThickRectangle
is considered valid only if the following conditions hold true:
height > 0
width > 0
thickness > 0
thickness <= min(height, width)
Circle
struct Circle{I <: Integer} <: AbstractCircle
position::Point{I}
diameter::I
end
An instance of Circle
is considered valid only if the following conditions hold true:
diameter > 0
FilledCircle
struct FilledCircle{I <: Integer} <: AbstractCircle
position::Point{I}
diameter::I
end
An instance of FilledCircle
is considered valid only if the following conditions hold true:
diameter > 0
ThickCircle
struct ThickCircle{I <: Integer} <: AbstractCircle
position::Point{I}
diameter::I
thickness::I
end
An instance of ThickCircle
is considered valid only if the following conditions hold true:
diameter > 0
thickness > 0
diameter
is odd, then 2 * thickness <= diameter + 1
diameter
is even, then 2 * thickness <= diameter
Bitmap
struct Bitmap{I <: Integer, B <: AbstractMatrix{Bool}} <: AbstractShape
position::Point{I}
bitmap::B
end
Can be used to draw a 1-bit image using some color on an image. For example, it is used for drawing character glyphs in Character
or TextLine
.
Image
struct Image{I <: Integer, A} <: AbstractShape
position::Point{I}
image::A
end
Can be used to draw an existing image on top of an image at some position. No need to pass color explicitly, the sub-image should already be colored. Whereas in Bitmap
, one needs to pass color explicitly and it can only be of a single color.
Character
struct Character{I <: Integer, C <: AbstractChar, F <: AbstractFont} <: AbstractShape
position::Point{I}
character::C
font::F
end
There are 6 monospace ASCII fonts are available at this point:
TERMINUS_16_8
(height 16 pixels, width 8 pixels)TERMINUS_BOLD_16_8
(height 16 pixels, width 8 pixels)TERMINUS_24_12
(height 24 pixels, width 12 pixels)TERMINUS_BOLD_24_12
(height 24 pixels, width 12 pixels)TERMINUS_32_16
(height 32 pixels, width 16 pixels)TERMINUS_BOLD_32_16
(height 32 pixels, width 16 pixels)Only glyphs for ASCII characters are available as of now.
TextLine
struct TextLine{I <: Integer, S, F <: AbstractFont} <: AbstractShape
position::Point{I}
text::S
font::F
end
There are 6 monospace ASCII fonts are available at this point:
TERMINUS_16_8
(height 16 pixels, width 8 pixels)TERMINUS_BOLD_16_8
(height 16 pixels, width 8 pixels)TERMINUS_24_12
(height 24 pixels, width 12 pixels)TERMINUS_BOLD_24_12
(height 24 pixels, width 12 pixels)TERMINUS_32_16
(height 32 pixels, width 16 pixels)TERMINUS_BOLD_32_16
(height 32 pixels, width 16 pixels)Only glyphs for ASCII characters are available as of now.
/src/fonts
directory in this repository, and is also available with a FAQ at http://scripts.sil.org/OFL.