ImageEn, unit iegdiplus

TIECanvas

TIECanvas


Description


TIECanvas is a GDI+ Graphics wrapper and VCL TCanvas wrapper. It is available via TIEBitmap.IECanvas


General Properties


Member Declaration Description
Brush property Brush: TIEBrush; The fill brush object
GDICanvas property GDICanvas: TCanvas; Access to the VCL TCanvas
InterpolationMode property InterpolationMode: TIECanvasInterpolationMode; Specify the algorithm that is used when images are scaled or rotated
Pen property Pen: TIEPen; The drawing pen object
PenPos property PenPos: TPoint; The current position of the pen (as set by MoveTo)
SetCompositingMode procedure SetCompositingMode(Mode: TIECanvasCompositingMode; Quality: TIECanvasCompositingQuality); How alpha compositing is performed. Suppose you create an object that has an alpha of 192, which is about 75% of 255. If your compositing mode is CompositingModeSourceOver, then areas filled with the object are a blend that is 75% brush color and 25% background color. If your compositing mode is CompositingModeSourceCopy, then the background color is not blended with the brush color. However, the color rendered by the brush has an intensity that is 75% of what it would be if the alpha component were 255
SmoothingMode property SmoothingMode: TIECanvasSmoothingMode; Specify whether smoothing (antialiasing) is applied to lines and curves and the edges of filled areas



Draw Methods


Member Declaration Description
Arc procedure Arc(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); Draw an arc in the area bounded by 4 points
DrawLine procedure DrawLine(X1, Y1, X2, Y2: double); Draw a line between two points
DrawLinesPath procedure DrawLinesPath(points: TIEDPointArray); Draw a series of lines using a point array
Ellipse procedure Ellipse(X1, Y1, X2, Y2: Integer); overload; procedure Ellipse(const Rect: TRect); overload; Draw an ellipse within a specified area
MoveTo procedure MoveTo(X, Y: integer); Move the pen position to start a draw operation (use before LineTo)
LineTo procedure LineTo(X, Y: integer); Draw a line from the current pen position (set by MoveTo) to a point
Pie procedure Pie(X: single; Y: single; Width: single; Height: single; StartAngle: single; SweepAngle: single); overload; procedure Pie(X1, Y1, X2, Y2, X3, Y3, X4, Y4: Integer); overload; Draw a portion of a circle
Polygon procedure Polygon(Points: array of TPoint); Draw a polygon specified by multiple points
Polyline procedure Polyline(Points: array of TPoint); Draw a series of joined lines specified by multiple points
Rectangle procedure Rectangle(X1, Y1, X2, Y2: Integer); overload; procedure Rectangle(const Rect: TRect); overload; Draw a rectangle within a specified area
RoundRect procedure RoundRect(X1, Y1, X2, Y2, X3, Y3: Integer); Draw a rounded rectangle within a specified area



Fill Methods


Member Declaration Description
FillRect procedure FillRect(const Rect: TRect); Fill an area with the current current brush
GradientFillRect procedure GradientFillRect(aRect: TRect; Dir: TIEGDIPlusGradient); overload; procedure GradientFillRect(aRect: TRect; FromColor, ToColor: TColor; Dir: TIEGDIPlusGradient); overload; Fill an area with a gradient (either colors specified or of the current brush)



Text Methods


Member Declaration Description
DrawText procedure DrawText(Text: WideString; BoundingRect: TRect); overload; procedure DrawText(Text: WideString; BoundingRect: TRect; Angle: Integer); overload; procedure DrawText(Text: WideString; X, Y : Integer; Angle: Integer = 0); overload; Draw text at a specified position (no wrapping) or within a rectangle (text may wrap)
Font property Font: TFont; The font use for text drawing and measurement
MeasureText function MeasureText(Text: WideString; BoundingRect: TRect; Angle: Integer = 0): TSize; overload; function MeasureText(Text: WideString; Angle: Integer = 0): TSize; overload; Returns the height and width of text using the current font. If a rect is specified then the width of the text is bounded, which may cause it to wrap.
TextHeight function TextHeight(const Text: WideString): Integer; Returns the height of the specified text using the current font (uses MeasureText)
TextRendering property TextRendering: TIETextRenderingHintMode; The quality of text output
TypographicDrawText property TypographicDrawText: Boolean; Typographic gives a tighter text output with less padding when using drawing and measuring text
TextWidth function TextWidth(const Text: WideString): Integer; Returns the width of the specified text using the current font (uses MeasureText)



Transformation Methods


Member Declaration Description
ResetTransform procedure ResetTransform(); Reset any rotation or transformation
Rotate procedure Rotate(Angle: double); Rotate the canvas content
Translate procedure Translate(dx: double; dy: double); Move the canvas content



Examples


// Draw an envelope with 50% transparency
with ImageEnView1.IEBitmap.IECanvas do
begin
  Pen.Mode := pmCopy;
  Pen.Style := psSolid;
  Pen.Color := clBlack;
  Pen.Transparency := 128;

  Brush.Color := clYellow;
  Brush.Style := bsSolid;
  Brush.Transparency := 128;

  // Draw outer rect
  Rectangle( 100, 100, 500, 300 );

  // Draw flap
  MoveTo( 100, 100 );
  LineTo( 300, 200 );
  LineTo( 500, 100 );
end;
ImageEnView1.Update();


// Draw an anti-aliased ellipse onto a TBitmap
iec := TIECanvas.Create(ABitmap.Canvas, true, true);
with iec do
begin
  Pen.Style := psSolid;
  Pen.Mode := pmCopy;
  Pen.Color := clRed;
  Brush.Style := bsClear
  Ellipse( Rect( 100, 100, 200, 200 ));
end;
iec.Free;


// Fill image with a vertical gradient from Red to Blue
ImageEnView1.IEBitmap.IECanvas.GradientFillRect( Rect( 0, 0, ImageEnView1.IEBitmap.Width, ImageEnView1.IEBitmap.Height ), clRed, clBlue, gpgVertical );
ImageEnView1.Update();


// Draw a semi-transparent text box onto a bitmap
const
  Horz_Margin = 8;
  Vert_Margin = 3;
  Center_Text = False;
var
  x, y: integer;
  tw, rw, rh: integer;
  iec: TIECanvas;
  ss: string;
begin
  ss := 'This is my text';
  x := 100;
  y := 100;

  iec := TIECanvas.Create( Bitmap.Canvas, true, true);

  iec.Font.Assign( GetTextFont() );
  tw := iec.TextWidth(ss);
  rw := imax( tw + 2 * Horz_Margin, iec.TextWidth(minText) + 2 * Horz_Margin );
  rh := iec.TextHeight(ss) + 2 * Vert_Margin;

  if Center_Text then
    dec( x, rw div 2 );

  iec.Brush.Color := clYellow;
  iec.Brush.Style := bsSolid;
  iec.Brush.Transparency := 196;

  iec.Pen.Color := clBlack;
  iec.Pen.Style := psSolid;
  iec.Rectangle( x, y, x + rw, y + rh );

  iec.Brush.Style := bsClear;
  iec.TextOut(x + ( rw - tw ) div 2, y + Vert_Margin, ss);
  iec.Free;
end;


// Highlight an area of a bitmap
iec := TIECanvas.Create(Bitmap.Canvas, false);
iec.Brush.Color := clRed;
iec.Brush.Style := bsSolid;
iec.Brush.Transparency := 125;
iec.FillRect( Rect( 100, 100, 300, 300 );
iec.Free;


// Draw a rounded, semi-transparent scrollbar (anti-aliased)
const
  RX = 12; // round width
  RY = 12; // round height
  MINSLIDERW = 8; // minimum slider width
var
  scrollPos, scrollCount: integer;
  sliderWidth: double;
begin
  x := 100;
  y := 100;
  Width := 300;
  Height := 16;
  scrollCount := 20;
  scrollPos := 3;

  with ImageEnView1.IEBitmap.IECanvas do
  begin
    // paint brush and border
    Brush.Style := bsSolid;
    Brush.Color := clWhite;
    Brush.Transparency := 64;
    Pen.Color := clWhite;
    Pen.Style := psSolid;
    Pen.Mode := pmCopy;
    Pen.Width := 1;
    Pen.Transparency := 128;
    RoundRect( x, y, x + width, y + height, RX, RY );

    // paint slider
    Brush.Style := bsSolid;
    Brush.Color := clBlack;
    Brush.Transparency := 128;
    Pen.Width := 1;
    Pen.Transparency := 128;
    sliderWidth := width / scrollCount;
    if sliderWidth < MINSLIDERW then
      sliderWidth := MINSLIDERW;
    RoundRect( x + trunc(scrollPos * sliderWidth), y + 1, x + trunc(scrollPos * sliderWidth) + trunc(asliderWidth), y + height - 1, RX, RY);
    end;
end;


// Draw an arrow at the end of a line that runs from x1, y1 to x2, y2
// brush and color must be already set
procedure IEDrawLineArrow(Canvas: TIECanvas; x1, y1, x2, y2: integer; w, h: integer);
const
  A90 = PI / 2;
var
  aa, bb, hw: double;
  pp: array[0..2] of TPoint;
  p1x, p1y: integer;
begin
  with Canvas do
  begin
    hw := w / 2;
    aa := ieangle(x1, y1, x2, y2, x1, y2);
    if x1 = x2 then
      if y1 < y2 then
        aa := -A90
      else
        aa := A90;
    if ((x1 > x2) and (y2 < y1)) or ((x1 < x2) and (y1 < y2)) then
      bb := 2 * pi - aa + A90
    else
      bb := aa + A90;
    if ((x2 < x1) and (y2 > y1)) or ((x2 < x1) and (y2 < y1)) or ((x1 < x2) and (y1 = y2)) then
    begin
      p1x := x1 + trunc(cos(bb - A90) * h);
      p1y := y1 + trunc(sin(bb - A90) * h);
    end
    else
    begin
      p1x := x1 + trunc(cos(bb + A90) * h);
      p1y := y1 + trunc(sin(bb + A90) * h);
    end;

    pp[0].x := p1x + trunc(cos(bb) * hw);
    pp[0].y := p1y + trunc(sin(bb) * hw);
    pp[1].x := p1x + trunc(cos(bb + pi) * hw);
    pp[1].y := p1y + trunc(sin(bb + pi) * hw);
    pp[2].x := x1;
    pp[2].y := y1;

    Polygon(pp);
  end;
end;


// Draw one of ImageEn's predefined shapes
procedure IEDrawShape(Canvas: TIECanvas;
                      Shape: TIEShape;
                      Left, Top, Width, Height: Integer; MaintainAspect: TIEBooleanEx;
                      BorderColor: TColor; BorderWidth: Integer;
                      FillColor: TColor; FillColor2: TColor = clNone; FillGradient: TIEGDIPlusGradient = gpgVertical;
                      AntiAlias: Boolean = True;
                      Angle: Integer = 0;
                      ShapeModifier: Integer = 0);
var
  arPts : Array[ 0 .. Max_Shape_Array_Points ] of TPoint;
  drawPts : Array[ 0 .. Max_Shape_Array_Points ] of TPoint;
  currX, currY: Integer;
  exWidth, exHeight: Integer;
  i: Integer;
  ptCount: Integer;
begin
  IEGenerateShapePoints( arPts, ptCount, Shape, 0, 0, 1000, 1000,
                         Angle, False,
                         ShapeModifier,
                         Width / Height );

  if BorderColor = clNone then
    BorderWidth := 0;

  exWidth := imax( 0, ( Width - BorderWidth ));
  exHeight := imax( 0, ( Height - BorderWidth ));

  for i := 0 to ptCount - 1 do
  begin
    currX := arPts[ i ].x;
    currY := arPts[ i ].y;

    drawPts[i].x := Left + BorderWidth div 2 + round( currX / 1000 * exWidth );
    drawPts[i].y := Top + BorderWidth div 2 + round( currY / 1000 * exHeight );
  end;

  // PAINT TO CANVAS
  if AntiAlias then
    Canvas.SmoothingMode := iesmAntialias
  else
    Canvas.SmoothingMode := iesmBestPerformance;

  with Canvas do
  begin
    if BorderWidth > 0 then
    begin
      Pen.Style := psSolid;
      Pen.Width := BorderWidth;
      Pen.Color := BorderColor;
    end
    else
      Pen.Style := psClear;
    Pen.Mode := pmCopy;
    Pen.LineJoin := ieljRound;

    if FillColor = clNone_ then
      Brush.Style := bsClear
    else
    begin
      Brush.Color := FillColor;
      Brush.Style := bsSolid;
    end;

    if ( FillGradient = gpgNone ) or ( FillColor2 = clNone_ ) then
      Brush.SetGradient( gpgNone, 0, 0 )
    else
    begin
      Brush.SetGradient( FillGradient, Width, Height );
      Brush.BackTransparency := 255;
      Brush.BackColor := FillColor2;
    end;

    Polygon( slice( drawpts, ptCount ));
  end;
end;


// Draw an ellipse
procedure IEDrawSimpleShape(Canvas: TIECanvas;
                            Left, Top, Width, Height: Integer;
                            BorderColor: TColor; BorderWidth: Integer;
                            FillColor: TColor; FillColor2: TColor = clNone; FillGradient: TIELayerGradient = grdVertical;
                            ZoomX: Double = 1; ZoomY: Double = 1;
                            AntiAlias: Boolean = True);
const
  Rect_Rounding = 20;
var
  drawGradient: Boolean;
  minZoom: Double;
begin
  drawGradient := ( FillGradient <> grdNone ) and
                  ( FillColor2 <> FillColor ) and
                  ( FillColor <> clNone ) and ( FillColor2 <> clNone );

  if AntiAlias then
    Canvas.SmoothingMode := iesmAntialias
  else
    Canvas.SmoothingMode := iesmBestPerformance;

  // Image has been scaled to zoom level, so ensure we scale the border too
  if BorderColor = clNone then
    BorderWidth := 0;
  if BorderWidth > 0 then
    BorderWidth := max( 1, Round( BorderWidth * minZoom ));

  // Border
  if ( BorderColor = clNone_ ) or ( BorderWidth < 1 ) then
    Canvas.Pen.Style := psClear
  else
    Canvas.Pen.Style := psSolid;
  Canvas.Pen.Color := BorderColor;
  Canvas.Pen.Width := BorderWidth;

  // Fill
  if ( FillColor = clNone_ ) then
    Canvas.Brush.Style := bsClear
  else
    Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := FillColor;

  inc( Left , BorderWidth div 2 );
  inc( Top , BorderWidth div 2 );
  dec( Width , BorderWidth );
  dec( Height, BorderWidth );

  if drawGradient = False then
    Canvas.Brush.SetGradient( gpgNone, 0, 0 )
  else
  begin
    Canvas.Brush.SetGradient( TIEGDIPlusGradient( ord( FillGradient ) + 1 ), Width, Height );
    Canvas.Brush.BackTransparency := 255;
    Canvas.Brush.BackColor := FillColor2;
  end;

  Canvas.Ellipse( Left, Top, Left + Width, Top + Height );
end;


// Draw text within a specified area onto a TIEBitmap
procedure TextOutEx(aBMP: TIEBitmap;
                    X, Y, W, H : Integer; const Text : String;
                    const sFontName : String; iFontSize : Integer; cFontColor : TColor; Style : TFontStyles;
                    Angle : Integer = 0;
                    bAntiAlias : Boolean = true; bAutoEnlarge : Boolean = False);
var
  AnExtent: TSize;
  Mask: TIEMask;
  x1, y1, x2, y2: Integer;
  CompCanvas: TIECanvas;
  iAlpha: Integer;
begin
  aBMP.Canvas.Font.Name := sFontName;
  aBMP.Canvas.Font.Size := iFontSize;
  aBMP.Canvas.Font.Color := cFontColor;
  aBMP.Canvas.Font.Style := Style;

  AnExtent := aBMP.IECanvas.MeasureText( Text );

  if Angle <> 0 then
    AnExtent := IERotatePoint2( AnExtent.cx, AnExtent.cy, Angle );

  if bAutoEnlarge and (( aBMP.Width < AnExtent.cx ) or ( aBMP.Height < AnExtent.cy )) then
  begin
    iAlpha := 255;
    if aBMP.HasAlphaChannel then
      iAlpha := aBMP.Alpha[0, 0];
    aBMP.Resize( iMax( aBMP.Width, AnExtent.cx ), iMax( aBMP.Height, AnExtent.cy ), Background, iAlpha);
  end;

  CompCanvas := aBMP.CreateROICanvas(Rect(0, 0, aBMP.Width, aBMP.Height), bAntiAlias, true, bAntiAlias);
  try
    if not bAntiAlias then // Cannot use together with alpha composting
      CompCanvas.TextRendering := ietrTextRenderingHintSingleBitPerPixel;

    CompCanvas.Brush.Color := aBMP.Canvas.Font.Color;
    CompCanvas.Font.Color := aBMP.Canvas.Font.Color;
    CompCanvas.Font.Name := aBMP.Canvas.Font.Name;
    CompCanvas.Font.Height := aBMP.Canvas.Font.Height;
    CompCanvas.Font.Style := aBMP.Canvas.Font.Style;

    if ( W = 0 ) and ( H = 0 ) then
      CompCanvas.DrawText( Text, X, Y, -Angle )
    else
      CompCanvas.DrawText( Text, Rect( X, Y, X + W, Y + H ), -Angle );
  finally
    CompCanvas.Free();
  end;
end;