tclBlend2d - Tcl meets Blend2d
Package Blend2d integrates the Blend2d vector engine in Tcl/Tk.
Blend2d is an open source, high quality, high performance vector graphics engine.
Blend2d is a binary package, distributed in a multi-platform bundle, i.e. it can be used on
Windows 64 bit
Linux 64 bit
MacOS 64 bit (... some limitations ...)
Just an example to get the flavor of how to use Blend2d:
# draw a circle ... package require Blend2d set sfc [BL::Surface new] $sfc clear $sfc configure -fill.style [BL::color orange] $sfc fill [BL::circle {150 150} 100] $sfc save "./image01.bmp" $sfc destroy
You can run Blend2d from a tclsh interpreter, without loading Tk. The following command
package require tclBlend2d
can be used in a tclsh interpreter to load the package without requiring Tk support. You will be still able to generate and save images, but of course some subcommands related to Tk won't be available.
The command
package require tkBlend2d
loads the full package (and requires Tk).
Note that
package require Blend2d
is equivalent to
package require tkBlend2d
The main concept of Tcl-Blend2d is the Surface.
A Surface comes with an internal framebuffer (32bit depth, with alpha support) and holds all of the graphics state parameters that describe how drawing is to be done. This includes parameters like the current line width, the current color (or gradient), a 2D transformation matrix and many other things.
A Surface can be created with the following commands
creates a new instance of the class BL::Surface called sfcName. Options can be set at creation time, or later with the configure method.
creates a new instance of the class BL::Surface returning a new unique sfcName. Options can be set at creation time, or later with the configure method.
destroys sfcName. Note that in general any oo-object like sfcName should be explicitly destroyed
duplicates sfcName. Return a new BL::Surface.
Note: the full stack of options is not duplicated; only the current options are duplicated.
returns the list of all the currently allocated surfaces.
The whole set of Surface's options is also called the drawing state.
A drawing state consists of
the 2D transformations that have been applied (i.e. translate, rotate and scale ... see below),
the current values of various attributes controlling how to fill and how to stroke all the basic and complex geometric entities,
and it can be manipulated with the cget/configure methods.
returns a list with all the valid options and their values.
returns the current value of the option optionName. Raise an error if optionName is not a valid option.
returns a list with two values: the named option and its value. Raise an error if optionName is not a valid option.
modifies all the named options with the specified values. Raise an error if any optionName is not recognized or its optionValue is not valid; in this case no option is modified.
Surface options are:
The whole drawing-state can be stored on an internal stack, and you can inspect, save and restore the whole drawing state (i.e. all the options) with just the following commands:
saves the current graphic-state on an internal stack.
pops the graphic-state from the stack. Raise an error if stack is empty.
returns the size of the internal stack (i.e. number of saved graphic-states)
sets the whole surface's graphic-state, including the internal stack. All the options (but -format and -threads) are reset to their default values.
There are 3 types of styles you can set for strokes and fills: SOLID, GRADIENT, PATTERN
A SOLID style is an uniform color (with optional alpha transparency). It can be specified as a simple hex number in 0xAARRGGBB format, 0xFFFF0000 is red 0xFF0000FF is blue or through the following utilities:
returns a 0xAARRGGBB color by combining the RR GG BB and the (optional) alpha arguments.
RR, GG, BB are integers 0..255 (best expressed as 0x00..0xFF), alpha is an optional parameter ranging from 0.0 (transparent) to 1.0 (opaque). Default alpha is 1.0
returns a 0xAARRGGBB color by combining the colorName and the (optional) alpha arguments.
colorName is a color name (e.g "lightblue") or a numeric-color like #rrggbb, alpha is an optional parameter ranging from 0.0 (transparent) to 1.0 (opaque). Default alpha is 1.0
This is an alternative way for specifying a color (HSB model).
See the "HSB color model" section at the end for more details.
A GRADIENT can be specified with the following syntax:
type should be one of the following values: LINEAR, RADIAL, CONICAL
values is a list of parameters (depending on type)
BL::gradient LINEAR {x0 y0 x1 y1} _stopList_ ?_options_?
BL::gradient RADIAL {x0 y0 x1 y1 radius} _stopList_ ?_options_?
BL::gradient CONICAL {x0 y0 angle} _stopList_ ?_options_?
stopList is a list of offset and colors (at least two pairs of offset color)
offset is a number between 0.0 and 1.0
color can be expressed as an hex number (0xAARRGGBB) or with the above cited BL::rgb , BL::color, HSB commands.
options are:
Gradient example:
# define an oblique LINEAR gradient set gr1 [BL::gradient LINEAR {0 0 400 400} \ [list 0.0 [BL::color lightblue] 0.8 [BL::color blue] 1.0 [BL::rgb 0 0 0 0.1]] \ ] $sfc fill [BL::circle {200 200} 100] -style $gr1
A PATTERN can be specified with the following syntax:
defines a pattern based on another sourceBitmap, i.e a SfcName, or an external JPEG,PNG,BMP filename.
Valid options are:
Blend2D provides both simple geometric types ( line, rectangle, circle ....) and complex geometric types (Path). The main difference between simple and complex geometry types derives from their implementation. Although all the geometric types could be implemented as oo-classes, this will tend to develop programs difficult to maintain, since in Tcl oo-objects should be explicitly destroyed. Therefore most of the following commands for building geometric types don't return oo-objects but simple tcl-lists/dictionaries, that are automatically disposed when they go out of scope.
Currently just one complex geometry-types (BL::Path) is implemented as oo-class, (and then it's programmers's responsability to explicitly destroy it).
A simple example for drawing a simple geometry is
$sfcName fill [BL::box 0 0 120 175.8]
The supported simple-geometries are:
Note that all these commands defining simple geometry types start with a lowercase letter. These commands do not create oo-objects; they simply return a special crafted list that should be passed to the fill/stroke methods. These objects (lists/dictionaries!) don't require an explicit "destroy" method.
Other than simple geometries there are complex geometries like BL::Path and they will be described in the following sections.
draws the outline of the specified geometry, accordling to the current drawing-state. Extra options listed after geometry are temporary set just for this operation. Note that some options like -stroke.width, -stroke.style, can be abbreviated as -width, -style, and so on.
draws (fills) the specified geometry, accordling to the current drawing-state. The special geometry all means "the whole framebuffer". Extra options listed after geometry are temporary set just for this operation. Note that within this fill operation, the option -fill.style can be abbreviated as -fill.
This is a shorthand for "sfcName fill all ?options?"
flushes the internal rendering command queue and wait for its completion (will block). (only useful in Multi-Thread contexts). This command is normally unnecessary, since a flush() is automatically performed before the image is copied/exported/displayed.
returns a list of two values: width and height of the surface (in pixel)
sets the surface MetaMatrix. TO BE DOC'ed ...
The following commands can be used for creating and manipulating a Path:
creates a new instance of the class BL::Path called pathName.
creates a new instance of the class BL::Path returning a new unique pathName.
destroys pathName.
duplicates pathName. Return a new path
returns the list of the currently available paths
adds one or more geometry to pathName. geometry is any geometric type above defined, including the same pathName.
Valid options are:
# starting from Blend2d 1.0, the "add" method also accepts a "BL::text" as a geometry. # All the glyphs are converted and added to a BLPath using a simple layout algorith set fontFace [BL::FontFace new "./Arial.ttf"] set fontName [BL::Font $fontFace 12.0] set blPath [BL::Path new] $blPath add [BL::text {100 100} $font "ABC .. Z"] # then you can get and manipulate its SVG representation set SVG [$blPath view] ...
creates a new BL::Path made by stroking the current path with the stroking options passed as arguments. Valid stroke-options are:
These stroke-options are a subset of the options used for the stroke method of the BL::Surface class.
# build path0 as a simple triangle set path0 [BL::Path new] $path0 add [BL::polygon {100 100} {150 200} {200 200}] # then derive a new path ... as the prevoius path but with a thick contour and rounded corners ..' set path1 [$path0 newStrokedPath -width 20 -join ROUND] ... rememeber to destroy path0 and path1
reads and parses the SVG-path-data commands in dataString and adds the equivalent Blend2d command. dataString must follow the rules for the "d" property of the SVG path elements, see the specs at https://www.w3.org/TR/SVG/paths.html#DProperty
set blPath [BL::Path new] # the following SVG-path is presented in this way just for readability .. $blPath addSVGpath " M 100 100 q -100 0 -200 -100 l 10.0 20.1 30 40 50 -5 h 1.5e+3 Z" # but it can also be specified in a compact form $blPath addSVGpath "M100+100q-100+0-200-100l10.0,20.1,30,40,50-4H2E+3h1.5e+3Z"
applies the 2D matrix transformation to the whole pathName.
fits (scale&translate) the whole pathName into the given rect.
sets the starting point0 (expressed as a list of two numbers) for the next commands ..
shrinks the internal capacity of the path to fit the current usage.
Get the path's bounding-box.
Note that bbox does not consider the line-width, offset, caps (these parameters are definied when stroking/filling the path). If path is empty returns {0.0 0.0 0.0 0.0}
Returns the path data in SVG format
returns the number of countours.
returns the number of simple curves of the i-th contour. If * is specified, return a list with the number of simple curves of every contour.
by using the parametric equation B(t) of the j-th curve of the i-th contour, evaluates one of the following OP functions at value t (t must be between 0.0 and 1.0):
at: returns the position {x y} at B(t)
tangent: returns the tangent versor {x y} at B(t)
normal: returns the normal versor {x y} at B(t)
tangentAt: returns the the position and the tangent versor at B(t)
normalAt: returns the the position and the normal versor at B(t)
If * is specified instead of the contour index, this command returns a list with all the OP evaluations at t for the j-th curves of every contour. If some contour has less than j curves, its evaluation is {}.
If * is specified instead of the curve index, this command returns a list with all the OP evaluations at t for every curve of the i-th contour.
If * is specified for both the contour index and the curve index,this command returns a list of list, i.e. for every contours returns a list of the evaluations of OP at t for every its single curve.
Note: Currently text support is still basic and subject to changes.
Before drawing some text, you need to load some fonts from an external font-file.
loads a fontfile and creates a new instance of the class BL::FontFace named faceName.
If fontfile is a font collection, you can specify which fontface to load. Default value for faceIdx is 0 (i.e. the first fontface). if faceIdx is greater than the number of the available fontfaces, the last fontface is loaded, and it can be inspected with the detail method.
loads a fontfile, creates a new instance of the class BL::FontFace returning a new unique faceName.
destroys faceName. Note that in general any oo-object like faceName should be explicitly destroyed
returns the list of all the currently allocated fontfaces.
returns a dictionary with some properties of the loaded faceName.
These are the currently listed properties ;more properties may be added in future Blend2d releases.
# load the last fontface from a fontfile-collection # ("AmericanTypewriter.ttc" can be found in the tclBlend2d-devkit distribution ) # Note that I want to load the last fontface, so I specify a large 'faceIdx' # surely greater than the available fontface (.. there're 6 fontfaces in this collection ..) set fface [BL::FontFace new "./AmericanTypewriter.ttc" 999] # pretty print details dict for {key value} [$fface details] { puts "[format "%25s %s" $key $value]" } # .... # other ops ... # $fface destroy
This produces the following output :
faceIndex 5 glyphCount 916 fullName American Typewriter Condensed Light familyName American Typewriter subfamilyName Condensed Light postScriptName AmericanTypewriter-CondensedLight unitsPerEm 1000 weight 300 style 0 stretch 3 hasCharToGlyphMapping 1
Once a BL::FontFace has been loaded,and before drawing some text or extracting some glyphs, you should create a BL::Font object based on an instance of BL::FontFace
creates a new instance of the class BL::Font, based on faceName, having size fontsize (float).
Note that although any text and glyph can be arbitrarialy scaled with the usual 2D trasnsformations, fontsize can be used to select some special glyphs that some fonts may make available for working with very small font sizes.
creates a new instance of the class BL::Font returning a new unique fontName.
destroys fontName. Note that in general any oo-object like fontName should be explicitly destroyed
returns the list of all the currently allocated fonts.
A fontName can be used for drawing some text like in the following example
set fontFace [BL::FontFace new "./Arial.ttf"] set fontName [BL::Font $fontFace 12.0] set sfc [BL::Surface new] $sfc fill [BL::text {100 100} $fontName "Hello World"] -style [BL::color orange]
but it can also used for extracting single glyphs from it.
returns a list of glyph-indexes, one glyph-index for each (Unicode) character in someText.
returns a new instance of BL::Path containing the geometrical representation of the given glyphIdx. Raise an error if glyphIdx is invalid.
Note: this method creates a new BL::Pathinstance, and it is user's responsability to destroy it explicitly.
Before drawing some text (or a single glyph) you should load a fontfile, then setup a BL::Font with a given size
set aFontFace [BL::FontFace new _fontfile_] set aFont [BL::Font new $aFontFace _size_]
note that both BL:FontFace and BL::Font create new objects, and therefore it's programmer's responsability to delete them (e.g call "$aFontFace destroy" )
The easiest way to draw a text on a Surface is to use the special 'geometry' BL::text with the fill/stroke methods
surfaceName fill [BL::text {10 20} $aFont "Hello World!!"]
Of course you can set the drawing-properties of the Surface as usual (color, gradient,line width, matrix transformation ....)
Alternatively, you can extract a single glyph from a font, store them as a BL::Path, and then manipulate it as usual
set aGlyph [$font glyph 44] ;# extract glyph n.44 $sfc stroke $aGlyph
Note that the glyph methods returns a new BL::Path object,and therefore it is programmer's responsability to free the resources (e.g. "$aGlyph destroy" )
TclBlend2d provides two basic ways to work with filters. You can apply a filter to a rectangular region of a Surface (currently only blur filter), or you can set a filter to a script, so that it will be applied to all the graphical primitives that will be rendered by this script.
applies a blur filter of size radius (from 2 to 254) to a rectangular region of sfcName
Valid options are:
all the graphical primitives created by this script that will be rendered on sfcName will be redirected on a special temporary layer, then the filter will be applied to this temporary layer and then it will be blended with the underlying Surface.
Parameters are:
Valid values are blur, shadow, and the special filter ignore. This latter filter means that no filter will be applied.
A list of options for filterType. (see below .....)
A tcl script. Usually this script should contain some rendering commands on sfcName. All these commands will temporary redirected to an automatically allocated temporary Surface. This temporary surface is initialized as a transparent surface and has the same 'state' (e,g the set of options) of sfcName. When script ends, the filter is applied to the whole temporary surface (or better, only to the bounding-box of the rendered primitives), and finally, this temporary Surface will be blended with the underlying sfcName.
Note that if this script changes the state of the (redirected) sfcName, these changes will be also visible in the original sfcName.
Warning: take care of not "popping" the initial stack level of sfcName. Method push and pop are allowed within script as long as they are properly paired.
$sfc reset $sfc clear -style [BL::color white] # # --- a shadowed blue/white/red disc # set center {100 150} $sfc filter shadow -radius 20 -dxy {5 9} { foreach circleRadius {90 60 30} color {lightblue white red} { $sfc fill [BL::circle $center $circleRadius] -style [BL::color $color] } } # # --- three shadowed discs # set center {300 150} foreach circleRadius {90 60 30} color {lightblue white red} { $sfc filter shadow -radius 20 -dxy {5 9} { $sfc fill [BL::circle $center $circleRadius] -style [BL::color $color] } }
Blend2d provides commands for loading graphics files in a Surface, as well for saving the Surface's internal framebuffer in a graphic file. Blend2d provides commands for copying (part of) the internal framebuffer among different Surfaces. If the Tk support is loaded, that is if you loaded the Blend2d or tkBlend2d packages, you can also exchange parts of the Surfaces framebuffer with tk photo images.
loads the contents of filename. Supported formats: png, jpeg, bmp.
WARNING: the internal framebuffer is resized.
saves the internal framebuffer in filename If -format is not specified, this command tries to guess the file-format from the file extension.
NOTE: currently only BMP and PNG encoder are available
copies (a sub-region of) srcSurface to the current sfcName. If no options are specified, this command copies the whole srcSurface starting at coordinates (0,0).
The following options may be specified:
copies (a sub-region of) srcSurface to the current sfcName. If no options are specified, this command copies the whole srcSurface starting at coordinates (0,0).
Note that if there's a matrix-trasformation (rotation, scaling, ..) on the current surface, this transformation will be applied to all points of the destination sub-region (i.e. the -from rectangle will be rotated, scaled, ...)
similar to the copy method. The only difference is that the source region (those specified by the -from option) will be copied in sfcName *without* any transformation.
The default -compop mode is SRC_OVER.
These commands require the Blend2d or tkBlend2d package. These commands are not available if you loaded the tclBlend2d package;
copies (a sub-region of) tkphoto to the current sfcName. If no options are specified, this command copies the whole srcSurface starting at coordinates (0,0).
NOTE: sfcName is not resized; you should take care to resize it in order to get all the portion of the tkphoto you are interested in.
copies (a sub-region of) sfcName to the current sfcName. If no options are specified, this command copies the whole srcSurface starting at coordinates (0,0).
These commands require the "Blend2d" or "tkBlend2d" package. These commands are not available if you loaded the "tclBlend2d" package;
Similar to the standard command "image create photo ...", this command creates a new image of type blend2d plus a new surface-object that can be used for manipulating the image.
Options are the same options used for the "BL::Surface create .." command.
The image can then be embedded in a widget (like a "label" or a "canvas"); every command like fill, stroke issued to the image name, will immediately change the displayed image.
Both "image delete sfcName" and "sfcName destroy" can be used to delete the image AND the related surface-object.
lists the name of the BL classes (e.g BL::Surface,BL::Path, ...)
returns the class name of objectName. objectName can be any tcloo object (not limited to BL:: objects)
lists the supported graphics file formats.
For each supported graphic file formats, returns a detailed list made of 5 elements: id, vendor, mimeType, extensions, features.
id is the key element to be used in load/save operations (e.g. JPEG)
vendor is the name of the codec's vendor.
mimetype is a string (e.g. image/jpeg)
extensions is a sequence of recognized filename-extensions; elements are separated by "|" (e.g. jpg|jpeg|jif|jfi|jfif)
features is a list of supported features
READ: reading is supported
WRITE: writing is supported
LOSSY: loosy compression
LOSSLESS: lossless compression
MULTI_FRAME: multiple frames (GIF).
IPTC: supported IPTC metadata.
EXIF: supported EXIF metadata.
XMP: supported XMP metadata.
lists all the enum categories
lists all the values for that _category_ e.g. BL::enum GRADIENT_TYPE --> LINEAR RADIAL CONICAL
returns a dictionary with info about the core Blend2d library. The dictionary keys are version, type (build-type)
returns a dictionary with info about the cpu architecture and the cpu features used by Blend2d. The dictionary keys are cpuArch, cpuFeatures, coreCount.
Blend2d provides some small helpers for working with transformation-matrix and colors
An affine matrix is a 3x3 matrix whose last column is fixed 0 0 1
a b 0 c d 0 e f 1
Given this rule it is convenient to express such matrices as a list of 6 numbers { a b c d e f } instead of 9 numbers.
Working with these matrices can be simplified by using the Mtx package included in Blend2D.
In the following paragraphs "M" stands for a matrix (a list of 6 numbers), "P" stands for a 2D point (a list of 2 numbers).
The following ops are supported
returns the identity matrix {1 0 0 1 0 0}
matrix multiplication
matrix inversion - Raise an error if M is not invertible.
map a Point
map a list of Points
return P1-P2
map a vector V : VxM(V,M) = PxM(V,M)-PxM(0,M)
scale sx sy around the fixed-point C
performs a rotation of angle around the fixex-point C
Blend2d internally works with colors expressed in terms of red,green,blue and alpha channels, but in some cases it is more natural to express color following the HSB color model, where:
h (hue) is a 0.0..360.0 angle
s (saturation) is 0.0 .. 1.0
b (brigthess) is 0.0 .. 1.0 ( 0 is black, 1 is white )
The following commands are availables for converting between between ARGB and HSB color models. alpha is 0.0 .. 1.0
returns an ARGB number (in decimal notation, not in hex notation)
returns a list with the HSB components. { h s b alpha }
Saving a Surface is currently limited to BMP or PNG files.
The -stroke.dasharray option is currently a no-op.
graphics
vector grahics
Copyright © 2021..2023 - A.Buratti