txt: ## dist_zef-dwarring-HTML-Canvas.md
  [![Actions Status](https://github.com/css-raku/HTML-Canvas-raku/workflows/test/badge.svg)](https://github.com/css-raku/HTML-Canvas-raku/actions)
  
  # HTML-Canvas-raku
  
  This is a Raku module for composing and rendering HTML-5 canvases.
  
  It supports the majority of the [HTML Canvas 2D Context](https://www.w3.org/TR/2dcontext/) API.
  
  A canvas may be constructed via the API, then rendered to JavaScript via the `toDataURL()`, `.js()` or `.to-html()` methods, or saved to a Cairo-supported format such as PNG, SVG or PDF.
  
  The module includes classes:
  
  * `HTML::Canvas`, a Raku implementation of the basic HTML Canvas 2D API.
  * `HTML::Canvas::Image` - for image loading in a variety of formats
  * `HTML::Canvas::Gradient` - for image gradients
  * `HTML::Canvas::Path2` - for path objects
  * `HTML::Canvas::To::Cairo` - a built-in renderer, which can output to several formats,
    including PNG, SVG and PDF.
  
  # Install
  
  This package depends on Cairo, FontConfig, Font::FreeType, Text::FriBidi and HarfBuzz. Additional fonts may also be required on your system:
  
  * the [freetype](https://www.freetype.org/download.html) native library needs to be on your system to enable Font::FreeType installation
  * Text::FriBidi is required for handling of bi-directional text.
  * the native `Cairo` library is also needed. See instructions at <https://cairographics.org/download/>.
  * Installation of the [fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/) native library is also required.
  
  # Example
  
  ```
  use v6;
  # Create a simple Canvas. Save as PNG and HTML
  
  use HTML::Canvas;
  my HTML::Canvas $canvas .= new: :width(150), :height(100);
  
  $canvas.context: -> \ctx {
      ctx.strokeRect(0, 0, 150, 100);
      ctx.save; {
          ctx.fillStyle = "orange";
          ctx.fillRect(10, 10, 50, 50);
  
          ctx.fillStyle = "rgba(0, 0, 200, 0.3)";
          ctx.fillRect(35, 35, 50, 50);
      }; ctx.restore;
  
      ctx.font = "18px Arial";
      ctx.fillText("Hello World", 40, 75);
  }
  
  # save canvas as PNG
  use Cairo;
  my Cairo::Image $img = $canvas.image;
  $img.write_png: "examples/canvas-demo.png";
  
  # also save canvas as HTML, source and data URL:
  #  1. Save source Javascript
  my $html = "<html><body>{ $canvas.to-html }</body></html>";
  "examples/canvas-demo-js.html".IO.spurt: $html;
  #  2. Save data URL Image
  my $data-uri = $canvas.toDataURL();
  $html = "<html><body><img src='$data-uri'/></body></html>";
  "examples/canvas-demo-url.html".IO.spurt: $html;
  
  
  ```
  
  ![canvas-demo.png](examples/canvas-demo.png)
  
  ## Saving as PDF
  
  ```
  use v6;
  use Cairo;
  use HTML::Canvas;
  use HTML::Canvas::To::Cairo;
  # create a 128 X 128 point PDF
  my Cairo::Surface::PDF $surface .= create("examples/read-me-example.pdf", 128, 128);
  
  # create a PDF with two pages
  # use a common cache for objects shared between pages such as
  # fonts and images. This reduces both processing times and PDF file sizes.
  my HTML::Canvas::To::Cairo::Cache $cache .= new;
  
  for 1..2 -> $page {
      my HTML::Canvas $canvas .= new: :$surface, :$cache;
      $canvas.context: {
          .font = "10pt times-roman bold";
          .fillStyle = "blue";
          .strokeStyle = "red";
          .save; {
              .fillStyle = "rgba(1.0, 0.2, 0.2, 0.25)";
              .rect(15, 20, 50, 50);
              .fill;
              .stroke;
          }; .restore;
          .fillText("Page $page/2", 12, 12);
      };
      $surface.show_page;
  }
  
  $surface.finish;
  
  
  ```
  
  ## Images
  
  The `HTML::Canvas::Image` class is used to upload images for inclusion in HTML documents,
  and/or rendering by back-ends.
  
  ```
  use HTML::Canvas;
  use HTML::Canvas::Image;
  
  my HTML::Canvas $canvas .= new;
  my @html-body;
  # add the image, as a hidden DOM item
  my HTML::Canvas::Image \image .= open("t/images/camelia-logo.png");
  @html-body.push: $canvas.to-html: image, :style("visibility:hidden");
  # draw it
  $canvas.context: -> \ctx {
      ctx.drawImage(image, 10, 10  );  
  };
  
  @html-body.push: $canvas.to-html;
  
  my $html = "<html><body>" ~ @html-body.join ~ "</body></html>";
  
  
  ```
  
  `HTML::Canvas::Image` can load a variety of image formats. The built-in
  `HTML::Canvas::To::Cairo` renderer only supports PNG images, as below:
  
  Currently supported image formats are:
  
  | Back-end | PNG | GIF | JPEG | BMP |
  | --- | --- | --- | --- | --- |
  | `HTML::Canvas (HTML)` | X | X | X | X |
  | `HTML::Canvas::To::Cairo` | X |  |  |  |
  | `HTML::Canvas::To::PDF` | X | X | X |  |
  
  ## Paths
  
  `HTML::Canvas::Path2D` can be used to create a re-usable path that can be passed to calls to the `fill()` or `stroke()` methods:
  
  ```
  use HTML::Canvas;
  use HTML::Canvas::Path2D;
  
  my HTML::Canvas $canvas .= new;
  
  $canvas.context: -> \ctx {
      # Create path
      my HTML::Canvas::Path2D \region .= new;
      region.moveTo(30, 90);
      region.lineTo(110, 20);
      region.lineTo(240, 130);
      region.lineTo(60, 130);
      region.lineTo(190, 20);
      region.lineTo(270, 90);
      region.closePath();
  
      ctx.fillStyle = 'green';
      ctx.fill(region, 'evenodd');
  
      ctx.translate(100, 100);
      ctx.fillStyle = 'blue';
      ctx.fill(region);
  }
  
  ```
  
  The following methods can be used in path construction:
  
  * `moveTo(Numeric \x, Numeric \y)`
  * `lineTo(Numeric \x, Numeric \y)`
  * `quadraticCurveTo(Numeric \cx, Numeric \cy, Numeric \x, Numeric \y)`
  * `bezierCurveTo(Numeric \cx1, Numeric \cy1, Numeric \cx2, Numeric \cy2, Numeric \x, Numeric \y)`
  * `rect(Numeric \x, Numeric \y, Numeric \w, Numeric \h)`
  * `arc(Numeric \x, Numeric \y, Numeric \r, Numeric \startAngle, Numeric \endAngle, Bool \antiClockwise = False)`
  * `closePath()`
  
  ## Font Loading
  
  ### Font Resources
  
  This module integrates with the [CSS::Font::Resources](https://css-raku.github.io/CSS-Font-Resources-raku/CSS/Font/Resources) module.
  
  A list of `@font-face` CSS font descriptors can be passed to the canvas object to specify font sources. Fonts are resolved
  the same way as [`@font-face` rules in a stylesheet](https://www.w3.org/TR/2018/REC-css-fonts-3-20180920/#font-resources).
  
  For example:
  
  ```
  use HTML::Canvas;
  use HTML::Canvas::To::Cairo;
  use CSS::Font::Descriptor;
  use Cairo;
  
  my CSS::Font::Descriptor $ugly .= new: :font-family<arial>, :src<url(resources/font/FreeMono.ttf)>;
  my HTML::Canvas $canvas .= new: :font-face[$ugly], :width(650), :height(400);
  $canvas<scale>(2.0, 3.0);
  $canvas<font> = "30px Arial";
  $canvas.fillText("Hello World",10,50);
  # save canvas as PNG
  my Cairo::Surface $surface = $canvas.image;
  $surface.write_png: "tmp/ariel-ugly.png";
  
  
  ```
  
  Note that supported fonts may be backend dependant.
  
  * `HTML::Canvas::To::Cairo` supports almost all common font formats via the FreeType/Cairo integration
  * `HTML::Canvas::To::PDF` supports a smaller set of font formats; Fonts with extensions `*.otf`, `*.ttf`, `*.cff`, `*.pfa`, `*.pfb` should work. But resources with extensions `*.woff`, `*.woff2`, and `*.eot` are ignored.
  
  ### Font System Loading
  
  Local fonts and fonts without matching `@font-face` font descriptors are resolved using FontConfig.
  If FontConfig fails to find a matching font, HTML::Canvas falls back to using a mono-spaced font (FreeMono).
  
  ## Methods
  
  The methods below implement the majority of the W3C [HTML Canvas 2D Context](https://www.w3.org/TR/2dcontext/) API.
  
  ## Setters/Getters
  
  #### lineWidth
  
  ```
  has Numeric $.lineWidth = 1.0;
  
  ```
  
  #### globalAlpha
  
  ```
  has Numeric $.globalAlpha = 1.0;
  
  ```
  
  #### lineCap
  
  ```
  subset LineCap of Str where 'butt'|'round'|'square';
  has LineCap $.lineCap = 'butt';
  
  ```
  
  #### lineJoin
  
  ```
  subset LineJoin of Str where 'bevel'|'round'|'miter';
  has LineJoin $.lineJoin = 'bevel';
  
  ```
  
  #### font
  
  ```
  has Str $.font = '10pt times-roman';
  
  ```
  
  #### textBaseline
  
  ```
  subset Baseline of Str where 'alphabetic'|'top'|'hanging'|'middle'|'ideographic'|'bottom';
  has Baseline $.textBaseline = 'alphabetic';
  
  ```
  
  #### textAlign
  
  ```
  subset TextAlignment of Str where 'start'|'end'|'left'|'right'|'center';
  has TextAlignment $.textAlign = 'start';
  
  ```
  
  #### direction
  
  ```
  subset TextDirection of Str where 'ltr'|'rtl';
  has TextDirection $.direction = 'ltr';
  
  ```
  
  #### fillStyle
  
  ```
  subset ColorSpec where Str|HTML::Canvas::Gradient|HTML::Canvas::Pattern;
  has ColorSpec $.fillStyle is rw = 'black';
  
  ```
  
  #### strokeStyle
  
  ```
  has ColorSpec $.strokeStyle is rw = 'black';
  
  ```
  
  #### setLineDash/getLineDash/lineDash
  
  ```
   has Numeric @.lineDash;
  
  ```
  
  #### lineDashOffset
  
  ```
    has Numeric $.lineDashOffset = 0.0;
  
  ```
  
  ## Graphics State
  
  #### `save()`
  
  #### `restore()`
  
  #### `scale(Numeric $x, Numeric $y)`
  
  #### `rotate(Numeric $rad)`
  
  #### `translate(Numeric $x, Numeric $y)`
  
  #### `transform(Numeric \a, Numeric \b, Numeric \c, Numeric \d, Numeric \e, Numeric \f)`
  
  #### `setTransform(Numeric \a, Numeric \b, Numeric \c, Numeric \d, Numeric \e, Numeric \f)`
  
  ## Painting Methods
  
  #### `clearRect(Numeric $x, Numeric $y, Numeric $w, Numeric $h)`
  
  #### `fillRect(Numeric $x, Numeric $y, Numeric $w, Numeric $h)`
  
  #### `strokeRect(Numeric $x, Numeric $y, Numeric $w, Numeric $h)`
  
  #### `beginPath()`
  
  #### `fill(FillRule $rule?)` or `fill(HTML::Canvas::Path2D $path, FillRule $rule?)`
  
  #### `stroke(HTML::Canvas::Path2D $path?)`
  
  #### `clip()`
  
  #### `fillText(Str $text, Numeric $x, Numeric $y, Numeric $max-width?)`
  
  #### `strokeText(Str $text, Numeric $x, Numeric $y, Numeric $max-width?)`
  
  #### `measureText(Str $text)`
  
  ## Path Methods
  
  #### `closePath()`
  
  #### `moveTo(Numeric \x, Numeric \y)`
  
  #### `lineTo(Numeric \x, Numeric \y)`
  
  #### `quadraticCurveTo(Numeric \cp1x, Numeric \cp1y, Numeric \x, Numeric \y)`
  
  #### `bezierCurveTo(Numeric \cp1x, Numeric \cp1y, Numeric \cp2x, Numeric \cp2y, Numeric \x, Numeric \y)`
  
  #### `rect(Numeric $x, Numeric $y, Numeric $w, Numeric $h)`
  
  #### `arc(Numeric $x, Numeric $y, Numeric $radius, Numeric $startAngle, Numeric $endAngle, Bool $counterClockwise?)`
  
  ## Images Patterns and Gradients
  
  #### drawImage:
  
  ```
  multi method drawImage( $image, Numeric \sx, Numeric \sy, Numeric \sw, Numeric \sh, Numeric \dx, Numeric \dy, Numeric \dw, Numeric \dh);
  multi method drawImage(CanvasOrXObject $image, Numeric $dx, Numeric $dy, Numeric $dw?, Numeric $dh?)
  
  ```
  
  #### `createLinearGradient(Numeric $x0, Numeric $y0, Numeric $x1, Numeric $y1)`
  
  #### `createRadialGradient(Numeric $x0, Numeric $y0, Numeric $r0, Numeric $x1, Numeric $y1, Numeric:D $r1)`
  
  #### `createPattern($image, HTML::Canvas::Pattern::Repetition $repetition = 'repeat')`
  
  Example:
  
  ```
  use HTML::Canvas;
  use HTML::Canvas::Image;
  
  my HTML::Canvas \ctx .= new;
  my @html-body;
  
  ## Images ##
  
  my HTML::Canvas::Image \image .= open("t/images/crosshair-100x100.jpg");
  
  # save to HTML
  @html-body.push: ctx.to-html: image, :style("visibility:hidden");
  # draw on the canvas
  ctx.drawImage(image,  20, 10,  50, 50);
  
  ## Patterns ##
  
  my \pat = ctx.createPattern(image,'repeat');
  ctx.fillStyle = pat;
  ctx.translate(10,50);
  ctx.fillRect(10,10,150,100);
  
  ## Gradients
  
  with ctx.createRadialGradient(75,50,5,90,60,100) -> $grd {
      $grd.addColorStop(0,"red");
      $grd.addColorStop(0.5,"white");
      $grd.addColorStop(1,"blue");
      ctx.fillStyle = $grd;
      ctx.translate(10,200);
      ctx.fillRect(10, 10, 150, 100);
  }
  
  say ctx.js;
  
  ```
  
  ## Image Data
  
  Currently support for `getImageData` and `putImageData` (3 argument format) only.
  
  #### `getImageData(Numeric sx, Numeric sy, Numeric sw, Numeric sh)`
  
  #### `putImageData(image-data, Numeric dx, Numeric dy)`
  
  ## Additional Rendering Backends
  
  * [HTML::Canvas::To::PDF](https://pdf-raku.github.io/HTML-Canvas-To-PDF-raku) - render to PDF, using the Raku [PDF](https://pdf-raku.github.io) tool-chain.
  