The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Canvas example

use strict;
use warnings;

use IUP ':all';
use IUP::Canvas::FileVector;
use IUP::Canvas::FileBitmap;

###global variables

my $STYLE_SIZE = 10;
my $pattern;
my $stipple;

my $IMAGE_SIZE = 100;
my $imagergba = IUP::Canvas::Bitmap->new(CD_RGBA, $IMAGE_SIZE, $IMAGE_SIZE); #XXX-FIXME segfault at this point!!!

###subroutines

sub InitGlobals {

  $pattern = IUP::Canvas::Pattern->new( [
    [CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE],
    [CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_BLUE, CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE],
    [CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_BLUE, CD_BLUE, CD_WHITE,CD_WHITE,CD_WHITE],
    [CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_BLUE, CD_BLUE, CD_BLUE, CD_WHITE,CD_WHITE],
    [CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_RED,  CD_BLUE, CD_BLUE, CD_BLUE, CD_WHITE,CD_WHITE],
    [CD_WHITE,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_BLUE, CD_BLUE, CD_WHITE,CD_WHITE],
    [CD_WHITE,CD_WHITE,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_BLUE, CD_WHITE,CD_WHITE],
    [CD_WHITE,CD_WHITE,CD_WHITE,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_GREEN,CD_WHITE,CD_WHITE],  
    [CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE],
    [CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE,CD_WHITE],
  ] );
  
  $stipple = IUP::Canvas::Stipple->new($STYLE_SIZE, $STYLE_SIZE);
  #initialize the stipple buffer with cross pattern
  for my $l (0..$STYLE_SIZE-1) {
    for my $c (0..$STYLE_SIZE-1) {
      $stipple->Pixel($c, $l, (($c % 4)==0) ? 1 : 0);
    }
  }

  #initialize the alpha image buffer with a degrade from transparent to opaque
  for my $l (0..$IMAGE_SIZE-1) {
    for my $c (0..$IMAGE_SIZE-1) {
      my $alpha = ($c*255)/($IMAGE_SIZE-1);
      if ($l==0 || $l==$IMAGE_SIZE-1 || $c==0 || $c==$IMAGE_SIZE-1) {
        $imagergba->Pixel($c, $l, 0, 0, 0, $alpha);
      }
      else {
        if ($l > $IMAGE_SIZE/2) {
          $imagergba->Pixel($c, $l, 95, 143, 95, $alpha);
        }
        else {
          $imagergba->Pixel($c, $l, 255, 95, 95, $alpha);
        }
      }
    }
  }
}

sub SimpleDraw {
  my $canvas = shift;
  my ($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3);
  
  # Get size in pixels to be used for computing coordinates.
  my ($w, $h, $w_mm, $h_mm) = $canvas->cdGetSize();

  # Clear the background to be white
  $canvas->cdBackground(CD_WHITE);
  $canvas->cdClear();

  # Draw a reactangle and a polyline at the bottom-left area,
  # using a thick line with transparency.
  # Notice that transparency is only supported in a few drivers,
  # and line join is not supported in the IMAGERGB driver.
  $canvas->cdLineWidth(3);
  $canvas->cdLineStyle(CD_CONTINUOUS);
  $canvas->cdForeground($canvas->cdEncodeAlpha(CD_DARK_MAGENTA, 128));
  $canvas->cdRect(100, 200, 100, 200);
  $canvas->cdBegin(CD_OPEN_LINES);
  $canvas->cdVertex(300, 250);
  $canvas->cdVertex(320, 270);
  $canvas->cdVertex(350, 260);
  $canvas->cdVertex(340, 200);
  $canvas->cdVertex(310, 210);
  $canvas->cdEnd();

  # Draw the red diagonal line with a custom line style.
  # Notice that line styles are not supported in the IMAGERGB driver.
  $canvas->cdForeground(CD_RED);
  $canvas->cdLineWidth(3);
  my $dashes = [20, 15, 5, 5];
  $canvas->cdLineStyleDashes($dashes);
  $canvas->cdLineStyle(CD_CUSTOM);
  $canvas->cdLine(0, 0, $w-1, $h-1);

  # Draw the blue diagonal line with a pre-defined line style.
  # Notice that the pre-defined line style is dependent on the driver.
  $canvas->cdForeground(CD_BLUE);
  $canvas->cdLineWidth(10);
  $canvas->cdLineStyle(CD_DOTTED);
  $canvas->cdLine(0, $h-1, $w-1, 0);

  # Reset line style and width
  $canvas->cdLineStyle(CD_CONTINUOUS);
  $canvas->cdLineWidth(1);

  # Draw an arc at bottom-left, and a sector at bottom-right.
  # Notice that counter-clockwise orientation of both.
  $canvas->cdInteriorStyle(CD_SOLID);
  $canvas->cdForeground(CD_MAGENTA);
  $canvas->cdSector($w-100, 100, 100, 100, 50, 180);
  $canvas->cdForeground(CD_RED);
  $canvas->cdArc(100, 100, 100, 100, 50, 180);

  # Draw a solid filled rectangle at center.
  $canvas->cdForeground(CD_YELLOW);
  $canvas->cdBox($w/2 - 100, $w/2 + 100, $h/2 - 100, $h/2 + 100);

  # Prepare font for text.
  $canvas->cdTextAlignment(CD_CENTER);
  $canvas->cdTextOrientation(70);
  $canvas->cdFont("Times", CD_BOLD, 24);

  # Draw text at center, with orientation,
  # and draw its bounding box.
  # Notice that in some drivers the bounding box is not precise.
  ($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3) = $canvas->cdGetTextBounds($w/2, $h/2, "cdMin Draw (çãí)");
  $canvas->cdForeground(CD_RED);
  $canvas->cdBegin(CD_CLOSED_LINES);
  $canvas->cdVertex($x0, $y0);
  $canvas->cdVertex($x1, $y1);
  $canvas->cdVertex($x2, $y2);
  $canvas->cdVertex($x3, $y3);
  $canvas->cdEnd();
  $canvas->cdForeground(CD_BLUE);
  $canvas->cdText($w/2, $h/2, "cdMin Draw (çãí)");

  # Prepare World Coordinates
  $canvas->wdViewport(0,$w-1,0,$h-1);
  if ($w>$h) {
      $canvas->wdWindow(0,$w/$h,0,1);
  }
  else {
      $canvas->wdWindow(0,1,0,$h/$w);
  }

  # Draw a filled blue rectangle in WC
  $canvas->wdBox(0.20, 0.30, 0.40, 0.50);
  $canvas->cdForeground(CD_RED);

  # Draw the diagonal of that rectangle in WC
  $canvas->wdLine(0.20, 0.40, 0.30, 0.50);

  # Prepare Vector Text in WC.
  $canvas->wdVectorCharSize(0.07);

  # Draw vector text, and draw its bounding box.
  # We also use this text to show when we are using a contextplus driver.
  $canvas->cdForeground(CD_RED);
  my $drect;
  my $contextplus; #XXX-TODO
  if ($contextplus) {
      ($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3) = $canvas->wdGetVectorTextBounds("WDj-Plus", 0.25, 0.35);
  }
  else {
      ($x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3) = $canvas->wdGetVectorTextBounds("WDj", 0.25, 0.35);
  }
  $canvas->cdBegin(CD_CLOSED_LINES);
  $canvas->wdVertex($x0, $y0);
  $canvas->wdVertex($x1, $y1);
  $canvas->wdVertex($x2, $y2);
  $canvas->wdVertex($x3, $y3);
  $canvas->cdEnd();
  $canvas->cdLineWidth(2);
  $canvas->cdLineStyle(CD_CONTINUOUS);
  if ($contextplus) {
      $canvas->wdVectorText(0.25, 0.35, "WDj-Plus");
  }
  else {
      $canvas->wdVectorText(0.25, 0.35, "WDj");
  }

  # Reset line width
  $canvas->cdLineWidth(1);

  # Draw a filled path at center-right (looks like a weird fish).
  # Notice that in PDF the arc is necessarily a circle arc, and not an ellipse.
  $canvas->cdForeground(CD_GREEN);
  $canvas->cdBegin(CD_PATH);
  $canvas->cdPathSet(CD_PATH_MOVETO);
  $canvas->cdVertex($w/2 + 200, $h/2);
  $canvas->cdPathSet(CD_PATH_LINETO);
  $canvas->cdVertex($w/2 + 230, $h/2 + 50);
  $canvas->cdPathSet(CD_PATH_LINETO);
  $canvas->cdVertex($w/2 + 250, $h/2 + 50);
  $canvas->cdPathSet(CD_PATH_CURVETO);
  $canvas->cdVertex($w/2+150+150, $h/2+200-50); #control point for start
  $canvas->cdVertex($w/2+150+180, $h/2+250-50); #control point for end
  $canvas->cdVertex($w/2+150+180, $h/2+200-50); #end point
  $canvas->cdPathSet(CD_PATH_CURVETO);
  $canvas->cdVertex($w/2+150+180, $h/2+150-50);
  $canvas->cdVertex($w/2+150+150, $h/2+100-50);
  $canvas->cdVertex($w/2+150+300, $h/2+100-50);
  $canvas->cdPathSet(CD_PATH_LINETO);
  $canvas->cdVertex($w/2+150+300, $h/2-50);
  $canvas->cdPathSet(CD_PATH_ARC);
  $canvas->cdVertex($w/2+300, $h/2); #center
  $canvas->cdVertex(200, 100); #width, height
  $canvas->cdVertex(-30*1000, -170*1000); #start angle, end angle (degrees / 1000);
  $canvas->cdPathSet(CD_PATH_FILL);
  $canvas->cdEnd();

  # Draw 3 pixels at center left.
  $canvas->cdPixel(10, $h/2+0, CD_RED);
  $canvas->cdPixel(11, $h/2+1, CD_GREEN);
  $canvas->cdPixel(12, $h/2+2, CD_BLUE);

  # Draw 4 mark types, distributed near each corner.
  $canvas->cdForeground(CD_RED);
  $canvas->cdMarkSize(30);
  $canvas->cdMarkType(CD_PLUS);
  $canvas->cdMark(200, 200);
  $canvas->cdMarkType(CD_CIRCLE);
  $canvas->cdMark($w - 200, 200);
  $canvas->cdMarkType(CD_HOLLOW_CIRCLE);
  $canvas->cdMark(200, $h - 200);
  $canvas->cdMarkType(CD_DIAMOND);
  $canvas->cdMark($w - 200, $h - 200);

  # Draw all the line style possibilities at bottom.
  # Notice that they have some small differences between drivers.
  $canvas->cdLineWidth(1);
  $canvas->cdLineStyle(CD_CONTINUOUS);
  $canvas->cdLine(0, 10, $w, 10);
  $canvas->cdLineStyle(CD_DASHED);
  $canvas->cdLine(0, 20, $w, 20);
  $canvas->cdLineStyle(CD_DOTTED);
  $canvas->cdLine(0, 30, $w, 30);
  $canvas->cdLineStyle(CD_DASH_DOT);
  $canvas->cdLine(0, 40, $w, 40);
  $canvas->cdLineStyle(CD_DASH_DOT_DOT);
  $canvas->cdLine(0, 50, $w, 50);

  # Draw all the hatch style possibilities in the top-left corner.
  # Notice that they have some small differences between drivers.
  $canvas->cdHatch(CD_VERTICAL);
  $canvas->cdBox(0, 50, $h - 60, $h);
  $canvas->cdHatch(CD_FDIAGONAL);
  $canvas->cdBox(50, 100, $h - 60, $h);
  $canvas->cdHatch(CD_BDIAGONAL);
  $canvas->cdBox(100, 150, $h - 60, $h);
  $canvas->cdHatch(CD_CROSS);
  $canvas->cdBox(150, 200, $h - 60, $h);
  $canvas->cdHatch(CD_HORIZONTAL);
  $canvas->cdBox(200, 250, $h - 60, $h);
  $canvas->cdHatch(CD_DIAGCROSS);
  $canvas->cdBox(250, 300, $h - 60, $h);

  # Draw 4 regions, in diamond shape,
  # at top, bottom, left, right,
  # using different interior styles.

  # At top, not filled polygon, notice that the last line style is used.
  $canvas->cdBegin(CD_CLOSED_LINES);
  $canvas->cdVertex($w/2, $h - 100);
  $canvas->cdVertex($w/2 + 50, $h - 150);
  $canvas->cdVertex($w/2, $h - 200);
  $canvas->cdVertex($w/2 - 50, $h - 150);
  $canvas->cdEnd();

  # At left, hatch filled polygon
  $canvas->cdHatch(CD_DIAGCROSS);
  $canvas->cdBegin(CD_FILL);
  $canvas->cdVertex(100, $h/2);
  $canvas->cdVertex(150, $h/2 + 50);
  $canvas->cdVertex(200, $h/2);
  $canvas->cdVertex(150, $h/2 - 50);
  $canvas->cdEnd();

  # At right, pattern filled polygon
  $canvas->cdPattern($pattern);
  $canvas->cdBegin(CD_FILL);
  $canvas->cdVertex($w - 100, $h/2);
  $canvas->cdVertex($w - 150, $h/2 + 50);
  $canvas->cdVertex($w - 200, $h/2);
  $canvas->cdVertex($w - 150, $h/2 - 50);
  $canvas->cdEnd();

  # At bottom, stipple filled polygon
  $canvas->cdStipple($stipple);
  $canvas->cdBegin(CD_FILL);
  $canvas->cdVertex($w/2, 100);
  $canvas->cdVertex($w/2 + 50, 150);
  $canvas->cdVertex($w/2, 200);
  $canvas->cdVertex($w/2 - 50, 150);
  $canvas->cdEnd();

  # Draw two beziers at bottom-left
  $canvas->cdBegin(CD_BEZIER);
  $canvas->cdVertex(100, 100);
  $canvas->cdVertex(150, 200);
  $canvas->cdVertex(180, 250);
  $canvas->cdVertex(180, 200);
  $canvas->cdVertex(180, 150);
  $canvas->cdVertex(150, 100);
  $canvas->cdVertex(300, 100);
  $canvas->cdEnd();

  # Draw the image on the top-right corner but increasing its actual size, and uses its full area
  $canvas->cdPutBitmap($imagergba, $w - 400, $h - 310, 3*$IMAGE_SIZE, 3*$IMAGE_SIZE);

  # Adds a new page, or
  # flushes the file, or
  # flushes the screen, or
  # swap the double buffer.
  $canvas->cdFlush();
}

###main program

my $canvas;
InitGlobals();

warn "Saving ...\n";
$canvas = IUP::Canvas::FileVector->new( format=>"SVG", filename=>"tmp-testoutput.svg", width=>270.933, height=>198.543, dpi=>120 );
SimpleDraw($canvas);
#$canvas->cdKillCanvas(); 
#$canvas->DESTROY(); 
undef $canvas; #XXX-FIXME why we need 'undef $canvas' and '$canvas->cdKillCanvas()' is not enough?

warn "Saving ...\n";
$canvas = IUP::Canvas::FileVector->new( format=>"EMF", filename=>"tmp-testoutput.emf", width=>1280, height=>938 );
SimpleDraw($canvas);
undef $canvas;

warn "Saving ...\n";
$canvas = IUP::Canvas::FileBitmap->new( width=>1280, height=>938, dpi=>120 );
SimpleDraw($canvas);
$canvas->cdDumpBitmap("tmp-testoutput.png", "PNG");
undef $canvas;

warn "Done!\n";