PLUG'N SCRIPT
rapid plugin development
Tutorial
DSP
KUIML
How-to
Scripts
  • Tutorial
  • Element Reference
Language basics
  • SKIN
  • DUMMY
  • INCLUDE
  • INCLUDE_ONCE
  • DEFINE
  • UNDEFINE
  • VARIABLE
  • LOCAL_VARIABLE
  • TEMPLATE
  • TEMPLATE_INNER_CONTENT
  • REPEAT
Data model
  • PARAM
  • ACTION
    • Action types
  • ACTION_TRIGGER
UI Layout and positioning
  • CELL
  • TABLE
UI Widgets
  • TEXT
  • TEXT_FIELD
  • TEXT_EDIT_BOX
  • CANVAS
    • Graphics API
  • svg
Common attrubutes
  • For all elements
  • Widgets
  • Param Widgets
  • Param Controls
  • Param Info Viewers
  • Text Widgets
  • Surface Viewers
  • Curve Viewers
  • 3D Objects
  • Parameters mapping
KUIMLElement ReferenceCANVASGraphics API
January 14, 2023

CANVAS Graphics API

This API is currently using a freeware Cairo Graphics Library wrapped with AngelScript. If you want to know more about some specific method usage and implementation and can look it up in Cairo API Reference, also the original Kt::Graphics reference can be helpful.

More usage examples can be found on the CANVAS page itself and in these drawing examples.

API Testbench

All examples on this page will use the following environment:

  1. ./Scripts/CanvasDemo/canvas.cxx // DSP part
  2. ./Scripts/CanvasDemo/canvas.kuiml // GUI part
  3. ./Scripts/CanvasDemo/canvas-data/render.as // render function

canvas.cxx contents:

  1. string name="CANVAS"; // just a script name

canvas.kuiml contents:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <SKIN>
  3. <!-- load a render script -->
  4. <SCRIPT src="$SCRIPT_DATA_PATH$/render.as" />

  5. <!-- create a canvas and run a render_script -->
  6. <CANVAS id="my_canvas" width="300" height="200"
  7. render_script="renderMyCanvas(this.height, this.width)"
  8. requires="my_canvas.width;my_canvas.height" />
  9. </SKIN>

canvas-data/render.as contents:

  1. // render function
  2. void renderMyCanvas(double h, double w) {
  3. // get current context
  4. Kt::Graphics::Context@ ctx = Kt::Graphics::GetCurrentContext();
  5. if (@ctx != null) {
  6. // set the color
  7. ctx.source.SetRGBA(1,0,0, 0.8); // r, g, b, alpha
  8. // draw a simple circle using arc
  9. ctx.path.Clear();
  10. ctx.path.Arc(w/2, h/2, w/4, 0, 360); // cx, cy, radius, angle_start, angle_end
  11. ctx.FillPath();
  12. }
  13. }

Note on inline formatting

To have a render function in the same kuiml file (not in a separate AngelScript file) like in these examples, you can use inline scripting, just remember to replace all " with &quot; and all < with &lt; . Replace // comments with /* */

You can try our online converter to do that.

In the following examples we'll be talking about the contents of the renderMyCanvas function.

Context object

The first thing you usually do is get a context object, and then you can use its methods and attributes to do the drawing.

  1. // get current context
  2. Kt::Graphics::Context@ ctx = Kt::Graphics::GetCurrentContext();
  3. if (@ctx != null) {
  4. ... do the drawing ...
  5. }

Using bitmaps

Instead of drawing on the screen you can create a bitmap object (or load it from file), get its context and draw on that. You can later use that bitmap as a source or mask pattern (see ctx.source.SetBitmap) and paint it on the screen or save it to a PNG file.

  1. // create a bitmap object
  2. Kt::Graphics::Bitmap@ bmp = Kt::Graphics::CreateBitmap(300,200);
  3.  
  4. // or instead load it from PNG/JPG/GIF/BMP/TIFF/HEIC/SVG file
  5. // Kt::Graphics::Bitmap@ bmp = Kt::Graphics::LoadImageFile("/path/file.png");
  6.  
  7. { // work with bitmap context in another scope
  8. Kt::Graphics::Context@ ctx = bmp.BuildContext();
  9. if (@ctx != null) {
  10.  
  11. .. do the drawing ..
  12.  
  13. // save bitmap to a file
  14. Kt::Graphics::SaveImageFile(bmp, "/path/to/file.png");
  15. }
  16. @ctx = null; // free context handle (just in case)
  17. }
  18.  
  19. // get current context (the screen)
  20. auto ctx = Kt::Graphics::GetCurrentContext();
  21. if (@ctx != null) {
  22. // display bitmap on the screen
  23. ctx.source.SetBitmap(bmp);
  24. ctx.Paint();
  25. }

Context methods

  1. ctx.StrokePath(); // Strokes the current path using current pattern
  2. ctx.FillPath(); // Fills the path using current pattern
  3. ctx.Paint(); // Paints the current pattern (clipped by clip region)
  4. ctx.PaintWithAlpha(double alpha); // Paints the current pattern (clipped by clip region) with additional alpha channel blend
  5. ctx.PaintWithMask(); // Paints the current pattern (clipped by clip region) using the current mask
  6. ctx.ClipWithPath(); // Intersects the clip region with current path
  7. ctx.WriteText(const char *text); // Draw text using current text settings and source pattern, with current position defined with path
  8. ctx.SaveState(); // Save current surface state (stack)
  9. ctx.RestoreState(); // Restores last saved surface state (stack)

Context methods example:

  1. // utility function to convert HEX color to RGB and add it to given context
  2. Kt::Graphics::DrawPattern@ setColorHex(Kt::Graphics::Context@ ctx, string hexcolor = "", double opacity = 1, bool selectAsSource = true) {
  3. // verify hex color string
  4. if (hexcolor == "") hexcolor = "777777";
  5. if (hexcolor.substr(0,1) == "#") hexcolor = hexcolor.substr(1,6);
  6. // convert to r,g,b with 0-1 range
  7. double r = double(parseInt(hexcolor.substr(0,2),16))/255.0;
  8. double g = double(parseInt(hexcolor.substr(2,2),16))/255.0;
  9. double b = double(parseInt(hexcolor.substr(4,2),16))/255.0;
  10. // convert opacity if it's in 0-100 range
  11. if (opacity > 1) opacity = opacity/100.0;
  12. // add a new flat color
  13. Kt::Graphics::DrawPattern@ pattern = ctx.patterns.NewRGBA (r,g,b,opacity);
  14. // apply it as a source (if needed, by default)
  15. if (selectAsSource) { pattern.SelectAsSource(); }
  16. // return that color for future use
  17. return pattern;
  18. }
  19.  
  20. // render function to show examples of all context methods
  21. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  22.  
  23. // set canvas width from the render function
  24. canvas_width = 500;
  25. canvas_height = 350;
  26.  
  27. // get these values as a double
  28. double h = canvas_height;
  29. double w = canvas_width;
  30.  
  31. // load used images
  32. auto logo_bmp = Kt::Graphics::LoadImageFile("/path/to/LM_logo.png");
  33. auto pattern_bmp = Kt::Graphics::LoadImageFile("/path/to/letimix.png");
  34.  
  35. // get current context (the screen)
  36. auto ctx = Kt::Graphics::GetCurrentContext();
  37. if (@ctx != null) {
  38.  
  39. // paint whole area with white
  40. auto white = setColorHex(ctx, "f4f4f8"); // utility function
  41. ctx.PaintWithAlpha(0.9); // with slight transparency
  42.  
  43. // add some vertical stripes
  44. // do some pre calculations
  45. double pad_x = w/15;
  46. double pad_y = w/20;
  47. double stripe_width = (w-pad_x*2)/4;
  48. double stripe_height = h - pad_y*2;
  49.  
  50. // add color and fill the stripe
  51. auto red = setColorHex(ctx, "#fe4a49");
  52. ctx.path.Clear();
  53. ctx.path.Rectangle(pad_x, pad_y, stripe_width, stripe_height);
  54. ctx.FillPath();
  55.  
  56. // add color and fill the stripe
  57. auto blue = setColorHex(ctx, "2ab7ca");
  58. ctx.path.Clear();
  59. ctx.path.Rectangle(pad_x + stripe_width, pad_y, stripe_width, stripe_height);
  60. ctx.FillPath();
  61.  
  62. // add color and fill the stripe
  63. auto yellow = setColorHex(ctx, "fed766");
  64. ctx.path.Clear();
  65. ctx.path.Rectangle(pad_x + stripe_width*2, pad_y, stripe_width, stripe_height);
  66. ctx.FillPath();
  67.  
  68. // add color and fill the stripe
  69. auto gray = setColorHex(ctx, "e6e6ea");
  70. ctx.path.Clear();
  71. ctx.path.Rectangle(pad_x + stripe_width*3, pad_y, stripe_width, stripe_height);
  72. ctx.FillPath();
  73.  
  74. // save state to undo translate and scale later
  75. ctx.SaveState();
  76.  
  77. // add repeated pattern with reflected logos
  78. ctx.transform.Scale(0.125, 0.125); // scale to make bmp smaller
  79. ctx.source.SetBitmap (pattern_bmp, 0, 0, Kt::Graphics::kExtendReflect);
  80. ctx.transform.Scale(8, 8); // get scale back
  81. // add another linear gradient as a mask
  82. auto gradient2 = ctx.patterns.NewLinearGradient(0,0,0,h);
  83. gradient2.AddColorStopRGBA(0.5, 0,0,0, 0.0);
  84. gradient2.AddColorStopRGBA(1, 0,0,0, 0.3);
  85. gradient2.SelectAsMask();
  86. // clip with center rectangle
  87. ctx.path.Clear();
  88. ctx.path.Rectangle(pad_x, pad_y, w-pad_x*2, h-pad_y*2);
  89. ctx.ClipWithPath();
  90. // paint it all
  91. ctx.PaintWithMask();
  92.  
  93. // get back to default translate and scale
  94. ctx.RestoreState();
  95. // save state to undo translate and scale later
  96. ctx.SaveState();
  97.  
  98. // add a white radial glow under the logo
  99. ctx.transform.Translate(w/2, h/2 - 10); // shift drawing to center
  100. auto gradient = ctx.patterns.NewRadialGradient(0,0,0, 0,0,h/2);
  101. gradient.AddColorStopRGBA(0.2, 1,1,1, 1);
  102. gradient.AddColorStopRGBA(1, 1,1,1, 0);
  103. gradient.SelectAsSource();
  104. ctx.Paint();
  105.  
  106. // get back to default translate and scale
  107. ctx.RestoreState();
  108. // save state for later
  109. ctx.SaveState();
  110.  
  111. // add a center logo
  112. ctx.transform.Translate(w/2, h/2 - 10); // shift drawing to center
  113. ctx.transform.Scale(0.85, 0.85); // scale drawing
  114.  
  115. // display a logo clipped with a circle
  116. ctx.path.Clear();
  117. ctx.path.Arc(0, 0, 90, 0, 360); // add a circle
  118. ctx.ClipWithPath();
  119. // add logo image as source and paint it
  120. ctx.source.SetBitmap (logo_bmp, logo_bmp.width/2, logo_bmp.height/2);
  121. ctx.Paint();
  122. // stroke a circle
  123. ctx.settings.set_lineWidth(5);
  124. gray.SelectAsSource();
  125. ctx.StrokePath();
  126.  
  127. // restore state
  128. ctx.RestoreState();
  129.  
  130. // write text under logo
  131. string s = "MAKE AND INSPIRE";
  132. ctx.font.SetFontSize(15);
  133. ctx.source.SetRGBA(0,0,0, 0.8);
  134. // center text
  135. double text_width = ctx.font.GetTextSize(s).x;
  136. ctx.path.MoveTo(w/2 - text_width/2,h/2+95);
  137. ctx.WriteText(s);
  138.  
  139. // add a "shadow" under the text
  140. ctx.path.RelMoveTo(-text_width*1.025,2);
  141. ctx.transform.Scale(1.05, 1.4);
  142. ctx.source.SetRGBA(0,0,0, 0.05);
  143. ctx.WriteText(s);
  144. }
  145. }

Context attributes

ctx.path (class Kt::Graphics::DrawPath)

The current path used for stroke, fill and clip. Can get some info in Cairo Path docs.

  1. ctx.path.MoveTo (double x, double y)
  2. ctx.path.LineTo (double x, double y)
  3. ctx.path.CurveTo (double x1, double y1, double x2, double y2, double x3, double y3) // draw a cubic Bezier spline
  4. ctx.path.Arc (double xc, double yc, double radius, double angle1, double angle2)
  5. ctx.path.ArcNegative (double xc, double yc, double radius, double angle1, double angle2) // draw an arc or a circle in the opposite direction
  6. ctx.path.Rectangle (double x, double y, double width, double height)
  7. ctx.path.RelMoveTo (double dx, double dy) // move relative to last point
  8. ctx.path.RelLineTo (double dx, double dy) // line relative to last point
  9. ctx.path.RelCurveTo (double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) // curve relative to last point
  10. ctx.path.Text (const char *utf8) // adds text as path
  11. ctx.path.Clear () // starts new path
  12. ctx.path.NewSubPath () // forgets last point, esp. useful when drawing arcs
  13. ctx.path.Close () // connects first and last points

ctx.path examples:

  1. // draw a line (1)
  2. ctx.path.Clear();
  3. ctx.path.MoveTo(20,20);
  4. ctx.path.LineTo(100, 100);
  5. ctx.StrokePath();
  6. ctx.WriteText("1");
  7.  
  8. // draw a curved line (2)
  9. ctx.path.Clear();
  10. ctx.path.CurveTo(100,20, 130,140, 160,20);
  11. ctx.StrokePath();
  12. ctx.WriteText("2");
  13.  
  14. // draw an arc (3)
  15. ctx.path.Clear();
  16. // xcenter, ycenter, radius, angle_start, angle_end (degrees)
  17. ctx.path.Arc(150,150, 30, 45, 270);
  18. ctx.StrokePath();
  19. ctx.WriteText("3");
  20.  
  21. // draw a negative Arc (opposite drawing direction) (4)
  22. ctx.path.Clear();
  23. ctx.path.ArcNegative(190,150, 30, 0, -90);
  24. ctx.StrokePath();
  25. ctx.WriteText("4");
  26.  
  27. // draw a circle (5)
  28. ctx.path.NewSubPath(); // doesn't clear current path, but forgets (disconnects from) last point
  29. ctx.path.Arc(250,70, 30, 0, 360);
  30. ctx.WriteText("5");
  31. ctx.StrokePath();
  32.  
  33. // draw a rectangle (6)
  34. ctx.path.Clear();
  35. ctx.path.Rectangle(320, 30, 60, 40);
  36. ctx.StrokePath();
  37. ctx.WriteText("6");
  38.  
  39. // draw a triangle (7)
  40. ctx.path.RelMoveTo(0, 100);
  41. ctx.path.RelLineTo(-30,50);
  42. ctx.path.RelLineTo(60,0);
  43. ctx.path.Close();
  44. ctx.StrokePath();
  45. ctx.WriteText("7");
  46.  
  47. // draw another curved line (8)
  48. ctx.path.RelCurveTo(40,0, 40,50, 80, 0);
  49. ctx.StrokePath();
  50. ctx.WriteText("8");
  51.  
  52. // draw text as path (9)
  53. ctx.path.MoveTo(60, 240);
  54. ctx.SaveState(); // to save font size
  55. ctx.font.SetFontSize(50);
  56. ctx.path.Text("Path examples");
  57. ctx.StrokePath();
  58. ctx.RestoreState(); // to restore font size
  59. ctx.WriteText("9");

ctx.settings (class Kt::Graphics::DrawSettings)

The settings used for drawing operations

  1. ctx.settings.set_lineWidth (double width)
  2. ctx.settings.set_blendMode (BlendMode op)
  3.  
  4. // line width and blend mode examples
  5. ctx.settings.set_lineWidth(1.5);
  6. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpMultiply);

Line width examples:

  1. // narrow line
  2. ctx.path.Clear();
  3. ctx.path.MoveTo(10, 20);
  4. ctx.path.RelLineTo(180, 0);
  5. ctx.settings.set_lineWidth(1);
  6. ctx.StrokePath();
  7. ctx.WriteText(" lineWidth: 1");
  8.  
  9. // wider line
  10. ctx.path.Clear();
  11. ctx.path.MoveTo(10, 48);
  12. ctx.path.RelLineTo(180, 0);
  13. ctx.settings.set_lineWidth(6);
  14. ctx.StrokePath();
  15. ctx.WriteText(" lineWidth: 6");
  16.  
  17. // wide line
  18. ctx.path.Clear();
  19. ctx.path.MoveTo(10, 76);
  20. ctx.path.RelLineTo(180, 0);
  21. ctx.settings.set_lineWidth(12);
  22. ctx.StrokePath();
  23. ctx.source.SetRGBA(0,0,0,1);
  24. ctx.WriteText(" lineWidth: 12");

Note on blend modes

Blendmode (compositing mode) used for rendering on the target graphics can be:

  • kDrawOpOver - draw source layer on top of destination layer [DEFAULT]
  • kDrawOpXor - source and destination are shown where there is only one of them
  • kDrawOpAdd - add source pattern and destination content.
  • kDrawOpMultiply - multiply source and destination. The result is at least as dark as the darker inputs.
  • kDrawOpDifference - takes the difference of the source and destination color.

Blendmodes are still experimental and may change in the future or not work in all contexts.

Example of different blend modes:

The same gradient repeated five times with different blend modes over multicolored background.
The gradient colors (RGBA) are #FFFFFFFF -> #FFFFFF00 -> #00000000 -> #000000FF
(white -> transparent white -> transparent black -> black)

Instead of black and white gradient using "rainbow" gradient without transparency.

  1. // render function to show examples of different blend modes
  2. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  3.  
  4. // set canvas width from the render function
  5. canvas_width = 700;
  6. canvas_height = 300;
  7.  
  8. // get these values as a double
  9. double h = canvas_height;
  10. double w = canvas_width;
  11.  
  12. // get current context (the screen)
  13. auto ctx = Kt::Graphics::GetCurrentContext();
  14. if (@ctx != null) {
  15.  
  16. ctx.SaveState();
  17.  
  18. // color gradient for background
  19. auto rgbgrad = ctx.patterns.NewLinearGradient(0,0,0,h);
  20. rgbgrad.AddColorStopRGBA(0, 1,0,0, 1);
  21. rgbgrad.AddColorStopRGBA(0.16, 1,1,0, 1);
  22. rgbgrad.AddColorStopRGBA(0.33, 0,1,0, 1);
  23. rgbgrad.AddColorStopRGBA(0.5, 0,1,1, 1);
  24. rgbgrad.AddColorStopRGBA(0.66, 0,0,1, 1);
  25. rgbgrad.AddColorStopRGBA(0.83, 1,0,1, 1);
  26. rgbgrad.AddColorStopRGBA(1, 1,0,0, 1);
  27. rgbgrad.SetExtend(Kt::Graphics::kExtendNone);
  28. rgbgrad.SelectAsSource();
  29. ctx.Paint();
  30.  
  31. // middle three lines
  32. // white
  33. ctx.path.Clear();
  34. ctx.path.Rectangle(0,h/2 - h/4,w,h/8);
  35. ctx.source.SetRGBA(1,1,1, 1);
  36. ctx.FillPath();
  37.  
  38. // gray
  39. ctx.path.Clear();
  40. ctx.path.Rectangle(0,h/2 - h/16,w,h/8);
  41. ctx.source.SetRGBA(0.5,0.5,0.5, 1);
  42. ctx.FillPath();
  43.  
  44. // black
  45. ctx.path.Clear();
  46. ctx.path.Rectangle(0,h/2 + h/8,w,h/8);
  47. ctx.source.SetRGBA(0,0,0, 1);
  48. ctx.FillPath();
  49.  
  50. // some pre-calculations
  51. double grad_pad = 15;
  52. double grad_width = (w-grad_pad*6)/5;
  53.  
  54. // add a test gradient
  55. auto gradient = ctx.patterns.NewLinearGradient(0,0,grad_width,0);
  56. // make gradient not repeating
  57. gradient.SetExtend(Kt::Graphics::kExtendNone);
  58.  
  59. // for b/w gradient
  60. // gradient.AddColorStopRGBA(0, 1,1,1, 1); // full white
  61. // gradient.AddColorStopRGBA(0.49, 1,1,1, 0); // transparent white
  62. // gradient.AddColorStopRGBA(0.51, 0,0,0, 0); // transparent black
  63. // gradient.AddColorStopRGBA(1, 0,0,0, 1); // full black
  64.  
  65. // for multicolor gradient
  66. gradient.AddColorStopRGBA(0, 1,0,0, 1);
  67. gradient.AddColorStopRGBA(0.16, 1,1,0, 1);
  68. gradient.AddColorStopRGBA(0.33, 0,1,0, 1);
  69. gradient.AddColorStopRGBA(0.5, 0,1,1, 1);
  70. gradient.AddColorStopRGBA(0.66, 0,0,1, 1);
  71. gradient.AddColorStopRGBA(0.83, 1,0,1, 1);
  72. gradient.AddColorStopRGBA(1, 1,0,0, 1);
  73.  
  74. // paint gradient with various blend modes
  75. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpOver);
  76. ctx.transform.Translate(grad_pad, 0);
  77. gradient.SelectAsSource();
  78. ctx.Paint();
  79.  
  80. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpXor);
  81. ctx.transform.Translate(grad_width+grad_pad, 0);
  82. gradient.SelectAsSource();
  83. ctx.Paint();
  84.  
  85. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpAdd);
  86. ctx.transform.Translate(grad_width+grad_pad, 0);
  87. gradient.SelectAsSource();
  88. ctx.Paint();
  89.  
  90. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpMultiply);
  91. ctx.transform.Translate(grad_width+grad_pad, 0);
  92. gradient.SelectAsSource();
  93. ctx.Paint();
  94.  
  95. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpDifference);
  96. ctx.transform.Translate(grad_width+grad_pad, 0);
  97. gradient.SelectAsSource();
  98. ctx.Paint();
  99.  
  100. ctx.RestoreState();
  101.  
  102. // draw separation lines between gradients
  103. ctx.source.SetRGBA(0,0,0, 0.3);
  104. ctx.settings.set_lineWidth(1.5);
  105. for (int n = 0; n<6; n++) {
  106. ctx.path.Clear();
  107. ctx.path.MoveTo(n*(grad_width+grad_pad) + grad_pad/2, 0);
  108. ctx.path.RelLineTo(0, h);
  109. ctx.StrokePath();
  110. }
  111.  
  112. // write text
  113. ctx.source.SetRGBA(1,1,1, 1);
  114. ctx.path.MoveTo(47, h/2 - h/16 + 14);
  115. // ctx.WriteText("Paint b/w RGBA gradient #FFFFFFFF -> #FFFFFF00 -> #0000000 -> #000000FF");
  116. ctx.WriteText("Paint RGBA multicolor gradient");
  117. ctx.path.MoveTo(47, h/2 + 14);
  118. ctx.WriteText("5 times with different blend modes over multicolored background");
  119. double y = h/2 + h/4 - h/22;
  120. ctx.path.MoveTo(47, y);
  121. ctx.WriteText("OpOver");
  122. ctx.path.MoveTo(55 + grad_width+grad_pad, y);
  123. ctx.WriteText("OpXor");
  124. ctx.path.MoveTo(50 + 2*(grad_width+grad_pad), y);
  125. ctx.WriteText("OpAdd");
  126. ctx.path.MoveTo(33 + 3*(grad_width+grad_pad), y);
  127. ctx.WriteText("OpMultiply");
  128. ctx.path.MoveTo(38 + 4*(grad_width+grad_pad), y);
  129. ctx.WriteText("OpDifference");
  130. }
  131. }

ctx.patterns (class Kt::Graphics::DrawPatternFactory)

This is a way to create "patterns" that can be used for drawing, painting or writing text.
A "pattern" is a flat color, a gradient or a bitmap (see ctx.source.SetBitmap below).

Any pattern can be selected for being used a "source" for methods like ctx.StrokePath, ctx.FillPath, ctx.Paint, ctx.PaintWithAlpha, ctx.WriteText.

Also any pattern can be selected as a "mask" to be used with ctx.PaintWithMask.

  1. // FLAT COLORS
  2.  
  3. // add a color
  4. Kt::Graphics::DrawPattern@ color = ctx.patterns.NewRGB (double red, double green, double blue)
  5. Kt::Graphics::DrawPattern@ color = ctx.patterns.NewRGBA (double red, double green, double blue, double alpha)
  6.  
  7. // use it whenever you need
  8. color.SelectAsSource() // for stroke, paint or text operations
  9.  
  10. // there's also a shortcut for setting a color with one line, like this:
  11. // ctx.source.SetRGBA(r,g,b) or ctx.source.SetRGBA(r,g,b,a) (see below)
  12. // it can be used if you don't need to select that color later again
  13.  
  14. // GRADIENTS
  15.  
  16. // add a linear gradient
  17. Kt::Graphics::GradientDrawPattern@ gradient = ctx.patterns.NewLinearGradient (double x0, double y0, double x1, double y1)
  18. // add a radial gradient
  19. Kt::Graphics::GradientDrawPattern@ gradient = ctx.patterns.NewRadialGradient (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1)
  20.  
  21. // add colors to the gradient
  22. gradient.AddColorStopRGB (double offset, double r, double g, double b)
  23. gradient.AddColorStopRGBA (double offset, double r, double g, double b, double a)
  24.  
  25. // set gradient properties (how to repeat it, how to resize)
  26. gradient.SetExtend (PatternExtend extend) // how should the gradient be extended
  27. gradient.SetFilter (PatternFilter filter) // the filter to use on resize
  28.  
  29. // use the gradient
  30. gradient.SelectAsSource() // for stroke, paint or text operations
  31. gradient.SelectAsMask() // for PaintWithMask
  32.  
  33. // BITMAPS
  34.  
  35. // you can also use bitmaps as a "pattern"
  36. // via ctx.source.SetBitmap or ctx.mask.SetBitmap (see below)

Example on adding a color and using a gradient as mask:

For masks only the transparency value in the gradient (or bitmap) is used (the color is ignored).

  1. // add a color
  2. auto yellow = ctx.patterns.NewRGBA(1,1,0, 0.5);
  3. yellow.SelectAsSource();
  4.  
  5. // add a gradient as a mask
  6. auto gradient = ctx.patterns.NewRadialGradient(w/2,h/2,0, w/2,h/2,h/2);
  7. gradient.AddColorStopRGBA(0.05, 0,0,0, 1); // opaque
  8. gradient.AddColorStopRGBA(0.95, 0,0,0, 0); // transparent
  9. gradient.SelectAsMask();
  10. ctx.PaintWithMask();

Example of a gradient and different PatternExtend modes:

For a linear gradient:

For a radial gradient:

  1. // render function to show examples of different Extend modes
  2. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  3.  
  4. // set canvas width from the render function
  5. canvas_width = 400;
  6. canvas_height = 150;
  7.  
  8. // get these values as a double
  9. double h = canvas_height;
  10. double w = canvas_width;
  11.  
  12. // get current context (the screen)
  13. auto ctx = Kt::Graphics::GetCurrentContext();
  14. if (@ctx != null) {
  15.  
  16. ctx.SaveState();
  17.  
  18. // add a demo gradient
  19. //auto gradient = ctx.patterns.NewLinearGradient(w/2+70,0,w-70,0);
  20. auto gradient = ctx.patterns.NewRadialGradient(w/2 + w/4,h/4,0, w/2 + w/4,h/4, 35);
  21. gradient.AddColorStopRGBA(0.1, 0,1,0, 0.3); // green
  22. gradient.AddColorStopRGBA(0.5, 1,0,0, 0.3); // red
  23. gradient.AddColorStopRGBA(0.9, 0,0,1, 0.3); // blue
  24.  
  25. // kExtendNone (gradient and bmp are not repeated)
  26. gradient.SetExtend(Kt::Graphics::kExtendNone);
  27. ctx.transform.Translate(-w/2,0);
  28. gradient.SelectAsSource();
  29.  
  30. // add an area to clip gradient
  31. ctx.path.Clear();
  32. ctx.path.Rectangle(w/2,0,w/2,h/2-5);
  33. ctx.ClipWithPath();
  34. // paint the gradient
  35. ctx.Paint();
  36.  
  37. ctx.RestoreState(); // to undo ClipWithPath
  38. ctx.SaveState();
  39.  
  40. // kExtendRepeat (gradient and bmp are repeated)
  41. gradient.SetExtend(Kt::Graphics::kExtendRepeat);
  42. ctx.transform.Translate(0,0);
  43. gradient.SelectAsSource();
  44. // add an area to clip gradient
  45. ctx.path.Clear();
  46. ctx.path.Rectangle(w/2+5,0,w/2,h/2-5);
  47. ctx.ClipWithPath();
  48. // paint the gradient
  49. ctx.Paint();
  50.  
  51. ctx.RestoreState();
  52. ctx.SaveState();
  53.  
  54. // kExtendReflect (gradient and bmp are reflected)
  55. ctx.transform.Translate(-w/2,h/2);
  56. gradient.SetExtend(Kt::Graphics::kExtendReflect);
  57. gradient.SelectAsSource();
  58. ctx.transform.Translate(w/2,-h/2);
  59. ctx.path.Clear();
  60. ctx.path.Rectangle(0,h/2+5,w/2-10,h/2);
  61. ctx.ClipWithPath();
  62. ctx.Paint();
  63.  
  64. ctx.RestoreState();
  65. ctx.SaveState();
  66.  
  67. // kExtendPad (gradient edges are repeaded, bmp like kExtendRepeat)
  68. ctx.transform.Translate(0,h/2);
  69. gradient.SetExtend(Kt::Graphics::kExtendPad);
  70. gradient.SelectAsSource();
  71. ctx.transform.Translate(0,-h/2);
  72. ctx.path.Clear();
  73. ctx.path.Rectangle(w/2+5,h/2+5,w/2-5,h/2);
  74. ctx.ClipWithPath();
  75. ctx.Paint();
  76.  
  77. ctx.RestoreState();
  78.  
  79. // write text
  80. ctx.source.SetRGB(0,0,0);
  81. ctx.font.SetFontSize(16);
  82. string s;
  83.  
  84. s = "kExtendNone";
  85. ctx.path.MoveTo(w/4 - ctx.font.GetTextSize(s).x/2, h/4 +5);
  86. ctx.WriteText(s);
  87.  
  88. s = "kExtendRepeat";
  89. ctx.path.MoveTo(3*w/4 - ctx.font.GetTextSize(s).x/2, h/4 +5);
  90. ctx.WriteText(s);
  91.  
  92. s = "kExtendReflect";
  93. ctx.path.MoveTo(w/4 - ctx.font.GetTextSize(s).x/2, 3*h/4 + 6);
  94. ctx.WriteText(s);
  95.  
  96. s = "kExtendPad";
  97. ctx.path.MoveTo(3*w/4 - ctx.font.GetTextSize(s).x/2, 3*h/4 + 6);
  98. ctx.WriteText(s);
  99. }
  100. }

Note on PatternExtend

PatternExtend is used to describe how pattern color/alpha will be determined for areas "outside" the pattern's natural area (for example, outside the surface bounds or outside the gradient geometry).

  • kExtendNone - pixels outside of the source pattern are fully transparent
  • kExtendRepeat - the pattern is tiled by repeating
  • kExtendReflect - the pattern is tiled by reflecting at the edges (only implemented for surface patterns)
  • kExtendPad - pixels outside of the pattern copy the closest pixel from the source (only implemented for surface patterns)

The default extend mode is kExtendNone for surface patterns and kExtendPad for gradient patterns (according to Cairo docs).

ctx.source (class Kt::Graphics::DrawPatternSelect)

Quick access to source pattern selection used for drawing and painting.

Basically this is a quick way to set a color instead of adding it as a pattern and then selecting it (see ctx.patterns above).

Also it has a method for using a bitmap as a source (with x, y coordinates for positioning).

  1. // set flat color as source
  2. ctx.source.SetRGB (double red, double green, double blue)
  3. ctx.source.SetRGBA (double red, double green, double blue, double alpha)
  4.  
  5. // set bitmap as source
  6. ctx.source.SetBitmap (const Bitmap &bitmap, double x, double y, PatternExtend ext=kExtendNone, PatternFilter filter=kFilterBilinear)

Examples on ctx.source methods

Trying various PatternExtend options with a bitmap:

  1. // render function to show examples of different ctx.source methods
  2. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  3.  
  4. // set canvas width from the render function
  5. canvas_width = 400;
  6. canvas_height = 150;
  7.  
  8. // get these values as a double
  9. double h = canvas_height;
  10. double w = canvas_width;
  11.  
  12. // get current context (the screen)
  13. auto ctx = Kt::Graphics::GetCurrentContext();
  14. if (@ctx != null) {
  15.  
  16. auto bmp = Kt::Graphics::LoadImageFile("/path/to/image.png");
  17.  
  18. // kExtendNone
  19. ctx.source.SetBitmap(bmp, -w/4+bmp.width/2, 0, Kt::Graphics::kExtendNone);
  20. ctx.PaintWithAlpha(0.33);
  21.  
  22. // kExtendRepeat
  23. ctx.SaveState();
  24. ctx.path.Clear();
  25. ctx.path.Rectangle(w/2+5,0,w/2,h/2-5);
  26. ctx.ClipWithPath();
  27. ctx.source.SetBitmap(bmp, 5, 0, Kt::Graphics::kExtendRepeat);
  28. ctx.PaintWithAlpha(0.33);
  29. ctx.RestoreState();
  30.  
  31. // kExtendReflect
  32. ctx.SaveState();
  33. ctx.path.Clear();
  34. ctx.path.Rectangle(0,h/2,w/2-5,h/2 -5);
  35. ctx.ClipWithPath();
  36. ctx.source.SetBitmap(bmp, 0, 14, Kt::Graphics::kExtendReflect);
  37. ctx.PaintWithAlpha(0.33);
  38. ctx.RestoreState();
  39.  
  40. // kExtendPad
  41. ctx.SaveState();
  42. ctx.path.Clear();
  43. ctx.path.Rectangle(w/2+5,h/2,w/2,h/2 -5);
  44. ctx.StrokePath();
  45. ctx.ClipWithPath();
  46. ctx.source.SetBitmap(bmp, 5, 14, Kt::Graphics::kExtendPad);
  47. ctx.PaintWithAlpha(0.33);
  48. ctx.RestoreState();
  49.  
  50. // write text
  51. ctx.source.SetRGB(0,0,0);
  52. ctx.font.SetFontSize(16);
  53. string s;
  54.  
  55. s = "kExtendNone";
  56. ctx.path.MoveTo(w/4 - ctx.font.GetTextSize(s).x/2, h/4 +5);
  57. ctx.WriteText(s);
  58.  
  59. s = "kExtendRepeat";
  60. ctx.path.MoveTo(3*w/4 - ctx.font.GetTextSize(s).x/2, h/4 +5);
  61. ctx.WriteText(s);
  62.  
  63. s = "kExtendReflect";
  64. ctx.path.MoveTo(w/4 - ctx.font.GetTextSize(s).x/2, 3*h/4 + 6);
  65. ctx.WriteText(s);
  66.  
  67. s = "kExtendPad";
  68. ctx.path.MoveTo(3*w/4 - ctx.font.GetTextSize(s).x/2, 3*h/4 );
  69. ctx.WriteText(s);
  70.  
  71. ctx.source.SetRGBA(0,0,0, 0.7);
  72. ctx.font.SetFontSize(12);
  73. s = "= kExtendRepeat for bitmaps";
  74. ctx.path.MoveTo(3*w/4 - ctx.font.GetTextSize(s).x/2, 3*h/4 + 16);
  75. ctx.WriteText(s);
  76. }
  77. }

Examples of different PatternFilters:

  1. // render function to show examples of different Filter types
  2. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  3.  
  4. // set canvas width from the render function
  5. canvas_width = 455;
  6. canvas_height = 420;
  7.  
  8. // get these values as a double
  9. double h = canvas_height;
  10. double w = canvas_width;
  11.  
  12. // get current context (the screen)
  13. auto ctx = Kt::Graphics::GetCurrentContext();
  14. if (@ctx != null) {
  15.  
  16. auto bmp = Kt::Graphics::LoadImageFile("/path/to/logo.png");
  17.  
  18. // paint the original
  19. ctx.source.SetBitmap(bmp, -w/2 + bmp.width/2);
  20. ctx.Paint();
  21.  
  22. ctx.transform.Translate(0, 10);
  23.  
  24. ctx.SaveState();
  25. // now scale to show various filters
  26. ctx.transform.Translate(0, bmp.height);
  27. ctx.transform.Scale(5, 5);
  28.  
  29. // kFilterFast
  30. ctx.source.SetBitmap(bmp, 0, 0, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterFast);
  31. ctx.Paint();
  32.  
  33. // kFilterGood
  34. ctx.source.SetBitmap(bmp, -bmp.width, 0, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterGood);
  35. ctx.Paint();
  36.  
  37. // kFilterBest
  38. ctx.source.SetBitmap(bmp, -bmp.width*2, 0, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterBest);
  39. ctx.Paint();
  40.  
  41. // kFilterNearest
  42. ctx.source.SetBitmap(bmp, 0, -bmp.height-8, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterNearest);
  43. ctx.Paint();
  44.  
  45. // kFilterBilinear
  46. ctx.source.SetBitmap(bmp, -bmp.width, -bmp.height-8, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterBilinear);
  47. ctx.Paint();
  48.  
  49. // kFilterGaussian
  50. ctx.source.SetBitmap(bmp, -bmp.width*2, -bmp.height-8, Kt::Graphics::kExtendNone, Kt::Graphics::kFilterGaussian);
  51. ctx.Paint();
  52.  
  53. ctx.RestoreState();
  54.  
  55. // write text
  56. ctx.source.SetRGBA(0,0,0, 0.7);
  57. ctx.font.SetFontSize(15);
  58. string s;
  59.  
  60. s = "kFilterFast";
  61. ctx.path.MoveTo(w/6 - ctx.font.GetTextSize(s).x/2, h/2 -15);
  62. ctx.WriteText(s);
  63.  
  64. s = "kFilterGood";
  65. ctx.path.MoveTo(w/2 - ctx.font.GetTextSize(s).x/2, h/2 -15);
  66. ctx.WriteText(s);
  67.  
  68. s = "kFilterBest";
  69. ctx.path.MoveTo(w/2 + w/3 - 5 - ctx.font.GetTextSize(s).x/2, h/2 -15);
  70. ctx.WriteText(s);
  71.  
  72.  
  73. s = "kFilterNearest";
  74. ctx.path.MoveTo(w/6 - ctx.font.GetTextSize(s).x/2, h-35);
  75. ctx.WriteText(s);
  76.  
  77. s = "kFilterBilinear";
  78. ctx.path.MoveTo(w/2 - ctx.font.GetTextSize(s).x/2, h-35);
  79. ctx.WriteText(s);
  80.  
  81. ctx.SaveState();
  82. ctx.source.SetRGBA(0,0,0, 0.6);
  83. ctx.font.SetFontSize(13);
  84. s = "(default for bitmaps)";
  85. ctx.path.MoveTo(w/2 - ctx.font.GetTextSize(s).x/2, h-18);
  86. ctx.WriteText(s);
  87. ctx.RestoreState();
  88.  
  89. s = "kFilterGaussian";
  90. ctx.path.MoveTo(w/2 + w/3 - 5 - ctx.font.GetTextSize(s).x/2, h-35);
  91. ctx.WriteText(s);
  92. }
  93. }

Note on PatternFilter

PatternFilter is used to indicate what filtering should be applied when reading pixel values from patterns.

  • kFilterFast - A high-performance filter, with quality similar to kFilterNearest 
  • kFilterGood - A reasonable-performance filter, with quality similar to kFilterBilinear 
  • kFilterBest - The highest-quality available, performance may not be suitable for interactive use. 
  • kFilterNearest - Nearest-neighbor filtering 
  • kFilterBilinear - Linear interpolation in two dimensions 
  • kFilterGaussian - This filter value is currently unimplemented, and should not be used in current code. 

The default filter for bitmaps is kFilterBilinear.

ctx.mask (class Kt::Graphics::DrawPatternSelect)

Can access the same methods as ctx.source (see above). Sets the mask pattern used for ctx.PaintWithMask.

Practically can be useful for using bitmaps with transparency as masks via ctx.mask.SetBitmap.

ctx.transform (class Kt::Graphics::DrawTransform)

2D geometrical transform applied to graphics context

These methods can help you move the center point with Translate (so that for example 0,0 becomes a center point, instead of top left corner), scale or even flip the coordinates with Scale (so that you can have your canvas with virtual coordinates like -1 to 1 and with Y coords going from bottom to top) and rotate the surface with Rotate.

  1. ctx.transform.Translate (double tx, double ty) // translate by (tx,ty)
  2. ctx.transform.Scale (double sx, double sy) // Scale using sx and sy factors
  3. ctx.transform.Rotate (double angle) // Rotation by angle, in degrees

Examples on ctx.transform

Using a ctx.path.Arc method and some transformations.

  1. // render function to show examples of different tranform operations
  2. void renderMyCanvas(Kt::Param & canvas_height, Kt::Param & canvas_width) {
  3.  
  4. // set canvas width from the render function
  5. canvas_width = 220;
  6. canvas_height = 220;
  7.  
  8. // get these values as a double
  9. double h = canvas_height;
  10. double w = canvas_width;
  11.  
  12. // get current context (the screen)
  13. auto ctx = Kt::Graphics::GetCurrentContext();
  14. if (@ctx != null) {
  15. // draw a rectangle on canvas border
  16. ctx.path.Clear();
  17. ctx.path.Rectangle(0,0,w,h);
  18. ctx.StrokePath();
  19.  
  20. // set line width, blend mode and font size
  21. ctx.settings.set_lineWidth(3);
  22. ctx.settings.set_blendMode(Kt::Graphics::kDrawOpMultiply);
  23. ctx.font.SetFontSize(20);
  24.  
  25. // move a position to center
  26. ctx.transform.Translate(w/2,h/2); // since now 0,0 is canvas center
  27.  
  28. // draw a bottom half-circle in red
  29. ctx.path.Clear();
  30. ctx.path.Arc(0,0,50,0,180); // cx, cy, radius, angle_start, angle_end
  31. ctx.source.SetRGBA(1,0,0,1);
  32. ctx.StrokePath();
  33. ctx.path.RelMoveTo(5, 20);
  34. ctx.WriteText(" 1");
  35.  
  36. // flip the Y coordinate (to count from bottom to top)
  37. ctx.transform.Scale(1,-1);
  38.  
  39. // draw a top half-circle in green, using the same Arc call
  40. // just to demostrate that coords are flipped
  41. ctx.path.Clear();
  42. ctx.path.Arc(0,0,50,0,180);
  43. ctx.path.Close();
  44. ctx.source.SetRGBA(0,0.8,0,1);
  45. ctx.StrokePath();
  46. ctx.path.RelMoveTo(-40, 20);
  47. ctx.WriteText(" 2");
  48.  
  49. // stretch the coords (and flip Y back)
  50. ctx.transform.Scale(1,-2);
  51.  
  52. // draw the blue vertical oval
  53. ctx.path.Clear();
  54. ctx.path.Arc(0,0,50,0,360);
  55. ctx.source.SetRGBA(0,0,1,1);
  56. ctx.StrokePath();
  57. ctx.path.RelMoveTo(-2, -5);
  58. ctx.WriteText(" 3");
  59.  
  60. // rotate 45%
  61. ctx.transform.Scale(1,0.5); // scale back
  62. ctx.transform.Rotate(45); // rotate
  63. ctx.transform.Scale(1,2); // scale (stretch) again
  64.  
  65. // draw magenta oval rotated 45%
  66. ctx.path.Clear();
  67. ctx.path.Arc(0,0,50,0,360);
  68. ctx.source.SetRGBA(1,0,1,1);
  69. ctx.StrokePath();
  70. ctx.path.RelMoveTo(5, 0);
  71. ctx.WriteText(" 4");
  72. }
  73. }

ctx.font (class Kt::Graphics::DrawFont)

Font and text drawing settings.

  1. // set font size
  2. ctx.font.SetFontSize (double size)
  3.  
  4. // set font face
  5. ctx.font.SelectFontFace (const char *family, FontSlant slant=kFontSlantNormal, FontWeight weight=kFontWeightNormal)
  6.  
  7. // slant can be: kFontSlantNormal, kFontSlantItalic
  8. // weight can be: kFontWeightNormal, kFontWeightBold
  9.  
  10. //////// GET METHODS ////////
  11.  
  12. // get text coords
  13. Kt::Graphics::XYCoordinates@ coords = ctx.font.GetTextSize (const string &text, TextExtentMode mode=kTextAsTypographicLine)
  14. // coords has coords.x and coords.y
  15.  
  16. // get text rectangle
  17. Kt::Graphics::Rectangle@ rect = ctx.font.GetTextExtents (const string &text, TextExtentMode mode=kTextAsTypographicLine)
  18. // rect has rect.origin.x, rect.origin.y, rect.size.x, rect.size.y
  19.  
  20. // mode can be:
  21. // kTextBoundaries - strict boundaries of the text,
  22. // kTextAsTypographicLine - boundaries of the text as part of a typographic line (usually larger than text boundaries)

ctx.font examples:

To quickly center some text you can use something like:

  1. // text horizontal center
  2. string s = "Some text";
  3. ctx.path.MoveTo(w/2 - ctx.font.GetTextSize(s).x/2, h/2);
  4. ctx.WriteText(s);

To learn more about ctx.font methods you can check out this demo:

demo of GetTextSize and GetTextExtents

  1. // demo of GetTextSize and GetTextExtents
  2. void renderMyCanvas(double h, double w) {
  3.  
  4. auto ctx = Kt::Graphics::GetCurrentContext();
  5. if (@ctx != null) {
  6.  
  7. // a demo text
  8. string s = "Graphics";
  9.  
  10. // set text properties
  11. ctx.font.SetFontSize(45);
  12. ctx.font.SelectFontFace("Courier New", Kt::Graphics::kFontSlantNormal, Kt::Graphics::kFontWeightBold);
  13.  
  14. // get text extents (dimentions) for current font and size
  15. // this gives only text size
  16. auto coords = ctx.font.GetTextSize (s);
  17. auto coords2 = ctx.font.GetTextSize (s, Kt::Graphics::kTextBoundaries);
  18. // this gives text size and origin coords
  19. auto rect = ctx.font.GetTextExtents (s);
  20. auto rect2 = ctx.font.GetTextExtents (s, Kt::Graphics::kTextBoundaries);
  21.  
  22. // shift one pixel down
  23. ctx.transform.Translate(0,1);
  24.  
  25. // draw the demo text centered on top
  26. ctx.path.Clear();
  27. ctx.path.MoveTo(w/2 - rect2.size.x/2, -rect2.origin.y);
  28. ctx.path.Text(s);
  29.  
  30. // select color, line with and do the text drawing
  31. ctx.source.SetRGBA (0.7, 0.2, 0.2, 1);
  32. ctx.settings.set_lineWidth(1);
  33. ctx.StrokePath();
  34.  
  35. // draw rectangle around text to show calculated size
  36. ctx.path.Clear();
  37. ctx.path.MoveTo(w/2 - rect2.size.x/2,0);
  38. ctx.path.RelLineTo(0,rect2.size.y);
  39. ctx.path.RelLineTo(rect2.size.x,0);
  40. ctx.path.RelLineTo(0,-rect2.size.y);
  41. ctx.path.Close();
  42. ctx.source.SetRGBA (0.2, 0.2, 0.6, 0.5);
  43. ctx.settings.set_lineWidth(1);
  44. ctx.StrokePath();
  45.  
  46. // now write measured coordinates
  47. ctx.source.SetRGBA (0, 0, 0, 1);
  48. ctx.font.SetFontSize(12);
  49.  
  50. ctx.path.MoveTo(5, 65);
  51. ctx.font.SetFontSize(16);
  52. ctx.WriteText("GetTextSize");
  53. ctx.font.SetFontSize(12);
  54. ctx.path.MoveTo(5, 85);
  55. ctx.WriteText("as typographic line: "+coords.x+", "+coords.y);
  56. ctx.path.MoveTo(5, 103);
  57. ctx.WriteText("strict boundaries: "+coords2.x+", "+coords2.y);
  58.  
  59. ctx.path.MoveTo(5, 130);
  60. ctx.font.SetFontSize(16);
  61. ctx.WriteText("GetTextExtents");
  62. ctx.font.SetFontSize(12);
  63. ctx.path.MoveTo(5, 150);
  64. ctx.WriteText("typo: "+rect.origin.x+", "+rect.origin.y+", "+rect.size.x+", "+rect.size.y);
  65. ctx.path.MoveTo(5, 168);
  66. ctx.WriteText("strict: "+rect2.origin.x+", "+rect2.origin.y+", "+rect2.size.x+", "+rect2.size.y);
  67. }
  68. }

2020 © Plug'n Script and KUIML by Blue Cat Audio  |  Site by LetiMix