(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *) (* Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved. Copyright (c) 2011-2017 by Xequte Software. This software comes without express or implied warranty. In no case shall the author be liable for any damage or unwanted behavior of any computer hardware and/or software. Author grants you the right to include the component in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE. ImageEn, IEvolution and ImageEn ActiveX may not be included in any commercial, shareware or freeware libraries or components. www.ImageEn.com *) (* File: iexLayers.pas Description: Handles the TIELayer and descendent classes for displaying layers in a TImageEnView File version 1120 Doc revision 1001 *) unit iexLayers; {$R-} {$Q-} {$I ie.inc} interface uses {$ifdef IEHASUITYPES} System.UITypes, {$endif} Windows, Messages, Graphics, Controls, Forms, Classes, SysUtils, StdCtrls, ExtCtrls, Contnrs, hyiedefs, iexBitmaps, ieview, imageenproc, hyieutils, iegdiplus; type {!! TIELayerKind Declaration TIELayerKind = (ielkImage, ielkShape, ielkLine, ielkPolyline, ielkText); Description Returns the type of a . Kind Class Description ielkImage Layer that contains an image ielkShape Layer that displays standard shapes (rectangles, ellipses, stars, etc) ielkLine Layer that displays a single line, optionally including a text label and start and ending arrows ielkPolyline Layer that displays a polyline or polgon comprising of multiple points ielkText Layer that displays text
Example 1 if ImageEnView1.CurrentLayer.Kind = ielkImage then TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfLanczos3; // Which is the same as... if ImageEnView1.CurrentLayer is TIEImageLayer then TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfLanczos3; Example 2 // Hide labels of all line layers when user clicks a check box procedure Tfmain.chkShowLabelsClick(Sender: TObject); var I: integer; begin for I := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Kind = ielkLine then begin if chkShowLabels.Checked then TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpAtEnd else TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpHide; end; ImageEnView1.Update(); end; !!} TIELayerKind = (ielkImage, ielkShape, ielkLine, ielkPolyline, ielkText); {!! TIEDrawingInfo Declaration } TIEDrawingInfo = record XDst: integer; // Destination x (output canvas) YDst: integer; // Destination y (output canvas) WidthDst: integer; // Destination width (output canvas) HeightDst: integer; // Destination height (output canvas) XSrc: integer; // Source x (input bitmap) YSrc: integer; // Source y (input bitmap) WidthSrc: integer; // Source width (input bitmap) HeightSrc: integer; // Source height (input bitmap) RotatedDest: array [0..3] of TPoint; // destination rotated points (output canvas) end; {!!} {!! TIEDrawLayerEvent Declaration } TIEDrawLayerEvent = procedure(Sender: TObject; dest: TIEBitmap; LayerIndex: Integer) of object; {!!} {!! TIEDrawLayerBoxEvent Declaration } TIEDrawLayerBoxEvent = procedure (Sender: TObject; ABitmap: TBitmap; LayerIndex: integer) of object; {!!} {!! TIEDrawLayerGrip Declaration } TIEDrawLayerGrip = procedure (Sender: TObject; ABitmap: TBitmap; LayerIndex: integer; Grip: Integer; Rect: TRect) of object; {!!} {!! TIELineEndShape Declaration type TIELineEndShape = (ieesNone, ieesArrow, ieesCircle); Description Value Description ieesNone No shape ieesArrow Arrow ieesCircle Circle
Example // Add yellow filled arrows and circle ends to our current line layer TIELineLayer( ImageEnView1.CurrentLayer ).StartShape := ieesArrow; TIELineLayer( ImageEnView1.CurrentLayer ).EndShape := ieesCircle; TIELineLayer( ImageEnView1.CurrentLayer ).FillColor := clYellow; TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); !!} TIELineEndShape = (ieesNone, ieesArrow, ieesCircle); {!! TIELineLabelPos Declaration TIELineLabelPos = (ielpHide, ielpAtStart, ielpAtEnd); Description Value Description ielpHide Does not show the text label even if text has been specified ielpAtStart Shows the text label at the start of the line ielpAtEnd Shows the text label at the end of the line
Examples // Move the label to the start of the line TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtStart; // Hide labels of all line layers when user clicks a check box procedure Tfmain.chkShowLabelsClick(Sender: TObject); var I: integer; begin for I := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Kind = ielkLine then begin if chkShowLabels.Checked then TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpAtEnd else TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpHide; end; ImageEnView1.Update(); end; !!} TIELineLabelPos = (ielpHide, ielpAtStart, ielpAtEnd); {!! TIELayerFeatures Declaration TIELayerFeatures = (ielfBorder, ielfFill, ielfGradient, ielfRotation, ielfMoveRotationCenter, ielfTextEditing); Description Kind Description Supported By ielfBorder Layer has a border or line that can be adjusted using and All ielfFill Layer has a solid fill that can be adjusted using , (only if is set), (only if =True), ielfGradient If the solid fill can be gradiated using and , (only if is set), ielfRotation Can be rotated by setting or using miRotateLayers All ielfMoveRotationCenter The center of layer rotation can be moved by setting or moving the center grip with miRotateLayers ielfTextEditing The layer has a text property and is not set to read-only , (only if is set)
Example // Show border color selector if layer type supports it btnSelBorder.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfBorder ); // Show fill color selector if layer type supports it btnSelFill.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfFill ); // Show gradient selector if layer type supports it btnGradient.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfGradient ); // Determine if the current layer type can be rotated canRotate := ImageEnView1.CurrentLayer.SupportsFeature( ielfRotation ); // Determine if the current layer type can be rotated canRotate := ImageEnView1.CurrentLayer.SupportsFeature( ielfRotation ); // Text can currently be edited for this layer edtText.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfTextEditing ); !!} TIELayerFeatures = (ielfBorder, ielfFill, ielfGradient, ielfRotation, ielfMoveRotationCenter, ielfTextEditing); {!! TIELayer Property Consts Property consts used by and : Const Value Property IELP_Width 'IELP_Width' IELP_Height 'IELP_Height' IELP_Visible 'IELP_Visible' IELP_VisibleBox 'IELP_VisibleBox' IELP_Selectable 'IELP_Selectable' IELP_Transparency 'IELP_Transparency' IELP_Opacity 'IELP_Opacity' IELP_PosX 'IELP_PosX' IELP_PosY 'IELP_PosY' IELP_Cropped 'IELP_Cropped' IELP_Locked 'IELP_Locked' IELP_Operation 'IELP_Operation' IELP_Name 'IELP_Name' IELP_IsMask 'IELP_IsMask' IELP_DrawOuter 'IELP_DrawOuter' IELP_AlphaEdgeFeathering 'IELP_AlphaEdgeFeathering,' IELP_GroupIndex 'IELP_GroupIndex' IELP_Selected 'IELP_Selected' IELP_AspectRatioLocked 'IELP_AspectRatioLocked' IELP_BorderColor 'IELP_BorderColor' IELP_BorderWidth 'IELP_BorderWidth' IELP_FillColor 'IELP_FillColor' IELP_FillColor2 'IELP_FillColor2' IELP_FillGradient 'IELP_FillGradient' IELP_Rotate 'IELP_Rotate' IELP_RotateCenterX 'IELP_RotateCenterX' IELP_RotateCenterY 'IELP_RotateCenterY' IELP_SoftShadowEnabled 'IELP_SoftShadowEnabled' SoftShadow.Enabled IELP_SoftShadowRadius 'IELP_SoftShadowRadius' SoftShadow.Radius IELP_SoftShadowOffsetX 'IELP_SoftShadowOffsetX' SoftShadow.OffsetX IELP_SoftShadowOffsetY 'IELP_SoftShadowOffsetY' SoftShadow.OffsetY IELP_SoftShadowIntensity 'IELP_SoftShadowIntensity' SoftShadow.Intensity IELP_SoftShadowColor 'IELP_SoftShadowColor' SoftShadow.ShadowColor IELP_ImageResampleFilter 'IELP_ImageResampleFilter' IELP_ImageUseResampleFilter 'IELP_ImageUseResampleFilter' IELP_Shape 'IELP_Shape' IELP_ShapeModifier 'IELP_ShapeModifier' IELP_LineColor 'IELP_LineColor' IELP_LineWidth 'IELP_LineWidth' IELP_LineFillColor 'IELP_LineFillColor' IELP_LabelText 'IELP_LabelText' IELP_LabelAlignment 'IELP_LabelAlignment' IELP_LabelPosition 'IELP_LabelPosition' IELP_LineEndShape 'IELP_LineEndShape' IELP_LineShapeSize 'IELP_LineShapeSize' IELP_LineStartShape 'IELP_LineStartShape' IELP_LineLength 'IELP_LineLength' IELP_PolylinePoints 'IELP_PolylinePoints' IELP_PolylineClosed 'IELP_PolylineClosed' IELP_FontName 'IELP_FontName' Font.Name, LabelFont.Name IELP_FontSize 'IELP_FontSize' Font.Size, LabelFont.Size IELP_FontColor 'IELP_FontColor' Font.Color, LabelFont.Color IELP_BorderShape 'IELP_BorderShape' , IELP_Text 'IELP_Text' IELP_AutoSize 'IELP_AutoSize' IELP_ReadOnly 'IELP_ReadOnly' , IELP_TextAlignment 'IELP_TextAlignment' IELP_TextLayout 'IELP_TextLayout' IELP_AntiAlias 'IELP_AntiAlias' IELP_SizeToFit 'IELP_SizeToFit' Calls either or IELP_RestoreSize 'IELP_RestoreSize' Calls IELP_RestoreAspectRatio 'IELP_RestoreAspectRatio' Calls (False) IELP_RestorePreferredAspectRatio 'IELP_RestorePreferredAspectRatio' Calls (True)
!!} const IELP_Width = 'IELP_Width'; IELP_Height = 'IELP_Height'; IELP_Visible = 'IELP_Visible'; IELP_VisibleBox = 'IELP_VisibleBox'; IELP_Selectable = 'IELP_Selectable'; IELP_Transparency = 'IELP_Transparency'; IELP_Opacity = 'IELP_Opacity'; IELP_PosX = 'IELP_PosX'; IELP_PosY = 'IELP_PosY'; IELP_Cropped = 'IELP_Cropped'; IELP_Locked = 'IELP_Locked'; IELP_Operation = 'IELP_Operation'; IELP_Name = 'IELP_Name'; IELP_IsMask = 'IELP_IsMask'; IELP_DrawOuter = 'IELP_DrawOuter'; IELP_AlphaEdgeFeathering = 'IELP_AlphaEdgeFeathering'; IELP_GroupIndex = 'IELP_GroupIndex'; IELP_Selected = 'IELP_Selected'; IELP_AspectRatioLocked = 'IELP_AspectRatioLocked'; IELP_BorderColor = 'IELP_BorderColor'; IELP_BorderWidth = 'IELP_BorderWidth'; IELP_FillColor = 'IELP_FillColor'; IELP_FillColor2 = 'IELP_FillColor2'; IELP_FillGradient = 'IELP_FillGradient'; IELP_Rotate = 'IELP_Rotate'; IELP_RotateCenterX = 'IELP_RotateCenterX'; IELP_RotateCenterY = 'IELP_RotateCenterY'; IELP_SoftShadowEnabled = 'IELP_SoftShadowEnabled'; IELP_SoftShadowRadius = 'IELP_SoftShadowRadius'; IELP_SoftShadowOffsetX = 'IELP_SoftShadowOffsetX'; IELP_SoftShadowOffsetY = 'IELP_SoftShadowOffsetY'; IELP_SoftShadowIntensity = 'IELP_SoftShadowIntensity'; IELP_SoftShadowColor = 'IELP_SoftShadowColor'; IELP_ImageResampleFilter = 'IELP_ImageResampleFilter'; IELP_ImageUseResampleFilter = 'IELP_ImageUseResampleFilter'; IELP_Shape = 'IELP_Shape'; IELP_ShapeModifier = 'IELP_ShapeModifier'; IELP_LineColor = 'IELP_LineColor'; IELP_LineWidth = 'IELP_LineWidth'; IELP_LineFillColor = 'IELP_LineFillColor'; IELP_LabelText = 'IELP_LabelText'; IELP_LabelAlignment = 'IELP_LabelAlignment'; IELP_LabelPosition = 'IELP_LabelPosition'; IELP_LineEndShape = 'IELP_LineEndShape'; IELP_LineShapeSize = 'IELP_LineShapeSize'; IELP_LineStartShape = 'IELP_LineStartShape'; IELP_LineLength = 'IELP_LineLength'; IELP_PolylinePoints = 'IELP_PolylinePoints'; IELP_PolylineClosed = 'IELP_PolylineClosed'; IELP_FontName = 'IELP_FontName'; IELP_FontSize = 'IELP_FontSize'; IELP_FontColor = 'IELP_FontColor'; IELP_BorderShape = 'IELP_BorderShape'; IELP_Text = 'IELP_Text'; IELP_AutoSize = 'IELP_AutoSize'; IELP_ReadOnly = 'IELP_ReadOnly'; IELP_TextAlignment = 'IELP_TextAlignment'; IELP_TextLayout = 'IELP_TextLayout'; IELP_AntiAlias = 'IELP_AntiAlias'; IELP_SizeToFit = 'IELP_SizeToFit'; IELP_RestoreSize = 'IELP_RestoreSize'; IELP_RestoreAspectRatio = 'IELP_RestoreAspectRatio'; IELP_RestorePreferredAspectRatio = 'IELP_RestorePreferredAspectRatio'; // INTERNAL ONLY IELP_LAYER_CACHE_CLEAR = 'IELP_LAYER_CACHE_CLEAR'; // Pass as true to free all fLayerCacheBitmap {!! TIELayer Description supports layer editing, allowing your users to build complex images from text, shapes, lines, polygon and other images, and merge them. All layer types can be created, resized, rotated and moved, either programatically of by the end-user. Loading and Saving Standard image types such as JPEG and BMP, do not support layers, so to preserve your layer information you will need to use one of the following formats: - ImageEn Native Format (*.ien): Maintains all layer information. Supported only by ImageEn (Loading and Saving) - Photoshop (*.psd): Widely used layer format. Only image layers are supported; non-image layers will be converted when saving (Loading and Saving) - Scalable Vector Graphics (*.svg): Vector image format for web browsers (Saving only) Layer Types TIELayer is the ancestor of all layer classes: Kind Class Description ielkImage Layer that contains an image ielkShape Layer that displays standard shapes (rectangles, ellipses, stars, etc) ielkLine Layer that displays a single line, optionally including a text label and start and ending arrows ielkPolyline Layer that displays a polyline or polgon comprising of multiple points ielkText Layer that displays text
Demos Name Location Description Layer Editing (Image Layers) \Demo\ImageEditing\Layers\ Usage of image layers Layer Editing (All Layer Types) \Demo\ImageEditing\Layers_AllTypes\ Usage of image, shape, text and line layers Layer Rotation \Demo\ImageEditing\RotateLayers\ Free rotation and resizing of layers of a ImageEn Layer Actions \Demo\Other\Actions_Layers\ Image Layering application built using only ImageEnView actions Dragging to Create Layers \Demo\DragDrop\Layers_DragDrop\ Dragging text, images and shapes onto a to create layers
Methods and Properties Provide generic access to properties in descendent classes Examples ImageEnView1.LayersAdd( ielkImage ); // Append an image layer ImageEnView1.IO.LoadFromFile('C:\image.jpg'); // Load image into the new/active layer // Add a yellow explosion shape layer at size 220 x 120 ImageEnView1.LayersAdd( iesExplosion, 50, 50, 220, 120 ); ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); // Append an image layer and assign a pink border ImageEnView1.LayersAdd( ielkImage ); // Append an image layer ImageEnView1.IO.LoadFromFile('C:\New Zealand.jpg'); // Load image into the new/active layer ImageEnView1.CurrentLayer.BorderColor := $008000FF; ImageEnView1.CurrentLayer.BorderWidth := 3; See Also - - - !!} type TIELayer = class private fLayerCacheBitmap: TIEBitmap; // Cached view of the current layer fLayerCacheValid : Boolean; // False when the cache image needs to redrawn fLayerCachefastDrawn: Boolean; // True if the cache image was created with fast drawing enabled fKind: TIELayerKind; fIsMask: Boolean; // This is the "layer mask" of previous layer fRotate: Double; fRotateCenterX: Double; // in percentage. 0.5=center fRotateCenterY: Double; // in percentage. 0.5=center fAntiAlias: Boolean; fOriginalAspectRatio: Double; // The aspect ratio the layer was designed at fResizedWidth, fResizedHeight: Double; // 0=original sizes. Use doubles to avoid rounding areas fAspectRatioLocked: Boolean; fBorderColor: TColor; fBorderWidth: Integer; fFillColor: TColor; fFillColor2: TColor; fFillGradient: TIEGradientDir; fLayerSize: Integer; // Size of the layer as stored in a stream fModified : Boolean; // True if layer has changed since loading fName: String; fDrawingInfo: TIEDrawingInfo; // filled by PaintToEx fDrawOuter: Boolean; fGuid: TGuid; fTag: Integer; fVisible: boolean; fVisibleBox: boolean; fTransparency: integer; // 255=opaque, 0=transparent fOpacity: double; fAlphaEdgeFeathering: Integer; fClientAreaBox: TRect; fCropped: boolean; fLocked: boolean; fSelectable: boolean; fOperation: TIERenderOperation; fUserDataLen: Integer; // used when save. If >0 then saves UserData content. Also UserData will be freed on destroy {$ifdef IEIncludeDeprecatedInV6} // Moved to TIEImageLayer class in 7.0.0 (2016-10-26) fResampleFilter: TResampleFilter; fUseResampleFilter: Boolean; {$ENDIF} function GetBitmap : TIEBitmap; virtual; abstract; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); virtual; abstract; function GetAsSVG(): string; virtual; abstract; function GetPosX: integer; function GetPosY: integer; procedure SetPosX(v: integer); procedure SetPosY(v: integer); function GetWidth: integer; function GetHeight: integer; procedure SetWidth(v: integer); procedure SetHeight(v: integer); procedure SetWidthD(v: Double); procedure SetHeightD(v: Double); function GetOriginalWidth: integer; function GetOriginalHeight: integer; procedure SetRotate(v: Double); procedure SetRotateCenterX(v: Double); procedure SetRotateCenterY(v: Double); function GetSelected: boolean; procedure SetSelected(const Value: boolean); procedure SetGroupIndex(const Value: Integer); procedure CalcClientAreaBox(); procedure CalcPaintPos(ImgWidth, ImgHeight: Integer; out XDst, YDst, WidthDst, HeightDst: integer; out XSrc, YSrc, WidthSrc, HeightSrc: integer); function LoadMetaFromStream(Stream: TStream): Integer; procedure SaveMetaToStream(Stream: TStream); function GetIsMask: Boolean; procedure SetIsMask(const Value: Boolean); procedure SetAspectRatioLocked(const Value: Boolean); procedure RenderLayerWithAdornments(DstBitmap: TIEBitmap; LyrIdx: Integer; SrcBitmap: TIEBitmap; CanModifySrc: Boolean; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter); function Owner_EnableAlphaChannel(): Boolean; function Owner_FastDrawingActive(): Boolean; function Owner_FastOutputActive(): Boolean; function GetBorderColor(): TColor; procedure SetBorderColor(value: TColor); function GetBorderWidth(): Integer; procedure SetBorderWidth(value: Integer); function GetFillColor(): TColor; procedure SetFillColor(value: TColor); procedure SetFillColor2(value: TColor); procedure SetFillGradient(value: TIEGradientDir); function GetModified(): Boolean; procedure SetModified(value: Boolean); procedure SetVisible(Value: Boolean); procedure SetVisibleBox(Value: Boolean); procedure SetTransparency(Value: integer); procedure SetOpacity(Value: double); procedure SetAlphaEdgeFeathering(Value: Integer); procedure SetCropped(Value: boolean); procedure SetLocked(Value: boolean); procedure SetSelectable(Value: boolean); procedure SetOperation(Value: TIERenderOperation); procedure SetUserDataLen(Value: Integer); procedure SetName(Value: String); procedure SetDrawOuter(Value: Boolean); procedure SetGuid(Value: TGuid); procedure SetTag(Value: Integer); public fOwner: TObject; // must be TImageEnView fSelected: Boolean; fCachedLayerMask: TIEBitmap; fPosX, fPosY: Double; // Use doubles to avoid rounding areas fGroupIndex: Integer; {!! TIELayer.SoftShadow Declaration property SoftShadow: ; Description Enables and sets the properties of the layer shadow. Note: Shadows cannot be enabled for the background layer (layer 0) Example // Display a soft shadow effect for the current layer ImageEnView1.CurrentLayer.SoftShadow.Enabled := True; ImageEnView1.Update(); See Also - !!} SoftShadow: TIEVSoftShadow; {!! TIELayer.UserData Declaration property UserData: pointer; Description Contains a pointer to a user data buffer. This can be used for your own purposes to store information about the layer. Example type TMyRecord = record SourceText: array[0..255] of AnsiChar; SourceWidth: integer; SourceHeight: integer; end; PMyRecord = ^TMyRecord; var rc: PMyRecord; begin New( rc ) With rc^ do begin Width := ...; Height := ...; Text := ...; end; ImageEnView1.CurrentLayer.UserData := rc; ImageEnView1.CurrentLayer.UserDataLen := SizeOf( PMyRecord ); end; See Also - . !!} UserData: pointer; {$ifdef IEIncludeDeprecatedInV6} // Moved to TIEImageLayer class in 7.0.0 (2016-10-26) Magnify: TIELayerMagnification; property ResampleFilter: TResampleFilter read fResampleFilter write fResampleFilter; property UseResampleFilter: Boolean read fUseResampleFilter write fUseResampleFilter; {$ENDIF} property AspectRatioLocked: Boolean read fAspectRatioLocked write SetAspectRatioLocked; property Rotate: Double read fRotate write SetRotate; property RotateCenterX: Double read fRotateCenterX write SetRotateCenterX; property RotateCenterY: Double read fRotateCenterY write SetRotateCenterY; property PosX: integer read GetPosX write SetPosX; property PosY: integer read GetPosY write SetPosY; property Width: integer read GetWidth write SetWidth; // displayed width of the layer property Height: integer read GetHeight write SetHeight; // displayed height of the layer property WidthD: Double read fResizedWidth write SetWidthD; // displayed width of the layer (as a double) property HeightD: Double read fResizedHeight write SetHeightD; // displayed height of the layer (as a double) property Selected: boolean read GetSelected write SetSelected; property GroupIndex: Integer read fGroupIndex write SetGroupIndex; property IsMask: Boolean read GetIsMask write SetIsMask; property Owner: TObject read fOwner; {!! TIELayer.Bitmap Declaration property Bitmap: ; Description If the layer is a then Bitmap provides read/write access to the image and alpha channel of the layer. For other TIELayer types, Bitmap provides read-only access to the layer content (e.g. to display an icon for the layer in a TImageEnMView). Example 1 // Replace the image of the current layer with a bitmap TIEImageLayer( ImageEnView1.CurrentLayer ).Bitmap.Assign( MyBitmap ); ImageEnView1.Update(); Example 2 // REFRESH LAYER VIEWER (Show thumbnails of all layers in a TImageEnMView - same as TImageEnMView.AssignLayers method) procedure Tfmain.RefreshLayerViewer; var i, idx: integer; begin // Fill ImageEnMView1 with all layers of ImageEnView1 ImageEnMView1.Clear; for i := 0 to ImageEnView1.LayersCount - 1 do begin idx := ImageEnMView1.AppendImage; ImageEnMView1.SetImage( idx, ImageEnView1.Layers[i].Bitmap ); ImageEnMView1.ImageTopText[i] := 'Layer ' + inttostr(i); end; // Mark selected layers and highlight the current layer ImageEnMView1.BeginSelectImages; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ i ].Selected then ImageEnMView1.SelectedImage := I; ImageEnMView1.SelectedImage := ImageEnView1.LayersCurrent; // Make it the active image ImageEnMView1.EndSelectImages; end; !!} property Bitmap: TIEBitmap read GetBitmap; {!! TIELayer.CopyToBitmap Declaration procedure CopyToBitmap(var Dest: ; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); virtual; abstract; Description Creates a bitmap representation of the current layer. You do not need to create Dest. It will be automatically created and sized as required. If CreateWidth and CreateHeight are not specified, the bitmap will be created at the current size of the layer. Set EnableAlpha to false if you do not want as alpha channel applied to Dest. If UseDisplayAR is true, then the image will be returned with the same aspect ratio it is displayed, If false, it is stretched to the specified CreateWidth and CreateHeight dimensions. Note: You must free Dest Example // Save the current layer as an image var bmp: TIEBitmap; Begin ImageEnView1.CurrentLayer.CopyToBitmap( bmp ); bmp.Write( 'D:\MyLayer.jpg' ); bmp.Free; end; // Assign Layer 1 to another ImageEnView var bmp: TIEBitmap; begin bmp := TIEBitmap.create; ImageEnView1.Layers[1].CopyToBitmap( bmp, ImageEnView2.ClientWidth, ImageEnView2.ClientHeight ); ImageEnView2.IEBitmap.Assign( bmp ); ImageEnView2.Update; bmp.Free(); end; // Show a preview in ImageEnView2 of the layer selected in ImageEnView1 procedure Tfmain.ImageEnView1LayerSelectionChange(Sender: TObject); var bmp: TIEBitmap; begin bmp := ImageEnView2.IEBitmap; ImageEnView1.CurrentLayer.CopyToBitmap( bmp, ImageEnView2.IdealImageWidth, ImageEnView2.IdealImageWidth ); ImageEnView2.Update(); end; !!} procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); virtual; abstract; {!! TIELayer.Kind Declaration property Kind: ; Description Returns the kind of layer. Read-Only Example 1 if ImageEnView1.CurrentLayer.Kind = ielkImage then TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfLanczos3; ImageEnView1.Update(); // Which is the same as... if ImageEnView1.CurrentLayer is TIEImageLayer then TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfLanczos3; ImageEnView1.Update(); Example 2 // Hide labels of all line layers when user clicks a check box procedure Tfmain.chkShowLabelsClick(Sender: TObject); var I: integer; begin ImageEnView1.LockUpdate(); for I := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Kind = ielkLine then begin if chkShowLabels.Checked then TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpAtEnd else TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpHide; end; ImageEnView1.UnlockUpdate(); end; !!} property Kind: TIELayerKind read fKind; {!! TIELayer.AntiAlias Declaration property AntiAlias: Boolean; Description Improves the quality of layer drawing by using anti-aliasing. Notes: - Does not apply to . For display quality of , see - Anti-Alias is not applied if is active Default: True Example // Disable anti-aliasing ImageEnView1.CurrentLayer.AntiAlias := False; ImageEnView1.Update(); !!} property AntiAlias: Boolean read fAntiAlias write fAntiAlias; // Returns the size of the bitmap if an image layer, otherwise the user's specified size for the object property OriginalWidth: integer read GetOriginalWidth; property OriginalHeight: integer read GetOriginalHeight; constructor Create(Owner: TObject); virtual; destructor Destroy; override; function ConvXScr2Bmp(x: Integer): Integer; function ConvYScr2Bmp(y: Integer): Integer; function ConvXBmp2Scr(x: Integer): Integer; function ConvYBmp2Scr(y: Integer): Integer; procedure Assign(Source: TIELayer); procedure Swap(OtherLayer: TIELayer); function SupportsFeature(Feature: TIELayerFeatures): Boolean; procedure GetProperties(Props: TStrings); procedure SetProperties(Props: TStrings); overload; procedure SetProperties(PropName, Value: String); overload; procedure SetDefaults; function GetLayerMask(): TIELayer; function GetIndex(): integer; procedure ConvertToImageLayer(QualityFactor: Double = 2; CropAlpha: Boolean = True); function PreferredAspectRatio(): Double; procedure RestoreAspectRatio(PreferredOnly: Boolean = True); {!! TIELayer.DrawingInfo Declaration property DrawingInfo: ; (read-only) Description Specifies the source and destination rectangle recorded on last drawing. !!} property DrawingInfo: TIEDrawingInfo read fDrawingInfo; {!! TIELayer.ClientAreaBox Declaration property ClientAreaBox: TRect; (Read-Only) Description Returns the drawing area of the layer. The coordinates are relative to the component client area. !!} property ClientAreaBox: TRect read fClientAreaBox; property Visible: boolean read fVisible write SetVisible; property VisibleBox: Boolean read fVisibleBox write SetVisibleBox; property Transparency: integer read fTransparency write SetTransparency; property Opacity: double read fOpacity write SetOpacity; property AlphaEdgeFeathering: Integer read fAlphaEdgeFeathering write SetAlphaEdgeFeathering; property Cropped: boolean read fCropped write SetCropped; property Locked: boolean read fLocked write SetLocked; property Selectable: boolean read fSelectable write SetSelectable; property Operation: TIERenderOperation read fOperation write SetOperation; property UserDataLen: Integer read fUserDataLen write SetUserDataLen; property Name: String read fName write SetName; property DrawOuter: Boolean read fDrawOuter write SetDrawOuter; property Guid: TGuid read fGuid write SetGuid; property Tag: Integer read fTag write SetTag; // Style property BorderColor: TColor read GetBorderColor write SetBorderColor; property BorderWidth: Integer read GetBorderWidth write SetBorderWidth; property FillColor: TColor read GetFillColor write SetFillColor; property FillColor2: TColor read fFillColor2 write SetFillColor2; property FillGradient: TIEGradientDir read fFillGradient write SetFillGradient; property Modified: Boolean read GetModified write SetModified; // Internal procedure PaintTo(DstBitmap: TIEBitmap; LyrIdx: Integer; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter; RotationFilter: TIEAntialiasMode; ResizingLayer: Boolean); Virtual; procedure LoadFromStream(Stream: TStream); Virtual; Abstract; procedure LoadFromLegacyStream(Stream: TStream; HdrVersion: Integer; FileFormat: TIOFileType); procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); Virtual; Abstract; procedure LayerChange(ResetLayerCache: Boolean = True); property AsSVG: string read GetAsSVG; end; {!! TIEImageLayer Description TImageEnView supports multiple layers, allowing the creation of a single image from multiple source images (which can be resized, rotated, moved, etc). TIEImageLayer is a descendent of which contains an image. Review the Layer Documentation for a full description of layer support. Methods and Properties /C> Unique to TIEImageLayer Example // Load an image layer and assign a pink border ImageEnView1.LayersAdd( ielkImage ); // Append an image layer ImageEnView1.IO.LoadFromFile('C:\New Zealand.jpg'); // Load image into the new/active layer ImageEnView1.CurrentLayer.BorderColor := $008000FF; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); // Fix the aspect ratio of an image (that has been resized) if ImageEnView1.CurrentLayer is TIEImageLayer then ImageEnView1.CurrentLayer.RestoreAspectRatio(); ImageEnView1.Update(); See Also - - - !!} TIEImageLayer = class( TIELayer ) private {$ifndef IEIncludeDeprecatedInV6} // Moved from TIELayer class in 7.0.0 (2016-10-26) fResampleFilter: TResampleFilter; fUseResampleFilter: Boolean; // if true uses this ResampleFilter instead of TImageEnView.ZoomFilter/LayersMergeFilter {$ENDIF} function GetBitmap : TIEBitmap; override; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); override; function GetAsSVG(): string; override; function GetBorderColor(): TColor; procedure SetBorderColor(value: TColor); function GetBorderWidth: Integer; procedure SetBorderWidth(value: Integer); // Moved from TIELayer class in 7.0.0 (2016-10-26) {$ifndef IEIncludeDeprecatedInV6} procedure SetResampleFilter(Value: TResampleFilter); procedure SetUseResampleFilter(Value : Boolean); {$ENDIF} public fBitmap: TIEBitmap; fFreeBitmapOnDestroy: boolean; {!! TIEImageLayer.Magnify Declaration property Magnify: Description Set properties if the layer is a magnification layer. Note: Only available to Demo Demos\Display\Magnify2\Magnify2.dpr !!} {$ifndef IEIncludeDeprecatedInV6} // Moved from TIELayer class in 7.0.0 (2016-10-26) Magnify: TIELayerMagnification; property ResampleFilter: TResampleFilter read fResampleFilter write SetResampleFilter; property UseResampleFilter: Boolean read fUseResampleFilter write SetUseResampleFilter; {$ENDIF} // Style property BorderColor: TColor read GetBorderColor write SetBorderColor; property BorderWidth: Integer read GetBorderWidth write SetBorderWidth; constructor Create(Owner: TObject; TemplateBitmap: TIEBitmap; JustAssign: boolean); reintroduce; overload; constructor Create(Owner: TObject; Width, Height : Integer); reintroduce; overload; constructor Create(Owner: TObject; TemplateLayer: TIELayer; QualityFactor: Double = 2; CropAlpha: Boolean = True); reintroduce; overload; destructor Destroy; override; procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); override; procedure PaintTo(DstBitmap: TIEBitmap; LyrIdx: Integer; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter; RotationFilter: TIEAntialiasMode; ResizingLayer: Boolean); override; function CropAlpha(): Boolean; procedure Clear(FillColor: TColor = clWhite; Width: Integer = 1; Height: Integer = 1); procedure RestoreSize(); function ExecuteOpenDialog(): Boolean; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); override; end; {!! TIEShapeLayer Description TImageEnView supports multiple layers, allowing the creation of a single image from multiple source images (which can be resized, rotated, moved, etc). TIEShapeLayer is a descendent of that displays one of ImageEn's pre-built shapes. Review the Layer Documentation for a full description of layer support. Methods and Properties Unique to TIEShapeLayer Example // Add a yellow explosion layer ImageEnView1.LayersAdd( ielkShape ); ImageEnView1.CurrentLayer.Shape := iesExplosion; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.BorderColor := $004080FF; ImageEnView1.CurrentLayer.BorderWidth := 2; ImageEnView1.Update(); // Remove the border... ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); See Also - - - - !!} TIEShapeLayer = class( TIELayer ) private fShape: TIEShape; fShapeModifier: Integer; function GetBitmap : TIEBitmap; override; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); override; function GetAsSVG(): string; override; function GetBorderColor(): TColor; procedure SetBorderColor(value: TColor); function GetBorderWidth(): Integer; procedure SetBorderWidth(value: Integer); function GetFillColor(): TColor; procedure SetFillColor(value: TColor); function GetFillColor2(): TColor; procedure SetFillColor2(value: TColor); function GetFillGradient(): TIEGradientDir; procedure SetFillGradient(value: TIEGradientDir); procedure SetShape(value: TIEShape); procedure SetShapeModifier(value: Integer); public property Shape: TIEShape read fShape write SetShape; property ShapeModifier: Integer read fShapeModifier write SetShapeModifier; // Style property BorderColor: TColor read GetBorderColor write SetBorderColor; property BorderWidth: Integer read GetBorderWidth write SetBorderWidth; property FillColor: TColor read GetFillColor write SetFillColor; property FillColor2: TColor read GetFillColor2 write SetFillColor2; property FillGradient: TIEGradientDir read GetFillGradient write SetFillGradient; constructor Create(Owner: TObject); override; destructor Destroy; override; procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); override; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); override; end; type TIEEndShapeDrawInfo = record Shape: TIELineEndShape; Pt1 : TPoint; Pt2 : TPoint; Pt3 : TPoint; end; {!! TIELineLayer Description TImageEnView supports multiple layers, allowing the creation of a single image from multiple source images (which can be resized, rotated, moved, etc). TIELineLayer is a descendent of that displays a single line. It can optionally display a text label and starting and ending arrows. Review the Layer Documentation for a full description of layer support. Methods and Properties Unique to TIELineLayer Examples // Add a layer with yellow filled arrows and circle ends ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).StartShape := ieesArrow; TIELineLayer( ImageEnView1.CurrentLayer ).EndShape := ieesCircle; TIELineLayer( ImageEnView1.CurrentLayer ).FillColor := clYellow; TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); // Hide labels of all line layers when user clicks a check box procedure Tfmain.chkShowLabelsClick(Sender: TObject); var I: integer; begin ImageEnView1.LockUpdate(); for I := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Kind = ielkLine then begin if chkShowLabels.Checked then TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpAtEnd else TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpHide; end; ImageEnView1.UnlockUpdate(); end; See Also - - - !!} TIELineLayer = class( TIELayer ) private fLabelFont: TFont; fLabelText: string; fLineLength: Double; fLastLineLength: Double; fStartShape: TIELineEndShape; fEndShape: TIELineEndShape; fShapeSize: integer; fLabelPosition: TIELineLabelPos; fAutoSize: boolean; fLabelShape: TIEShape; fLabelAlignment: TIEAlignment; fReadOnly: Boolean; fLineColor: TColor; // Also used for Line End shapes fLineWidth: Integer; // Also used for Line End shapes fLineFillColor: TColor; // Only used for Line End shapes fLineRect: TRect; // Rect where line is drawn (Pt1 is Left,Top. Pt2 is Right,Bottom) fLabelRect: TRect; // Rect where text label is drawn fStartShapePoints: TIEEndShapeDrawInfo; // Where the starting shape is drawn fEndShapePoints: TIEEndShapeDrawInfo; // Where the ending shape is drawn function GetBitmap : TIEBitmap; override; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); override; function GetAsSVG(): string; override; procedure SetLabelFont(const Value: TFont); procedure SetLabelText(const Value: string); procedure SetLabelPosition(const Value: TIELineLabelPos); procedure SetAutoSize(const Value: boolean); procedure SetReadOnly(const Value: boolean); procedure SetStartShape(const Value: TIELineEndShape); procedure SetEndShape(const Value: TIELineEndShape); procedure SetShapeSize(const Value: Integer); function GetLabelBorderColor(): TColor; procedure SetLabelBorderColor(value: TColor); function GetLabelBorderWidth(): Integer; procedure SetLabelBorderWidth(value: Integer); function GetLabelFillColor(): TColor; procedure SetLabelFillColor(value: TColor); function GetLabelFillColor2(): TColor; procedure SetLabelFillColor2(value: TColor); function GetLabelFillGradient(): TIEGradientDir; procedure SetLabelFillGradient(value: TIEGradientDir); procedure SetLineColor(const Value: TColor); procedure SetLineWidth(const Value: Integer); procedure SetLineFillColor(const Value: TColor); function GetLineLength: Integer; procedure SetLineLength(const Value: Integer); function GetLinePoints: TRect; procedure SetLinePoints(Value: TRect); procedure SetLabelShape(Value: TIEShape); procedure SetLabelAlignment(Value: TIEAlignment); public property ReadOnly: Boolean read fReadOnly write SetReadOnly; property LabelShape: TIEShape read fLabelShape write SetLabelShape; property LabelAlignment: TIEAlignment read fLabelAlignment write SetLabelAlignment; // Not exposed in doc property AutoSize: boolean read fAutoSize write SetAutoSize; property LabelPosition: TIELineLabelPos read fLabelPosition write SetLabelPosition; property LabelText: String read fLabelText write SetLabelText; property LabelFont: TFont read fLabelFont write SetLabelFont; // Rect where line is drawn (Pt1 is Left,Top. Pt2 is Right,Bottom) property LinePoints: TRect read GetLinePoints write SetLinePoints; // The position where the text label is drawn property LabelRect: TRect read fLabelRect; property StartShape: TIELineEndShape read fStartShape write SetStartShape; property EndShape: TIELineEndShape read fEndShape write SetEndShape; property ShapeSize: Integer read fShapeSize write SetShapeSize; procedure SizeToFit(); procedure ActivateEditor(); property LineColor: TColor read fLineColor write SetLineColor; property LineWidth: Integer read fLineWidth write SetLineWidth; property FillColor: TColor read fLineFillColor write SetLineFillColor; // Style property LabelBorderColor: TColor read GetLabelBorderColor write SetLabelBorderColor; property LabelBorderWidth: Integer read GetLabelBorderWidth write SetLabelBorderWidth; property LabelFillColor: TColor read GetLabelFillColor write SetLabelFillColor; property LabelFillColor2: TColor read GetLabelFillColor2 write SetLabelFillColor2; property LabelFillGradient: TIEGradientDir read GetLabelFillGradient write SetLabelFillGradient; property LineLength: Integer read GetLineLength write SetLineLength; constructor Create(Owner: TObject); override; destructor Destroy; override; procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); override; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); override; end; {!! TIEPolylineLayer Description TImageEnView supports multiple layers, allowing the creation of a single image from multiple source images (which can be resized, rotated, moved, etc). TIEPolylineLayer is a descendent of that displays a line formed from multiple points. It can also be closed to display a polygon. Review the Layer Documentation for a full description of layer support. Methods and Properties Unique to TIEPolylineLayer Example // Draw a triangle polygon With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); PolylineClosed := True; end; ImageEnView1.Update(); // Which is the same as... TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( [ Point(500, 0), Point(1000, 1000), Point(0, 1000) ], True ); ImageEnView1.Update(); // Which is the same as... TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesTriangle, True ); ImageEnView1.Update(); // If PolylineClosed is not enabled, we get a polyline, instead of a polygon TIEPolylineLayer( ImageEnView1.CurrentLayer ).PolylineClosed := False; ImageEnView1.Update(); See Also - - - !!} TIEPolylineLayer = class( TIELayer ) private fPolyPoints: pointer; // array of TPoint. Coordinates are in bitmap pixels, they are never translated or resized. // C++Builder doesn't work with fPolyPoints as PPointArray fPolyPointCount: integer; fPolyPointsAllocated: integer; // allocated Polyline points fDrawnPoints: pointer; fDrawnPointCount: integer; fDrawnPointsAllocated: integer; fPolylineClosed: boolean; function GetBitmap : TIEBitmap; override; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); override; function GetAsSVG(): string; override; function GetPoints(index: integer): TPoint; function GetPointCount(): integer; function GetLineColor(): TColor; procedure SetLineColor(value: TColor); function GetLineWidth(): Integer; procedure SetLineWidth(value: Integer); function GetFillColor(): TColor; procedure SetFillColor(value: TColor); procedure SetPolylineClosed(value: Boolean); public property PolylineClosed: Boolean read fPolylineClosed write SetPolylineClosed; property Points[index: integer]: TPoint read GetPoints; property PointCount: integer read GetPointCount; // Style property LineColor: TColor read GetLineColor write SetLineColor; property LineWidth: Integer read GetLineWidth write SetLineWidth; property FillColor: TColor read GetFillColor write SetFillColor; constructor Create(Owner: TObject); override; destructor Destroy; override; procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); override; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); override; procedure ClearAllPoints(); procedure SetPoints(Points: array of TPoint; ClosePolyline: Boolean); overload; procedure SetPoints(Points: array of TPoint); overload; procedure SetPoints(Shape: TIEShape; ClosePolyline: Boolean = True); overload; procedure AddPoint(X, Y: integer); procedure RemovePoint(Index: integer); procedure SimplifyPolygon(MaxPoints: integer); end; {!! TIETextLayer Description TImageEnView supports multiple layers, allowing the creation of a single image from multiple source images (which can be resized, rotated, moved, etc). TIETextLayer is a descendent of that displays text. Review the Layer Documentation for a full description of layer support. Methods and Properties Unique to TIETextLayer Examples // Append a text layer ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'This is a Text Layer'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderColor := clBlack; TIETextLayer( ImageEnView1.CurrentLayer ).BorderWidth := 1; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clWhite; ImageEnView1.Update(); // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 'Arial Black', 42, clRed, [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; See Also - - - !!} TIETextLayer = class( TIELayer ) private fFont: TFont; fText: string; fAutoSize: boolean; fBorderShape: TIEShape; fAlignment: TIEAlignment; fLayout: TIELayout; fReadOnly: Boolean; function GetBitmap : TIEBitmap; override; procedure CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); override; function GetAsSVG(): string; override; procedure SetFont(const Value: TFont); procedure SetText(const Value: string); procedure SetAutoSize(const Value: boolean); procedure SetReadOnly(const Value: boolean); procedure SetBorderShape(const Value: TIEShape); function GetBorderColor(): TColor; procedure SetBorderColor(value: TColor); function GetBorderWidth(): Integer; procedure SetBorderWidth(value: Integer); function GetFillColor(): TColor; procedure SetFillColor(value: TColor); function GetFillColor2(): TColor; procedure SetFillColor2(value: TColor); function GetFillGradient(): TIEGradientDir; procedure SetFillGradient(value: TIEGradientDir); procedure SetAlignment(value: TIEAlignment); procedure SetLayout(value: TIELayout); public property Alignment: TIEAlignment read fAlignment write SetAlignment; property Layout: TIELayout read fLayout write SetLayout; // Style property BorderColor: TColor read GetBorderColor write SetBorderColor; property BorderWidth: Integer read GetBorderWidth write SetBorderWidth; property FillColor: TColor read GetFillColor write SetFillColor; property FillColor2: TColor read GetFillColor2 write SetFillColor2; property FillGradient: TIEGradientDir read GetFillGradient write SetFillGradient; property AutoSize: boolean read fAutoSize write SetAutoSize; property Text: String read fText write SetText; property Font: TFont read fFont write SetFont; property BorderShape: TIEShape read fBorderShape write SetBorderShape; property ReadOnly: Boolean read fReadOnly write SetReadOnly; procedure ActivateEditor(); procedure SizeToText(EnlargeOnly: Boolean = False); constructor Create(Owner: TObject); override; destructor Destroy; override; procedure CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); override; procedure LoadFromStream(Stream: TStream); override; procedure SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); override; end; function IESimplifyPolygon(tol: double; V: array of TPoint): TIEArrayOfTPoint; procedure IECleanupLayers(); function IETryIEN(Stream: TStream): Boolean; procedure IELayersMerge(Layer1, Layer2, LayerMask: TIELayer; Destination: TIEBitmap; ZoomFilter: TResampleFilter; Background: TColor; RelativePositions: Boolean; ForceCropLayer2: Boolean = False); procedure ReadLayerPropsFromStream(Stream: TStream; ResetPos: Boolean; // Position Stream after read to inital pos out RecSize: Integer; // Total size of layer data block out LayerKind: TIELayerKind; // Type of layer out GUID: TGuid); // Layer identifier type TLayerHeader=packed record Magic: array [0..12] of AnsiChar; // must be IELayers_File_Magic Version: Integer; // must be IELayers_File_Version FileFormat: TIOFileType; LayersCount: Integer; end; const IELayers_File_Version = 7003; Layers_Thumbnail_Format = ioPNG; { 10 (~ ImageEn 6.3.2) - Legacy load format - Last version that supported only layer types 7000 (unreleased): - First version that is handled by TImageEnIO - Contains thumbnail - Supports layer kinds 7001 (unreleased): - Add Tag property 7002 (unreleased): - Changed linelayer storage to store line length 7003 (ImageEn 7.0.0): - Store size of thumbnail } IELayers_File_Magic : AnsiString = 'IMAGEENLAYERS'; IELayer_Pos_Left = MaxInt - 11; IELayer_Pos_HCenter = MaxInt - 10; IELayer_Pos_Right = MaxInt - 9; IELayer_Pos_Top = IELayer_Pos_Left; IELayer_Pos_VCenter = IELayer_Pos_HCenter; IELayer_Pos_Bottom = IELayer_Pos_Right; implementation uses imageenview, math, imageenio, iexCanvasUtils, ietextc, iesettings, iexSVG {$IfDef UNICODE}, AnsiStrings {$EndIf} {$ifdef DelphiXE5orNewer},System.Types{$endif} {$ifdef IEUSEVCLZLIB}, zlib{$else}, iezlib{$endif}; var fGlobalCacheBitmap: TIEBitmap; // Image that is shared by all non-image layers const Zero_Alpha_Color = $0; Full_Alpha_Color = $02FFFFFF; function CoCreateGuid(out guid: TGUID): HResult; stdcall; external 'ole32.dll' name 'CoCreateGuid'; // Delete cache bitmap procedure IECleanupLayers(); begin if assigned( fGlobalCacheBitmap ) then FreeAndNil( fGlobalCacheBitmap ); end; {!! IELayersMerge Declaration procedure IELayersMerge(Layer1, Layer2, LayerMask: ; Destination: ; ZoomFilter: ; Background: TColor; RelativePositions: Boolean); Description Merges two layers to the destination bitmap. ZoomFilter specifies the filter to use when layers needs to be stretched. Background is the color used to fill empty regions. LayerMask is the upper layer's mask. This can be 'nil' if no layer mask exists. If RelativePositions = false the output layer should have posx = 0 and posy = 0 because the required space is added to the destination bitmap. If ForceCropLayer2 = true, then any parts of Layer 2 lying outside of layer 1 will be cropped. If False, cropping will only occur if is enabled. Example // this merges all layers of ImageEnView1 to tempIE (invisible), then saves to jpeg file var tempIE: TImageEnView; tempBMP: TIEBitmap; i: Integer; begin tempIE := TImageEnView.Create(nil); tempIE.Layers[0].Bitmap.Assign( ImageEnView1.Layers[0].Bitmap ); tempBMP := TIEBitmap.Create; for i := 1 to ImageEnView1.LayersCount-1 do begin IELayersMerge( tempIE.Layers[0], ImageEnView1.Layers[i], nil, tempBMP, rfNone, clBlack ); tempIE.Layers[0].Bitmap.Assign( tempBMP ); end; tempBMP.free; tempIE.Background := clBlack; tempIE.RemoveAlphaChannel(true); tempIE.IO.SaveToFile('output.jpg'); tempIE.free; end; !!} procedure IELayersMerge(Layer1, Layer2, LayerMask: TIELayer; Destination: TIEBitmap; ZoomFilter: TResampleFilter; Background: TColor; RelativePositions: Boolean; ForceCropLayer2: Boolean = False); var // l0...is layer 0 (down layer) // l1...is layer 1 (up layer) // l2...is layer mask of layer 1 l0bitmap, l1bitmap, l2bitmap: TIEBitmap; l0alpha, l1alpha: TIEBitmap; l0transp, l1transp: integer; l0palpha, l1palpha: pbyte; l1transp255, l0transp255: double; l1opacity, l0opacity: double; l0prgb, l1prgb: PRGB; l2pbyte: pbyte; l0posx, l1posx, l2posx: integer; l0posy, l1posy, l2posy: integer; l0row, l1row, l2row: integer; l0col, l1col, l2col: integer; l1cropped: Boolean; proc0, proc1: TImageEnProc; l0width, l1width, l2width: integer; l0height, l1height, l2height: integer; outbitmap: TIEBitmap; outalpha: TIEBitmap; outwidth, outheight: Integer; row, col: integer; SimAlphaRow0, SimAlphaRow1: array of byte; ConvRGBRow0, ConvRGBRow1: array of TRGB; pdestalpha: pbyte; pdest: PRGB; aa, bb, cc, opt1: double; maxwidth, maxheight: integer; minposx, minposy, maxposx: Integer; all0: array of byte; allBak: array of TRGB; vv: TRGB; op: TIERenderOperation; i, a, r, g, b: integer; doFreeLayer1, doFreeLayer2: Boolean; zf: TResampleFilter; begin doFreeLayer1 := False; doFreeLayer2 := False; // If Layer1 or Layer2 are not TIEImageLayer then they must be converted to a TIEImageLayer if not ( Layer1 is TIEImageLayer ) then begin Layer1 := TIEImageLayer.create( Layer1.fOwner, Layer1 ); doFreeLayer1 := True; end; if not ( Layer2 is TIEImageLayer ) then begin Layer2 := TIEImageLayer.create( Layer2.fOwner, Layer2 ); doFreeLayer2 := True; end; l2Width := 0; l2Height := 0; op := Layer2.Operation; proc0 := TImageEnProc.Create(nil); proc1 := TImageEnProc.Create(nil); proc0.AutoUndo := True; proc1.AutoUndo := True; l0bitmap := nil; l1bitmap := nil; l2bitmap := nil; try // layer 0 vars l0bitmap := Layer1.Bitmap; l0width := Layer1.Width; l0height := Layer1.Height; if (l0width <> l0bitmap.Width) or (l0height <> l0bitmap.Height) then begin // resize the layer l0bitmap := TIEBitmap.Create; proc0.AttachedIEBitmap := Layer1.Bitmap; zf := ZoomFilter; if TIEImageLayer( Layer1 ).UseResampleFilter then zf := TIEImageLayer( Layer1 ).ResampleFilter; proc0.ResampleTo(l0bitmap, l0width, l0height, zf); end; l0posx := Layer1.PosX; l0posy := Layer1.PosY; if l0bitmap.HasAlphaChannel then l0alpha := l0bitmap.AlphaChannel else l0alpha := nil; l0transp := Layer1.Transparency; l0transp255 := l0transp / 255.0; l0opacity := Layer1.Opacity; SetLength(SimAlphaRow0, l0bitmap.Width); FillChar(SimAlphaRow0[0], l0bitmap.Width, 255); SetLength(ConvRGBRow0, l0bitmap.Width); // layer 1 vars l1bitmap := Layer2.Bitmap; l1width := Layer2.Width; l1height := Layer2.Height; if ForceCropLayer2 then l1cropped := true else l1cropped := Layer2.Cropped and not RelativePositions; if (l1width <> l1bitmap.Width) or (l1height <> l1bitmap.Height) then begin // resize the layer l1bitmap := TIEBitmap.Create; proc1.AttachedIEBitmap := Layer2.Bitmap; zf := ZoomFilter; if TIEImageLayer( Layer2 ).UseResampleFilter then zf := TIEImageLayer( Layer2 ).ResampleFilter; proc1.ResampleTo(l1bitmap, l1width, l1height, zf); end; l1posx := Layer2.PosX; l1posy := Layer2.PosY; if l1bitmap.HasAlphaChannel then l1alpha := l1bitmap.AlphaChannel else l1alpha := nil; l1transp := Layer2.Transparency; l1transp255 := l1transp / 255.0; l1opacity := Layer2.Opacity; SetLength(SimAlphaRow1, l1bitmap.Width); FillChar(SimAlphaRow1[0], l1bitmap.Width, 255); SetLength(ConvRGBRow1, l1bitmap.Width); // layer mask vars (of layer 1) if LayerMask <> nil then begin LayerMask.Bitmap.PixelFormat := ie8g; // in case it is not! l2width := LayerMask.Width; l2height := LayerMask.Height; if (l2width <> LayerMask.Bitmap.Width) or (l2height <> LayerMask.Bitmap.Height) then begin // resize the layer l2bitmap := TIEBitmap.Create; l2bitmap.Allocate(l2width, l2height, ie8g); _IEBmpStretchEx(LayerMask.Bitmap, l2bitmap, nil, nil); end else l2bitmap := LayerMask.Bitmap; l2posx := LayerMask.PosX; l2posy := LayerMask.PosY; end else begin l2posx := 0; l2posy := 0; end; // output vars if l0posx < 0 then begin inc(l1posx, -l0posx); inc(l2posx, -l0posx); l0posx := 0; end; if l0posy < 0 then begin inc(l1posy, -l0posy); inc(l2posy, -l0posy); l0posy := 0; end; if (l1posx < 0) and not l1cropped then begin inc(l0posx, -l1posx); inc(l2posx, -l1posx); l1posx := 0; end; if (l1posy < 0) and not l1cropped then begin inc(l0posy, -l1posy); inc(l2posy, -l1posy); l1posy := 0; end; if l1cropped then begin maxwidth := l0width + l0posx; maxheight := l0height + l0posy; end else begin maxwidth := imax(l0width + l0posx, l1width + l1posx); maxheight := imax(l0height + l0posy, l1height + l1posy); end; if not l1cropped then // todo: @FAB: Please check this begin minposx := imin(l0posx, l1posx); minposy := imin(l0posy, l1posy); end else begin // todo: @FAB: Changed this from 0,0 to handle layer 0 not being positioned at 0,0 // Not sure what the full effect of this will be minposx := l0posx; minposy := l0posy; end; outwidth := maxwidth - minposx; outheight := maxheight - minposy; outbitmap := Destination; if (outwidth <> outbitmap.Width) or (outheight <> outbitmap.Height) or (outbitmap.PixelFormat <> ie24RGB) then outbitmap.Allocate(outwidth, outheight, ie24RGB); outalpha := outbitmap.AlphaChannel; // this creates alpha channel outalpha.Full := false; SetLength(all0, outwidth * 4); FillChar(all0[0], outwidth * 4, 0); // set background row vv := TColor2TRGB(Background); SetLength(allBak, outwidth * 2); pdest := @allBak[0]; for i := 1 to outwidth do begin pdest^ := vv; inc(pdest); end; // combine images for row := minposy to minposy + outheight - 1 do begin // set layer 0 pointers l0row := row - l0posy; if (l0row >= 0) and (l0row < l0bitmap.Height) then begin if assigned(l0alpha) then l0palpha := l0alpha.Scanline[l0row] else l0palpha := @SimAlphaRow0[0]; if l0bitmap.PixelFormat = ie24RGB then l0prgb := l0bitmap.Scanline[l0row] else begin // convert one row of l0bitmap to 24bit _ConvRow1To24(l0bitmap.Scanline[l0row], pbyte(@ConvRGBRow0[0]), l0Width); l0prgb := @ConvRGBRow0[0]; end; end else begin l0palpha := @all0[0]; l0prgb := @allBak[0]; end; // set layer 1 pointers l1row := row - l1posy; if (l1row >= 0) and (l1row < l1Height) then begin if assigned(l1alpha) then l1palpha := l1alpha.ScanLine[l1row] else l1palpha := @SimAlphaRow1[0]; if l1bitmap.PixelFormat = ie24RGB then l1prgb := l1bitmap.Scanline[l1row] else begin // convert one row of l1bitmap to 24bit _ConvRow1To24(l1bitmap.Scanline[l1row], pbyte(@ConvRGBRow1[0]), l1Width); l1prgb := @ConvRGBRow1[0]; end; end else begin l1palpha := @all0[0]; l1prgb := @allBak[0]; end; // set layer mask pointers if LayerMask <> nil then begin l2row := row - l2posy; if (l2row >= 0) and (l2row < l2Height) then l2pbyte := l2bitmap.Scanline[l2row] else l2pbyte := @all0[0]; end else begin l2pbyte := @all0[0]; end; // set output pointers pdest := outbitmap.Scanline[row - minposy]; pdestalpha := outalpha.Scanline[row - minposy]; // main loop l0col := minposx - l0posx; l1col := minposx - l1posx; l2col := minposx - l2posx; maxposx := minposx + outwidth - 1; if l1col > 0 then begin inc(l1prgb, l1col); inc(l1palpha, l1col); end; if l2col > 0 then inc(l2pbyte, l2col); for col := minposx to maxposx do begin // combine pixels if (l0col >= 0) and (l1col >= 0) and (l0col < l0Width) and (l1col < l1Width) then begin if l0palpha^ < l0transp then aa := l0palpha^ / 255.0 * l0opacity else aa := l0transp255 * l0opacity; if LayerMask <> nil then begin if (l2col >= 0) and (l2col < l2Width) then begin bb := imin(imin(l1palpha^, l2pbyte^), l1transp) / 255 * l1opacity; inc(l2pbyte); end else bb := 0.0; end else begin if l1palpha^ < l1transp then bb := l1palpha^ / 255.0 * l1opacity else bb := l1transp255 * l1opacity; end; opt1 := (1.0 - bb) * aa; cc := bb + opt1; vv := l0prgb^; if op = ielNormal then vv := l1prgb^ else IEBlend(l1prgb^, vv, op, row); if cc <> 0.0 then begin r := round((bb * vv.r + opt1 * l0prgb^.r) / cc); g := round((bb * vv.g + opt1 * l0prgb^.g) / cc); b := round((bb * vv.b + opt1 * l0prgb^.b) / cc); pdest^.r := blimit(r); pdest^.g := blimit(g); pdest^.b := blimit(b); end else pdest^ := vv; a := round(cc * 255.0); pdestalpha^ := ilimit(a, 0, 255); inc(l0palpha); inc(l0prgb); inc(l1palpha); inc(l1prgb); end else if (l0col >= 0) and (l0col < l0Width) then begin // copy only l0bitmap pdest^ := l0prgb^; pdestalpha^ := trunc(imin(l0palpha^, l0transp) * l0opacity); inc(l0palpha); inc(l0prgb); end else if (l1col >= 0) and (l1col < l1Width) then begin // copy only l1bitmap pdest^ := l1prgb^; if LayerMask <> nil then begin if (l2col >= 0) and (l2col < l2Width) then begin pdestalpha^ := trunc(imin(imin(l1palpha^, l2pbyte^), l1transp) * l1opacity); inc(l2pbyte); end else pdestalpha^ := 0; end else begin if l1palpha^ < l1transp then pdestalpha^ := trunc(l1palpha^ * l1opacity) else pdestalpha^ := trunc(l1transp * l1opacity); end; inc(l1palpha); inc(l1prgb); end else begin // transparent area pdestalpha^ := 0; pdest^ := TColor2TRGB(Background); end; inc(pdest); inc(pdestalpha); inc(l0col); inc(l1col); inc(l2col); end; end; // IELayersMerge should not change source bitmaps, but when proc0.ResampleTo or proc1.ResampleTo is called we need // to restore original bitmaps if proc0.CanUndo then proc0.Undo; if proc1.CanUndo then proc1.Undo; finally FreeAndNil(proc0); FreeAndNil(proc1); if (LayerMask <> nil) and (LayerMask.Bitmap <> l2bitmap) then FreeAndNil(l2Bitmap); if l0bitmap <> Layer1.Bitmap then l0bitmap.Free; if l1bitmap <> Layer2.Bitmap then l1bitmap.Free; if doFreeLayer1 then Layer1.Free; if doFreeLayer2 then Layer2.Free; end; // verify if outalpha is full and remove it if not needed outalpha.SyncFull; if outalpha.Full then begin // remove alpha outbitmap.RemoveAlphaChannel; end; end; // Returns true is Stream is a ImageEn Layers file function IETryIEN(Stream: TStream): Boolean; var l: int64; recHead: TLayerHeader; begin l := Stream.Position; result := true; Stream.Read(recHead, sizeof(TLayerHeader)); if ( {$IfDef DelphiXE4orNewer}AnsiStrings.{$EndIf} StrLComp(recHead.Magic, PAnsiChar(IELayers_File_Magic), length(IELayers_File_Magic)) <> 0) or (recHead.Version <= 0) then result := false; Stream.Position := l; end; procedure InitBitmap(var Bitmap: TIEBitmap; w, h: Integer; FillColor: TColor = clWhite); begin if assigned( Bitmap ) and (( Bitmap.Width <> w ) or ( Bitmap.Height <> h ) or (Bitmap.PixelFormat = ie32RGB)) then FreeAndNil( Bitmap ); if not assigned( Bitmap ) then Bitmap := TIEBitmap.Create( w, h, ie24RGB ); Bitmap.Fill( FillColor ); end; procedure InitBitmapRGBA(var Bitmap: TIEBitmap; w, h: Integer); begin if assigned( Bitmap ) and (( Bitmap.Width <> w ) or ( Bitmap.Height <> h ) or (Bitmap.PixelFormat <> ie32RGB)) then FreeAndNil( Bitmap ); if not assigned( Bitmap ) then Bitmap := TIEBitmap.Create( w, h, ie32RGB ); Bitmap.Fill( clWhite ); // Note: Used as the blend color for the anti-aliasing of GDI+ objects Bitmap.AlphaChannel.Fill(0); end; // Gradients only supported when Shape = iesRectangle procedure IEDrawSimpleShape(Canvas: TIECanvas; Left, Top, Width, Height: Integer; BorderColor: TColor; BorderWidth: Integer; FillColor: TColor; FillColor2: TColor = clNone_; FillGradient: TIEGradientDir = gdVertical; Zoom: Double = 1; Shape : TIEShape = iesRectangle; AntiAlias: Boolean = True); const Rect_Rounding = 20; var drawGradient: Boolean; prevSmoothingMode : TIECanvasSmoothingMode; begin if Shape <> iesRectangle then FillColor2 := clNone_; drawGradient := ( FillColor2 <> FillColor ) and ( FillColor <> clNone_ ) and ( FillColor2 <> clNone_ ); prevSmoothingMode := Canvas.SmoothingMode; try 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 * Zoom )); // 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 drawGradient or ( 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 then begin Canvas.GradientFillRect( Rect( Left, Top, Left + Width - 1, Top + Height - 1), FillColor, FillColor2, FillGradient = gdVertical ); Canvas.Brush.Style := bsClear; end; case Shape of iesEllipse : Canvas.Ellipse ( Left, Top, Left + Width, Top + Height ); iesRectangle : Canvas.Rectangle( Left, Top, Left + Width, Top + Height ); iesRoundRect : Canvas.RoundRect( Left, Top, Left + Width, Top + Height, Round( Rect_Rounding * Zoom ), Round( Rect_Rounding * Zoom )); end; finally Canvas.SmoothingMode := prevSmoothingMode; end; end; // draw text to the coordinates x1, y1, x2, y2 on Bitmap.IECanvas function IEDrawText(Canvas: TIECanvas; x1, y1, x2, y2: integer; Zoom: double; Text: WideString; Font: TFont; TextAlign: TIEAlignment; TextLayout: TIELayout; TextAngle: Integer; BorderColor: TColor; BorderWidth: Integer; FillColor: TColor; FillColor2: TColor; FillGradient: TIEGradientDir; TextAutoSize: boolean; AntiAlias: Boolean; Shape : TIEShape; EstimateSizeOnly: boolean = False ): TSize; const Maintain_Alignment_On_Rotate = True; Shape_Border = 1; // Drawing too close to the boundary can affect transparency (No alpha). This will prevent it var borderPadding: Integer; ox, oy: integer; dx, dy: integer; fa: double; nx2, ny2: integer; haveBorder: Boolean; OutSize: TSize; ellipseHPadding, ellipseVPadding : Integer; wasTextRendering: TIETextRenderingHintMode; begin if Shape = iesEllipse then begin TextAlign := iejCenter; TextLayout := ielCenter; end; wasTextRendering := Canvas.TextRendering; try if AntiAlias then Canvas.TextRendering := ietrTextRenderingHintAntiAlias else Canvas.TextRendering := ietrTextRenderingHintSingleBitPerPixel; haveBorder := ( BorderColor <> clNone_ ) and ( BorderWidth > 0 ); borderPadding := 0; if haveBorder then borderPadding := round((BorderWidth + 3) * Zoom ); while TextAngle < 0 do TextAngle := TextAngle + 360; Canvas.Font.Assign( Font ); Canvas.Font.Height := Round( Font.Height * Zoom ); if TextAutoSize or EstimateSizeOnly then OutSize := Canvas.MeasureText( Text, True ) else OutSize := Canvas.MeasureText( Text, rect( x1, y1, x2, y2 ), -TextAngle, True ); dx := OutSize.cX; dy := OutSize.cY; // Text can't be wider than object if ( EstimateSizeOnly = False ) and ( TextAngle mod 180 = 0 ) and ( dx > x2 - x1 ) then begin while dx > x2 - x1 do begin SetLength( Text, Length( Text ) - 1 ); dx := Canvas.TextWidth( Text + '...' ) + 2 * borderPadding; if Text = '' then Break; end; Text := Text + '...'; end; fa := IEDegreesToRadians( -TextAngle ); // angle in radians nx2 := x2; ny2 := y2; if EstimateSizeOnly then begin nx2 := trunc(x1 + abs(dx * cos(fa)) + abs(dy * sin(fa))) + 3 * borderPadding; // 3 for overflow ny2 := trunc(y1 + abs(dx * sin(fa)) + abs(dy * cos(fa))) + 2 * borderPadding; end; ox := 0; case TextAlign of iejLeft: begin if fa < PI / 2 then ox := 0 else if fa < PI then ox := trunc(- dx * cos(fa)) else if fa < PI * 3 / 2 then ox := trunc(- dx * cos(fa) - dy * sin(fa)) else if fa < PI * 2 then ox := trunc(- dy * sin(fa)); inc( ox, x1 + borderPadding ); end; iejRight: begin if fa < PI / 2 then ox := trunc(nx2 - x1 - dx * cos(fa) - dy * sin(fa)) else if fa < PI then ox := trunc(nx2 - x1 - dy * sin(fa)) else if fa < PI * 3 / 2 then ox := trunc(nx2 - x1) else if fa < PI * 2 then ox := trunc(nx2 - x1 - dx * cos(fa)); inc( ox, x1 - borderPadding ); end; iejCenter, iejJustify: begin ox := x1 + trunc(nx2 - x1 - dx * cos(fa) - dy * sin(fa)) div 2; end; end; case TextLayout of ielBottom: oy := y1 + trunc(ny2 - abs(dx * sin(fa)) - abs(dy * cos(fa))) - borderPadding; ielCenter: oy := y1 + trunc(ny2 - y1 - abs(dx * sin(fa)) - abs(dy * cos(fa))) div 2; else { ielTop } oy := y1 + borderPadding; end; ellipseHPadding := 0; ellipseVPadding := 0; if EstimateSizeOnly and ( Shape = iesEllipse ) then begin // PAD SHAPE TO ALLOW SPACE FOR ELLIPSE OutSize := Canvas.MeasureText( 'W', True ); ellipseHPadding := OutSize.cX; ellipseVPadding := OutSize.cY; end; Result.cX := nx2 + 1 + ellipseHPadding; Result.cY := ny2 + 1 + ellipseVPadding; if not EstimateSizeOnly then begin // Draw border if haveBorder or ( FillColor <> clNone_ ) then IEDrawSimpleShape( Canvas, x1, y1, x2 - x1 + 1, y2 - y1 + 1 - Shape_Border, // Just put at boundary BorderColor, BorderWidth, FillColor, FillColor2, FillGradient, Zoom, Shape, AntiAlias ); // draw text if Text <> '' then begin Canvas.Brush.Style := bsSolid; Canvas.Brush.Color := Font.Color; Canvas.DrawText( Text, rect( ox, oy, nx2, ny2 ), -TextAngle, True ) end; end; finally Canvas.TextRendering := wasTextRendering; end; end; // *************************************************************************************** // // ** ** // // ** TIELayer ** // // ** ** // // *************************************************************************************** // constructor TIELayer.Create(Owner: TObject); begin inherited Create; CoCreateGuid(fGUID); fOwner := Owner; fCachedLayerMask := nil; fLayerCacheBitmap := nil; fLayerCacheValid := False; fOriginalAspectRatio := 0; softShadow := TIEVSoftShadow.Create; fModified := False; end; destructor TIELayer.Destroy; begin if fUserDataLen > 0 then freemem(UserData); if assigned(fCachedLayerMask) then FreeAndNil(fCachedLayerMask); FreeAndNil( fLayerCacheBitmap ); FreeAndNil( SoftShadow ); inherited Destroy; end; procedure TIELayer.LayerChange(ResetLayerCache: Boolean = True); begin fModified := True; if ResetLayerCache then fLayerCacheValid := False; if assigned( fOwner ) then TImageEnView( fOwner ).ImageChange(); end; {!! TIELayer.Modified Declaration property Modified: Boolean; Description Returns true if the layer has been changed since it was created or loaded. Example // Get list of changed layers changedLayers := ''; for I := 0 to ImageEnView1.LayersCount -1 do if ImageEnView1.Layers[I].Modified then changedLayers := changedLayers + IntToStr( I ) + ', '; // Mark all layers as unmodified for I := 0 to ImageEnView1.LayersCount -1 do ImageEnView1.Layers[I].Modified := False; !!} function TIELayer.GetModified(): Boolean; begin Result := fModified; if ( Self is TIEImageLayer ) and TIEImageLayer(Self).fBitmap.Modified then Result := True; end; procedure TIELayer.SetModified(value: Boolean); begin fModified := value; if ( Value = False ) and ( Self is TIEImageLayer ) and assigned( TIEImageLayer(Self).fBitmap ) then TIEImageLayer(Self).fBitmap.Modified := False; if value then fLayerCacheValid := False; end; procedure TIELayer.SetDefaults; procedure _InitFont(var Font: TFont; FontSize: Integer); begin Font.Charset := DEFAULT_CHARSET; Font.Color := clBlack; Font.Size := FontSize; Font.Name := 'Arial'; Font.Style := []; end; begin fVisible := true; fTransparency := 255; // full opaque fOpacity := 1.0; // full opaque fPosX := 0; fPosY := 0; fClientAreaBox := Rect(0, 0, 0, 0); fResizedWidth := 0; fResizedHeight := 0; fCropped := false; fVisibleBox := true; fSelectable := true; fLocked := false; fOperation := ielNormal; UserData := nil; fUserDataLen := 0; IsMask := false; fDrawOuter := false; FillChar(fDrawingInfo, sizeof(fDrawingInfo), 0); fRotate := 0; fRotateCenterX := 0.5; fRotateCenterY := 0.5; fSelected := False; fAlphaEdgeFeathering := 0; fGroupIndex := 0; fAspectRatioLocked := False; fAntiAlias := True; fLayerCacheValid := False; with SoftShadow do begin Enabled := false; Radius := 3; OffsetX := 0; OffsetY := 0; Intensity := 100; ShadowColor := CreateRGB(0, 0, 0); end; if Self is TIEImageLayer then with TIEImageLayer( Self ) do begin fBorderColor := clNone_; fBorderWidth := 1; Magnify.Enabled := false; Magnify.Rate := 2; Magnify.Style := iemRectangle; Magnify.Source := iemCanvas; fResampleFilter := rfFastLinear; fUseResampleFilter := False; end else if Self is TIEShapeLayer then with TIEShapeLayer( Self ) do begin fShape := iesEllipse; fBorderColor := clBlack; fBorderWidth := 1; fFillColor := clRed; fFillColor2 := clNone_; fFillGradient := gdVertical; fShapeModifier := 0; end else if Self is TIELineLayer then with TIELineLayer( Self ) do begin fAutoSize := True; fLineColor := clBlack; fLineWidth := 1; fLineFillColor := clWhite; fBorderColor := clBlack; fBorderWidth := 1; fFillColor := clWhite; fFillColor2 := clNone_; fFillGradient := gdVertical; _InitFont( fLabelFont, 12 ); fLabelText := ''; fLabelAlignment := iejLeft; fLabelPosition := ielpAtEnd; fLabelShape := iesRectangle; fReadOnly := False; fEndShape := ieesNone; fStartShape := ieesNone; fShapeSize := 20; end else if Self is TIEPolylineLayer then with TIEPolylineLayer( Self ) do begin fBorderColor := clBlack; fBorderWidth := 1; fFillColor := clWhite; fFillColor2 := clNone_; fFillGradient := gdVertical; fPolylineClosed := False; ClearAllPoints(); end else if Self is TIETextLayer then with TIETextLayer( Self ) do begin _InitFont( fFont, 14 ); fBorderColor := clNone_; fBorderWidth := 1; fFillColor := clNone_; fFillColor2 := clNone_; fFillGradient := gdVertical; fBorderShape := iesRectangle; fText := IEGlobalSettings().DefaultLayerText; fAutoSize := False; fReadOnly := False; fAlignment := iejLeft; fLayout := ielTop; end; end; {!! TIELayer.BorderColor Declaration property BorderColor: TColor; Description Provides generic access to the color of the border/line of the layer. BorderColor accesses the following properties: Class Property (also sets )
Examples // Load an image layer and assign a pink border ImageEnView1.LayersAdd( ielkImage ); // Append an image layer ImageEnView1.IO.LoadFromFile('C:\New Zealand.jpg'); // Load image into the new/active layer ImageEnView1.CurrentLayer.BorderColor := $008000FF; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); // Set style properties to an orange border with yellow fill ImageEnView1.CurrentLayer.BorderColor := $004080FF; ImageEnView1.CurrentLayer.BorderWidth := 2; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove the border... ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); See Also - TIELayer.BorderWidth !!} function TIELayer.GetBorderColor: TColor; begin if Kind = ielkLine then Result := TIELineLayer( Self ).fLineColor else Result := fBorderColor; end; procedure TIELayer.SetBorderColor(value: TColor); begin fBorderColor := Value; if Kind = ielkLine then TIELineLayer( Self ).fLineColor := Value; LayerChange(); end; {!! TIELayer.BorderWidth Declaration property BorderWidth: Integer; Description Provides generic access to the width of the border/line of the layer. BorderWidth accesses the following properties: Class Property (also sets )
Example // Load an image layer and assign a pink border ImageEnView1.LayersAdd( ielkImage ); // Append an image layer ImageEnView1.IO.LoadFromFile('C:\New Zealand.jpg'); // Load image into the new/active layer ImageEnView1.CurrentLayer.BorderColor := $008000FF; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); // Set style properties to an orange border with yellow fill ImageEnView1.CurrentLayer.BorderColor := $004080FF; ImageEnView1.CurrentLayer.BorderWidth := 2; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove the border... ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); See Also - TIELayer.BorderColor !!} function TIELayer.GetBorderWidth(): Integer; begin if Kind = ielkLine then Result := TIELineLayer( Self ).fLineWidth else Result := fBorderWidth; end; procedure TIELayer.SetBorderWidth(value: Integer); begin fBorderWidth := Value; if Kind = ielkLine then TIELineLayer( Self ).fLineWidth := Value; LayerChange(); end; {!! TIELayer.FillColor Declaration property FillColor: TColor; Description Provides generic access to the fill color of the layer. Set to clNone for no fill (i.e. transparent background) FillColor accesses the following properties: Class Property N/A (also sets )
Example // Set fill color for a shape to yellow ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove fill color from shape ImageEnView1.CurrentLayer.FillColor := clNone; ImageEnView1.Update(); See Also - TIELayer.FillColor2 - TIELayer.FillGradient !!} function TIELayer.GetFillColor(): TColor; begin if Kind = ielkLine then Result := TIELineLayer( Self ).fLineFillColor else Result := fFillColor; end; procedure TIELayer.SetFillColor(value: TColor); begin fFillColor := Value; if Kind = ielkLine then TIELineLayer( Self ).fLineFillColor := Value; LayerChange(); end; {!! TIELayer.FillColor2 Declaration property FillColor2: TColor; Description Provides generic access to the secondary gradient fill color of the layer. If FillColor2 is clNone, the layer is filled by a solid color specified by . If FillColor2 is different from it is drawn as a gradient. The direction of the gradient is specified by . FillColor2 accesses the following properties: Class Property N/A N/A
Example // Set a vertical gradient fill for an ellipse ImageEnView1.CurrentLayer.FillColor2 := clRed; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.FillGradient := clVertical; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); // Set a horizontal gradient fill for the label of a line layer ImageEnView1.CurrentLayer.FillColor := clRed; ImageEnView1.CurrentLayer.FillColor2 := clYellow; ImageEnView1.CurrentLayer.FillGradient := clHorizontal; ImageEnView1.CurrentLayer.BorderColor := clBlack; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.FillColor - TIELayer.FillGradient !!} procedure TIELayer.SetFillColor2(value: TColor); begin fFillColor2 := Value; LayerChange(); end; {!! TIELayer.FillGradient Declaration property FillGradient: ; Description Provides generic access to the gradient fill direction for the layer. FillGradient accesses the following properties: Class Property N/A N/A
Example // Set a vertical gradient fill for an ellipse ImageEnView1.CurrentLayer.FillColor2 := clRed; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.FillGradient := clVertical; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); // Set a horizontal gradient fill for the label of a line layer ImageEnView1.CurrentLayer.FillColor := clRed; ImageEnView1.CurrentLayer.FillColor2 := clYellow; ImageEnView1.CurrentLayer.FillGradient := clHorizontal; ImageEnView1.CurrentLayer.BorderColor := clBlack; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.FillColor - TIELayer.FillColor2 !!} procedure TIELayer.SetFillGradient(value: TIEGradientDir); begin fFillGradient := value; LayerChange(); end; {!! TIELayer.GroupIndex Declaration property GroupIndex: Integer; Description Specifies the Group ID of the layer. When a layer is selected all other layers with the same group ID are automatically selected too. GroupIndex can be any value. A GroupIndex of 0 means the layer is not grouped. Note: GroupIndex is only valid if multiple layer selection is enabled. Example // Group all layers (except background) ImageEnView1.LockUpdate(); for i := 1 to ImageEnView1.LayersCount - 1 do ImageEnView1.Layers[ I ].GroupIndex := Random( Max_Int ); ImageEnView1.UnlockUpdate(); // Ungroup all layers ImageEnView1.LockUpdate(); for i := 0 to ImageEnView1.LayersCount - 1 do ImageEnView1.Layers[ I ].GroupIndex := 0; ImageEnView1.UnlockUpdate(); See Also - - !!} // Note: calls update procedure TIELayer.SetGroupIndex(const Value: Integer); var ieview: TImageEnView; i: Integer; begin fGroupIndex := Value; ieview := (fOwner as TImageEnView); if assigned(ieview) then begin if value <> 0 then begin // if selected then select all other members of this group if fSelected then ieview.SelectByGroupIndex( Value, True, False ) else // If others of group are already selected then select this layer for i := 0 to ieview.LayersCount - 1 do if ieview.Layers[ i ].GroupIndex = Value then begin if ieview.Layers[ i ].Selected then fSelected := True; Break; end; end; ieview.Update; end; LayerChange( False ); end; {!! TIELayer.Assign Declaration procedure Assign(Source: ); Description Copy the content of a layer to the current one. Example // Assign layers from one ImageEnView to another // Note: ImageEnView2.assign( ImageEnView1 ) will assign all content including layers for I := 0 to ImageEnView1.LayersCount - 1 do begin iLayer := ImageEnView2.LayersAdd; // append a new layer ImageEnView2.Layers[ iLayer ].Assign( ImageEnView1.Layers[ i ] ); end; ImageEnView2.Update(); !!} procedure TIELayer.Assign(Source: TIELayer); begin fResizedWidth := Source.fResizedWidth; fResizedHeight := Source.fResizedHeight; fVisible := Source.fVisible; fVisibleBox := Source.fVisibleBox; fSelectable := Source.fSelectable; fTransparency := Source.fTransparency; fOpacity := Source.fOpacity; PosX := Source.PosX; PosY := Source.PosY; fClientAreaBox := Source.fClientAreaBox; fCropped := Source.fCropped; fLocked := Source.fLocked; fOperation := Source.fOperation; // Do not copy user data (UserData may contain objects or memory buffer that will never get freed) // UserData := Source.UserData; // UserDataLen := Source.UserDataLen; fUserDataLen := 0; fName := Source.fName; fIsMask := Source.fIsMask; fDrawOuter := Source.fDrawOuter; fAlphaEdgeFeathering := Source.fAlphaEdgeFeathering; fGroupIndex := Source.fGroupIndex; fSelected := Source.fSelected; fAspectRatioLocked := Source.fAspectRatioLocked; fBorderColor := Source.fBorderColor; fBorderWidth := Source.fBorderWidth; fFillColor := Source.fFillColor; fFillColor2 := Source.fFillColor2; fFillGradient := Source.fFillGradient; fRotate := Source.fRotate; fAntiAlias := Source.fAntiAlias; fOriginalAspectRatio := Source.fOriginalAspectRatio; fRotateCenterX := Source.fRotateCenterX; fRotateCenterY := Source.fRotateCenterY; // Soft shadow SoftShadow.Assign( Source.SoftShadow ); if ( Self is TIEImageLayer ) and ( Source is TIEImageLayer ) then with TIEImageLayer( Self ) do begin fBitmap.Assign( TIEImageLayer( Source ).fBitmap); Magnify := TIEImageLayer( Source ).Magnify; fResampleFilter := TIEImageLayer( Source ).fResampleFilter; fUseResampleFilter := TIEImageLayer( Source ).fUseResampleFilter; end else if ( Self is TIEShapeLayer ) and ( Source is TIEShapeLayer ) then with TIEShapeLayer( Self ) do begin fShape := TIEShapeLayer( Source ).fShape; fShapeModifier := TIEShapeLayer( Source ).fShapeModifier; end else if ( Self is TIELineLayer ) and ( Source is TIELineLayer ) then with TIELineLayer( Self ) do begin fAutoSize := TIELineLayer( Source ).fAutoSize; fLineColor := TIELineLayer( Source ).fLineColor; fLineWidth := TIELineLayer( Source ).fLineWidth; fLineFillColor := TIELineLayer( Source ).fLineFillColor; fLabelFont.Assign( TIELineLayer( Source ).fLabelFont ); fLabelText := TIELineLayer( Source ).fLabelText; fLabelAlignment := TIELineLayer( Source ).fLabelAlignment; fLabelPosition := TIELineLayer( Source ).fLabelPosition; fLabelShape := TIELineLayer( Source ).fLabelShape; fReadOnly := TIELineLayer( Source ).fReadOnly; fEndShape := TIELineLayer( Source ).fEndShape; fShapeSize := TIELineLayer( Source ).fShapeSize; fStartShape := TIELineLayer( Source ).fStartShape; fLastLineLength := TIELineLayer( Source ).fLastLineLength; end else if ( Self is TIEPolylineLayer ) and ( Source is TIEPolylineLayer ) then with TIEPolylineLayer( Self ) do begin fPolyPointCount := TIEPolylineLayer( Source ).fPolyPointCount; fPolyPointsAllocated := fPolyPointCount; // allocates only actually necessary items getmem( fPolyPoints, fPolyPointCount * sizeof(TPoint)); copymemory( fPolyPoints, TIEPolylineLayer( Source ).fPolyPoints, fPolyPointCount * sizeof(TPoint)); fPolylineClosed := TIEPolylineLayer( Source ).fPolylineClosed; end else if ( Self is TIETextLayer ) and ( Source is TIETextLayer ) then with TIETextLayer( Self ) do begin Font.Assign( TIETextLayer( Source ).Font ); fBorderShape := TIETextLayer( Source ).fBorderShape; fText := TIETextLayer( Source ).fText; fAutoSize := TIETextLayer( Source ).fAutoSize; fReadOnly := TIETextLayer( Source ).fReadOnly; fAlignment := TIETextLayer( Source ).fAlignment; fLayout := TIETextLayer( Source ).fLayout; end; LayerChange(); end; {!! TIELayer.GetProperties Declaration procedure GetProperties(Props: TStrings); Description Returns all properties of the layer as a list of Name=Value pairs. Names will be drawn from the . Changes made to the list can be applied using . Sample Output IELP_BorderColor=clNone IELP_BorderWidth=0 IELP_FillColor=clYellow IELP_FillColor2=clRed IELP_FillGradient=1 IELP_Rotate=0 Example // Save properties of the current layer to a file ss := TStringList.create(); ImageEnView1.CurrentLayer.GetProperties( ss ); ss.SaveToFile( 'D:\CurrentLayer.txt' ); ss.Free(); See Also - - !!} procedure TIELayer.GetProperties(Props: TStrings); procedure _WriteProp(const Prop, Value: string); begin Props.Add( Prop + '=' + Value ); end; procedure _WritePropI(const Prop: string; Value: Integer); begin Props.Add( Prop + '=' + IntToStr( Value )); end; procedure _WritePropB(const Prop: string; Value: Boolean); begin if Value then Props.Add( Prop + '=True' ) else Props.Add( Prop + '=False' ); end; procedure _WritePropD(const Prop: string; Value: Double); begin Props.Add( Prop + '=' + FloatToStr( Value )); end; procedure _WritePropC(const Prop: string; Value: TColor); begin Props.Add( Prop + '=' + ColorToString( Value )); end; var I: Integer; pointStr: string; begin Props.Clear(); _WritePropI( IELP_Width , Width ); _WritePropI( IELP_Height , Height ); _WritePropB( IELP_Visible , fVisible ); _WritePropB( IELP_VisibleBox , fVisibleBox ); _WritePropB( IELP_Selectable , fSelectable ); _WritePropI( IELP_Transparency , fTransparency ); _WritePropD( IELP_Opacity , fOpacity ); _WritePropI( IELP_PosX , PosX ); _WritePropI( IELP_PosY , PosY ); _WritePropB( IELP_Cropped , fCropped ); _WritePropB( IELP_Locked , fLocked ); _WritePropI( IELP_Operation , ord( fOperation )); _WriteProp( IELP_Name , fName ); _WritePropB( IELP_IsMask , fIsMask ); _WritePropB( IELP_DrawOuter , fDrawOuter ); _WritePropI( IELP_AlphaEdgeFeathering, fAlphaEdgeFeathering ); _WritePropI( IELP_GroupIndex , fGroupIndex ); _WritePropB( IELP_Selected , fSelected ); _WritePropB( IELP_AspectRatioLocked, fAspectRatioLocked ); _WritePropC( IELP_BorderColor , fBorderColor ); _WritePropI( IELP_BorderWidth , fBorderWidth ); _WritePropC( IELP_FillColor , fFillColor ); _WritePropC( IELP_FillColor2 , fFillColor2 ); _WritePropI( IELP_FillGradient , ord( fFillGradient )); _WritePropB( IELP_AntiAlias , fAntiAlias ); _WritePropD( IELP_Rotate , fRotate ); _WritePropD( IELP_RotateCenterX , fRotateCenterX ); _WritePropD( IELP_RotateCenterY , fRotateCenterY ); // Soft shadow with SoftShadow do begin _WritePropB( IELP_SoftShadowEnabled , Enabled ); _WritePropD( IELP_SoftShadowRadius , Radius ); _WritePropI( IELP_SoftShadowOffsetX , OffsetX ); _WritePropI( IELP_SoftShadowOffsetY , OffsetY ); _WritePropI( IELP_SoftShadowIntensity , Intensity ); _WritePropC( IELP_SoftShadowColor , TRGB2TColor( ShadowColor )); end; if Self is TIEImageLayer then with TIEImageLayer( Self ) do begin _WritePropI( IELP_ImageResampleFilter , ord( fResampleFilter )); _WritePropB( IELP_ImageUseResampleFilter , fUseResampleFilter ); end else if Self is TIEShapeLayer then with TIEShapeLayer( Self ) do begin _WritePropI( IELP_Shape , ord( fShape )); _WritePropI( IELP_ShapeModifier , fShapeModifier ); end else if Self is TIELineLayer then with TIELineLayer( Self ) do begin _WritePropC( IELP_LineColor , fLineColor ); _WritePropI( IELP_LineWidth , fLineWidth ); _WritePropC( IELP_LineFillColor , fLineFillColor ); _WriteProp( IELP_FontName , fLabelFont.Name ); _WritePropI( IELP_FontSize , fLabelFont.Size ); _WritePropC( IELP_FontColor , fLabelFont.Color ); _WriteProp( IELP_LabelText , fLabelText ); _WritePropI( IELP_LabelAlignment , ord( fLabelAlignment )); _WritePropI( IELP_LabelPosition , ord( fLabelPosition )); _WritePropI( IELP_BorderShape , ord( fLabelShape )); _WritePropB( IELP_ReadOnly , fReadOnly ); _WritePropI( IELP_LineEndShape , ord( fEndShape )); _WritePropI( IELP_LineShapeSize , fShapeSize ); _WritePropI( IELP_LineStartShape , ord( fStartShape )); _WritePropI( IELP_LineLength , Round( fLineLength )); end else if Self is TIEPolylineLayer then with TIEPolylineLayer( Self ) do begin pointStr := ''; for I := 0 to PointCount - 1 do pointStr := pointStr + IntToStr( Points[ i ].X ) + ',' + IntToStr( Points[ i ].Y ) + ','; if pointStr <> '' then SetLength( pointStr, Length( pointStr ) - 1 ); _WriteProp( IELP_PolylinePoints , pointStr ); _WritePropB( IELP_PolylineClosed , fPolylineClosed ); end else if Self is TIETextLayer then with TIETextLayer( Self ) do begin _WriteProp( IELP_FontName , Font.Name ); _WritePropI( IELP_FontSize , Font.Size ); _WritePropC( IELP_FontColor , Font.Color ); _WritePropI( IELP_BorderShape , ord( fBorderShape )); _WriteProp( IELP_Text , fText ); _WritePropB( IELP_AutoSize , fAutoSize ); _WritePropB( IELP_ReadOnly , fReadOnly ); _WritePropI( IELP_TextAlignment , ord( fAlignment )); _WritePropI( IELP_TextLayout , ord( fLayout )); end; end; {!! TIELayer.SetProperties Declaration procedure GetProperties(Props: TStrings); Description Sets properties of the layer using a list of Name=Value pairs. Names will be drawn from the . Properties can be retrieved using . Sample Input IELP_BorderColor=clNone IELP_BorderWidth=0 IELP_FillColor=clYellow IELP_FillColor2=clRed IELP_FillGradient=1 IELP_Rotate=0 Examples // Set properties of the current using a file ss := TStringList.create(); ss.LoadFromFile( 'D:\CurrentLayer.txt' ); ImageEnView1.CurrentLayer.SetProperties( ss ); ImageEnView1.Update(); ss.Free(); // Apply a thick green border to all selected layers ss := TStringList.create(); ss.Add( IELP_BorderColor + '=clGreen' ); ss.Add( IELP_BorderWidth + '=10' ); for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then ImageEnView1.Layers[ I ].SetProperties( ss ); ImageEnView1.Update(); ss.Free(); See Also - - - !!} procedure TIELayer.SetProperties(Props: TStrings); var i, P: Integer; propName, propValue: string; begin for i := 0 to Props.Count - 1 do begin propName := Props[ i ]; P := AnsiPos( {$ifdef Delphi7orNewer}Props.NameValueSeparator{$else}'='{$endif}, propName ); if P <> 0 then SetLength( propName, P - 1 ) else propName := ''; propValue := Copy( Props[ i ], Length( propName ) + 2, MaxInt ); SetProperties( propName, propValue ); end; end; procedure TIELayer.SetProperties(PropName, Value: String); function _IsProp(const Prop: string): Boolean; begin Result := CompareText( Prop, PropName ) = 0; end; function _GetNextPoint(var Points: string) : integer; var idx: Integer; begin idx := pos( ',', Points ); Result := StrToInt( Copy( Points, 1, idx - 1 )); Delete( Points, 1, idx ); end; var pointStr: string; begin PropName := Trim( propName ); Value := Trim( Value ); if PropName <> '' then try if _IsProp( IELP_LAYER_CACHE_CLEAR ) then FreeAndNil( fLayerCacheBitmap ) else if _IsProp( IELP_Width ) then Width := StrToInt( Value ) else if _IsProp( IELP_Height ) then Height := StrToInt( Value ) else if _IsProp( IELP_Visible ) then fVisible := IEStr2BoolS( Value ) else if _IsProp( IELP_VisibleBox ) then fVisibleBox := IEStr2BoolS( Value ) else if _IsProp( IELP_Selectable ) then fSelectable := IEStr2BoolS( Value ) else if _IsProp( IELP_Transparency ) then fTransparency := StrToInt( Value ) else if _IsProp( IELP_Opacity ) then fOpacity := StrToFloat( Value ) else if _IsProp( IELP_PosX ) then PosX := StrToInt( Value ) else if _IsProp( IELP_PosY ) then PosY := StrToInt( Value ) else if _IsProp( IELP_Cropped ) then fCropped := IEStr2BoolS( Value ) else if _IsProp( IELP_Locked ) then fLocked := IEStr2BoolS( Value ) else if _IsProp( IELP_Operation ) then fOperation := TIERenderOperation( StrToInt( Value )) else if _IsProp( IELP_Name ) then fName := Value else if _IsProp( IELP_IsMask ) then fIsMask := IEStr2BoolS( Value ) else if _IsProp( IELP_DrawOuter ) then fDrawOuter := IEStr2BoolS( Value ) else if _IsProp( IELP_AlphaEdgeFeathering ) then fAlphaEdgeFeathering := StrToInt( Value ) else if _IsProp( IELP_GroupIndex ) then fGroupIndex := StrToInt( Value ) else if _IsProp( IELP_Selected ) then fSelected := IEStr2BoolS( Value ) else if _IsProp( IELP_AspectRatioLocked ) then fAspectRatioLocked := IEStr2BoolS( Value ) else if _IsProp( IELP_BorderColor ) then fBorderColor := StringToColor( Value ) else if _IsProp( IELP_BorderWidth ) then fBorderWidth := StrToInt( Value ) else if _IsProp( IELP_FillColor ) then fFillColor := StringToColor( Value ) else if _IsProp( IELP_FillColor2 ) then fFillColor2 := StringToColor( Value ) else if _IsProp( IELP_FillGradient ) then fFillGradient := TIEGradientDir( StrToInt( Value )) else if _IsProp( IELP_AntiAlias ) then fAntiAlias := IEStr2BoolS( Value ) else if _IsProp( IELP_Rotate ) then fRotate := StrToFloat( Value ) else if _IsProp( IELP_RotateCenterX ) then fRotateCenterX := StrToFloat( Value ) else if _IsProp( IELP_RotateCenterY ) then fRotateCenterY := StrToFloat( Value ) else if _IsProp( IELP_RestorePreferredAspectRatio ) then RestoreAspectRatio( True ) else if _IsProp( IELP_RestoreAspectRatio ) then RestoreAspectRatio( False ) else // Soft Shadow if _IsProp( IELP_SoftShadowEnabled ) then SoftShadow.Enabled := IEStr2BoolS( Value ) else if _IsProp( IELP_SoftShadowRadius ) then SoftShadow.Radius := StrToFloat( Value ) else if _IsProp( IELP_SoftShadowOffsetX ) then SoftShadow.OffsetX := StrToInt( Value ) else if _IsProp( IELP_SoftShadowOffsetY ) then SoftShadow.OffsetY := StrToInt( Value ) else if _IsProp( IELP_SoftShadowIntensity ) then SoftShadow.Intensity := StrToInt( Value ) else if _IsProp( IELP_SoftShadowColor ) then SoftShadow.ShadowColor := TColor2TRGB( StringToColor( Value )) else // TIEImageLayer if _IsProp( IELP_ImageResampleFilter ) and ( Self is TIEImageLayer ) then TIEImageLayer( Self ).fResampleFilter := TResampleFilter( StrToInt( Value )) else if _IsProp( IELP_ImageUseResampleFilter ) and ( Self is TIEImageLayer ) then TIEImageLayer( Self ).fUseResampleFilter := IEStr2BoolS( Value ) else if _IsProp( IELP_RestoreSize ) and ( Self is TIEImageLayer ) then TIEImageLayer( Self ).RestoreSize() else // TIEShapeLayer if _IsProp( IELP_Shape ) and ( Self is TIEShapeLayer ) then TIEShapeLayer( Self ).fShape := TIEShape( StrToInt( Value )) else if _IsProp( IELP_ShapeModifier ) and ( Self is TIEShapeLayer ) then TIEShapeLayer( Self ).fShapeModifier := StrToInt( Value ) else // TIELineLayer if _IsProp( IELP_LineColor ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLineColor := StringToColor( Value ) else if _IsProp( IELP_LineWidth ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLineWidth := StrToInt( Value ) else if _IsProp( IELP_LineFillColor ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLineFillColor := StringToColor( Value ) else if _IsProp( IELP_FontName ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelFont.Name := Value else if _IsProp( IELP_FontSize ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelFont.Size := StrToInt( Value ) else if _IsProp( IELP_FontColor ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelFont.Color := StringToColor( Value ) else if _IsProp( IELP_LabelText ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelText := Value else if _IsProp( IELP_LabelAlignment ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelAlignment := TIEAlignment( StrToInt( Value )) else if _IsProp( IELP_LabelPosition ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelPosition := TIELineLabelPos( StrToInt( Value )) else if _IsProp( IELP_BorderShape ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLabelShape := TIEShape( StrToInt( Value )) else if _IsProp( IELP_ReadOnly ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fReadOnly := IEStr2BoolS( Value ) else if _IsProp( IELP_LineEndShape ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fEndShape := TIELineEndShape( StrToInt( Value )) else if _IsProp( IELP_LineShapeSize ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fShapeSize := StrToInt( Value ) else if _IsProp( IELP_LineStartShape ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fStartShape := TIELineEndShape( StrToInt( Value )) else if _IsProp( IELP_LineLength ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).fLastLineLength := StrToInt( Value ) // NB: not fLineLength else if _IsProp( IELP_SizeToFit ) and ( Self is TIELineLayer ) then TIELineLayer( Self ).SizeToFit() else // TIEPolylineLayer if _IsProp( IELP_PolylinePoints ) and ( Self is TIEPolylineLayer ) then begin TIEPolylineLayer( Self ).ClearAllPoints(); pointStr := Value + ','; while pointStr <> '' do TIEPolylineLayer( Self ).AddPoint( _GetNextPoint( pointStr ), _GetNextPoint( pointStr )); end else if _IsProp( IELP_PolylineClosed ) and ( Self is TIEPolylineLayer ) then TIEPolylineLayer( Self ).fPolylineClosed := IEStr2BoolS( Value ) else // TIETextLayer if _IsProp( IELP_FontName ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).Font.Name := Value else if _IsProp( IELP_FontSize ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).Font.Size := StrToInt( Value ) else if _IsProp( IELP_FontColor ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).Font.Color := StringToColor( Value ) else if _IsProp( IELP_BorderShape ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fBorderShape := TIEShape( StrToInt( Value )) else if _IsProp( IELP_Text ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fText := Value else if _IsProp( IELP_AutoSize ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fAutoSize := IEStr2BoolS( Value ) else if _IsProp( IELP_ReadOnly ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fReadOnly := IEStr2BoolS( Value ) else if _IsProp( IELP_TextAlignment ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fAlignment := TIEAlignment( StrToInt( Value )) else if _IsProp( IELP_TextLayout ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).fLayout := TIELayout( StrToInt( Value )) else if _IsProp( IELP_SizeToFit ) and ( Self is TIETextLayer ) then TIETextLayer( Self ).SizeToText(); LayerChange(); except // conversion error end; end; {!! TIELayer.PreferredAspectRatio Declaration function PreferredAspectRatio(): Double; Description Returns the best ratio of Width/Height to display this layer. Some layer types look best at their original aspect ratio (i.e. the ratio of Height:Width). This is particularly true of images and some shapes. Result is 0 if this layer type does not have a preferred aspect ratio. Typical results: Portrait image: 0.67 Landscape image: 1.33 Star shape: 1 Text box: 0 (i.e. no preferred ratio) Example // Force aspect ratio locking if the object prefers it ImageEnView1.CurrentLayer.AspectRatioLocked := ImageEnView1.CurrentLayer.PreferredAspectRatio <> 0; See Also - - - !!} function TIELayer.PreferredAspectRatio(): Double; begin Result := 0; if Self is TIEImageLayer and not TIEImageLayer( Self ).Magnify.Enabled then Result := TIEImageLayer( Self ).Width / TIEImageLayer( Self ).Height else if Self is TIEShapeLayer then Result := IEShapePreferredAspectRatio( TIEShapeLayer( Self ).Shape ); end; {!! TIELayer.RestoreAspectRatio Declaration procedure RestoreAspectRatio(PreferredOnly: Boolean = True); Description Sizes the layer to restore its preferred or original aspect ratio (i.e. the ratio of Height:Width). Some layer types look best at their original aspect ratio. This is particularly true of images and some shapes. Calling RestoreAspectRatio will resize it (reducing its display size) to display it correctly. If PreferredOnly = True then it is only sized if it has a . If PreferredOnly = False and it does not have a then it is restored to its design size. Example // Fix the aspect ratio for the selected layer if it is an image if ImageEnView1.CurrentLayer is TIEImageLayer then ImageEnView1.CurrentLayer.RestoreAspectRatio(); ImageEnView1.Update(); // Create a layer at 50,50 and display an image (maintaining its aspect ratio) ImageEnView1.LockUpdate(); ImageEnView1.LayersAdd( 100, 100, ie24RGB, 50, 50 ); ImageEnView1.IO.LoadFromFile( 'D:\image.jpeg' ); ImageEnView1.CurrentLayer.RestoreAspectRatio(); ImageEnView1.UnlockUpdate(); See Also - - - - !!} procedure TIELayer.RestoreAspectRatio(PreferredOnly: Boolean = True); var aRect: TRect; aspectRatio: Double; imgWidth, imgHeight: Integer; begin if Self is TIEImageLayer then begin imgWidth := OriginalWidth; imgHeight := OriginalHeight; end else begin aspectRatio := PreferredAspectRatio; if ( aspectRatio = 0 ) and ( PreferredOnly = False ) then aspectRatio := fOriginalAspectRatio; imgWidth := Round( 1000 * aspectRatio ); imgHeight := 1000; end; if ( imgWidth < 1 ) or ( imgHeight < 1 ) then exit; aRect := GetImageRectWithinArea( imgWidth, imgHeight, Width, Height ); PosX := PosX + aRect.Left; PosY := PosY + aRect.Top; Width := aRect.Right - aRect.Left; Height := aRect.Bottom - aRect.Top; LayerChange(); end; {!! TIELayer.SupportsFeature Declaration function SupportsFeature(Feature: ): Boolean; Description Returns true if the specified feature is supported by this layer type Kind Description Supported By ielfBorder Layer has a border or line that can be adjusted using and All ielfFill Layer has a solid fill that can be adjusted using , (only if label or end shapes are visible), (only if =True), ielfGradient If the solid fill can be gradiated using and , (only if is set), ielfRotation Can be rotated by setting or using miRotateLayers All ielfMoveRotationCenter The center of layer rotation can be moved by setting or moving the center grip with miRotateLayers ielfTextEditing The layer has a text property and is not set to read-only , (only if is set)
Example // Show border color selector if layer type supports it btnSelBorder.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfBorder ); // Show fill color selector if layer type supports it btnSelFill.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfFill ); // Show gradient selector if layer type supports it btnGradient.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfGradient ); // Determine if the current layer type can be rotated canRotate := ImageEnView1.CurrentLayer.SupportsFeature( ielfRotation ); // Determine if the current layer type can be rotated canRotate := ImageEnView1.CurrentLayer.SupportsFeature( ielfRotation ); // Text can currently be edited for this layer edtText.Enabled := ImageEnView1.CurrentLayer.SupportsFeature( ielfTextEditing ); !!} function TIELayer.SupportsFeature(Feature: TIELayerFeatures): Boolean; begin Result := False; case Feature of ielfBorder : Result := fKind in [ ielkImage, ielkShape, ielkLine, ielkPolyline, ielkText ]; ielfFill : if fKind = ielkLine then Result := (( TIELineLayer( Self ).LabelText <> '' ) and ( TIELineLayer( Self ).LabelPosition <> ielpHide )) or ( TIELineLayer( Self ).StartShape <> ieesNone ) or ( TIELineLayer( Self ).EndShape <> ieesNone ) else if fKind = ielkPolyline then Result := TIEPolylineLayer( Self ).PolylineClosed else Result := fKind in [ ielkShape, ielkText ]; ielfGradient : if fKind = ielkLine then Result := ( TIELineLayer( Self ).LabelText <> '' ) and ( TIELineLayer( Self ).LabelPosition <> ielpHide ) else Result := fKind in [ ielkShape, ielkText ]; ielfRotation : Result := fKind in [ ielkImage, ielkShape, ielkLine, ielkPolyline, ielkText ]; ielfMoveRotationCenter : Result := fKind in [ ielkImage ]; ielfTextEditing : begin Result := Result; if fKind = ielkText then Result := not TIETextLayer( Self ).fReadOnly else if fKind = ielkLine then Result := ( TIELineLayer( Self ).fReadOnly = False ) and (( TIELineLayer( Self ).LabelRect.Left <> 0 ) or ( TIELineLayer( Self ).LabelRect.Right <> 0 )); // can only edit text if label is visible end; end; end; {!! TIELayer.Swap Declaration procedure Swap(OtherLayer: ); Description Swaps the content of two layers. Note: Both layers must be of the same layer type Example // Swap the current layer with the second one ImageEnView1.CurrentLayer.Swap( ImageEnView1.Layers[ 1 ]); ImageEnView1.Update(); !!} procedure TIELayer.Swap(OtherLayer: TIELayer); procedure IESwapLP(var a: TIELineLabelPos; var b: TIELineLabelPos); var t: TIELineLabelPos; begin t := a; a := b; b := t; end; procedure IESwapAS(var a: TIELineEndShape; var b: TIELineEndShape); var t: TIELineEndShape; begin t := a; a := b; b := t; end; procedure IESwapGD(var a: TIEGradientDir; var b: TIEGradientDir); var t: TIEGradientDir; begin t := a; a := b; b := t; end; procedure IESwapFQ(var a: TIEFontQuality; var b: TIEFontQuality); var t: TIEFontQuality; begin t := a; a := b; b := t; end; procedure IESwapAL(var a: TIEAlignment; var b: TIEAlignment); var t: TIEAlignment; begin t := a; a := b; b := t; end; procedure IESwapLY(var a: TIELayout; var b: TIELayout); var t: TIELayout; begin t := a; a := b; b := t; end; begin if Kind <> OtherLayer.Kind then raise EIEException.create( 'Layers must be of same type' ); IESwap( fResizedWidth, OtherLayer.fResizedWidth); IESwap( fResizedHeight, OtherLayer.fResizedHeight); IESwap( fVisible, OtherLayer.fVisible); IESwap( fVisibleBox, OtherLayer.fVisibleBox); IESwap( fSelectable, OtherLayer.fSelectable); IESwap( fTransparency, OtherLayer.fTransparency); IESwap( fOpacity, OtherLayer.fOpacity); IESwap( fPosX, OtherLayer.fPosX); IESwap( fPosY, OtherLayer.fPosY); IESwap( fCropped, OtherLayer.fCropped); IESwap( fLocked, OtherLayer.fLocked); IESwap( fOperation, OtherLayer.fOperation); IESwap( UserData, OtherLayer.UserData); IESwap( fUserDataLen, OtherLayer.fUserDataLen); IESwap( fName, OtherLayer.fName); IESwap( fIsMask, OtherLayer.fIsMask); IESwap( fDrawOuter, OtherLayer.fDrawOuter); IESwap( fGUID, OtherLayer.fGUID); IESwap( fAlphaEdgeFeathering, OtherLayer.fAlphaEdgeFeathering); IESwap( fGroupIndex, OtherLayer.fGroupIndex); IESwap( fSelected, OtherLayer.fSelected); IESwap( fAspectRatioLocked, OtherLayer.fAspectRatioLocked ); IESwap( fTag, OtherLayer.fTag); IESwap( fBorderColor, OtherLayer.fBorderColor ); IESwap( fBorderWidth, OtherLayer.fBorderWidth ); IESwap( fFillColor, OtherLayer.fFillColor ); IESwap( fFillColor2, OtherLayer.fFillColor2 ); IESwapGD( fFillGradient, OtherLayer.fFillGradient ); IESwap( fRotate, OtherLayer.fRotate ); IESwap( fRotateCenterX, OtherLayer.fRotateCenterX ); IESwap( fRotateCenterY, OtherLayer.fRotateCenterY ); IESwap( fAntiAlias, OtherLayer.fAntiAlias ); IESwap( fOriginalAspectRatio, OtherLayer.fOriginalAspectRatio ) ; // Soft shadow IESwap( softShadow.Enabled , OtherLayer.softShadow.Enabled); IESwap( softShadow.Radius , OtherLayer.softShadow.Radius); IESwap( softShadow.OffsetX , OtherLayer.softShadow.OffsetX); IESwap( softShadow.OffsetY , OtherLayer.softShadow.OffsetY); IESwap( softShadow.Intensity , OtherLayer.softShadow.Intensity); IESwap( softShadow.ShadowColor , OtherLayer.softShadow.ShadowColor); if ( OtherLayer is TIEImageLayer ) and ( Self is TIEImageLayer ) then with TIEImageLayer( Self ) do begin TIEImageLayer( OtherLayer ).fBitmap.SwitchTo(fBitmap); IESwap(fFreeBitmapOnDestroy, TIEImageLayer( OtherLayer ).fFreeBitmapOnDestroy); IESwap(Magnify, TIEImageLayer( OtherLayer ).Magnify); IESwap(fResampleFilter, TIEImageLayer( OtherLayer ).fResampleFilter); IESwap(fUseResampleFilter, TIEImageLayer( OtherLayer ).fUseResampleFilter); if assigned(fOwner) and assigned((fOwner as TImageEnView).fIEBitmap) and ((fOwner as TImageEnView).fIEBitmap = TIEImageLayer( OtherLayer ).fBitmap) then begin (fOwner as TImageEnView).fIEBitmap := fBitmap; if fBitmap.EncapsulatedFromTBitmap then (fOwner as TImageEnView).fBitmap := fBitmap.VclBitmap else (fOwner as TImageEnView).fBitmap := nil; end; end else if ( OtherLayer is TIEShapeLayer ) and ( Self is TIEShapeLayer ) then with TIEShapeLayer( Self ) do begin IESwap( fShape, TIEShapeLayer( OtherLayer ).fShape ); IESwap( fShapeModifier, TIEShapeLayer( OtherLayer ).fShapeModifier ); end else if ( OtherLayer is TIELineLayer ) and ( Self is TIELineLayer ) then with TIELineLayer( Self ) do begin IESwap( fAutoSize , TIELineLayer( OtherLayer ).fAutoSize ); IESwap( fLineColor , TIELineLayer( OtherLayer ).fLineColor ); IESwap( fLineWidth , TIELineLayer( OtherLayer ).fLineWidth ); IESwap( fLineFillColor , TIELineLayer( OtherLayer ).fLineFillColor ); IESwap( fLabelFont , TIELineLayer( OtherLayer ).fLabelFont ); IESwap( fLabelText , TIELineLayer( OtherLayer ).fLabelText ); IESwapAL( fLabelAlignment, TIELineLayer( OtherLayer ).fLabelAlignment ); IESwapLP( fLabelPosition , TIELineLayer( OtherLayer ).fLabelPosition ); IESwap( fLabelShape , TIELineLayer( OtherLayer ).fLabelShape ); IESwap( fReadOnly , TIELineLayer( OtherLayer ).fReadOnly ); IESwapAS( fStartShape , TIELineLayer( OtherLayer ).fStartShape ); IESwapAS( fEndShape , TIELineLayer( OtherLayer ).fEndShape ); IESwap( fShapeSize , TIELineLayer( OtherLayer ).fShapeSize ); IESwap( fLastLineLength , TIELineLayer( OtherLayer ).fLastLineLength ); end else if ( OtherLayer is TIEPolylineLayer ) and ( Self is TIEPolylineLayer ) then with TIEPolylineLayer( Self ) do begin // todo: @FAB: This code OK? IESwap( fPolyPoints , TIEPolylineLayer( OtherLayer ).fPolyPoints ); IESwap( fPolyPointCount , TIEPolylineLayer( OtherLayer ).fPolyPointCount ); IESwap( fPolyPointsAllocated , TIEPolylineLayer( OtherLayer ).fPolyPointsAllocated ); IESwap( fDrawnPoints , TIEPolylineLayer( OtherLayer ).fDrawnPoints ); IESwap( fDrawnPointCount , TIEPolylineLayer( OtherLayer ).fDrawnPointCount ); IESwap( fDrawnPointsAllocated , TIEPolylineLayer( OtherLayer ).fDrawnPointsAllocated ); IESwap( fPolylineClosed , TIEPolylineLayer( OtherLayer ).fPolylineClosed ); end else if ( OtherLayer is TIETextLayer ) and ( Self is TIETextLayer ) then with TIETextLayer( Self ) do begin IESwap( fFont, TIETextLayer( OtherLayer ).fFont ); IESwap( fBorderShape, TIETextLayer( OtherLayer ).fBorderShape ); IESwap( fText, TIETextLayer( OtherLayer ).fText ); IESwap( fAutoSize, TIETextLayer( OtherLayer ).fAutoSize ); IESwap( fReadOnly, TIETextLayer( OtherLayer ).fReadOnly ); IESwapAL( fAlignment, TIETextLayer( OtherLayer ).fAlignment ); IESwapLY( fLayout, TIETextLayer( OtherLayer ).fLayout ); end; LayerChange(); OtherLayer.LayerChange(); end; // Does not reset position! // Incompatible with old TIELayer.SaveInfo procedure TIELayer.SaveMetaToStream(Stream: TStream); var val, l: integer; begin l := Stream.Position; Stream.Write(l, sizeof(integer)); // Place holder. Descendent classes will fill with size val := IELayers_File_Version; Stream.Write( val, sizeof( integer )); // Save Version val := ord( Kind ); Stream.Write( val, sizeof( integer )); // Layer kind Stream.Write( fGUID, sizeof(TGuid)); val := Round( fResizedWidth ); Stream.Write( val, sizeof( integer )); val := Round( fResizedHeight ); Stream.Write( val, sizeof( integer )); Stream.Write( fVisible, sizeof(fVisible)); Stream.Write( fVisibleBox, sizeof(fVisibleBox)); Stream.Write( fSelectable, sizeof(fSelectable)); Stream.Write( fTransparency, sizeof(fTransparency)); Stream.Write( fOpacity, sizeof(fOpacity)); val := Trunc( fPosX ); Stream.Write( val, sizeof( Integer )); val := Trunc( fPosY ); Stream.Write( val, sizeof( Integer )); Stream.Write( fClientAreaBox, sizeof(fClientAreaBox)); Stream.Write( fCropped, sizeof(fCropped)); Stream.Write( fLocked, sizeof(fLocked)); Stream.Write( fOperation, sizeof(fOperation)); Stream.Write( fUserDataLen, sizeof(fUserDataLen)); if (UserData <> nil) and (fUserDataLen > 0) then Stream.Write(pbyte(UserData)^, fUserDataLen); IESaveStringToStreamW(Stream, fName); Stream.Write( fIsMask, sizeof(fIsMask)); Stream.Write( fDrawOuter, sizeof(fDrawOuter)); Stream.Write( fRotate, sizeof(double)); Stream.Write( fRotateCenterX, sizeof(double)); Stream.Write( fRotateCenterY, sizeof(double)); Stream.Write( fAlphaEdgeFeathering, sizeof(fAlphaEdgeFeathering)); Stream.Write( fSelected, sizeof(boolean)); Stream.Write( fGroupIndex, sizeof(integer)); Stream.Write( fAspectRatioLocked, SizeOf( Boolean )); Stream.Write( fAntiAlias, SizeOf( Boolean )); Stream.Write( fOriginalAspectRatio, SizeOf( Double )); Stream.Write( fTag, SizeOf( Integer )); Stream.Write( fBorderColor, SizeOf( TColor )); Stream.Write( fBorderWidth, SizeOf( Integer )); Stream.Write( fFillColor, SizeOf( TColor )); Stream.Write( fFillColor2, SizeOf( TColor )); Stream.Write( fFillGradient, SizeOf( TIEGradientDir )); // Soft shadow Stream.Write( softShadow.Enabled, sizeof(boolean)); Stream.Write( softShadow.Radius, sizeof(double)); Stream.Write( softShadow.OffsetX, sizeof(integer)); Stream.Write( softShadow.OffsetY, sizeof(integer)); Stream.Write( softShadow.Intensity, sizeof(integer)); Stream.Write( softShadow.ShadowColor, sizeof(TRGB)); end; // Ensure code match with TIELayer.LoadMetaFromStream procedure ReadLayerPropsFromStream(Stream: TStream; ResetPos: Boolean; // Position Stream after read to inital pos out RecSize: Integer; // Total size of layer data block out LayerKind: TIELayerKind; // Type of layer out GUID: TGuid); // Layer identifier var l, val, ver: integer; begin l := Stream.Position; Stream.Read( RecSize, sizeof( Integer )); // Size Stream.Read( ver, sizeof( Integer )); // Version Stream.Read( val, sizeof( Integer )); // Layer Kind LayerKind := TIELayerKind( val ); Stream.Read(GUID, sizeof(TGuid)); // Identifier if ResetPos then Stream.Position := l; end; // Incompatible with old TIELayer.LoadInfo // Returns layer save version function TIELayer.LoadMetaFromStream(Stream: TStream): Integer; var val: integer; begin Stream.Read( fLayerSize, sizeof(fLayerSize)); // Size Stream.Read( Result, sizeof( Integer )); // Version Stream.Read( val, sizeof( Integer )); // Layer Kind - don't store Stream.Read( fGUID, sizeof(TGuid)); Stream.Read( val, sizeof( Integer )); fResizedWidth := val; Stream.Read( val, sizeof( Integer )); fResizedHeight := val; Stream.Read( fVisible, sizeof(fVisible)); Stream.Read( fVisibleBox, sizeof(fVisibleBox)); Stream.Read( fSelectable, sizeof(fSelectable)); Stream.Read( fTransparency, sizeof(fTransparency)); Stream.Read( fOpacity, sizeof(fOpacity)); Stream.Read( val, sizeof( Integer )); fPosX := val; Stream.Read( val, sizeof( Integer )); fPosY := val; Stream.Read( fClientAreaBox, sizeof(fClientAreaBox)); Stream.Read( fCropped, sizeof(fCropped)); Stream.Read( fLocked, sizeof(fLocked)); Stream.Read( fOperation, sizeof(fOperation)); if ( fUserDataLen > 0 ) and ( UserData <> nil ) then begin freemem( UserData ); fUserDataLen := 0; UserData := nil; end; Stream.Read( fUserDataLen, sizeof( fUserDataLen )); if fUserDataLen > 0 then begin getmem( UserData, fUserDataLen); Stream.Read(pbyte(UserData)^, fUserDataLen); end; IELoadStringFromStreamW(Stream, fName); Stream.Read( fIsMask, sizeof(fIsMask)); Stream.Read( fDrawOuter, sizeof(fDrawOuter)); Stream.Read( fRotate, sizeof(double)); Stream.Read( fRotateCenterX, sizeof(double)); Stream.Read( fRotateCenterY, sizeof(double)); Stream.Read( fAlphaEdgeFeathering, sizeof(fAlphaEdgeFeathering)); Stream.Read( fSelected, SizeOf( Boolean )); Stream.Read( fGroupIndex, sizeof(Integer)); Stream.Read( fAspectRatioLocked, SizeOf( Boolean )); Stream.Read( fAntiAlias, SizeOf( Boolean )); Stream.Read( fOriginalAspectRatio, SizeOf( Double )); if Result >= 7001 then Stream.Read( fTag, SizeOf( Integer )); Stream.Read( fBorderColor, SizeOf( TColor )); Stream.Read( fBorderWidth, SizeOf( Integer )); Stream.Read( fFillColor, SizeOf( TColor )); Stream.Read( fFillColor2, SizeOf( TColor )); Stream.Read( fFillGradient, SizeOf( TIEGradientDir )); // Soft shadow Stream.Read( softShadow.Enabled, sizeof(boolean)); Stream.Read( softShadow.Radius, sizeof(double)); Stream.Read( softShadow.OffsetX, SizeOf( integer )); Stream.Read( softShadow.OffsetY, SizeOf( integer )); Stream.Read( softShadow.Intensity, sizeof(integer)); Stream.Read( softShadow.ShadowColor, sizeof(TRGB)); LayerChange(); end; procedure TIELayer.LoadFromLegacyStream(Stream: TStream; HdrVersion: Integer; FileFormat: TIOFileType); var val: Integer; poslo, poshi: Dword; p1: int64; ms: TMemoryStream; dw: Dword; LZStream: TZDecompressionStream; lnative: Boolean; {$ifndef IEIncludeDeprecatedInV6} dummy: TIEMagnifyStyle; dummy2: TIEMagnifySource; dummy3: TResampleFilter; {$ENDIF} ansiName: AnsiString; iev: TImageEnView; begin if not assigned( fOwner ) then raise EIEException.create( 'Onwer not assigned' ); iev := TImageEnView( fOwner ); Stream.Read( fVisible, sizeof(boolean)); Stream.Read( fVisibleBox, sizeof(boolean)); Stream.Read( fTransparency, sizeof(integer)); if HdrVersion >= 7 then Stream.Read( fOpacity, sizeof(double)); Stream.Read( val, sizeof( integer )); fPosX := val; Stream.Read( val, sizeof( integer )); fPosY := val; Stream.Read( fCropped, sizeof(boolean)); Stream.Read( fLocked, sizeof(boolean)); {$ifdef IEIncludeDeprecatedInV6} // Magnify moved to TIEImageLayer class in 7.0.0 (2016-10-26) Stream.Read( Magnify.Enabled, sizeof(boolean)); Stream.Read( Magnify.Rate, sizeof(double)); Stream.Read( Magnify.Style, sizeof(TIEMagnifyStyle)); if HdrVersion >= 3 then Stream.Read( Magnify.Source, sizeof(TIEMagnifySource)); {$ELSE} Stream.Read( bval, sizeof(boolean)); Stream.Read( dval, sizeof(double)); Stream.Read( dummy, sizeof(TIEMagnifyStyle)); if HdrVersion >= 3 then Stream.Read( dummy2, sizeof(TIEMagnifySource)); {$ENDIF} Stream.Read( fOperation, sizeof(TIERenderOperation)); Stream.Read( val, sizeof( integer )); WidthD := val; Stream.Read( val, sizeof( integer )); HeightD := val; if HdrVersion >= 3 then begin {$ifdef IEIncludeDeprecatedInV6} // ResampleFilter moved to TIEImageLayer class in 7.0.0 (2016-10-26) Stream.Read( fResampleFilter, sizeof(TResampleFilter)); Stream.Read( fUseResampleFilter, sizeof(boolean)); {$ELSE} Stream.Read( dummy3, sizeof(TResampleFilter)); Stream.Read( bval, sizeof(boolean)); {$ENDIF} IELoadStringFromStream(Stream, ansiName); fName := string( ansiName ); if ( fUserDataLen > 0) and ( UserData <> nil ) then begin freemem( UserData ); fUserDataLen := 0; UserData := nil; end; Stream.Read( fUserDataLen, sizeof(integer)); if fUserDataLen > 0 then begin getmem( UserData, fUserDataLen); Stream.Read(pbyte( UserData )^, fUserDataLen); end; Stream.Read(fIsMask, sizeof(boolean)); end; if HdrVersion >= 4 then Stream.Read( fSelectable, sizeof(boolean)); if HdrVersion >= 6 then Stream.Read( fDrawOuter, sizeof(Boolean)); if HdrVersion >= 8 then Stream.Read( fAlphaEdgeFeathering, SizeOf(Integer)); if HdrVersion >= 9 then begin Stream.Read( fRotateCenterX, sizeof(Double)); Stream.Read( fRotateCenterY, sizeof(Double)); Stream.Read( fRotate, sizeof(Double)); end; if HdrVersion >= 9 then begin Stream.Read( fGroupIndex, sizeof(Integer)); Stream.Read( fSelected, sizeof(Boolean)); end; fClientAreaBox := Rect(0, 0, 0, 0); Stream.Read(poslo, sizeof(dword)); Stream.Read(poshi, sizeof(dword)); p1 := Stream.Position; Stream.Position := poslo+(poshi shl 32); iev.LayersCurrent := iev.LayersCount; if (FileFormat = -1) or (FileFormat = -2) then begin // use internal file format Stream.Read(dw, sizeof(dword)); // compressed stream size ms := TMemoryStream.Create; try ms.SetSize(dw); // to speed up loading if dw > 0 then IECopyFrom(ms, Stream, dw); ms.Position := 0; if FileFormat = -1 then begin LZStream := TZDecompressionStream.Create(ms); try iev.fIEBitmap.LoadRAWFromBufferOrStream(nil, LZStream); finally FreeAndNil(LZStream); end; end else iev.fIEBitmap.LoadRAWFromBufferOrStream(nil, ms); finally FreeAndNil(ms); end; end else begin // use standard file formats lnative := iev.IO.NativePixelFormat; if fIsMask then iev.IO.NativePixelFormat := true; iev.IO.LoadFromStream(Stream, FileFormat); iev.IO.NativePixelFormat := lnative; end; fModified := False; Stream.Position := p1; end; {!! TIELayer.PosX Declaration property PosX: Integer; Description Specifies the horizontal position of the layer relative to the background image (layer 0). These consts are also supported: Const Description IELayer_Pos_Left Adjust PosX so layer is aligned to the left of the background layer IELayer_Pos_HCenter Adjust PosX so layer is aligned to the horizontal center of the background layer IELayer_Pos_Right Adjust PosX so layer is aligned to the right of the background layer
Example // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 'Arial Black', 42, clRed, [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; See Also -
!!} function TIELayer.GetPosX: integer; begin Result := Trunc( fPosX ); end; procedure TIELayer.SetPosX(v: integer); begin if v < IELayer_Pos_Left then fPosX := v else if ( fOwner = nil ) or ( TImageEnView( fOwner ).Layers[ 0 ].Width < 2 ) then fPosX := 0 else if v = IELayer_Pos_Left then fPosX := TImageEnView( fOwner ).Layers[ 0 ].PosX else if v = IELayer_Pos_HCenter then fPosX := TImageEnView( fOwner ).Layers[ 0 ].PosX + ( TImageEnView( fOwner ).Layers[ 0 ].Width - Width ) div 2 else if v = IELayer_Pos_Right then fPosX := TImageEnView( fOwner ).Layers[ 0 ].PosX + TImageEnView( fOwner ).Layers[ 0 ].Width - Width; // Call LayerChange without resetting the layer cache LayerChange( False ); end; {!! TIELayer.PosY Declaration property PosY: Integer; Description Specifies the vertical position of the layer relative to the background image (layer 0). These consts are also supported: Const Description IELayer_Pos_Top Adjust PosY so layer is aligned to the top of the background layer IELayer_Pos_VCenter Adjust PosY so layer is aligned to the vertical center of the background layer IELayer_Pos_Bottom Adjust PosY so layer is aligned to the bottom of the background layer
Example // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 'Arial Black', 42, clRed, [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; See Also -
!!} function TIELayer.GetPosY: integer; begin Result := Trunc( fPosY ); end; procedure TIELayer.SetPosY(v: integer); begin if v < IELayer_Pos_Top then fPosY := v else if ( fOwner = nil ) or ( TImageEnView( fOwner ).Layers[ 0 ].Height < 2 ) then fPosY := 0 else if v = IELayer_Pos_Top then fPosY := TImageEnView( fOwner ).Layers[ 0 ].PosY else if v = IELayer_Pos_VCenter then fPosY := TImageEnView( fOwner ).Layers[ 0 ].PosY + ( TImageEnView( fOwner ).Layers[ 0 ].Height - Height ) div 2 else if v = IELayer_Pos_Bottom then fPosY := TImageEnView( fOwner ).Layers[ 0 ].PosY + TImageEnView( fOwner ).Layers[ 0 ].Height - Height; // Call LayerChange without resetting the layer cache LayerChange( False ); end; {!! TIELayer.Width Declaration property Width: Integer; Description Specifies the layer size (i.e. display width when zoom is 100%). Example // Make all selected layers 1/3 size ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then begin ImageEnView1.Layers[ I ].Width := ImageEnView1.Layers[ I ].Width div 3; ImageEnView1.Layers[ I ].Height := ImageEnView1.Layers[ I ].Height div 3; end; ImageEnView1.LayersFixSizes( LYR_SELECTED_LAYERS ); ImageEnView1.UnlockUpdate; See Also - - - !!} function TIELayer.GetWidth: integer; begin if ( Self is TIEImageLayer ) and ( fResizedWidth = 0 ) then result := TIEImageLayer( Self ).fBitmap.Width else result := iMax( 1, Round( fResizedWidth )); end; procedure TIELayer.SetWidth(v: integer); begin SetWidthD( v ); end; procedure TIELayer.SetWidthD(v: Double); var changedVal: Boolean; begin changedVal := Round( fResizedWidth ) <> Round ( v ); fResizedWidth := v; if changedVal then begin if Self is TIELineLayer then TIELineLayer( Self ).fLastLineLength := -1; LayerChange(); end; end; {!! TIELayer.Height Declaration property Height: Integer; Description Specifies the layer size (i.e. display height when zoom is 100%). Example // Make all selected layers 1/3 size ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then begin ImageEnView1.Layers[ I ].Width := ImageEnView1.Layers[ I ].Width div 3; ImageEnView1.Layers[ I ].Height := ImageEnView1.Layers[ I ].Height div 3; end; ImageEnView1.LayersFixSizes( LYR_SELECTED_LAYERS ); ImageEnView1.UnlockUpdate; See Also - - - !!} function TIELayer.GetHeight: integer; begin if ( Self is TIEImageLayer ) and ( fResizedHeight = 0 ) then result := TIEImageLayer( Self ).fBitmap.Height else result := iMax( 1, Round( fResizedHeight )); end; procedure TIELayer.SetHeight(v: integer); begin SetHeightD( v ); end; procedure TIELayer.SetHeightD(v: Double); var changedVal: Boolean; begin changedVal := Round( fResizedHeight ) <> Round ( v ); fResizedHeight := v; if changedVal then begin if Self is TIELineLayer then TIELineLayer( Self ).fLastLineLength := -1; LayerChange(); end; end; // Returns the size of the bitmap.width if an image layer, otherwise the user's specified size for the object function TIELayer.GetOriginalWidth: integer; begin if Self is TIEImageLayer then result := TIEImageLayer( Self ).fBitmap.Width else result := iMax( 1, Round( fResizedWidth )); end; // Returns the size of the bitmap.height if an image layer, otherwise the user's specified size for the object function TIELayer.GetOriginalHeight: integer; begin if Self is TIEImageLayer then result := TIEImageLayer( Self ).fBitmap.Height else result := iMax( 1, Round( fResizedHeight )); end; {!! TIELayer.AspectRatioLocked Declaration property AspectRatioLocked: Boolean; Description When enabled the for the layer will be enforced regardless of the setting for . Default: False Example // Force aspect ratio locking if the object prefers it ImageEnView1.CurrentLayer.AspectRatioLocked := ImageEnView1.CurrentLayer.PreferredAspectRatio <> 0; ImageEnView1.Update(); !!} procedure TIELayer.SetAspectRatioLocked(const Value: Boolean); begin fAspectRatioLocked := Value; if Value then begin if Self is TIEPolylineLayer then RestoreAspectRatio( False ) else RestoreAspectRatio( True ); end; LayerChange( False ); end; procedure TIELayer.SetIsMask(const Value: Boolean); begin if Value and (( Self is TIEImageLayer ) = False ) then raise EIEException.create( 'IsMask can only be applied to TIEImageLayer' ); fIsMask := Value; LayerChange(); end; {!! TIELayer.Rotate Declaration property Rotate: Double; Description Specifies the layer rotation angle in degrees counter-clockwise. Rotation and Resize cannot be used at the same time. To allow resize after a layer rotation, it must be enacted, i.e. actually rotate the bitmap. Conversely to allow rotation after a resize, the resizing must be enacted, actually resizing the bitmap. To enact layer rotation, call . To enact layer resizing, call . Finally, multiple rotations can cause the bitmap to add an external, transparent border. To remove this border call . Note: When rotation is handled by (setting miRotateLayers), you don't need to call LayersFixRotations, LayersFixSizes and LayersFixBorders. Examples // Rotate a line ImageEnView1.CurrentLayer.Rotate := 235; ImageEnView1.Update(); // Set rotation of all selected layers ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then ImageEnView1.Layers[ I ].Rotate := 90; ImageEnView1.LayersFixRotations( LYR_SELECTED_LAYERS ); ImageEnView1.UnlockUpdate; // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 'Arial Black', 42, clRed, [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; Demos Demos\ImageEditing\Layers\Layers.dpr Demos\ImageEditing\Layers_AllTypes\Layers.dpr Demos\ImageEditing\RotateLayers\RotateLayers.dpr See Also - - !!} procedure TIELayer.SetRotate(v: Double); begin if (frac(v) = 0) and (trunc(v) mod 360 = 0) then fRotate := 0 else fRotate := v; while fRotate > 360 do fRotate := fRotate - 360; while fRotate < -360 do fRotate := fRotate + 360; LayerChange(); if ( Self is TIETextLayer ) and TIETextLayer( Self ).AutoSize then TIETextLayer( Self ).SizeToText() else if ( Self is TIELineLayer ) and TIELineLayer( Self ).AutoSize then TIELineLayer( Self ).SizeToFit(); end; {!! TIELayer.RotateCenterX Declaration property RotateCenterX: Double; Description Specifies the horizontal rotation center, in percentage of layer size. 0.5 means center (default), while 0 is left side and 1 is right side. Also allowed are values less than 0 and greater than 1 (e.g. 2 would rotate at one width to the right of the image). This value (and ) is modified when user moves the central grip, when layers rotation is active. Note: Applies only to Default: 0.5 Example // Move rotation center to 25% in from top-left corner ImageEnView1.CurrentLayer.RotateCenterX := 0.25; ImageEnView1.CurrentLayer.RotateCenterY := 0.25; ImageEnView1.Update(); See Also - - !!} procedure TIELayer.SetRotateCenterX(v: Double); begin fRotateCenterX := v; LayerChange(); end; {!! TIELayer.RotateCenterY Declaration property RotateCenterY: Double; Description Specifies the vertical rotation center, in percentage of layer size. 0.5 means center (default), while 0 is top side and 1 is bottom side. Also allowed are values less than 0 and greater than 1 (e.g. 2 would rotate at one height below the image). This value (and ) is modified when user moves the central grip, when layers rotation is active. Note: Applies only to Default: 0.5 Example // Move rotation center to 25% in from top-left corner ImageEnView1.CurrentLayer.RotateCenterX := 0.25; ImageEnView1.CurrentLayer.RotateCenterY := 0.25; ImageEnView1.Update(); See Also - - !!} procedure TIELayer.SetRotateCenterY(v: Double); begin fRotateCenterY := v; LayerChange(); end; procedure TIELayer.SetSelected(const Value: boolean); var ieview : TImageEnView; begin ieview := (fOwner as TImageEnView); if assigned(ieview) then begin if loAllowMultiSelect in ieview.LayerOptions then if fSelected <> Value then begin fSelected := Value; ieview.CallBitmapChangeEvents; ieview.Update; end; end; end; {!! TIELayer.ConvXScr2Bmp Declaration function ConvXScr2Bmp(x: Integer): Integer; Description Converts screen coordinates to bitmap coordinates, with consideration to the layer position and size. See Also - - - - !!} function TIELayer.ConvXScr2Bmp(x: Integer): Integer; var ieview: TImageEnView; begin result := 0; ieview := (fOwner as TImageEnView); if assigned(ieview) and (Width <> 0) then // note 1.0 required to make operation as double (otherwise overflow may occur) result := trunc( 1.0 * ieview.XScr2Bmp(x - trunc( PosX * ieview.ZoomX / 100 ), false) * GetOriginalWidth / Width ); end; {!! TIELayer.ConvYScr2Bmp Declaration function ConvYScr2Bmp(y: Integer): Integer; Description Converts screen coordinates to bitmap coordinates, with consideration to the layer position and size. See Also - - - - !!} function TIELayer.ConvYScr2Bmp(y: Integer): Integer; var ieview: TImageEnView; begin result := 0; ieview := (fOwner as TImageEnView); if assigned(ieview) and (Height <> 0) then // note 1.0 required to make operation as double (otherwise overflow may occur) result := trunc( 1.0 * ieview.YScr2Bmp(y - trunc( PosY * ieview.ZoomY / 100 ), false) * GetOriginalHeight / Height ); end; {!! TIELayer.ConvXBmp2Scr Declaration function ConvXBmp2Scr(x: Integer): Integer; Description Converts bitmap coordinates to screen coordinates, with consideration to the layer position and size. See Also - - - - !!} function TIELayer.ConvXBmp2Scr(x: Integer): Integer; var ieview: TImageEnView; bmpW: Integer; begin result := 0; ieview := (fOwner as TImageEnView); bmpW := GetOriginalWidth; if assigned(ieview) and ( bmpW > 0 ) then // note 1.0 required to make operation as double (otherwise overflow may occur) result := ieview.XBmp2Scr(trunc(1.0 * x * Width / bmpW), false) + trunc( PosX * ieview.ZoomX / 100 ); end; {!! TIELayer.ConvYBmp2Scr Declaration function ConvYBmp2Scr(y: Integer): Integer; Description Converts bitmap coordinates to screen coordinates, with consideration to the layer position and size. See Also - - - - !!} function TIELayer.ConvYBmp2Scr(y: Integer): Integer; var ieview: TImageEnView; bmpH: Integer; begin result := 0; ieview := (fOwner as TImageEnView); bmpH := GetOriginalHeight; if assigned(ieview) and ( bmpH > 0 ) then // note 1.0 required to make operation as double (otherwise overflow may occur) result := ieview.YBmp2Scr(trunc(1.0 * y * Height / bmpH), false) + trunc( PosY * ieview.ZoomY / 100 ); end; procedure TIELayer.CalcClientAreaBox(); var ieview: TImageEnView; lyrX, lyrY, lyrW, lyrH: integer; {} function AlignXBmp2Scr(v: integer; ref: integer): integer; begin if TImageEnView( fOwner ).XScr2Bmp(v, false) < ref then result := v + 1 else if ieview.XScr2Bmp(v, false) > ref then result := v - 1 else result := v; end; {} function AlignYBmp2Scr(v: integer; ref: integer): integer; begin if TImageEnView( fOwner ).YScr2Bmp(v, false) < ref then result := v + 1 else if ieview.YScr2Bmp(v, false) > ref then result := v - 1 else result := v; end; {} begin ieview := TImageEnView( fOwner ); if not assigned( ieview ) then exit; lyrX := ieview.XBmp2Scr(PosX, false); lyrX := AlignXBmp2Scr(lyrX, PosX); lyrY := ieview.YBmp2Scr(PosY, false); lyrY := AlignYBmp2Scr(lyrY, PosY); lyrW := ieview.XBmp2Scr(PosX + GetWidth, false); lyrW := AlignXBmp2Scr(lyrW, PosX + GetWidth); dec(lyrW, lyrX); lyrH := ieview.YBmp2Scr(PosY + GetHeight, false); lyrH := AlignYBmp2Scr(lyrH, PosY + GetHeight); dec(lyrH, lyrY); fClientAreaBox := Rect(lyrX, lyrY, lyrX + lyrW, lyrY + lyrH); end; // ScaleToZoom: Vector layers are created at zoom level rather than design level procedure TIELayer.CalcPaintPos(ImgWidth, ImgHeight: Integer; out XDst, YDst, WidthDst, HeightDst: integer; out XSrc, YSrc, WidthSrc, HeightSrc: integer); var ieview: TImageEnView; currW, currH: Integer; layer0Left, layer0Top, layer0Right, layer0Bottom: Integer; begin ieview := TImageEnView( fOwner ); if not assigned( ieview ) then exit; XDst := fClientAreaBox.Left; YDst := fClientAreaBox.Top; WidthDst := fClientAreaBox.Right - XDst; HeightDst := fClientAreaBox.Bottom - YDst; XSrc := 0; YSrc := 0; WidthSrc := ImgWidth; HeightSrc := ImgHeight; if fCropped or ieview.LayersCropped then begin currW := GetWidth; currH := GetHeight; layer0Left := ieview.Layers[0].PosX; layer0Top := ieview.Layers[0].PosY; layer0Right := ieview.Layers[0].PosX + ieview.Layers[0].Width; layer0Bottom := ieview.Layers[0].PosY + ieview.Layers[0].Height; // cropped if ieview.XScr2Bmp(XDst, false) < layer0Left then begin XSrc := - trunc(( PosX - layer0Left ) * ( ImgWidth / currW )); WidthSrc := ImgWidth - XSrc; XDst := ieview.XBmp2Scr( layer0Left, false ); WidthDst := ieview.XBmp2Scr( currW + PosX, false ) - XDst; end; if ieview.YScr2Bmp(YDst, false) < layer0Top then begin YSrc := - trunc(( PosY - layer0Top ) * ( ImgHeight / currH )); HeightSrc := ImgHeight - YSrc; YDst := ieview.YBmp2Scr( layer0Top, false ); HeightDst := ieview.YBmp2Scr( currH + PosY, false ) - YDst; end; if ieview.XScr2Bmp(XDst + WidthDst, false) > layer0Right then begin WidthDst := ieview.XBmp2Scr( layer0Right, false ) - XDst; WidthSrc := trunc(WidthDst * ( ImgWidth / (fClientAreaBox.Right - fClientAreaBox.Left))); end; if ieview.YScr2Bmp(YDst + HeightDst, false) > layer0Bottom then begin HeightDst := ieview.YBmp2Scr( layer0Bottom, false ) - YDst; HeightSrc := trunc(HeightDst * ( ImgHeight / (fClientAreaBox.Bottom - fClientAreaBox.Top ))); end; end; fDrawingInfo.XDst := XDst; fDrawingInfo.YDst := YDst; fDrawingInfo.WidthDst := WidthDst; fDrawingInfo.HeightDst := HeightDst; fDrawingInfo.XSrc := XSrc; fDrawingInfo.YSrc := YSrc; fDrawingInfo.WidthSrc := WidthSrc; fDrawingInfo.HeightSrc := HeightSrc; {$IFDEF IEDEBUG} OutputDebugStringA(PAnsiChar('TIELayer.PaintTo')); OutputDebugStringA(PAnsiChar(string( ' XDst='+IntToStr(lXDst)+' YDst='+IntToStr(lYDst)+ ' WidthDst='+IntToStr(WidthDst)+' HeightDst='+IntToStr(HeightDst)+ ' XSrc='+IntToStr(lXSrc)+' YSrc='+IntToStr(lYSrc)+ ' WidthSrc='+IntToStr(WidthSrc)+' HeightSrc='+IntToStr(HeightSrc) ))); {$ENDIF} end; procedure TIELayer.PaintTo(DstBitmap: TIEBitmap; LyrIdx: Integer; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter; RotationFilter: TIEAntialiasMode; ResizingLayer: Boolean); var lXSrc, lYSrc, lWidthSrc, lHeightSrc: integer; lXDst, lYDst, lWidthDst, lHeightDst: integer; dummy1, dummy2: PInteger; fastDrawing: Boolean; createWidth, createHeight: Integer; layersCaching: Boolean; function _CacheAvailable(CWidth, CHeight: Integer) : boolean; begin Result := layersCaching and assigned ( fLayerCacheBitmap ) and fLayerCacheValid and ( fLayerCacheBitmap.Width = CWidth ) and ( fLayerCacheBitmap.Height = CHeight ); end; begin if fOriginalAspectRatio = 0 then fOriginalAspectRatio := OriginalWidth / OriginalHeight; CalcClientAreaBox(); fastDrawing := Owner_FastDrawingActive(); layersCaching := False; if assigned( fOwner ) then layersCaching := ( TImageEnView( fOwner ).LayersCaching = -1 ) or ( LyrIdx < TImageEnView( fOwner ).LayersCaching ); createWidth := GetWidth; createHeight := GetHeight; if assigned( fOwner ) and ( layersCaching or not fastDrawing ) then begin // Scale to zoom createWidth := Round( createWidth * TImageEnView( fOwner ).ZoomX / 100 ); createHeight := Round( createHeight * TImageEnView( fOwner ).ZoomY / 100 ); end; CalcPaintPos(createWidth, createHeight, lXDst, lYDst, lWidthDst, lHeightDst, lXSrc, lYSrc, lWidthSrc, lHeightSrc); if fAntiAlias and ( Kind = ielkShape ) then if ( fastDrawing = False ) or ( FastDrawing and _CacheAvailable( 2 * createWidth, 2 * createHeight ) and not fLayerCachefastDrawn) then begin createWidth := 2 * createWidth; createHeight := 2 * createHeight; lXSrc := 2 * lXSrc; lYSrc := 2 * lYSrc; lWidthSrc := 2 * lWidthSrc; lHeightSrc := 2 * lHeightSrc ; if Filter = rfNone then Filter := rfFastLinear; end; dummy1 := nil; dummy2 := nil; if layersCaching then begin // If we want high quality and cache bitmap is low quality then redraw if ( fastDrawing = False ) and assigned ( fLayerCacheBitmap ) and fLayerCachefastDrawn then fLayerCacheValid := False; if _CacheAvailable( createWidth, createHeight ) = False then begin // cache image is not valid CopyToBitmapEx( fLayerCacheBitmap, createWidth, createHeight, fastDrawing, EnableAlpha, False ); fLayerCachefastDrawn := fastDrawing; end; RenderLayerWithAdornments(DstBitmap, LyrIdx, fLayerCacheBitmap, True, dummy1, dummy2, UpdRect, lXDst, lYDst, lWidthDst, lHeightDst, lXSrc, lYSrc, lWidthSrc, lHeightSrc, EnableAlpha, SolidBackground, Filter ); fLayerCacheValid := True; end else begin CopyToBitmapEx( fGlobalCacheBitmap, createWidth, createHeight, fastDrawing, EnableAlpha, False ); RenderLayerWithAdornments(DstBitmap, LyrIdx, fGlobalCacheBitmap, True, dummy1, dummy2, UpdRect, lXDst, lYDst, lWidthDst, lHeightDst, lXSrc, lYSrc, lWidthSrc, lHeightSrc, EnableAlpha, SolidBackground, Filter ); end; end; {!! TIELayer.GetLayerMask Declaration function GetLayerMask(): ; Description Returns the layer mask associated with this layer. Returns "nil" if no layer mask exists. !!} function TIELayer.GetLayerMask(): TIELayer; var ieview: TImageEnView; idx: integer; begin result := nil; ieview := (fOwner as TImageEnView); if assigned(ieview) then begin idx := GetIndex(); if (idx > - 1) and (idx + 1 < ieview.LayersList.Count) and (ieview.Layers[idx + 1].IsMask) then result := ieview.Layers[idx + 1]; end; end; {!! TIEImageLayer.IsMask Declaration property IsMask: Boolean; Description If True this is a layer mask. A layer mask contains a gray scale image (ie8g) which is connected to the upper layer (i.e. if Layer 3 is a mask, then it will apply to layer 2). The layer mask specifies what parts of the upper layer is visible (i.e. mask pixels of 0 will hide the underlying image. Whereas, pixels of 255 will be fully visible). A layer mask should be invisible (=False). // This is an example of a mask image (right-click to save to file). The black areas will become fully transparent in the underlying image. The gray will have 50% transparency and the white will be fully opaque. Default: False Notes: - This property is only valid for image layers - Mask layers will only affect image layers Example // Clear and load our image into Layer 0 ImageEnView1.ClearAll(); ImageEnView1.IO.LoadFromFile( 'C:\Image.jpg' ); // Now add our mask layer ImageEnView1.LayersAdd( ielkImage ); ImageEnView1.IO.LoadFromFile( 'C:\Mask.png' ); TIEImageLayer( ImageEnView1.CurrentLayer ).IsMask := True; ImageEnView1.CurrentLayer.Visible := False; ImageEnView1.CurrentLayer.PosX := 0; ImageEnView1.CurrentLayer.PosY := 0; ImageEnView1.CurrentLayer.Width := ImageEnView1.Layers[0].Width; ImageEnView1.CurrentLayer.Height := ImageEnView1.Layers[0].Height; Source Image: Mask Image: Result (on a white TImageEnView): !!} function TIELayer.GetIsMask: Boolean; begin Result := False; if Self is TIEImageLayer then Result := fIsMask; end; {!! TIELayer.Selected Declaration property Selected: boolean; Description True if the layer is currently selected. A selected text layer: !!} function TIELayer.GetSelected: boolean; var ieview: TImageEnView; begin ieview := (fOwner as TImageEnView); if assigned(ieview) then begin if loAllowMultiSelect in ieview.LayerOptions then Result := fSelected else Result := ieview.LayersList.IndexOf(self) = ieview.LayersCurrent; end else result := false; end; {!! TIELayer.GetIndex Declaration function GetIndex(): integer; Description Returns the index of this layer inside the list. Returns -1 if not found. !!} // -1 = not found function TIELayer.GetIndex(): integer; var ieview: TImageEnView; begin ieview := (fOwner as TImageEnView); if assigned(ieview) then result := ieview.LayersList.IndexOf(self) else result := -1; end; {!! TIELayer.Visible Declaration property Visible: Boolean; Description Set to True to make the layer visible, or False to hide it. Default: True Example // Toggle visibility of current layer ImageEnView1.CurrentLayer.Visible := not ImageEnView1.CurrentLayer.Visible; ImageEnView1.Update(); !!} procedure TIELayer.SetVisible(Value: Boolean); begin fVisible := Value; LayerChange( False ); end; {!! TIELayer.VisibleBox Declaration property VisibleBox: boolean; Description Display a selection box around the layer. If VisibleBox is disabled, there is no visual indication that the layer is selected. A selected text layer: Default: True Also, see: Example // Toggle box of current layer ImageEnView1.CurrentLayer.VisibleBox := not ImageEnView1.CurrentLayer.VisibleBox; ImageEnView1.Update(); !!} procedure TIELayer.SetVisibleBox(Value: Boolean); begin fVisibleBox := Value; LayerChange( False ); end; {!! TIELayer.Transparency Declaration property Transparency: integer; Description Set the overall transparency of the layer in the range from 0 (fully transparent) to 255 (totally opaque). Use instead of Transparency when the image has an alpha channel. Default: 255 (fully opaque) See Also - Example // Make all selected layers 50% transparency for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then ImageEnView1.Layers[ I ].Transparency := 128; ImageEnView1.Update(); !!} procedure TIELayer.SetTransparency(Value: integer); begin fTransparency := Value; LayerChange( False ); end; {!! TIELayer.Opacity Declaration property Opacity: double; Description Set the overall opacity of the layer in the range from 0 (fully transparent) to 1.0 (totally opaque). Use Opacity instead of when the image has an alpha channel. Default: 1.0 (fully opaque) See Also - - Example // Make all selected layers 50% opacity for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then ImageEnView1.Layers[ I ].Opacity := 0.5; ImageEnView1.Update(); !!} procedure TIELayer.SetOpacity(Value: double); begin fOpacity := Value; LayerChange( False ); end; {!! TIELayer.AlphaEdgeFeathering Declaration property AlphaEdgeFeathering: Integer; Description If the layer has an alpha channel then edges of the image will be "feathered." Feathering softens the edges of an image by applying alpha transparency at a rate that is proportional to the distance to the edge (specifically, adding a gradient in the alpha channel). The value (0 to 255) indicates the depth in pixels of the feather effect. Default: 0 (no edge feathering) See Also - - Example // Apply alpha edge feathering to all selected layers for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Selected then ImageEnView1.Layers[ I ].AlphaEdgeFeathering := 5; ImageEnView1.Update(); !!} procedure TIELayer.SetAlphaEdgeFeathering(Value: Integer); begin fAlphaEdgeFeathering := Value; LayerChange( False ); end; {!! TIELayer.Cropped Declaration property Cropped: Boolean; Description When enabled, any part of the layer that is outside the background image (layer 0) area will not be displayed. If this value is false, then controls whether layers are cropped to the background. Default: False Example // Crop the display of only the current layer ImageEnView1.LayersCropped := False; ImageEnView1.CurrentLayer.Cropped := True; ImageEnView1.Update(); // Crop the display of all layers ImageEnView1.LayersCropped := True; ImageEnView1.Update(); // Don't crop the display of any layers ImageEnView1.UnlockUpdate(); ImageEnView1.LayersCropped := False; for i := 0 to ImageEnView1.LayersCount - 1 do ImageEnView1.Layers[ I ].Cropped := False; ImageEnView1.LockUpdate(); !!} procedure TIELayer.SetCropped(Value: boolean); begin fCropped := Value; LayerChange( False ); end; {!! TIELayer.Locked Declaration property Locked: Boolean; Description When False the user can move or resize the layer. Also enables display of the layer border and resizing grips. Default: False Example // Prevent movement of current layer ImageEnView1.CurrentLayer.Locked := True; !!} procedure TIELayer.SetLocked(Value: boolean); begin fLocked := Value; LayerChange( False ); end; {!! TIELayer.Selectable Declaration property Selectable: boolean; Description If true, the layer is selectable by the user. A selected text layer: Default: True Example // Prevent selection of current layer ImageEnView1.CurrentLayer.Selectable := True; !!} procedure TIELayer.SetSelectable(Value: boolean); begin fSelectable := Value; LayerChange( False ); end; {!! TIELayer.Operation Declaration property Operation: ; Description Specifies the color operation to execute between this layer and the background layer. Default: ielNormal Example // Average current layer with background ImageEnView1.CurrentLayer.Operation := ielAverage; ImageEnView1.Update(); !!} procedure TIELayer.SetOperation(Value: TIERenderOperation); begin fOperation := Value; LayerChange( False ); end; {!! TIELayer.UserDataLen Declaration property UserDataLen: Integer; Description Specifies the length of UserData buffer. If this value is greater than zero: - When you save the layer (LayersSaveTo..) the content of buffer is saved (and restored with LayersLoadFrom..) - The user data is freed when the layer is destroyed Example type TMyRecord = record SourceText: array[0..255] of AnsiChar; SourceWidth: integer; SourceHeight: integer; end; PMyRecord = ^TMyRecord; var rc: PMyRecord; begin New( rc ) With rc^ do begin Width := ...; Height := ...; Text := ...; end; ImageEnView1.CurrentLayer.UserData := rc; ImageEnView1.CurrentLayer.UserDataLen := SizeOf( PMyRecord ); end; See Also - !!} procedure TIELayer.SetUserDataLen(Value: Integer); begin fUserDataLen := Value; LayerChange( False ); end; {!! TIELayer.Name Declaration property Name: String; Description Specifes a name for the layer. This is not used by ImageEn. Example procedure TfrmMain.ievMainLayerNotify(Sender: TObject; layer: Integer; event: TIELayerEvent); begin // Give each later a date based name ievMain.Layers[layer].Name := 'Layer created at ' + DateTimeToStr( now ); end; !!} procedure TIELayer.SetName(Value: String); begin fName := Value; LayerChange( False ); end; {!! TIELayer.DrawOuter Declaration property DrawOuter: Boolean; Description If True, the unselected layers are drawn as "grayed". The current layer is drawn normally. Default: False Note: Only the current layer is shown as ungrayed. All other layers, even if there are multiple selected layers Example // Grey areas outside of current layer ImageEnView1.CurrentLayer.DrawOuter := True; ImageEnView1.Update(); !!} procedure TIELayer.SetDrawOuter(Value: Boolean); begin fDrawOuter := Value; LayerChange( False ); end; {!! TIELayer.Guid Declaration property Guid: TGuid; Description A unique identifier for this layer. !!} procedure TIELayer.SetGuid(Value: TGuid); begin fGuid := Value; LayerChange( False ); end; {!! TIELayer.Tag Declaration property Tag: Integer; Description An integer value that you can use for your own purposes. Example procedure TfrmMain.ievMainLayerNotify(Sender: TObject; layer: Integer; event: TIELayerEvent); begin // Assign date to each layer ievMain.Layers[layer].Tag := Trunc( now ); end; !!} procedure TIELayer.SetTag(Value: Integer); begin fTag := Value; LayerChange( False ); end; function TIELayer.Owner_EnableAlphaChannel(): Boolean; begin Result := true; if assigned( fOwner ) then Result := TImageEnView( fOwner ).EnableAlphaChannel; end; function TIELayer.Owner_FastDrawingActive(): Boolean; begin Result := False; if assigned( fOwner ) then Result := TImageEnView( fOwner ).LayersFastDrawingActive; end; function TIELayer.Owner_FastOutputActive(): Boolean; begin Result := False; if assigned( fOwner ) then Result := TImageEnView( fOwner ).LayersFastOutput; end; // Render SrcBitmap to DstBitmap adding a softshadow and feathering if enabled procedure TIELayer.RenderLayerWithAdornments(DstBitmap: TIEBitmap; LyrIdx: Integer; SrcBitmap: TIEBitmap; CanModifySrc: Boolean; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter); var needNewBitmap: Boolean; shadowW, shadowH: Integer; bmpW, bmpH: Integer; ieview: TImageEnView; TempBmp : TIEBitmap; fastDrawing: Boolean; begin ieview := (fOwner as TImageEnView); fastDrawing := Owner_FastDrawingActive(); // If this is an image layer, we can only modify a copy of the image needNewBitmap := False; if fastDrawing = False then needNewBitmap := ( fAlphaEdgeFeathering > 0 ) or (( LyrIdx > 0 ) and SoftShadow.Enabled ); if needNewBitmap and ( CanModifySrc = False ) then begin TempBmp := TIEBitmap.Create( SrcBitmap ); RenderLayerWithAdornments(DstBitmap, LyrIdx, TempBmp, True, XLUT, YLUT, UpdRect, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, EnableAlpha, SolidBackground, Filter); TempBmp.Free; exit; end; if ( fAlphaEdgeFeathering > 0 ) and ( fastDrawing = False ) then SrcBitmap.FeatherAlphaEdges( fAlphaEdgeFeathering ); if SoftShadow.Enabled and ( LyrIdx > 0 ) and ( fastDrawing = False ) then begin bmpW := SrcBitmap.Width; bmpH := SrcBitmap.Height; _IEAddSoftShadow(SrcBitmap, Trunc(SoftShadow.Radius * ( ieview.ZoomX + ieview.ZoomY ) / 200), Trunc(SoftShadow.OffsetX * ieview.ZoomX / 100), Trunc(SoftShadow.OffsetY * ieview.ZoomY / 100), SoftShadow.Intensity, TRUE, SoftShadow.ShadowColor, nil, Nil); shadowW := SrcBitmap.Width - bmpW; shadowH := SrcBitmap.Height - bmpH; XDst := XDst - Round( shadowW / 2 * GetWidth / bmpW * ieview.ZoomX / 100 ); YDst := YDst - Round( shadowH / 2 * GetHeight / bmpH * ieview.ZoomY / 100 ); dxDst := dxDst + Round( shadowW * GetWidth / bmpW * ieview.ZoomX / 100 ); dyDst := dyDst + Round( shadowH * GetHeight / bmpH * ieview.ZoomY / 100 ); XSrc := imax( 0, XSrc - shadowW div 2 ); YSrc := imax( 0, YSrc - shadowH div 2 ); dxSrc := dxSrc + shadowW; dySrc := dySrc + shadowH; end; SrcBitmap.RenderToTIEBitmap(DstBitmap, XLUT, YLUT, UpdRect, XDst, YDst, dxDst, dyDst, XSrc, YSrc, dxSrc, dySrc, EnableAlpha, SolidBackground, fTransparency, Filter, true, fOperation, fOpacity); end; {!! TIELayer.ConvertToImageLayer Declaration procedure ConvertToImageLayer(QualityFactor: Double = 2; CropAlpha: Boolean = True); Description Changes the type of the current layer to . This will change it from a vector-based layer to a standard bitmap layer. Bitmap layers can be edited using standard image modification features, but the quality will be lost if you resize the layer. QualityFactor determines the size that the layer bitmap is created. A QualityFactor of 1 will create the bitmap at the current display size, whereas a QualityFactor of 2 would create it at double the display size (allowing it to be zoomed up 200% without loss of quality). If CropAlpha is true, then it remove any alpha from the edges of the layer. Note: - For text layers, a QualityFactor of 1 usually works best - To convert multiple layers, use Example // Convert the current layer to an image, and apply a Negative effect ImageEnView1.CurrentLayer.ConvertToImageLayer(); ImageEnView1.Proc.Negative(); !!} procedure TIELayer.ConvertToImageLayer(QualityFactor: Double = 2; CropAlpha: Boolean = True); var ieview: TImageEnView; begin ieview := (fOwner as TImageEnView); if assigned(ieview) then ieview.LayersConvertToImageLayersEx( GetIndex, QualityFactor, CropAlpha, False, ieview.Proc.AutoUndo and ( loAutoUndoChangesByCode in ieview.LayerOptions )); end; // *************************************************************************************** // // ** ** // // ** TIEImageLayer ** // // ** ** // // *************************************************************************************** // constructor TIEImageLayer.Create(Owner: TObject; TemplateBitmap: TIEBitmap; JustAssign: boolean); var bmp: TBitmap; begin inherited Create(Owner); fKind := ielkImage; if JustAssign and assigned( TemplateBitmap ) then begin fBitmap := TemplateBitmap; end else begin fBitmap := TIEBitmap.Create; if assigned(TemplateBitmap) then begin if TemplateBitmap.EncapsulatedFromTBitmap then begin bmp := TBitmap.Create(); bmp.Width := 1; bmp.Height := 1; bmp.PixelFormat := TemplateBitmap.VclBitmap.PixelFormat; bmp.Width := TemplateBitmap.Width; bmp.Height := TemplateBitmap.Height; fBitmap.EncapsulateTBitmap(bmp, true); end else begin fBitmap.Location := TemplateBitmap.Location; fBitmap.Allocate(TemplateBitmap.Width, TemplateBitmap.Height, TemplateBitmap.PixelFormat); end; end; end; fFreeBitmapOnDestroy := true; SetDefaults; end; constructor TIEImageLayer.Create(Owner: TObject; Width, Height : Integer); begin Create( Owner, nil, False ); fBitmap.Allocate( Width, Height ); end; // Make a image layer clone of another layer, even if it is a non-image layer constructor TIEImageLayer.Create(Owner: TObject; TemplateLayer: TIELayer; QualityFactor: Double = 2; CropAlpha: Boolean = True); var bmp: TIEBitmap; begin bmp := nil; // Let it auto-create TemplateLayer.CopyToBitmap( bmp, Trunc( TemplateLayer.Width * QualityFactor ), Trunc( TemplateLayer.Height * QualityFactor ), True, False ); Create( Owner, bmp, True ); // Note: Following properties are not applied to image, but are assigned as params anyway // Transparency, Opacity, SoftShadow, AlphaEdgeFeathering Assign( TemplateLayer ); fRotate := 0; { rotate is already effected in the conversion } // Remove border BorderColor := clNone_; if QualityFactor = 1 then RestoreSize(); if CropAlpha then Self.CropAlpha(); end; destructor TIEImageLayer.Destroy; begin if fFreeBitmapOnDestroy then begin if fBitmap.EncapsulatedFromTBitmap then begin fBitmap.VclBitmap.Free; fBitmap.VclBitmap := nil; end; FreeAndNil(fBitmap); end; inherited Destroy; end; function TIEImageLayer.GetBitmap : TIEBitmap; begin Result := fBitmap; end; {!! TIEImageLayer.ResampleFilter Declaration property ResampleFilter: ; Description When is true, this property specifies a resample filter to use instead of default to improve the quality of images. The default display filter is specified by . The filter used when merging layers is specified by . Default: rfFastLinear Note: Only available to . To improve the display quality of other layers, use . Example // Use rfTriangle for just the current layer TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfTriangle; TIEImageLayer( ImageEnView1.CurrentLayer ).UseResampleFilter := True; ImageEnView1.Update(); See Also - - - - - !!} {$ifndef IEIncludeDeprecatedInV6} // Moved from TIELayer class in 7.0.0 (2016-10-26) procedure TIEImageLayer.SetResampleFilter(Value: TResampleFilter); begin fResampleFilter := Value; LayerChange(); end; {$ENDIF} {!! TIEImageLayer.UseResampleFilter Declaration property UseResampleFilter: boolean; Description Enables the usage of the quality filter specified by instead of the default. The default display filter is specified by . The filter used when merging layers is specified by . Default: False Note: Only available to . To improve the display quality of other layers, use . Example // Use rfTriangle for just the current layer TIEImageLayer( ImageEnView1.CurrentLayer ).ResampleFilter := rfTriangle; TIEImageLayer( ImageEnView1.CurrentLayer ).UseResampleFilter := True; ImageEnView1.Update(); See Also - - - - - !!} {$ifndef IEIncludeDeprecatedInV6} // Moved from TIELayer class in 7.0.0 (2016-10-26) procedure TIEImageLayer.SetUseResampleFilter(Value : Boolean); begin fUseResampleFilter := Value; LayerChange(); end; {$ENDIF} {!! TIEImageLayer.BorderColor Declaration property BorderColor: TColor; Description The color of the frame around the image. By default, image layers do not show a border (i.e. BorderColor = clNone). Set a valid color for BorderColor to show a border. Default: clNone Example // Add a thick pink border to the image layer TIEImageLayer( ImageEnView1.CurrentLayer ).BorderColor := $008000FF; TIEImageLayer( ImageEnView1.CurrentLayer ).BorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderColor - !!} function TIEImageLayer.GetBorderColor: TColor; begin Result := fBorderColor; end; procedure TIEImageLayer.SetBorderColor(value: TColor); begin fBorderColor := Value; LayerChange(); end; {!! TIEImageLayer.BorderWidth Declaration property BorderWidth: Integer; Description The width of the frame around the image. Note: By default, image layers do not show a border. Set a valid color for to show a border. Default: 1 Example // Add a thick pink border to the image layer TIEImageLayer( ImageEnView1.CurrentLayer ).BorderColor := $008000FF; TIEImageLayer( ImageEnView1.CurrentLayer ).BorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - !!} function TIEImageLayer.GetBorderWidth: Integer; begin Result := fBorderWidth; end; procedure TIEImageLayer.SetBorderWidth(value: Integer); begin fBorderWidth := Value; LayerChange(); end; procedure TIEImageLayer.CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); var resamSize: TPoint; begin if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; if Dest = nil then InitBitmap( Dest, 1, 1 ); Dest.Assign( fBitmap ); if UseDisplayAR then begin // Size to display AR resamSize := GetImageSizeWithinArea( Width, Height, CreateWidth, CreateHeight ); Dest.Resample( resamSize.X, resamSize.Y, fResampleFilter ); if EnableAlpha then Dest.AlphaChannel; // create alpha channel Dest.Resize( CreateWidth, CreateHeight, clWhite, 0, iehCenter, ievCenter ); end else Dest.Resample( CreateWidth, CreateHeight, fResampleFilter ); if not EnableAlpha then Dest.RemoveAlphaChannel(); end; procedure TIEImageLayer.CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); begin CopyToBitmapEx( Dest, CreateWidth, CreateHeight, Owner_FastOutputActive(), EnableAlpha, UseDisplayAR ); end; procedure TIEImageLayer.PaintTo(DstBitmap: TIEBitmap; LyrIdx: Integer; XLUT, YLUT: pinteger; UpdRect: PRect; xDst, yDst, dxDst, dyDst: integer; xSrc, ySrc, dxSrc, dySrc: integer; EnableAlpha: boolean; SolidBackground: boolean; Filter: TResampleFilter; RotationFilter: TIEAntialiasMode; ResizingLayer: Boolean); var borderW: Integer; borderBMP: TIEBitmap; drawBorderAfter: Boolean; j: integer; lXSrc, lYSrc, lWidthSrc, lHeightSrc: integer; lXDst, lYDst, lWidthDst, lHeightDst: integer; dummy2, dummy3: PInteger; rotbmp, tmpbmp: TIEBitmap; lresw, lresh: Double; lposx, lposy: integer; w, h: integer; ieview: TImageEnView; x1, y1, x2, y2: integer; lBitmap: TIEBitmap; procedure _DrawBorder(Canvas: TIECanvas; BorderWidth: Integer; DestX, DestY, DestWidth, DestHeight: Integer); begin if ( BorderWidth > 0 ) and ( fBorderColor <> clNone_ ) and ( DestWidth > 0 ) and ( DestHeight > 0 ) then with Canvas do begin Pen.Color := fBorderColor; Pen.Width := BorderWidth; Pen.Style := psSolid; Brush.Style := bsClear; Rectangle( DestX + BorderWidth div 2, DestY + BorderWidth div 2, DestX + DestWidth + 1 - BorderWidth div 2, DestY + DestHeight + 1 - BorderWidth div 2 ); end; end; begin ieview := TImageEnView( fOwner ); if Owner_FastDrawingActive() then begin Filter := rfNone; RotationFilter := ierNone; end; lBitmap := fBitmap; // DRAW BORDER? drawBorderAfter := ( LyrIdx = 0 ) or not SoftShadow.Enabled; // if drawing a soft-shadow we need the border inside the shadow borderW := Round( fBorderWidth * min( fBitmap.Width / Width, fBitmap.Height / Height )); if drawBorderAfter or ( borderW < 1 ) or ( fBorderColor = clNone_ ) then borderBMP := nil else begin borderBMP := TIEBitmap.create( lBitmap ); _DrawBorder( borderBMP.IECanvas, borderW, 0, 0, lBitmap.Width, lBitmap.Height ); lBitmap := borderBMP; end; if ((TImageEnView(fOwner).LayersCount = 1) and (fResizedWidth = 0) and (fResizedHeight = 0) and (PosX = 0) and (PosY = 0) and (Rotate = 0.0)) then begin // QUICK OUTPUT IF ADVANCED DRAW OPTIONS NOT USED {$IFDEF IEDEBUG} OutputDebugStringA(PAnsiChar('TIEImageLayer.PaintTo')); OutputDebugStringA(PAnsiChar(string( ' XDst='+IntToStr( xDst )+' YDst='+IntToStr( yDst )+ ' WidthDst='+IntToStr( dxDst )+' HeightDst='+IntToStr( dyDst )+ ' XSrc='+IntToStr( xSrc )+' YSrc='+IntToStr( ySrc )+ ' WidthSrc='+IntToStr( dxSrc )+' HeightSrc='+IntToStr( dySrc ) ))); {$ENDIF} RenderLayerWithAdornments(DstBitmap, LyrIdx, lBitmap, False, XLUT, YLUT, UpdRect, xDst, yDst, dxDst, dyDst, xSrc, ySrc, dxSrc, dySrc, EnableAlpha, SolidBackground, Filter); fClientAreaBox := Rect( xDst, yDst, xDst + dxDst, yDst + dyDst ); fDrawingInfo.XDst := xDst; fDrawingInfo.YDst := yDst; fDrawingInfo.WidthDst := dxDst; fDrawingInfo.HeightDst := dyDst; fDrawingInfo.XSrc := xSrc; fDrawingInfo.YSrc := ySrc; fDrawingInfo.WidthSrc := dxSrc; fDrawingInfo.HeightSrc := dySrc; end else begin // ROTATION OR OTHER ADVANCED DRAW OPTIONS USED lresw := 0; lresh := 0; lposx := 0; lposy := 0; if Rotate <> 0 then begin // here ResizedWidth and ResizedHeight should be 0, but anyway here we accept other values lresw := fResizedWidth; lresh := fResizedHeight; lposx := PosX; lposy := PosY; w := Width; h := Height; if (w = lBitmap.Width) and (h = lBitmap.Height) then begin tmpbmp := lBitmap; end else begin tmpbmp := TIEBitmap.create(w, h, lBitmap.PixelFormat); _IEResampleIEBitmap( lBitmap, tmpbmp, rfNone, nil, nil); end; if RotationFilter in [ ierBilinear, ierBicubic ] then begin tmpbmp.AlphaChannel; rotbmp := TIEBitmap.Create(); IEQRotateTo(tmpbmp, rotbmp, Rotate, clBlack, RotationFilter, nil, nil); IEQRotateTo8(tmpbmp.AlphaChannel, rotbmp.AlphaChannel, Rotate, clBlack, RotationFilter ); if tmpbmp <> lBitmap then tmpbmp.Free(); rotbmp.AlphaChannel.SyncFull(); end else begin rotbmp := TIEVirtualRotatedBitmap.Create(tmpbmp, Rotate, clBlack, tmpbmp <> lBitmap); rotbmp.ReplaceAlphaChannel( TIEVirtualRotatedBitmap.Create(tmpbmp.AlphaChannel, Rotate, 0) ); rotbmp.AlphaChannel.Full := false; end; lBitmap := rotbmp; fResizedWidth := lBitmap.Width; fResizedHeight := lBitmap.Height; with fDrawinginfo do begin RotatedDest[0].X := 0; RotatedDest[0].Y := 0; RotatedDest[1].X := w; RotatedDest[1].Y := 0; RotatedDest[2].X := w; RotatedDest[2].Y := h; RotatedDest[3].X := 0; RotatedDest[3].Y := h; IERotatePoints(RotatedDest, 4, Rotate, trunc(fRotateCenterX * w), trunc(fRotateCenterY * h)); PosX := lposx+imin(imin(imin(RotatedDest[0].X, RotatedDest[1].X), RotatedDest[2].X), RotatedDest[3].X); PosY := lposy+imin(imin(imin(RotatedDest[0].Y, RotatedDest[1].Y), RotatedDest[2].Y), RotatedDest[3].Y); for j := 0 to 3 do begin RotatedDest[j].X := trunc(( lposx + RotatedDest[j].X ) * ieview.ZoomX / 100 ) + ieview.OffsetX; RotatedDest[j].Y := trunc(( lposy + RotatedDest[j].Y ) * ieview.ZoomY / 100 ) + ieview.OffsetY; end; end; end else rotbmp := nil; if (LyrIdx > 0) and (Magnify.Enabled) and (Magnify.Rate >= 1) then begin // THIS IS A MAGNIFICATION LAYER if not ResizingLayer then // needed because aspect ratio-resizing doesn't work with magnify layers begin if fResizedWidth > 0 then lBitmap.Width := Round( fResizedWidth ); if fResizedHeight > 0 then lBitmap.Height := Round( fResizedHeight ); end; w := trunc( lBitmap.Width / (Magnify.Rate / ( ieview.ZoomX / 100))); h := trunc( lBitmap.Height / (Magnify.Rate / ( ieview.ZoomY / 100))); x1 := ieview.XBmp2Scr(PosX, false) + trunc( lBitmap.Width * ieview.ZoomX / 100 / 2); y1 := ieview.YBmp2Scr(PosY, false) + trunc( lBitmap.Height * ieview.ZoomY / 100 / 2); x2 := x1 + w; y2 := y1 + h; x1 := x1 - w div 2; y1 := y1 - h div 2; x2 := x2 - w div 2; y2 := y2 - h div 2; case Magnify.Source of iemCanvas: begin // gets all from current canvas (already painted layers and the background) lBitmap.Location := ieTBitmap; lBitmap.Canvas.CopyRect(Rect(0, 0, lBitmap.Width, lBitmap.Height), DstBitmap.Canvas, Rect(x1, y1, x2, y2)); end; iemBackgroundLayer: begin // gets image from layer 0 if lBitmap.PixelFormat <> ie24RGB then lBitmap.PixelFormat := ie24RGB; x1 := ieview.XScr2Bmp(x1, false); y1 := ieview.YScr2Bmp(y1, false); x2 := ieview.XScr2Bmp(x2, false); y2 := ieview.YScr2Bmp(y2, false); w := x2 - x1 + 1; h := y2 - y1 + 1; if (y1 >= 0) and (x1 >= 0) and (x1 < ieview.Layers[0].Bitmap.Width - w) and (y1 < ieview.Layers[0].Bitmap.Height - h) and (w < ieview.Layers[0].Bitmap.Width) and (h < ieview.Layers[0].Bitmap.Height) then begin lBitmap.Fill(0); ieview.Layers[0].Bitmap.RenderToTIEBitmapEx( lBitmap, 0, 0, lBitmap.Width, lBitmap.Height, x1, y1, w, h, True, 255, Filter, ielNormal); end; end; end; case Magnify.Style of iemRectangle: lBitmap.AlphaChannel.Fill(255); // do nothing iemEllipse: begin lBitmap.AlphaChannel.Location := ieTBitmap; lBitmap.AlphaChannel.Fill(0); lBitmap.AlphaChannel.Full := false; with lBitmap.AlphaChannel.VclBitmap.Canvas do begin Brush.Style := bsSolid; Brush.Color := $01000000 or $FF; Pen.Style := psSolid; Pen.Mode := pmCopy; Pen.Color := $01000000 or $FF; Pen.Width := 1; Ellipse(0, 0, lBitmap.Width - 1, lBitmap.Height - 1); end; end; end; end; // end of magnify layer support CalcClientAreaBox(); CalcPaintPos(lBitmap.Width, lBitmap.Height, lXDst, lYDst, lWidthDst, lHeightDst, lXSrc, lYSrc, lWidthSrc, lHeightSrc); dummy2 := nil; dummy3 := nil; RenderLayerWithAdornments(DstBitmap, LyrIdx, lBitmap, False, dummy2, dummy3, UpdRect, lXDst, lYDst, lWidthDst, lHeightDst, lXSrc, lYSrc, lWidthSrc, lHeightSrc, EnableAlpha, SolidBackground, Filter); // DRAW BORDER? borderW := Round( fBorderWidth * ieview.Zoom / 100 ); if drawBorderAfter then _DrawBorder( DstBitmap.IECanvas, borderW, lXDst, lYDst, lWidthDst, lHeightDst ); fDrawingInfo.XDst := lXDst; fDrawingInfo.YDst := lYDst; fDrawingInfo.WidthDst := lWidthDst; fDrawingInfo.HeightDst := lHeightDst; fDrawingInfo.XSrc := lXSrc; fDrawingInfo.YSrc := lYSrc; fDrawingInfo.WidthSrc := lWidthSrc; fDrawingInfo.HeightSrc := lHeightSrc; if assigned(rotbmp) then begin FreeAndNil(rotbmp); fResizedWidth := lresw; fResizedHeight := lresh; PosX := lposx; PosY := lposy; end; end; FreeAndNil( borderBMP ); end; procedure TIEImageLayer.LoadFromStream(Stream: TStream); var bitmapSaved: boolean; saveVer: Integer; fmt: integer; dw: Dword; ms: TMemoryStream; LZStream: TZDecompressionStream; io: TImageEnIO; l: Integer; begin l := Stream.Position; saveVer := LoadMetaFromStream( Stream ); if saveVer < 6400 then raise EIEException.create( 'Unknown data version' ); Stream.Read( Magnify, sizeof(Magnify)); Stream.Read( fResampleFilter, sizeof( fResampleFilter)); Stream.Read( fUseResampleFilter, sizeof( fUseResampleFilter)); Stream.Read(bitmapSaved, sizeof(boolean)); Stream.Read(fmt, sizeof(Integer)); if bitmapSaved then begin if (fmt = -1) or (fmt = -2) then begin // use internal file format Stream.Read(dw, sizeof(dword)); // compressed stream size ms := TMemoryStream.Create; try ms.SetSize(dw); // to speed up loading if dw > 0 then IECopyFrom(ms, Stream, dw); ms.Position := 0; if fmt = -1 then begin LZStream := TZDecompressionStream.Create(ms); try fBitmap.LoadRAWFromBufferOrStream(nil, LZStream); finally FreeAndNil(LZStream); end; end else fBitmap.LoadRAWFromBufferOrStream(nil, ms); finally FreeAndNil(ms); end; end else begin // use standard file formats io := TImageEnIO.CreateFromBitmap( fBitmap ); try if IsMask then io.NativePixelFormat := true; io.LoadFromStream(Stream, fmt); finally io.Free; end; Stream.Position := l + fLayerSize; // Ensure we are positioned at end of layer record end; end; fModified := False; fBitmap.Modified := False; end; // warning: ioTIFF not supported // if CompressionFormat = -1 then use internal compressed format (preserves pixelformat and transparency) // if CompressionFormat = -2 then use internal non-compressed format (preserves pixelformat and transparency) procedure TIEImageLayer.SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); var l, sz, fmt: integer; ms: TMemoryStream; SaveBitmap: Boolean; LZStream: TZCompressionStream; dw: Dword; io : TImageEnIO; begin {$ifdef IEINCLUDEPNG} if CompressionFormat = ioTIFF then CompressionFormat := ioPNG; {$endif} sz := 0; l := Stream.Position; SaveMetaToStream( Stream ); Stream.Write( Magnify, sizeof( Magnify)); Stream.Write( fResampleFilter, sizeof( fResampleFilter)); Stream.Write( fUseResampleFilter, sizeof( fUseResampleFilter)); saveBitmap := ( MetaOnly = False ) and ( fBitmap.Width > 1 ); Stream.Write(saveBitmap, sizeof(boolean)); fmt := CompressionFormat; Stream.Write(fmt, sizeof(Integer)); if saveBitmap then begin if (CompressionFormat = -1) or (CompressionFormat = -2) then begin // use internal format (preserves pixelformat and alpha channel). Also this is LZ compressed if CompressionFormat = -1. ms := TMemoryStream.Create; try sz := fBitmap.Height * fBitmap.Rowlen div 2; // aproximated size if fBitmap.HasAlphaChannel then sz := sz + fBitmap.AlphaChannel.Height * fBitmap.AlphaChannel.Rowlen; if sz < IEGetMemory(true) then begin try ms.Size := sz; except end; end; if CompressionFormat = -1 then begin LZStream := TZCompressionStream.Create(ms, zcDefault, 15); try fBitmap.SaveRAWToBufferOrStream(nil, LZStream, false); finally FreeAndNil(LZStream); end; end else fBitmap.SaveRAWToBufferOrStream(nil, ms, true); sz := ms.Position; dw := sz; Stream.Write(dw, sizeof(dword)); // write compressed stream size ms.Position := 0; if sz > 0 then IECopyFrom(Stream, ms, sz); finally FreeAndNil(ms); end; end else begin io := TImageEnIO.CreateFromBitmap( fBitmap ); try // use standard image formats case fBitmap.PixelFormat of ie1g: begin io.Params.BitsPerSample := 1; io.Params.SamplesPerPixel := 1; end; ie8g: begin io.Params.BitsPerSample := 8; io.Params.SamplesPerPixel := 1; io.Params.JPEG_ColorSpace := ioJPEG_GRAYLEV; end; else begin io.Params.BitsPerSample := 8; io.Params.SamplesPerPixel := 3; io.Params.JPEG_ColorSpace := ioJPEG_YCbCr; end; end; io.SaveToStream(Stream, CompressionFormat); finally io.Free; end; end; end; // Update position sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Fill size Stream.Position := l + sz; // Position at end of layer record fLayerSize := sz; end; function TIEImageLayer.GetAsSVG(): string; var SaveImageFormat: TIOFileType; begin SaveImageFormat := ioPNG; if assigned(fOwner) then SaveImageFormat := (fOwner as TImageEnView).IO.Params.SVG_ImageCompression; Result := CreateSVGImageTag( fBitmap, SaveImageFormat, PosX, PosY, Width, Height, fBorderWidth, fBorderColor, Rotate, fTransparency); end; {!! TIEImageLayer.Clear Declaration procedure Clear(FillColor: TColor = clWhite; Width: Integer = 1; Height: Integer = 1); Description Removes any transparent area on the edge of the layer bitmap, repositioning and resizing the resulting layer to the visible rectangle. Result is true if the bitmap was cropped (i.e. alpha was removed). Example // Clear the current image, but maintain its existing size if ImageEnView1.CurrentLayer is TIEImageLayer then TIEImageLayer( ImageEnView1.CurrentLayer ).Clear( clWhite, ImageEnView1.CurrentLayer.Width, ImageEnView1.CurrentLayer.Height ); ImageEnView1.Update(); !!} procedure TIEImageLayer.Clear(FillColor: TColor = clWhite; Width: Integer = 1; Height: Integer = 1); var oldWidth, oldHeight: Integer; begin oldWidth := Width; oldHeight := Height; fBitmap.Allocate( max( 1, Width ), Max( 1, Height )); fBitmap.Fill( FillColor ); fResizedWidth := 0; fResizedHeight := 0; if Width <= 1 then fPosX := 1 else fPosX := fPosX + ( oldWidth - Width ) div 2; if Height <= 1 then fPosY := 1 else fPosY := fPosX + ( oldHeight - Height ) div 2; LayerChange(); end; {!! TIEImageLayer.CropAlpha Declaration function CropAlpha(): Boolean; Description Removes any transparent area on the edge of the layer bitmap, repositioning and resizing the resulting layer to the visible rectangle. Result is true if the bitmap was cropped (i.e. alpha was removed). Example if ImageEnView1.CurrentLayer is TIEImageLayer then TIEImageLayer( ImageEnView1.CurrentLayer ).CropAlpha(); ImageEnView1.Update(); See Also - - !!} function TIEImageLayer.CropAlpha(): Boolean; var beforeWidth, beforeHeight: Integer; scaleX, scaleY: Double; begin Result := False; beforeWidth := fBitmap.Width; beforeHeight := fBitmap.Height; if fBitmap.CropAlpha() = False then exit; scaleX := 1.0; scaleY := 1.0; if fResizedWidth > 0 then scaleX := fResizedWidth / beforeWidth; if fResizedHeight > 0 then scaleY := fResizedHeight / beforeHeight; fPosX := fPosX + Trunc(( beforeWidth - fBitmap.Width ) / 2 * scaleX ); fPosY := fPosY + Trunc(( beforeHeight - fBitmap.Height ) / 2 * scaleY ); if fResizedWidth > 0 then fResizedWidth := fResizedWidth * fBitmap.Width / beforeWidth; if fResizedHeight > 0 then fResizedHeight := fResizedHeight * fBitmap.Height / beforeHeight; Result := True; LayerChange(); end; {!! TIEImageLayer.ExecuteOpenDialog Declaration function ExecuteOpenDialog(): Boolean; Description Displays an open image dialog (using ) to allow the user to browse for an image. It is applied to the current layer. Example if ImageEnView1.CurrentLayer is TIEImageLayer then TIEImageLayer( ImageEnView1.CurrentLayer ).ExecuteOpenDialog(); !!} function TIEImageLayer.ExecuteOpenDialog(): Boolean; var imgFilename: string; ieview: TImageEnView; begin Result := False; if fOwner = nil then exit; imgFilename := TImageEnView( fOwner ).IO.ExecuteOpenDialog(''); if imgFilename <> '' then begin ieview := (fOwner as TImageEnView); if assigned(ieview) and ieview.Proc.AutoUndo and ( loAutoUndoChangesbyUser in ieview.LayerOptions ) then ieview.Proc.SaveUndo( IEMsg( IEMsg_SelectImage ), ieuImage, True, IEOP_OTHER ); LayerChange(); Result := Bitmap.Read( imgFilename ); RestoreAspectRatio(); if Assigned( fOwner ) then TImageEnView( fOwner ).Update(); end end; {!! TIEImageLayer.RestoreSize Declaration procedure RestoreSize(); Description Sizes the layer to original dimensions (i.e. display at 100% zoom). Example if ImageEnView1.CurrentLayer is TIEImageLayer then ImageEnView1.CurrentLayer.RestoreSize(); ImageEnView1.Update(); See Also - !!} procedure TIEImageLayer.RestoreSize(); begin fResizedWidth := 0; fResizedHeight := 0; end; // *************************************************************************************** // // ** ** // // ** TIEShapeLayer ** // // ** ** // // *************************************************************************************** // constructor TIEShapeLayer.Create(Owner: TObject); begin inherited Create(Owner); fKind := ielkShape; SetDefaults; fResizedWidth := 100; fResizedHeight := 100; end; destructor TIEShapeLayer.Destroy; begin // inherited Destroy; end; // Bitmap is created if nil // must be freed procedure TIEShapeLayer.CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); var drawRect: TRect; procedure _DrawShape_GDI(); var drawLeft, drawTop, drawWidth, drawHeight: Integer; begin if EnableAlpha then begin InitBitmapRGBA( Dest, CreateWidth, CreateHeight ); // Use ie32RGB for RGBA support Dest.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); end else InitBitmap( Dest, CreateWidth, CreateHeight ); drawLeft := drawRect.Left; drawTop := drawRect.Top; drawWidth := drawRect.Right - drawRect.Left; drawHeight := drawRect.Bottom - drawRect.Top; if AspectRatioLocked = True then // Lock to 1:1 begin if drawWidth > drawHeight then begin drawWidth := drawHeight; drawLeft := ( Dest.Width - drawWidth ) div 2; end else if drawWidth > drawHeight then begin drawHeight := drawWidth; drawTop := ( Dest.Height - drawHeight ) div 2; end; end; IEDrawSimpleShape(Dest.IECanvas, drawLeft, drawTop, drawWidth, drawHeight, fBorderColor, fBorderWidth, fFillColor, fFillColor2, fFillGradient, min( CreateWidth / GetWidth, CreateWidth / GetHeight ), // = Zoom fShape, False {Handled by scaling} ); if EnableAlpha then Dest.SynchronizeRGBA( True, True ) else Dest.RemoveAlphaChannel(); end; procedure _DrawShape_RGN(Bitmap: TIEBitmap; DrawingAlpha : Boolean); var drawBorderColor, drawFillColor, drawFillColor2 : TColor; drawBorderWidth: Integer; maintainAR: TIEBooleanEx; begin drawBorderColor := fBorderColor; drawFillColor := fFillColor ; drawFillColor2 := fFillColor2 ; if DrawingAlpha then begin if drawBorderColor <> clNone_ then drawBorderColor := Full_Alpha_Color; if drawFillColor <> clNone_ then drawFillColor := Full_Alpha_Color; drawFillColor2 := clNone_; end; // Image has been scaled to zoom level, so ensure we scale the border too drawBorderWidth := fBorderWidth; if drawBorderWidth > 0 then drawBorderWidth := max( 1, Round( fBorderWidth * min( CreateWidth / GetWidth, CreateWidth / GetHeight ))); if AspectRatioLocked then maintainAR := iebTrue else maintainAR := iebFalse; IEDrawShape( Bitmap.Canvas, fShape, drawRect.Left, drawRect.Top, drawRect.Right - drawRect.Left, drawRect.Bottom - drawRect.Top, maintainAR, drawBorderColor, drawBorderWidth, drawFillColor, drawFillColor2, fFillGradient, Round( Rotate ), fShapeModifier ); end; var useIECanvas: Boolean; begin // Use TIECanvas for faster handling of unrotated rects and ellipses useIECanvas := ( fShape in [ iesEllipse, iesRectangle, iesRoundRect ] ) and ( Round( Rotate ) mod 90 = 0 ); if useIECanvas and ( fShape <> iesRectangle ) then useIECanvas := (( fFillColor = fFillColor2 ) or ( fFillColor = clNone_ ) or ( fFillColor2 = clNone_ )); // i.e. no gradient if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; drawRect := Rect( 0, 0, CreateWidth, CreateHeight ); if UseDisplayAR then drawRect := GetImageRectWithinArea( Width, Height, CreateWidth, CreateHeight ); if useIECanvas then begin // Draw using TIECanvas _DrawShape_GDI(); end else begin // Draw using TCanvas InitBitmap( Dest, CreateWidth, CreateHeight ); if EnableAlpha = False then Dest.RemoveAlphaChannel() else begin Dest.AlphaChannel.PixelFormat := ie8g; Dest.AlphaChannel.VclBitmap.PixelFormat := pf8bit; IESetGrayPalette( Dest.AlphaChannel.VclBitmap ); Dest.AlphaChannel.Fill(0); _DrawShape_RGN( Dest.AlphaChannel, True ); end; _DrawShape_RGN( Dest, False ); end; end; procedure TIEShapeLayer.CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); var antiAliasFactor: Integer; zf: TResampleFilter; begin if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; antiAliasFactor := 1; if fAntiAlias and not Owner_FastOutputActive() then antiAliasFactor := 2; begin CreateWidth := CreateWidth * antiAliasFactor; CreateHeight := CreateHeight * antiAliasFactor; end; CopyToBitmapEx( Dest, CreateWidth, CreateHeight, Owner_FastOutputActive(), EnableAlpha, UseDisplayAR ); if antiAliasFactor <> 1 then begin // Halve the size to effect anti-alias zf := fResampleFilter; if ( zf = rfNone ) and assigned( Owner ) then zf := TImageEnView( Owner ).LayersMergeFilter; Dest.Resample( 1 / antiAliasFactor, zf ); end; end; function TIEShapeLayer.GetBitmap : TIEBitmap; begin CopyToBitmap( fGlobalCacheBitmap, iMax( 1, Round( fResizedWidth )), iMax( 1, Round( fResizedHeight )), Owner_EnableAlphaChannel, False ); Result := fGlobalCacheBitmap; end; {!! TIEShapeLayer.BorderColor Declaration property BorderColor: TColor; Description The color of the frame around the shape. To hide the frame set BorderColor to clNone or to 0. Default: clBlack Example // Add an explosion layer with an orange border and a yellow fill ImageEnView1.LayersAdd( ielkShape ); ImageEnView1.CurrentLayer.BorderColor := $004080FF; ImageEnView1.CurrentLayer.BorderWidth := 2; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove the border... ImageEnView1.CurrentLayer.BorderColor := clNone; // Same as setting BorderWidth := 0; ImageEnView1.Update(); See Also - TIELayer.BorderColor - !!} function TIEShapeLayer.GetBorderColor: TColor; begin Result := fBorderColor; end; procedure TIEShapeLayer.SetBorderColor(value: TColor); begin fBorderColor := Value; LayerChange(); end; {!! TIEShapeLayer.BorderWidth Declaration property BorderWidth: Integer; Description The width of the frame around the shape. To hide the frame set BorderWidth to 0 or to clNone. Default: 1 Example // Add an explosion layer with an orange border and a yellow fill ImageEnView1.LayersAdd( ielkShape ); ImageEnView1.CurrentLayer.BorderColor := $004080FF; ImageEnView1.CurrentLayer.BorderWidth := 2; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove the border... ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - !!} function TIEShapeLayer.GetBorderWidth: Integer; begin Result := fBorderWidth; end; procedure TIEShapeLayer.SetBorderWidth(value: Integer); begin fBorderWidth := Value; LayerChange(); end; {!! TIEShapeLayer.FillColor Declaration property FillColor: TColor; Description The color of the shape. To make the shape transparent, set FillColor to clNone. If FillColor is different from it will be drawn as a gradient. Default: clRed Example // Set fill color for a shape to yellow ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove fill color from shape ImageEnView1.CurrentLayer.FillColor := clNone; ImageEnView1.Update(); See Also - TIELayer.FillColor - - !!} function TIEShapeLayer.GetFillColor: TColor; begin Result := fFillColor; end; procedure TIEShapeLayer.SetFillColor(value: TColor); begin fFillColor := Value; LayerChange(); end; {!! TIEShapeLayer.FillColor2 Declaration property FillColor2: TColor; Description The end color for the shape gradient. If FillColor2 is clNone, the shape is filled by a solid color specified by . If FillColor2 is different from it is drawn as a gradient. The direction of the gradient is specified by . Default: clNone Example // Set a vertical gradient fill for an ellipse ImageEnView1.CurrentLayer.FillColor2 := clRed; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.FillGradient := clVertical; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); // Disable the gradient fill TIEShapeLayer( ImageEnView1.CurrentLayer ).FillColor2 := clNone; ImageEnView1.Update(); See Also - TIELayer.FillColor2 - - !!} function TIEShapeLayer.GetFillColor2: TColor; begin Result := fFillColor2; end; procedure TIEShapeLayer.SetFillColor2(value: TColor); begin fFillColor2 := Value; LayerChange(); end; {!! TIEShapeLayer.FillGradient Declaration property FillGradient: ; Description The direction of the gradient used for the shape fill. If is different from the shape is filled with a gradient. FillGradient specifies the direction. Default: gdVertical Example // Set a vertical gradient fill for an ellipse ImageEnView1.CurrentLayer.FillColor2 := clRed; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.FillGradient := clVertical; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); See Also - TIELayer.FillGradient - - !!} function TIEShapeLayer.GetFillGradient: TIEGradientDir; begin Result := fFillGradient; end; procedure TIEShapeLayer.SetFillGradient(value: TIEGradientDir); begin fFillGradient := Value; LayerChange(); end; {!! TIEShapeLayer.Shape Declaration property Shape: ; Description The shape displayed by the layer. Over sixty shapes are available. The style of some shapes can be modified using Default: iesEllipse Examples // Append a Star layer ImageEnView1.LayersAdd( ielkShape ); TIEShapeLayer( ImageEnView1.CurrentLayer ).Shape := iesStar5; TIEShapeLayer( ImageEnView1.CurrentLayer ).AspectRatioLocked := True; ImageEnView1.CurrentLayer.FillColor := clRed; ImageEnView1.Update(); // Explosion Shape ImageEnView1.CurrentLayer.Shape := iesExplosion; // Triangle Shape ImageEnView1.CurrentLayer.Shape := iesTriangle; // Arrow Shape ImageEnView1.CurrentLayer.Shape := iesShootingArrowSW; // Ellipse Shape ImageEnView1.CurrentLayer.Shape := iesEllipse; // Lightning Shape ImageEnView1.CurrentLayer.Shape := iesLightningLeft; !!} procedure TIEShapeLayer.SetShape(value: TIEShape); begin fShape := Value; LayerChange(); end; {!! TIEShapeLayer.ShapeModifier Declaration property ShapeModifier: Integer; Description Changes the display of certain shapes. Shape Effect Range Default iesCustomShape Specifies the number of sides of the shape 3 - 50 10 iesCustomStar Specifies the number of points of the star 3 - 50 10 iesCustomExplosion Specifies the number of points of the explosion 3 - 5012 iesEllipseSegment Specifies the width of the ellipse segment (in degrees) 1 - 90 45
Default: 0 (uses the default for that shape) Example // Append a 12-pointed star layer ImageEnView1.LayersAdd( ielkShape ); TIEShapeLayer( ImageEnView1.CurrentLayer ).Shape := iesCustomStar; TIEShapeLayer( ImageEnView1.CurrentLayer ).ShapeModifier := 12; ImageEnView1.Update(); // Append a 30 point explosion layer ImageEnView1.LayersAdd( ielkShape ); TIEShapeLayer( ImageEnView1.CurrentLayer ).Shape := iesCustomExplosion; TIEShapeLayer( ImageEnView1.CurrentLayer ).ShapeModifier := 30; ImageEnView1.Update(); !!} procedure TIEShapeLayer.SetShapeModifier(value: Integer); begin fShapeModifier := Value; LayerChange(); end; procedure TIEShapeLayer.LoadFromStream(Stream: TStream); var saveVer: Integer; begin saveVer := LoadMetaFromStream( Stream ); if saveVer < 6400 then raise EIEException.create( 'Unknown data version' ); // Other props Stream.Read( fShape, SizeOf( TIEShape )); Stream.Read( fShapeModifier, SizeOf( Integer )); fModified := False; end; procedure TIEShapeLayer.SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); var l, sz: integer; begin l := Stream.Position; SaveMetaToStream( Stream); // other props Stream.Write( fShape, SizeOf( TIEShape )); Stream.Write( fShapeModifier, SizeOf( Integer )); // Update position sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Fill size Stream.Position := l + sz; // Position at end of layer record end; function TIEShapeLayer.GetAsSVG(): string; var aLayer: TIEImageLayer; begin Result := CreateSVGShapeTag( fShape, PosX, PosY, Width, Height, fBorderWidth, fBorderColor, fFillColor, Rotate, fTransparency ); if Result = '' then begin // it will be a shape type that cannot be converted to points aLayer := TIEImageLayer.Create( nil, Self, 2, False ); Result := aLayer.AsSVG; aLayer.Free; end; end; // *************************************************************************************** // // ** ** // // ** TIELineLayer ** // // ** ** // // *************************************************************************************** // constructor TIELineLayer.Create(Owner: TObject); begin inherited Create(Owner); fKind := ielkLine; fLabelFont := TFont.Create; SetDefaults; fResizedWidth := 100; fResizedHeight := 100; SizeToFit(); fLineRect := Rect( 0, 0, 0, 0 ); fLabelRect := Rect( 0, 0, 0, 0 ); fStartShapePoints.Shape := ieesNone; fEndShapePoints.Shape := ieesNone; end; destructor TIELineLayer.Destroy; begin FreeAndNil( fLabelFont ); inherited; end; procedure IEDrawLineEndShape(Canvas: TIECanvas; x1, y1, x2, y2: integer; Shape: TIELineEndShape; Size: integer; Zoom: Double; out DrawInfo: TIEEndShapeDrawInfo); const Angle_Divisor = 12; var pp: array[0..2] of TPoint; dx, dy, dsq, udx, udy: Double; begin Size := Round( Size * Zoom ); if Size < 2 then exit; DrawInfo.Shape := Shape; case Shape of ieesArrow : begin dx := x1 - x2; dy := y1 - y2; dsq := Sqrt( dx * dx + dy * dy ); if dsq = 0 then exit; udx := dx / dsq; udy := dy / dsq; pp[0].x := Round( x2 + Size / 2 * ( udx * Sqrt( Angle_Divisor ) / 2 - udy * 1/2 )); pp[0].y := Round( y2 + Size / 2 * ( udx * 1/2 + udy * Sqrt( Angle_Divisor ) / 2 )); pp[1].x := Round( x2 + Size / 2 * ( udx * Sqrt( Angle_Divisor ) / 2 + udy * 1/2 )); pp[1].y := Round( y2 + Size / 2 * ( - udx * 1/2 + udy * Sqrt( Angle_Divisor ) / 2 )); pp[2].x := x2; pp[2].y := y2; Canvas.Polygon(pp); DrawInfo.Pt1 := Point( Round( pp[0].X / Zoom ), Round( pp[0].Y / Zoom )); DrawInfo.Pt2 := Point( Round( pp[1].X / Zoom ), Round( pp[1].Y / Zoom )); DrawInfo.Pt3 := Point( Round( pp[2].X / Zoom ), Round( pp[2].Y / Zoom )); end; ieesCircle: begin Canvas.Ellipse( x2 - Size div 2, y2 - Size div 2, x2 + Size div 2, y2 + Size div 2 ); DrawInfo.pt1 := Point( Round(( x2 - Size / 2 ) / Zoom ), Round(( y2 - Size / 2 ) / Zoom )); // top left of ellipse rect DrawInfo.pt2 := Point( Round(( x2 + Size / 2 ) / Zoom ), Round(( y2 + Size / 2 ) / Zoom )); // bottom right of ellipse end; end; end; function IEDrawLine(Canvas: TIECanvas; PosX, PosY, Width, Height: Integer; Zoom: Double; Angle: Integer; LineColor: TColor; LineWidth: Integer; StartingShape, EndingShape: TIELineEndShape; ShapeSize: Integer; ShapeFillColor: TColor; // Shape uses LineColor and LineWidth for Pen LabelPosition: TIELineLabelPos; LabelText: String; LabelAlign: TIEAlignment; LabelFont: TFont; LabelShape: TIEShape; // only iesRectangle, iesRoundRect, iesEllipse LabelBorderColor: TColor; LabelBorderWidth: Integer; LabelFillColor: TColor; LabelFillColor2: TColor; LabelFillGradient: TIEGradientDir; AntiAlias: boolean; TextAntiAlias: boolean; out LineRect: TRect; out LabelRect: TRect; out StartShapePoints: TIEEndShapeDrawInfo; out EndShapePoints: TIEEndShapeDrawInfo; UpdateSize: Boolean = False; DesiredLineLength: Double = -1): TSize; const Arrow_Angle = 30; var Pt1, Pt2: TPoint; prevSmoothingMode : TIECanvasSmoothingMode; startShapeAtLeft, startShapeAtTop, endShapeAtLeft, endShapeAtTop: Boolean; labelAtLeft, labelAtTop: Boolean; leftPadding, topPadding, rightPadding, bottomPadding: Integer; LabelSize: TSize; labelVisible: Boolean; offPt: TPoint; sizeToLineLength: Boolean; spaceForShapes: Boolean; labelLeft, labelTop: Integer; procedure _ResetPadding(); begin leftPadding := 0; topPadding := 0; rightPadding := 0; bottomPadding := 0; end; function _GetLineBounds() : TSize; var linePt1, linePt2: TPoint; begin CalcLineWithinRect( Rect( PosX, PosY, PosX + Width, PosY + Height ), Angle, linePt1, linePt2 ); result.cX := abs( linePt1.X - linePt2.X ); result.cY := abs( linePt1.Y - linePt2.Y ); end; procedure _GetShapePadding(Shape: TIELineEndShape; ShapeAtLeft, ShapeAtTop: Boolean); var adjShapeSize: Double; lineBounds: TSize; begin if not ( Shape in [ ieesArrow, ieesCircle ]) then exit; adjShapeSize := ( ShapeSize + LineWidth / 2 ) * Zoom; if Shape = ieesArrow then adjShapeSize := 0.8 * adjShapeSize; lineBounds := _GetLineBounds; if ( lineBounds.cX < adjShapeSize ) or ( lineBounds.cX < LabelSize.cX ) then begin leftPadding := max( leftPadding, Trunc( LineWidth / 2 ) + Trunc( adjShapeSize / 2 )); rightPadding := max( rightPadding, Ceil( LineWidth / 2 ) + Ceil( adjShapeSize / 2 )); end else if ShapeAtLeft then begin inc( leftPadding, LineWidth + Round( adjShapeSize / 2 )); end else // Right begin inc( rightPadding, LineWidth + Round( adjShapeSize / 2 )); end; if ( lineBounds.cY < adjShapeSize ) or ( lineBounds.cY < LabelSize.cY ) then begin topPadding := Max( topPadding, Trunc( LineWidth / 2 ) + Trunc( adjShapeSize / 2 )); bottomPadding := Max( bottomPadding, Ceil( LineWidth / 2 ) + Ceil( adjShapeSize / 2 )); end else if ShapeAtTop then begin inc( topPadding, LineWidth + Round( adjShapeSize / 2 )); end else // Bottom begin inc( bottomPadding, LineWidth + Round( adjShapeSize / 2 )); end; end; procedure _GetLabelPadding(); var lineBounds: TSize; begin lineBounds := _GetLineBounds; if lineBounds.cX < LabelSize.cX then begin end else if labelAtLeft then inc( leftPadding, LabelSize.cX div 2 ) else // Right inc( rightPadding, LabelSize.cX div 2 ); if lineBounds.cY < LabelSize.cY then begin end else if LabelAtTop then inc( topPadding, LabelSize.cY div 2 ) else // Bottom inc( bottomPadding, LabelSize.cY div 2 ); end; // Result is false if padding for shapes exceeds bounds function _CalcPadding(StartShape, EndShape: TIELineEndShape; IncludeLabel: Boolean = True): Boolean; begin _ResetPadding(); // Shapes _GetShapePadding( StartShape, startShapeAtLeft, startShapeAtTop ); _GetShapePadding( EndShape, endShapeAtLeft, endShapeAtTop ); Result := ( leftPadding + rightPadding <= Width ) and ( topPadding + bottomPadding <= Height ); // Label if IncludeLabel then _GetLabelPadding(); end; function CalcLabelSize(): TSize; begin Result := IEDrawText( Canvas, PosX, PosY, PosX + Width, PosX + Height, Zoom, LabelText, LabelFont, LabelAlign, ielCenter, 0, {Angle } LabelBorderColor, LabelBorderWidth, LabelFillColor, LabelFillColor2, LabelFillGradient, True, AntiAlias, LabelShape, True); end; begin LineRect := Rect( 0, 0, 0, 0 ); LabelRect := Rect( 0, 0, 0, 0 ); StartShapePoints.Shape := ieesNone; EndShapePoints.Shape := ieesNone; Result.cX := -1; Result.cY := -1; sizeToLineLength := UpdateSize and ( DesiredLineLength > 0 ); if sizeToLineLength then begin // Get the box needed to display the line offPt := OffsetPoint( Point( 0, 0 ), DesiredLineLength * Zoom, Angle ); Width := iMax( 1, Round( abs( offPt.X ))); Height := iMax( 1, Round( abs( offPt.Y ))); end; labelVisible := ( LabelText <> '' ) and ( LabelPosition <> ielpHide ); if LineWidth > 0 then LineWidth := imax( 1, Round( LineWidth * Zoom )); // Don't allow clear backgrounds as we must erase white lines if LabelFillColor = clNone_ then LabelFillColor := clWhite; if ShapeFillColor = clNone_ then ShapeFillColor := clWhite; LabelSize.cX := 0; LabelSize.cY := 0; if labelVisible then begin LabelSize := CalcLabelSize(); if UpdateSize = False then begin if LabelSize.cX > Width then LabelSize.cX := Width; if LabelSize.cY > Height then LabelSize.cY := Height; end; // Cannot have a label and a shape in some position case LabelPosition of ielpAtStart : StartingShape := ieesNone; ielpAtEnd : EndingShape := ieesNone; end; end; while Angle < 0 do Angle := Angle + 360; while Angle >= 360 do Angle := Angle - 360; startShapeAtLeft := ( Angle >= 90 ) and ( Angle < 270 ); startShapeAtTop := ( Angle < 180 ); endShapeAtLeft := not startShapeAtLeft; endShapeAtTop := not startShapeAtTop; labelAtLeft := startShapeAtLeft; labelAtTop := startShapeAtTop; if LabelPosition = ielpAtEnd then begin labelAtLeft := not LabelAtLeft; labelAtTop := not LabelAtTop; end; spaceForShapes := _CalcPadding( StartingShape, EndingShape ); if (spaceForShapes = False ) and (UpdateSize = False) then begin // Not enough space to show shapes, so HIDE StartingShape := ieesNone; EndingShape := ieesNone; _CalcPadding( ieesNone, ieesNone ); end; prevSmoothingMode := Canvas.SmoothingMode; if AntiAlias then Canvas.SmoothingMode := iesmAntialias else Canvas.SmoothingMode := iesmBestPerformance; try if sizeToLineLength then _CalcPadding( ieesNone, ieesNone, False ) else if UpdateSize then begin if Width - leftPadding - rightPadding < LineWidth then Width := LineWidth + leftPadding + rightPadding; if Height - topPadding - bottomPadding < LineWidth then Height := LineWidth + topPadding + bottomPadding; _CalcPadding( ieesNone, ieesNone, True ); end; CalcLineWithinRect( Rect( PosX + leftPadding, PosY + topPadding, PosX + Width - rightPadding, PosY + Height - bottomPadding ), Angle, Pt1, Pt2 ); if ( Pt1.X = -1 ) and ( Pt1.Y = -1 ) and ( Pt2.X = -1 ) and ( Pt2.Y = -1 ) then exit; // invalid rect // Re-calc padding with start/end shapes if UpdateSize then _CalcPadding( StartingShape, EndingShape ); Result.cX := abs( Pt1.X - Pt2.X ) + leftPadding + rightPadding; if sizeToLineLength then Result.cX := Result.cX + LabelSize.cX div 2; if Result.cX < LabelSize.cX then Result.cX := LabelSize.cX; Result.cY := abs( Pt1.Y - Pt2.Y ) + topPadding + bottomPadding; if sizeToLineLength then Result.cY := Result.cY + LabelSize.cY div 2; if Result.cY < LabelSize.cY then Result.cY := LabelSize.cY; LineRect := Rect( Round( Pt1.x / Zoom ), Round( Pt1.y / Zoom ), Round( Pt2.x / Zoom ), Round( Pt2.Y / Zoom )); if UpdateSize then exit; // NOW PAINTING with Canvas do begin Pen.Color := $01010101; // needed otherwise next Pen.Color is not set (gdi bug workaround?) if ( LineWidth > 0 ) and ( LineColor <> clNone_ ) then begin Pen.Style := psSolid; Pen.Width := LineWidth; Pen.Color := LineColor; end else Pen.Style := psClear; Pen.Mode := pmCopy; Brush.Style := bsClear; end; // DRAW LINE Canvas.DrawLine(Pt1.X, Pt1.Y, Pt2.X, Pt2.Y); // DRAW ARROWS Canvas.Brush.Color := ShapeFillColor; Canvas.Brush.Style := bsSolid; IEDrawLineEndShape( Canvas, Pt1.X, Pt1.Y, Pt2.X, Pt2.Y, StartingShape, ShapeSize, Zoom, StartShapePoints); IEDrawLineEndShape( Canvas, Pt2.X, Pt2.Y, Pt1.X, Pt1.Y, EndingShape, ShapeSize, Zoom, EndShapePoints); // DRAW TEXT if labelVisible then begin // Get rect of label if labelAtLeft then labelLeft := min( Pt1.X, Pt2.X ) - LabelSize.cX div 2 else labelLeft := max( Pt1.X, Pt2.X ) - Ceil( LabelSize.cX / 2 ); if labelLeft + LabelSize.cX > PosX + Width then labelLeft := PosX + Width - LabelSize.cX; if labelLeft < PosX then labelLeft := PosX; if LabelAtTop then labelTop := min( Pt1.Y, Pt2.Y ) - LabelSize.cY div 2 else labelTop := max( Pt1.Y, Pt2.Y ) - Ceil( LabelSize.cY / 2 ); if labelTop < PosY then labelTop := PosY else if labelTop + labelSize.cY > PosY + Height then labelTop := PosY + Height - labelSize.cY; IEDrawText( Canvas, labelLeft, labelTop, labelLeft + labelSize.cX, labelTop + labelSize.cY, Zoom, LabelText, LabelFont, LabelAlign, ielCenter, 0, {Angle } LabelBorderColor, LabelBorderWidth, LabelFillColor, LabelFillColor2, LabelFillGradient, True, AntiAlias, LabelShape, UpdateSize); LabelRect := Rect( Round( labelLeft / Zoom ), Round( labelTop / Zoom ), Round(( labelLeft + labelSize.cX ) / Zoom ), Round(( labelTop + labelSize.cY ) / Zoom )); end; finally Canvas.SmoothingMode := prevSmoothingMode; end; end; // Bitmap is created if nil // must be freed procedure TIELineLayer.CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); var newWidth, newHeight, minSize: Double; OutSize: TSize; sizeChanged: Boolean; begin if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; if EnableAlpha then begin InitBitmapRGBA( Dest, CreateWidth, CreateHeight ); // Use ie32RGB for RGBA support Dest.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); end else InitBitmap( Dest, CreateWidth, CreateHeight ); OutSize := IEDrawLine( Dest.IECanvas, 0, 0, Dest.Width, Dest.Height, Zoom, Round( Rotate ), fLineColor, fLineWidth, fStartShape, fEndShape, fShapeSize, fLineFillColor, fLabelPosition, fLabelText, fLabelAlignment, fLabelFont, fLabelShape, fBorderColor, fBorderWidth, fFillColor, fFillColor2, fFillGradient, fAntiAlias and not FastDrawing, fAntiAlias, // Ignore fast drawing for text fLineRect, fLabelRect, fStartShapePoints, fEndShapePoints, UpdateSize, fLastLineLength ); fLineLength := _DistPoint2Point( fLineRect.Left, fLineRect.Top, fLineRect.Right, fLineRect.Bottom ); if fLastLineLength <= 0 then fLastLineLength := fLineLength; if UpdateSize then begin if ( OutSize.cX < 0 ) or ( OutSize.cY < 0 ) then exit; // "LineWidth" padding on each side of line minSize := 3 * fLineWidth; newWidth := max( minSize, OutSize.cX ); newHeight := max( minSize, OutSize.cY ); sizeChanged := ( fResizedWidth <> newWidth ) or ( fResizedHeight <> newHeight ); fPosX := fPosX + ( fResizedWidth - newWidth ) / 2; fResizedWidth := newWidth; fPosY := fPosY + ( fResizedHeight - newHeight ) / 2 ; fResizedHeight := newHeight; if sizeChanged then LayerChange(); end else begin if EnableAlpha then Dest.SynchronizeRGBA( True, True ) else Dest.RemoveAlphaChannel() end; end; // Don't need UseDisplayAR. AR is always maintained for line layers procedure TIELineLayer.CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); var Zoom: Double; wasLineRect: TRect; wasLabelRect: TRect; wasStartShapePoints: TIEEndShapeDrawInfo; wasEndShapePoints: TIEEndShapeDrawInfo; wasLineLength, wasLastLineLength: Double; begin Zoom := 1; if ( CreateWidth > 0 ) and ( CreateHeight > 0 ) then Zoom := min( CreateWidth / OriginalWidth, CreateHeight / OriginalHeight ); wasLineRect := fLineRect; wasLabelRect := fLabelRect; wasStartShapePoints := fStartShapePoints; wasEndShapePoints := fEndShapePoints; wasLineLength := fLineLength; wasLastLineLength := fLastLineLength; CopyToBitmapEx( Dest, CreateWidth, CreateHeight, Owner_FastOutputActive(), EnableAlpha, UseDisplayAR, False, False, Zoom ); // Don't update layout vars because bitmap may be different size fLineRect := wasLineRect; fLabelRect := wasLabelRect; fStartShapePoints := wasStartShapePoints; fEndShapePoints := wasEndShapePoints; fLineLength := wasLineLength; fLastLineLength := wasLastLineLength; end; {!! TIELineLayer.SizeToFit Declaration procedure TIELineLayer.SizeToFit(); Description Updates the size of the layer to fit the displayed angle. This is useful if you have manually set the width/height of the layer. Example with ImageEnView1 do begin LayersAdd( ielkLine ); CurrentLayer.Rotate := 30; CurrentLayer.Width := 500; CurrentLayer.Height := 500; TIELineLayer( CurrentLayer ).SizeToFit(); Update(); end; !!} procedure TIELineLayer.SizeToFit(); begin CopyToBitmapEx( fGlobalCacheBitmap, Round( fResizedWidth ), Round( fResizedHeight ), True, False, True, True ) end; function TIELineLayer.GetBitmap : TIEBitmap; begin CopyToBitmap( fGlobalCacheBitmap, iMax( 1, Round( fResizedWidth )), iMax( 1, Round( fResizedHeight )), Owner_EnableAlphaChannel, False ); Result := fGlobalCacheBitmap; end; procedure TIELineLayer.LoadFromStream(Stream: TStream); var saveVer: Integer; dDummy: Double; begin saveVer := LoadMetaFromStream( Stream ); if saveVer < 6400 then raise EIEException.create( 'Unknown data version' ); // Other props Stream.Read( fLineColor, SizeOf( TColor )); Stream.Read( fLineWidth, SizeOf( Integer )); Stream.Read( fLineFillColor, SizeOf( TColor )); IELoadFontFromStream(Stream, fLabelFont ); IELoadStringFromStreamW(Stream, fLabelText); Stream.Read( fLabelAlignment, SizeOf( TIEAlignment )); Stream.Read( fLabelPosition, SizeOf( TIELineLabelPos )); Stream.Read( fLabelShape, SizeOf( TIEShape )); Stream.Read( fReadOnly, SizeOf( Boolean )); Stream.Read( fShapeSize, sizeof( integer )); Stream.Read( fStartShape, sizeof( TIELineEndShape )); Stream.Read( fEndShape, sizeof( TIELineEndShape )); if saveVer <= 7001 then begin fLastLineLength := -1; Stream.Read( dDummy, sizeof( Double )); Stream.Read( dDummy, sizeof( Double )); end else Stream.Read( fLastLineLength, sizeof( Double )); if saveVer >= 7001 then Stream.Read( fAutoSize , SizeOf( Boolean )); fModified := False; end; procedure TIELineLayer.SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); var l, sz: integer; begin l := Stream.Position; SaveMetaToStream( Stream); // other props Stream.Write( fLineColor, SizeOf( TColor )); Stream.Write( fLineWidth, SizeOf( Integer )); Stream.Write( fLineFillColor, SizeOf( TColor )); IESaveFontToStream(Stream, fLabelFont ); IESaveStringToStreamW(Stream, fLabelText); Stream.Write( fLabelAlignment, SizeOf( TIEAlignment )); Stream.Write( fLabelPosition, SizeOf( TIELineLabelPos )); Stream.Write( fLabelShape, SizeOf( TIEShape )); Stream.Write( fReadOnly, SizeOf( Boolean )); Stream.Write( fShapeSize, sizeof( integer )); Stream.Write( fStartShape, sizeof( TIELineEndShape )); Stream.Write( fEndShape, sizeof( TIELineEndShape )); Stream.Write( fLastLineLength, sizeof( Double )); Stream.Write( fAutoSize , SizeOf( Boolean )); // Update position sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Fill size Stream.Position := l + sz; // Position at end of layer record end; function TIELineLayer.GetAsSVG(): string; function _DrawShape(ShapePoints: TIEEndShapeDrawInfo): string; var pp: array[0..2] of TPoint; begin case ShapePoints.Shape of ieesCircle : begin Result := CreateSVGShapeTag( iesEllipse, PosX + ShapePoints.Pt1.X, PosY + ShapePoints.Pt1.Y, ShapePoints.Pt2.X - ShapePoints.Pt1.X, ShapePoints.Pt2.Y - ShapePoints.Pt1.Y, LineWidth, LineColor, LabelFillColor, 0 {Rotate}, fTransparency ); end; ieesArrow : begin pp[ 0 ]:= Point( PosX + ShapePoints.Pt1.X, PosY + ShapePoints.Pt1.Y ); pp[ 1 ]:= Point( PosX + ShapePoints.Pt2.X, PosY + ShapePoints.Pt2.Y ); pp[ 2 ]:= Point( PosX + ShapePoints.Pt3.X, PosY + ShapePoints.Pt3.Y ); Result := CreateSVGPolylineTag( pp, 3, True, LineWidth, LineColor, LabelFillColor, 0 {Rotate}, Point(0,0), fTransparency ); end; end; end; var labelVisible: Boolean; lineTag, startShapeTag, endShapeTag, textTag: string; begin Result := ''; if ( fLineRect.Left = 0 ) and ( fLineRect.Right = 0 ) and ( fLineRect.Top = 0 ) and ( fLineRect.Bottom = 0 ) then CopyToBitmapEx( fGlobalCacheBitmap, -1, -1, True, False, True ); // So fLineRect is updated lineTag := CreateSVGLineTag( Point( PosX + fLineRect.Left, PosY + fLineRect.Top ), Point( PosX + fLineRect.Right, PosY + fLineRect.Bottom ), LineWidth, LineColor, fTransparency ); startShapeTag := _DrawShape( fStartShapePoints ); endShapeTag := _DrawShape( fEndShapePoints ); textTag := ''; labelVisible := fLabelText <> ''; if ( fLabelRect.Left = 0 ) and ( fLabelRect.Right = 0 ) then labelVisible := False; if labelVisible then textTag := CreateSVGTextTag( fLabelText, LabelFont, PosX + fLabelRect.Left, PosY + fLabelRect.Top, fLabelRect.Right - fLabelRect.Left, fLabelRect.Bottom - fLabelRect.Top, fLabelAlignment, ielCenter, 0 { TextAngle }, LabelBorderWidth, LabelBorderColor, LabelFillColor, fLabelShape, fTransparency ); Result := lineTag + startShapeTag + endShapeTag + textTag; end; {!! TIELineLayer.LabelFont Declaration property LabelFont: TFont; Description Specifies the font of the label text. Example // Sets 'Arial' as font type for the current line layer TIELineLayer( ImageEnView1.CurrentLayer ).LabelFont.Name := 'Arial'; ImageEnView1.Update(); See Also -
- - - !!} procedure TIELineLayer.SetLabelFont(const Value: TFont); begin fLabelFont := Value; LayerChange(); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.LabelBorderColor Declaration property LabelBorderColor: TColor; Description The color of the frame around the text label. To hide the border set BorderColor to clNone or to 0. Default: clBlack Example // Add text label to our arrow (with black border and gradient fill) TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtEnd; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderColor - - !!} function TIELineLayer.GetLabelBorderColor: TColor; begin Result := fBorderColor; end; procedure TIELineLayer.SetLabelBorderColor(value: TColor); begin fBorderColor := Value; LayerChange(); end; {!! TIELineLayer.LabelBorderWidth Declaration property LabelBorderWidth: Integer; Description The width of the frame around the text label. To hide the border, set LabelBorderColor to clNone or to 0. Default: 1 Example // Add text label to our arrow (with black border and gradient fill) TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtEnd; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - - !!} function TIELineLayer.GetLabelBorderWidth: Integer; begin Result := fBorderWidth; end; procedure TIELineLayer.SetLabelBorderWidth(value: Integer); begin fBorderWidth := Value; LayerChange(); end; {!! TIELineLayer.LabelFillColor Declaration property LabelFillColor: TColor; Description The color of the text label. The fill color must be valid (i.e. clNone is not supported). If LabelFillColor is different from it will be drawn as a gradient. Default: clWhite Example // Add text label to our arrow (with black border and gradient fill) TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtEnd; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.FillColor - - - !!} function TIELineLayer.GetLabelFillColor: TColor; begin Result := fFillColor; end; procedure TIELineLayer.SetLabelFillColor(value: TColor); begin fFillColor := Value; LayerChange(); end; {!! TIELineLayer.LabelFillColor2 Declaration property LabelFillColor2: TColor; Description The end color for the text label gradient. If LabelFillColor2 is clNone, the text box is filled by a solid color specified by . If LabelFillColor2 is different from it is drawn as a gradient. The direction of the gradient is specified by . Default: clNone Example // Set a horizontal gradient fill for the label of a line layer TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); // Which is the same as... ImageEnView1.CurrentLayer.FillColor := clRed; ImageEnView1.CurrentLayer.FillColor2 := clYellow; ImageEnView1.CurrentLayer.FillGradient := clHorizontal; ImageEnView1.CurrentLayer.BorderColor := clBlack; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); // Disable the gradient fill of the label TIELineLayer( ImageEnView1.CurrentLayer ).LabelFillColor2 := clNone; ImageEnView1.Update(); See Also - TIELayer.FillColor2 - - !!} function TIELineLayer.GetLabelFillColor2: TColor; begin Result := fFillColor2; end; procedure TIELineLayer.SetLabelFillColor2(value: TColor); begin fFillColor2 := Value; LayerChange(); end; {!! TIELineLayer.LabelFillGradient Declaration property LabelFillGradient: ; Description The direction of the gradient used for the text label fill. If is different from the text box is filled with a gradient. LabelFillGradient specifies the direction. Default: gdVertical Example // Set a horizontal gradient fill for the label of a line layer TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); // Which is the same as... ImageEnView1.CurrentLayer.FillColor := clRed; ImageEnView1.CurrentLayer.FillColor2 := clYellow; ImageEnView1.CurrentLayer.FillGradient := clHorizontal; ImageEnView1.CurrentLayer.BorderColor := clBlack; ImageEnView1.CurrentLayer.BorderWidth := 3; ImageEnView1.Update(); See Also - TIELayer.FillGradient - - !!} function TIELineLayer.GetLabelFillGradient: TIEGradientDir; begin Result := fFillGradient; end; {!! TIELineLayer.LineLength Declaration property LineLength: Integer; Description Provides an alternative way to set the size of the line (other than setting the rectangle via and ). Comparison TIELineLayer provides three ways to position the line depending on your requirements. All the following create a 45 deg. line from 100,100 to 300,300 1. Standard TIELayer methods ImageEnView1.CurrentLayer.PosX := 100; ImageEnView1.CurrentLayer.PosY := 100; ImageEnView1.CurrentLayer.Width := 200; ImageEnView1.CurrentLayer.Height := 200; 2. Setting starting and end points TIELineLayer( ImageEnView1.CurrentLayer ).LinePoints := Rect( 100, 100, 300, 300 ); 2. Setting line length TIELineLayer( ImageEnView1.CurrentLayer ).AutoSize := False; ImageEnView1.CurrentLayer.PosX := 100; ImageEnView1.CurrentLayer.PosY := 100; ImageEnView1.CurrentLayer.Rotate := -45; TIELineLayer( ImageEnView1.CurrentLayer ).LineLength := 280; Example // Create a layer 100 pixels long at 45 degrees ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).LineLength := 100; TIELineLayer( ImageEnView1.CurrentLayer ).Rotate := 45; ImageEnView1.Update(); See Also - !!} function TIELineLayer.GetLineLength: Integer; begin Result := Round( fLineLength ); end; procedure TIELineLayer.SetLineLength(const Value: Integer); var wasPosX, wasPosY: Integer; begin wasPosX := PosX; wasPosY := PosY; fLastLineLength := Value; SizeToFit(); // Size from top, left PosX := wasPosX; PosY := wasPosY; end; {!! TIELineLayer.LinePoints Declaration property LineLength: TRect; Description Provides an alternate method to set the position of a line, by specifying its two end points. The points are expressed within a rect, i.e. Point 1 is (Left, Top) and Point 2 is (Right, Bottom). Note: When setting LinePoints, end shapes and label are not taken into account Comparison TIELineLayer provides three ways to position the line depending on your requirements. All the following create a 45 deg. line from 100,100 to 300,300 1. Standard TIELayer methods ImageEnView1.CurrentLayer.PosX := 100; ImageEnView1.CurrentLayer.PosY := 100; ImageEnView1.CurrentLayer.Width := 200; ImageEnView1.CurrentLayer.Height := 200; 2. Setting starting and end points TIELineLayer( ImageEnView1.CurrentLayer ).LinePoints := Rect( 100, 100, 300, 300 ); 2. Setting line length TIELineLayer( ImageEnView1.CurrentLayer ).AutoSize := False; ImageEnView1.CurrentLayer.PosX := 100; ImageEnView1.CurrentLayer.PosY := 100; ImageEnView1.CurrentLayer.Rotate := -45; TIELineLayer( ImageEnView1.CurrentLayer ).LineLength := 280; Example // Create a line from 100,100 to 200,200 ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).LinePoints := Rect( 100, 100, 200, 200 ); ImageEnView1.Update(); // Display points of the current line layer with TIELineLayer( ImageEnView1.CurrentLayer ) do begin lblPoint1.Caption := Format( 'Point 1: %d, %d', [ LinePoints.Left, LinePoints.Top ]); lblPoint2.Caption := Format( 'Point 2: %d, %d', [ LinePoints.Right, LinePoints.Bottom ]); end; See Also - !!} function TIELineLayer.GetLinePoints: TRect; begin if ( fLineRect.Left = 0 ) and ( fLineRect.Right = 0 ) and ( fLineRect.Top = 0 ) and ( fLineRect.Bottom = 0 ) then CopyToBitmapEx( fGlobalCacheBitmap, -1, -1, True, False, True ); // So fLineRect is updated result := fLineRect; end; procedure TIELineLayer.SetLinePoints(Value: TRect); var lineLength: Double; begin fRotate := IERadiansToDegrees( IEAngle2( Value.Left, Value.Top, Value.Right, Value.Bottom )); lineLength := _DistPoint2Point( Value.Left, Value.Top, Value.Right, Value.Bottom ); SetLineLength( Round( lineLength )); PosX := min( Value.Left, Value.Right ); PosY := min( Value.Top, Value.Bottom ); end; procedure TIELineLayer.SetLabelFillGradient(value: TIEGradientDir); begin fFillGradient := Value; LayerChange(); end; {!! TIELineLayer.FillColor Declaration property FillColor: TColor; Description The fill for the and . Notes: - The border style is the same as for the line ( and - Gradients are not supported Default: clWhite Example // Add yellow filled arrows and circle ends to our current line layer TIELineLayer( ImageEnView1.CurrentLayer ).StartShape := ieesArrow; TIELineLayer( ImageEnView1.CurrentLayer ).EndShape := ieesCircle; TIELineLayer( ImageEnView1.CurrentLayer ).FillColor := clYellow; TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); See Also - TIELayer.FillColor - !!} procedure TIELineLayer.SetLineFillColor(const Value: TColor); begin fLineFillColor := Value; LayerChange(); end; {!! TIELineLayer.LineColor Declaration property LineColor: TColor; Description The color of the line and the border of and . Default: clBlack Example // Add a thick green line layer ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).LineColor := clGreen; TIELineLayer( ImageEnView1.CurrentLayer ).LineWidth := 5; ImageEnView1.Update(); See Also - TIELayer.BorderColor - - !!} procedure TIELineLayer.SetLineColor(const value: TColor); begin fLineColor := Value; LayerChange(); end; {!! TIELineLayer.LineWidth Declaration property LineWidth: Integer; Description The width of the line and the border of and . Default: 1 Example // Add a thick green line layer ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).LineColor := clGreen; TIELineLayer( ImageEnView1.CurrentLayer ).LineWidth := 5; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - - !!} procedure TIELineLayer.SetLineWidth(const value: Integer); begin fLineWidth := Value; LayerChange(); end; {!! TIELineLayer.LabelShape Declaration property LabelShape: ; Description The shape of the text label. Note: Only the following shapes are supported: iesRectangle, iesRoundRect, iesEllipse Default: iesRectangle Example // Add a circular "Here" label ImageEnView1.LayersAdd( ielkLine ); TIELineLayer( ImageEnView1.CurrentLayer ).LabelShape := iesEllipse; TIELineLayer( ImageEnView1.CurrentLayer ).LabelText := 'Here'; ImageEnView1.Update(); // Add rectangular text label to our line TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtEnd; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor := clRed; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillColor2 := clYellow; TIELineLayer(ImageEnView1.CurrentLayer).LabelFillGradient := clHorizontal; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderColor := clBlack; TIELineLayer(ImageEnView1.CurrentLayer).LabelBorderWidth := 3; ImageEnView1.Update(); See Also - - - - !!} procedure TIELineLayer.SetLabelShape(Value: TIEShape); begin fLabelShape := Value; LayerChange(); end; {!! TIELineLayer.LabelAlignment Declaration property LabelAlignment: ; Description Specifies the alignment of the text label. Notes: iejJustify is unsupported for TIELineLayers Default: iejLeft Example // Center the text for the label of the current line TIELineLayer( ImageEnView1.CurrentLayer ).LabelAlignment := iejCenter; ImageEnView1.Update(); See Also - - - - !!} procedure TIELineLayer.SetLabelAlignment(Value: TIEAlignment); begin fLabelAlignment := Value; LayerChange(); end; {!! TIELineLayer.LabelText Declaration property LabelText: String; Description When a value is specified for LabelText, a text label will be displayed at the end of the line. Example TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtEnd; TIELineLayer( ImageEnView1.CurrentLayer ).LabelText := 'Test Label'; ImageEnView1.Update(); See Also - - - - !!} procedure TIELineLayer.SetLabelText(const Value: string); begin fLabelText := Value; LayerChange(); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.LabelPosition Declaration property LabelPosition: ; Description Specifies the position and visibility of the text label. Value Description ielpHide Does not show the text label even if text has been specified ielpAtStart Shows the text label at the start of the line ielpAtEnd Shows the text label at the end of the line
Default: ielpAtEnd Examples // Move the label to the start of the line TIELineLayer( ImageEnView1.CurrentLayer ).LabelPosition := ielpAtStart; // Hide labels of all line layers when user clicks a check box procedure Tfmain.chkShowLabelsClick(Sender: TObject); var I: integer; begin ImageEnView1.LockUpdate(); for I := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1.Layers[ I ].Kind = ielkLine then begin if chkShowLabels.Checked then TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpAtEnd else TIELineLayer( ImageEnView1.Layers[ I ]).LabelPosition := ielpHide; end; ImageEnView1.UnlockUpdate(); end; See Also -
- - - !!} procedure TIELineLayer.SetLabelPosition(const Value: TIELineLabelPos); begin fLabelPosition := Value; LayerChange(); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.ActivateEditor Declaration procedure ActivateEditor(); Description Activates editing of the text label by the user (i.e. user can begin typing to change the text) Note: Has no effecr if the label is not visible Example // Display the text editor for the current layer if Layer is TIELineLayer TIELineLayer( ImageEnView1.CurrentLayer ).ActivateEditor() else if Layer is TIETextLayer TIETextLayer( ImageEnView1.CurrentLayer ).ActivateEditor(); See Also - !!} procedure TIELineLayer.ActivateEditor(); begin if assigned( fOwner ) and (( fLabelRect.Right - fLabelRect.Left ) > 0 ) then TImageEnView( fOwner ).LayersActivateTextEditor( GetIndex ); end; {!! TIELineLayer.StartShape Declaration property StartShape: ; Description Specifies the shape that is displayed at the start of the line. Notes: - The border width and color of the arrow will be the same as the line (i.e. specified by and ) - The fill is specified by (Gradients are not supported) - If a label is displayed and = ielpAtStart, then the StartShape will not be shown Default: ieesNone Example // Add yellow filled arrows and circle ends to our current line layer TIELineLayer( ImageEnView1.CurrentLayer ).StartShape := ieesArrow; TIELineLayer( ImageEnView1.CurrentLayer ).EndShape := ieesCircle; TIELineLayer( ImageEnView1.CurrentLayer ).FillColor := clYellow; TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); See Also - - !!} procedure TIELineLayer.SetStartShape(const Value: TIELineEndShape); begin fStartShape := Value; LayerChange(); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.EndShape Declaration property EndShape: ; Description Specifies the shape that is displayed at the end of the line. Notes: - The border width and color of the arrow will be the same as the line (i.e. specified by and ) - The fill is specified by (Gradients are not supported) - If a label is displayed and = ielpAtEnd, then the EndShape will not be shown Default: ieesNone Example // Add yellow filled arrows and circle ends to our current line layer TIELineLayer( ImageEnView1.CurrentLayer ).StartShape := ieesArrow; TIELineLayer( ImageEnView1.CurrentLayer ).EndShape := ieesCircle; TIELineLayer( ImageEnView1.CurrentLayer ).FillColor := clYellow; TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); See Also - - !!} procedure TIELineLayer.SetEndShape(const Value: TIELineEndShape); begin fEndShape := Value; LayerChange(); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.ShapeSize Declaration property ShapeSize: integer; Description Specifies the size of the arrows at the start and end of the line. Notes: - The border width and color of the arrow will be the same as the line (i.e. specified by and ) - The fill is specified by (Gradients are not supported) Default: 20 Example // Enlarge the arrows TIELineLayer( ImageEnView1.CurrentLayer ).ShapeSize := 25; ImageEnView1.Update(); See Also - - !!} procedure TIELineLayer.SetShapeSize(const Value: Integer); begin fShapeSize := Value; LayerChange(); if fAutoSize then SizeToFit(); end; procedure TIELineLayer.SetAutoSize(const Value: boolean); begin fAutoSize := Value; LayerChange( False ); if fAutoSize then SizeToFit(); end; {!! TIELineLayer.ReadOnly Declaration property ReadOnly: Boolean; Description Prevents the user from editing the text of the label. When ReadOnly is false, the user can double-click the label or click F2 to start editing of the label text. ReadOnly prevents the user from editing the text. Default: False Example // Prevent editing of the current layer text TIELineLayer( ImageEnView1.CurrentLayer ).ReadOnly := False; !!} procedure TIELineLayer.SetReadOnly(const Value: boolean); begin fReadOnly := Value; LayerChange( False ); end; // *************************************************************************************** // // ** ** // // ** TIEPolylineLayer ** // // ** ** // // *************************************************************************************** // constructor TIEPolylineLayer.Create(Owner: TObject); begin inherited Create(Owner); fKind := ielkPolyline; fPolyPoints := nil; fPolyPointCount := 0; fPolyPointsAllocated := 0; fDrawnPoints := nil; fDrawnPointCount := 0; fDrawnPointsAllocated := 0; SetDefaults; fResizedWidth := 100; fResizedHeight := 100; end; destructor TIEPolylineLayer.Destroy; begin if fDrawnPoints <> nil then begin freemem(fDrawnPoints); fDrawnPoints := nil; end; fDrawnPointCount := 0; fDrawnPointsAllocated := 0; ClearAllPoints(); inherited; end; procedure IEDrawPolyline(Canvas: TIECanvas; PosX, PosY, Width, Height: Integer; ZoomX, ZoomY: Double; Layer: TIEPolylineLayer; PolyPoints: pointer; // array of TPoint. Coordinates are in bitmap pixels, they are never translated or resized. // C++Builder doesn't work with PolyPoints as PPointArray PolyPointCount: integer; // PolyPoints count PolyPointsAllocated: integer; // allocated polyline points PolylineClosed: boolean; // the polygon is closes (filled with a brush) var fDrawnPoints: pointer; var fDrawnPointCount: integer; var fDrawnPointsAllocated: integer; LineColor: TColor; LineWidth: Integer; FillColor: TColor; FillColor2: TColor; FillGradient: TIEGradientDir; AntiAlias: Boolean; Angle: Integer; AspectRatioLocked: Boolean); var currX, currY: Integer; i: Integer; pts: PPointArray; prevSmoothingMode : TIECanvasSmoothingMode; flipHorz, flipVert, invertDir: Boolean; tempWidth, tempHeight: Integer; begin // ImageEn angles are counter-clockwise Angle := 360 - Angle; while Angle >= 360 do Dec( Angle, 360 ); while Angle < 0 do Inc( Angle, 360 ); if LineWidth > 0 then LineWidth := imax( 1, Round( LineWidth * ( ZoomX + ZoomY ) / 2 )); prevSmoothingMode := Canvas.SmoothingMode; if AntiAlias then Canvas.SmoothingMode := iesmAntialias else Canvas.SmoothingMode := iesmBestPerformance; try with Canvas do begin Pen.Color := $01010101; // needed otherwise next Pen.Color is not set (gdi bug workaround?) if LineColor = clNone_ then LineWidth := 0; if LineWidth > 0 then begin Pen.Style := psSolid; Pen.Width := LineWidth; Pen.Color := LineColor; 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 fDrawnPointCount <> PolyPointCount then begin fDrawnPointCount := PolyPointCount; if fDrawnPointCount > fDrawnPointsAllocated then begin if assigned(fDrawnPoints) then freemem(fDrawnPoints); fDrawnPointsAllocated := fDrawnPointCount * 2; getmem(fDrawnPoints, fDrawnPointsAllocated * sizeof(TPoint)); end; end; // for 90 degree rotates, do flip/inversions for speed flipHorz := ( Angle = 180 ) or ( Angle = 270 ); flipVert := ( Angle = 90 ) or ( Angle = 180 ); invertDir := (Angle = 90) or ( Angle = 270 ); if invertDir and AspectRatioLocked then begin if Width > Height then begin tempWidth := Width; Width := Round( Height * Height / Width ) ; PosX := PosX + ( tempWidth - Width ) div 2; end else begin tempHeight := Height; Height := Round( Width * Width / Height ) ; PosY := PosY + ( tempHeight - Height ) div 2; end; end; pts := ppointarray(fDrawnPoints); for i := 0 to PolyPointCount - 1 do begin currX := PPointArray(PolyPoints)[ i ].x; currY := PPointArray(PolyPoints)[ i ].y; // FLIP HORZ if flipHorz then currX := 1000 - currX; // FLIP VERT if flipVert then currY := 1000 - currY; if invertDir then begin pts[i].x := PosX + LineWidth div 2 + round( currY / 1000 * ( Width - LineWidth )); pts[i].y := PosY + LineWidth div 2 + round( currX / 1000 * ( Height - LineWidth )); end else begin pts[i].x := PosX + LineWidth div 2 + round( currX / 1000 * ( Width - LineWidth )); pts[i].y := PosY + LineWidth div 2 + round( currY / 1000 * ( Height - LineWidth )); end; end; // Free rotation if Angle mod 90 <> 0 then begin IERotatePoints( slice( pts^, PolyPointCount ), PolyPointCount, - Angle, PosX + LineWidth div 2 + Width div 2, PosY + LineWidth div 2 + Height div 2 ); IEScalePoints( slice( pts^, PolyPointCount ), PolyPointCount, PosX + LineWidth div 2, PosY + LineWidth div 2, PosX + Width - LineWidth, PosY + Height - LineWidth, AspectRatioLocked ); end; if PolylineClosed then Polygon( slice( pts^, PolyPointCount )) else Polyline( slice( pts^, PolyPointCount )); end; finally Canvas.SmoothingMode := prevSmoothingMode; end; end; // Bitmap is created if nil // must be freed procedure TIEPolylineLayer.CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); var drawRect: TRect; begin if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; if EnableAlpha then begin InitBitmapRGBA( Dest, CreateWidth, CreateHeight ); // Use ie32RGB for RGBA support Dest.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); end else InitBitmap( Dest, CreateWidth, CreateHeight ); drawRect := Rect( 0, 0, Dest.Width, Dest.Height ); if UseDisplayAR then drawRect := GetImageRectWithinArea( Width, Height, Dest.Width, Dest.Height ); IEDrawPolyline( Dest.IECanvas, drawRect.Left, drawRect.Top, drawRect.Right - drawRect.Left, drawRect.Bottom - drawRect.Top, CreateWidth / GetWidth, CreateHeight / GetHeight, Self, fPolyPoints, fPolyPointCount, fPolyPointsAllocated, fPolylineClosed, fDrawnPoints, fDrawnPointCount, fDrawnPointsAllocated, fBorderColor, fBorderWidth, fFillColor, fFillColor2, fFillGradient, fAntiAlias and not FastDrawing, Round( Rotate ), fAspectRatioLocked ); if EnableAlpha then Dest.SynchronizeRGBA( True, True ) else Dest.RemoveAlphaChannel() end; procedure TIEPolylineLayer.CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); begin CopyToBitmapEx( Dest, CreateWidth, CreateHeight, Owner_FastOutputActive(), EnableAlpha, UseDisplayAR ); end; function TIEPolylineLayer.GetBitmap : TIEBitmap; begin CopyToBitmap( fGlobalCacheBitmap, iMax( 1, Round( fResizedWidth )), iMax( 1, Round( fResizedHeight )), Owner_EnableAlphaChannel, False ); Result := fGlobalCacheBitmap; end; {!! TIEPolylineLayer.FillColor Declaration property FillColor: TColor; Description The color of the polygon. To create a polygon you must close the polyline using . To make the text box transparent set FillColor to clNone. Gradients are not supported. Default: clWhite Example // Set fill color to yellow ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); // Remove fill color ImageEnView1.CurrentLayer.FillColor := clNone; ImageEnView1.Update(); See Also - TIELayer.FillColor !!} function TIEPolylineLayer.GetFillColor: TColor; begin Result := fFillColor; end; procedure TIEPolylineLayer.SetFillColor(value: TColor); begin fFillColor := Value; LayerChange(); end; {!! TIEPolylineLayer.LineColor Declaration property LineColor: TColor; Description The color of the polyline. Default: clBlack Example // Add a pink polyline ImageEnView1.LayersAdd( ielkPolyline ); TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesShootingArrowSW, True ); TIEPolylineLayer( ImageEnView1.CurrentLayer ).LineColor := $00C080FF; TIEPolylineLayer( ImageEnView1.CurrentLayer ).LineWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderColor - !!} function TIEPolylineLayer.GetLineColor: TColor; begin Result := fBorderColor; end; procedure TIEPolylineLayer.SetLineColor(value: TColor); begin fBorderColor := value; LayerChange(); end; {!! TIEPolylineLayer.LineWidth Declaration property LineWidth: Integer; Description The width of the polyline. Default: 1 Example // Add a pink polyline ImageEnView1.LayersAdd( ielkPolyline ); TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesShootingArrowSW, True ); TIEPolylineLayer( ImageEnView1.CurrentLayer ).LineColor := $00C080FF; TIEPolylineLayer( ImageEnView1.CurrentLayer ).LineWidth := 3; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - !!} function TIEPolylineLayer.GetLineWidth: Integer; begin Result := fBorderWidth; end; procedure TIEPolylineLayer.SetLineWidth(value: Integer); begin fBorderWidth := value; LayerChange(); end; {!! TIEPolylineLayer.PolylineClosed Declaration property PolylineClosed: boolean; Description Set PolylineClosed to True to connect the first and final points of the polyline. This will create a polygon. If the polygon is closed it will be filled using . Default: False Example // Draw a polyline With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); end; ImageEnView1.Update(); // Close the polyline, to create a polygon TIEPolylineLayer( ImageEnView1.CurrentLayer ).PolylineClosed := True; ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.Update(); !!} procedure TIEPolylineLayer.SetPolylineClosed(value: Boolean); begin fPolylineClosed := value; LayerChange(); end; procedure TIEPolylineLayer.LoadFromStream(Stream: TStream); var saveVer: Integer; begin saveVer := LoadMetaFromStream( Stream ); if saveVer < 6400 then raise EIEException.create( 'Unknown data version' ); // Other props // todo: @FAB: This code OK? ClearAllPoints(); Stream.Read(fPolyPointCount, sizeof(integer)); fPolyPointsAllocated := fPolyPointCount; getmem(fPolyPoints, sizeof(TPoint) * fPolyPointCount); Stream.Read(pbyte(fPolyPoints)^, sizeof(TPoint) * fPolyPointCount); Stream.Read(fPolylineClosed, sizeof(boolean)); fModified := False; end; procedure TIEPolylineLayer.SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); var l, sz: integer; begin l := Stream.Position; SaveMetaToStream( Stream); // other props // todo: @FAB: This code OK? Stream.Write(fPolyPointCount, sizeof(integer)); Stream.Write(pbyte(fPolyPoints)^, sizeof(TPoint) * fPolyPointCount); Stream.Write(fPolylineClosed, sizeof(boolean)); // Update position sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Fill size Stream.Position := l + sz; // Position at end of layer record end; function TIEPolylineLayer.GetAsSVG(): string; var pts: TIEArrayOfTPoint; i: Integer; RotateCenter: TPoint; begin SetLength( pts, fPolyPointCount ); for i := 0 to fPolyPointCount - 1 do begin pts[i].X := PPointArray(fPolyPoints)[ i ].x; pts[i].Y := PPointArray(fPolyPoints)[ i ].y; end; RotateCenter := Point( PosX + Width div 2, PosY + Height div 2 ); IEScalePoints( pts, fPolyPointCount, PosX + fBorderWidth div 2, PosY + fBorderWidth div 2, PosX + Width - fBorderWidth, PosY + Height - fBorderWidth, AspectRatioLocked ); Result := CreateSVGPolylineTag( pts, fPolyPointCount, fPolylineClosed, BorderWidth, BorderColor, FillColor, Rotate, RotateCenter, fTransparency ); end; {!! TIEPolylineLayer.Points Declaration property Points[index: integer]: TPoint; Description Returns the points of the polyline. Each point of the polyline is represented by an x and y value in the range 0 to 1000. Where (0, 0) is the top-left pixel of the layer and (1000, 1000) is the bottom-right. Use to determine the number of points in the Polyline. See Also - - - !!} function TIEPolylineLayer.GetPoints(index: integer): TPoint; begin Result := Point(-1, -1); if index < fPolyPointCount then begin result.x := PPointArray(fPolyPoints)[index].x; result.y := PPointArray(fPolyPoints)[index].y; end; end; {!! TIEPolylineLayer.PointCount Declaration property PointCount: integer; Description Returns the count of points of the polyline. Use to obtain the coordinates of point that compose the Polyline. !!} function TIEPolylineLayer.GetPointCount(): integer; begin result := fPolyPointCount; end; {!! TIEPolylineLayer.SetPoints Declaration procedure SetPoints(Points: array of TPoint); overload; procedure SetPoints(Points: array of TPoint; ClosePolyline: Boolean); overload; procedure SetPoints(Shape: ; ClosePolyline: Boolean = True); overload; Description Set the points of the polyline. Each point of the polyline is represented by an x and y value in the range 0 to 1000. Where (0, 0) is the top-left pixel of the layer and (1000, 1000) is the bottom-right. If you use the Shape overload, the point array will be filled with a . Not all shapes are supported. Shapes that are not included in will raise an exception. will be set to ClosePolyline. Example // Draw a triangle polygon With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); PolylineClosed := True; end; ImageEnView1.Update(); // Which is the same as... TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( [ Point(500, 0), Point(1000, 1000), Point(0, 1000) ], True ); ImageEnView1.Update(); // Which is the same as... TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesTriangle, True ); ImageEnView1.Update(); // If PolylineClosed is not enabled, we get a polyline, instead of a polygon TIEPolylineLayer( ImageEnView1.CurrentLayer ).PolylineClosed := False; ImageEnView1.Update(); // Fill points with Star shape TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesStar5, True ); // Fill points with Explosion shape TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesExplosion, True ); // Fill points with Arrow shape TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesShootingArrowSW, True ); // Fill points with Lightning shape TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesLightningLeft, True ); See Also - - - !!} procedure TIEPolylineLayer.SetPoints(Points: array of TPoint; ClosePolyline: Boolean); begin SetPoints( Points ); fPolylineClosed := ClosePolyline; end; procedure TIEPolylineLayer.SetPoints(Points: array of TPoint); var i: integer; begin ClearAllPoints(); for i := 0 to High(Points) do AddPoint(Points[i].x, Points[i].y); end; procedure TIEPolylineLayer.SetPoints(Shape: TIEShape; ClosePolyline: Boolean = True); var arPts : Array[ 0 .. Shape_Array_Max_Points ] of TPoint; pts: Integer; i: integer; begin IEGenerateShapePoints( arPts, pts, Shape, 0, 0, 1000, 1000 ); ClearAllPoints(); for i := 0 to pts - 1 do AddPoint( arPts[i].x, arPts[i].y ); fPolylineClosed := ClosePolyline; fOriginalAspectRatio := IEShapePreferredAspectRatio( Shape ); end; {!! TIEPolylineLayer.AddPoint Declaration procedure AddPoint(X, Y: integer); Description Add a point to the end of a polyline. Each point of the polyline is represented by an x and y value in the range 0 to 1000. Where (0, 0) is the top-left pixel of the layer and (1000, 1000) is the bottom-right. Example // Draw a polyline With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); end; ImageEnView1.Update(); // Draw a triangle polygon With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); PolylineClosed := True; end; ImageEnView1.Update(); See Also - - - !!} // changes Points, PolylineCount, x1,y1,x2,y2, fPolyBaseWidth, fPolyBaseHeight // x,y must be in bitmap coordinates procedure TIEPolylineLayer.AddPoint(X, Y: integer); var nn: PPointArray; begin if X < 0 then X := 0; if X > 1000 then X := 1000; if Y < 0 then Y := 0; if Y > 1000 then Y := 1000; if ( fPolyPointCount = 0 ) or ( X <> PPointarray(fPolyPoints)[fPolyPointCount - 1].X ) or ( Y <> PPointarray(fPolyPoints)[fPolyPointCount - 1].Y ) then begin inc(fPolyPointCount); if fPolyPointCount > fPolyPointsAllocated then begin fPolyPointsAllocated := fPolyPointCount * 2; getmem(nn, fPolyPointsAllocated * sizeof(TPoint)); move(PPointArray(fPolyPoints)[0], nn[0], (fPolyPointCount - 1) * sizeof(TPoint)); freemem(fPolyPoints); fPolyPoints := nn; end; PPointArray(fPolyPoints)[fPolyPointCount - 1].x := X; PPointArray(fPolyPoints)[fPolyPointCount - 1].y := Y; end; LayerChange(); end; {!! TIEPolylineLayer.ClearAllPoints Declaration procedure ClearAllPoints(); Description Removes all points from the polyline. Example // Draw a triangle polygon With TIEPolylineLayer( ImageEnView1.CurrentLayer ) do begin ClearAllPoints(); AddPoint( 500, 0 ); AddPoint( 1000, 1000 ); AddPoint( 0, 1000 ); PolylineClosed := True; end; ImageEnView1.Update(); See Also - - - - !!} procedure TIEPolylineLayer.ClearAllPoints(); begin if fPolyPoints <> nil then freemem( fPolyPoints ); fPolyPoints := nil; fPolyPointsAllocated := 0; fPolyPointCount := 0; LayerChange(); end; {!! TIEPolylineLayer.RemovePoint Declaration procedure RemovePoint(Index: integer); Description Removes point of Index from a Polyline. Example // Remove the last point from the selected Polyline TIEPolylineLayer( ImageEnView1.CurrentLayer ).RemovePoint( TIEPolylineLayer( ImageEnView1.CurrentLayer ).PointCount - 1 ); ImageEnView1.Update(); See Also - - - !!} procedure TIEPolylineLayer.RemovePoint(Index: integer); var i, idx: integer; pts: array of TPoint; begin if ( Index < 0 ) or ( Index > fPolyPointCount - 1 ) then exit; SetLength( pts, fPolyPointCount - 1 ); idx := 0; for i := 0 to fPolyPointCount - 1 do if I <> Index then begin pts[ idx ].x := PPointArray(fPolyPoints)[ I ].x; pts[ idx ].y := PPointArray(fPolyPoints)[ I ].y; inc( idx ); end; SetPoints( pts ); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Polyline simplify type Vector = record x, y: double; end; type Segment = record P0, P1: Vector; end; // difference function diff(u, v: Vector): Vector; begin result.x := u.x - v.x; result.y := u.y - v.y; end; // dot product function dot(u, v: Vector): double; begin result := u.x * v.x + u.y * v.y; end; // squared length of vector function norm2(v: Vector): double; begin result := dot(v, v); end; // length of vector function norm(v: Vector): double; begin result := sqrt(norm2(v)); end; // distance squared function d2(u, v: Vector): double; begin result := norm2(diff(u, v)); end; // distance function d(u, v: Vector): double; begin result := norm(diff(u, v)); end; // sum function sum(u, v: Vector): Vector; begin result.x := u.x + v.x; result.y := u.y + v.y; end; // vector*scalar function mulvs(u: Vector; s: double): Vector; begin result.x := u.x * s; result.y := u.y * s; end; // TPoint to Vector function tpv(p: TPoint): Vector; begin result.x := p.x; result.y := p.y; end; // This is the Douglas-Peucker recursive simplification routine procedure simplifyDP(tol: double; v: TIEArrayOfTPoint; j, k: integer; mk: TIEArrayOfInteger); var maxi, i: integer; maxd2: double; tol2: double; S: Segment; u: Vector; cu: double; w: Vector; Pb: Vector; b, cw, dv2: double; begin if (k <= j + 1) then exit; maxi := j; maxd2 := 0; tol2 := tol * tol; S.P0 := tpv(v[j]); S.P1 := tpv(v[k]); u := diff(S.P1, S.P0); cu := dot(u, u); for i := j + 1 to k - 1 do begin w := diff(tpv(v[i]), S.P0); cw := dot(w, u); if (cw <= 0) then dv2 := d2(tpv(v[i]), S.P0) else if (cu <= cw) then dv2 := d2(tpv(v[i]), S.P1) else begin b := cw / cu; Pb := sum(S.P0, mulvs(u, b)); dv2 := d2(tpv(v[i]), Pb); end; if (dv2 <= maxd2) then continue; maxi := i; maxd2 := dv2; end; if (maxd2 > tol2) then begin mk[maxi] := 1; simplifyDP(tol, v, j, maxi, mk); simplifyDP(tol, v, maxi, k, mk); end; end; // tol = tolerance // V : input array function IESimplifyPolygon(tol: double; V: array of TPoint): TIEArrayOfTPoint; var i, k, m, pv: integer; tol2: double; vt: TIEArrayOfTPoint; mk: TIEArrayOfInteger; n: integer; begin n := length(V); SetLength(result, n); SetLength(vt, n); SetLength(mk, n); FillChar(mk[0], n * sizeof(integer), 0); tol2 := tol * tol; // Vertex Reduction within tolerance of prior vertex cluster vt[0] := V[0]; k := 1; pv := 0; for i := 1 to n - 1 do begin if d2(tpv(V[i]), tpv(V[pv])) < tol2 then continue; vt[k] := V[i]; inc(k); pv := i; end; if (pv < n - 1) then begin vt[k] := V[n - 1]; inc(k); end; // Douglas-Peucker Polyline simplification mk[k - 1] := 1; mk[0] := mk[k - 1]; simplifyDP(tol, vt, 0, k - 1, mk); // m := 0; for i := 0 to k - 1 do if (mk[i] <> 0) then begin result[m] := vt[i]; inc(m); end; SetLength(result, m); // resize output array end; // End of Polyline simplify ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! TIEPolylineLayer.SimplifyPolygon Declaration procedure SimplifyPolygon(MaxPoints: integer); Description Replaces a high resolution polyline with a lower resolution polyline with fewer vertices (MaxPoints). Example TIEPolylineLayer( ImageEnView1.CurrentLayer ).SimplifyPolygon(30); // simplify the polygon to max 30 points ImageEnView1.Update(); !!} procedure TIEPolylineLayer.SimplifyPolygon(MaxPoints: integer); var i: integer; ia, oa: TIEArrayOfTPoint; tolerance: double; begin tolerance := 0.1; repeat SetLength(ia, fPolyPointCount); for i := 0 to fPolyPointCount - 1 do begin ia[i].x := PPointArray(fPolyPoints)[i].x; ia[i].y := PPointArray(fPolyPoints)[i].y; end; oa := IESimplifyPolygon(tolerance, ia); SetPoints(oa); tolerance := tolerance + 0.1; until length(oa) <= MaxPoints; end; // *************************************************************************************** // // ** ** // // ** TIETextLayer ** // // ** ** // // *************************************************************************************** // constructor TIETextLayer.Create(Owner: TObject); begin inherited Create(Owner); fKind := ielkText; fFont := TFont.Create; SetDefaults; fResizedWidth := 100; fResizedHeight := 100; end; destructor TIETextLayer.Destroy; begin FreeAndNil( fFont ); inherited; end; // Bitmap is created if nil // must be freed procedure TIETextLayer.CopyToBitmapEx(var Dest: TIEBitmap; CreateWidth : Integer; CreateHeight : Integer; FastDrawing: Boolean; EnableAlpha: Boolean; UseDisplayAR: Boolean; UpdateSize: Boolean = False; EnlargeOnly: Boolean = False; Zoom: Double = 1); var drawRect: TRect; textSize: TSize; begin if CreateWidth < 1 then CreateWidth := OriginalWidth; if CreateHeight < 1 then CreateHeight := OriginalHeight; if EnableAlpha then begin InitBitmapRGBA( Dest, CreateWidth, CreateHeight ); // Use ie32RGB for RGBA support Dest.IECanvas.SetCompositingMode(ieCompositingModeSourceOver, ieCompositingQualityDefault); end else InitBitmap( Dest, CreateWidth, CreateHeight ); drawRect := Rect( 0, 0, Dest.Width, Dest.Height ); if UseDisplayAR then drawRect := GetImageRectWithinArea( Width, Height, Dest.Width, Dest.Height ); textSize := IEDrawText( Dest.IECanvas, drawRect.Left, drawRect.Top, drawRect.Right, drawRect.Bottom, min( CreateWidth / GetWidth, CreateHeight / GetHeight ), WideString( fText ), fFont, fAlignment, fLayout, Round( Rotate ), fBorderColor, fBorderWidth, fFillColor, fFillColor2, fFillGradient, fAutosize, fAntiAlias, // Use anti-alias for text regardless of FastDrawing fBorderShape, UpdateSize ); if UpdateSize then begin if EnlargeOnly then begin Width := max( Width, textSize.cX ); Height := max( Height, textSize.cY ); end else begin Width := textSize.cX; Height := textSize.cY; end; end else begin if EnableAlpha then Dest.SynchronizeRGBA( True, True ) else Dest.RemoveAlphaChannel() end; end; procedure TIETextLayer.CopyToBitmap(var Dest: TIEBitmap; CreateWidth : Integer = -1; CreateHeight : Integer = -1; EnableAlpha: Boolean = True; UseDisplayAR: Boolean = True); var wasPixelFormat: TIEPixelFormat; begin wasPixelFormat := ie24RGB; if assigned( Dest ) and ( Dest.PixelFormat <> ieNull ) then wasPixelFormat := Dest.PixelFormat; CopyToBitmapEx(Dest, CreateWidth, CreateHeight, Owner_FastOutputActive(), EnableAlpha, UseDisplayAR, False ); Dest.PixelFormat := wasPixelFormat; end; function TIETextLayer.GetBitmap : TIEBitmap; begin CopyToBitmap( fGlobalCacheBitmap, iMax( 1, Round( fResizedWidth )), iMax( 1, Round( fResizedHeight )), Owner_EnableAlphaChannel, False ); Result := fGlobalCacheBitmap; end; {!! TIETextLayer.BorderColor Declaration property BorderColor: TColor; Description The color of the frame around the text box. To hide the text box frame set BorderColor to clNone or to 0. Default: clNone Example // Add a text layer with a black border and a white fill ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Text in Yellow box'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderColor := clBlack; TIETextLayer( ImageEnView1.CurrentLayer ).BorderWidth := 1; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clWhite; ImageEnView1.Update(); See Also - TIELayer.BorderColor - - !!} function TIETextLayer.GetBorderColor: TColor; begin Result := fBorderColor; end; procedure TIETextLayer.SetBorderColor(value: TColor); begin fBorderColor := Value; LayerChange(); end; {!! TIETextLayer.BorderWidth Declaration property BorderWidth: Integer; Description The width of the frame around the text box. To hide the text box frame set BorderWidth to 0 or to clNone. Default: 1 Example // Add a text layer with a black border and a white fill ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Text in Yellow box'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderColor := clBlack; TIETextLayer( ImageEnView1.CurrentLayer ).BorderWidth := 1; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clWhite; ImageEnView1.Update(); See Also - TIELayer.BorderWidth - - !!} function TIETextLayer.GetBorderWidth: Integer; begin Result := fBorderWidth; end; procedure TIETextLayer.SetBorderWidth(value: Integer); begin fBorderWidth := Value; LayerChange(); end; {!! TIETextLayer.FillColor Declaration property FillColor: TColor; Description The color of the text box. To make the text box transparent set FillColor to clNone. If FillColor is different from it will be drawn as a gradient. Default: clNone Example // Add a text layer with a black border and a white fill ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Text in Yellow box'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderColor := clBlack; TIETextLayer( ImageEnView1.CurrentLayer ).BorderWidth := 1; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clWhite; ImageEnView1.Update(); See Also - TIELayer.FillColor - - !!} function TIETextLayer.GetFillColor: TColor; begin Result := fFillColor; end; procedure TIETextLayer.SetFillColor(value: TColor); begin fFillColor := Value; LayerChange(); end; {!! TIETextLayer.FillColor2 Declaration property FillColor2: TColor; Description The end color for the text box gradient. If FillColor2 is clNone, the text box is filled by a solid color specified by . If FillColor2 is different from it is drawn as a gradient. The direction of the gradient is specified by . Note: Gradients are not supported if is iesEllipse Default: clNone Example // Disable the gradient fill TIETextLayer( ImageEnView1.CurrentLayer ).FillColor2 := clNone; // Add a red/blue horizontal gradient TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clRed; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor2 := clBlue; TIETextLayer( ImageEnView1.CurrentLayer ).FillGradient := gdHorizontal; ImageEnView1.Update(); See Also - TIELayer.FillColor2 - - !!} function TIETextLayer.GetFillColor2: TColor; begin Result := fFillColor2; end; procedure TIETextLayer.SetFillColor2(value: TColor); begin fFillColor2 := Value; LayerChange(); end; {!! TIETextLayer.FillGradient Declaration property FillGradient: ; Description The direction of the gradient used for the text box fill. If is different from the text box is filled with a gradient. FillGradient specifies the direction. Note: Gradients are not supported if is iesEllipse Default: gdVertical Example // Add a red/blue horizontal gradient TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clRed; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor2 := clBlue; TIETextLayer( ImageEnView1.CurrentLayer ).FillGradient := gdHorizontal; ImageEnView1.Update(); See Also - TIELayer.FillGradient - - !!} function TIETextLayer.GetFillGradient: TIEGradientDir; begin Result := fFillGradient; end; procedure TIETextLayer.SetFillGradient(value: TIEGradientDir); begin fFillGradient := Value; LayerChange(); end; {!! TIETextLayer.Alignment Declaration property Alignment: ; Description Specifies the text alignment. Notes: - iejJustify is unsupported for TIETextLayers - iejCenter is always used if is iesEllipse Default: iejLeft Example // Center the text for the current text layer TIETextLayer( ImageEnView1.CurrentLayer ).Alignment := iejCenter; ImageEnView1.Update(); See Also - !!} procedure TIETextLayer.SetAlignment(value: TIEAlignment); begin fAlignment := Value; LayerChange(); end; {!! TIETextLayer.Layout Declaration property Layout: ; Description Specifies the vertical alignment of text. Note: ielCenter is always used if is iesEllipse Default: ielTop Example // Center the text for the current text layer TIETextLayer( ImageEnView1.CurrentLayer ).Alignment := iejCenter; ImageEnView1.Update(); See Also - !!} procedure TIETextLayer.SetLayout(value: TIELayout); begin fLayout := Value; LayerChange(); end; procedure TIETextLayer.LoadFromStream(Stream: TStream); var saveVer: Integer; begin saveVer := LoadMetaFromStream( Stream ); if saveVer < 6400 then raise EIEException.create( 'Unknown data version' ); // Other props IELoadStringFromStreamW(Stream, fText); Stream.Read( fBorderShape, SizeOf( TIEShape )); IELoadFontFromStream(Stream, fFont ); Stream.Read( fAutoSize , SizeOf( Boolean )); Stream.Read( fReadOnly , SizeOf( Boolean )); Stream.Read( fAlignment , SizeOf( TIEAlignment )); Stream.Read( fLayout , SizeOf( TIELayout )); fModified := False; end; procedure TIETextLayer.SaveToStream(Stream: TStream; MetaOnly: Boolean = False; CompressionFormat: TIOFileType = -2); var l, sz: integer; begin l := Stream.Position; SaveMetaToStream( Stream); // other props IESaveStringToStreamW(Stream, fText); Stream.Write( fBorderShape, SizeOf( TIEShape )); IESaveFontToStream(Stream, fFont ); Stream.Write( fAutoSize , SizeOf( Boolean )); Stream.Write( fReadOnly , SizeOf( Boolean )); Stream.Write( fAlignment , SizeOf( TIEAlignment )); Stream.Write( fLayout , SizeOf( TIELayout )); // Update position sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Fill size Stream.Position := l + sz; // Position at end of layer record end; function TIETextLayer.GetAsSVG(): string; begin Result := CreateSVGTextTag( Text, Font, PosX, PosY, Width, Height, fAlignment, fLayout, Rotate, fBorderWidth, fBorderColor, fFillColor, fBorderShape, fTransparency ); end; {!! TIETextLayer.Font Declaration property Font: TFont; Description Specifies the font of the text. Example // Sets 'Arial' as font type for the current text layer TIETextLayer( ImageEnView1.CurrentLayer ).Font.Name := 'Arial'; ImageEnView1.Update(); !!} procedure TIETextLayer.SetFont(const Value: TFont); begin fFont := Value; LayerChange(); if fAutoSize then SizeToText(); end; {!! TIETextLayer.Text Declaration property Text: String; Description Specifies the displayed text. Note: The default text for new layers is specified by Example // Append a text layer ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'This is a Text Layer'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderColor := clBlack; TIETextLayer( ImageEnView1.CurrentLayer ).BorderWidth := 1; TIETextLayer( ImageEnView1.CurrentLayer ).FillColor := clWhite; ImageEnView1.Update(); !!} procedure TIETextLayer.SetText(const Value: string); begin fText := Value; LayerChange(); if fAutoSize then SizeToText(); end; {!! TIETextLayer.AutoSize Declaration property AutoSize: boolean; Description Use AutoSize to make the layer automatically adjust the size to accommodate the width of the text. When AutoSize is false, the text object has a fixed width. When AutoSize is true, the size of the object is re-adjusted whenever the user edits the text. Default: False See Also - !!} procedure TIETextLayer.SetAutoSize(const Value: boolean); begin fAutoSize := Value; LayerChange( False ); if fAutoSize then SizeToText(); end; {!! TIETextLayer.ReadOnly Declaration property ReadOnly: Boolean; Description Prevents the user from editing the text of the layer. When ReadOnly is false, the user can double-click a text layer or click F2 to start editing of the layer text. ReadOnly prevents the user from editing the text. Default: False Example // Prevent editing of the current layer text TIETextLayer( ImageEnView1.CurrentLayer ).ReadOnly := False; !!} procedure TIETextLayer.SetReadOnly(const Value: boolean); begin fReadOnly := Value; LayerChange( False ); end; {!! TIETextLayer.BorderShape Declaration property BorderShape: ; Description The shape around the text. Note: Only the following shapes are supported: iesRectangle, iesRoundRect, iesEllipse Default: iesRectangle Example // Add an elliptical text layer ImageEnView1.LayersAdd( ielkText ); TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Text in Ellipse'; TIETextLayer( ImageEnView1.CurrentLayer ).BorderShape := iesEllipse; ImageEnView1.Update(); See Also - - !!} procedure TIETextLayer.SetBorderShape(const Value: TIEShape); begin fBorderShape := Value; LayerChange(); if fAutoSize then SizeToText(); end; {!! TIETextLayer.SizeToText Declaration procedure TIETextLayer.SizeToText(EnlargeOnly: Boolean = False); Description Updates the size of the layer to fit the displayed text. If EnlargeOnly is true, the layer will not be reduced in size to fit the text more tightly, only enlarged to ensure all text is visible. Example // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 'Arial Black', 42, clRed, [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; See Also - !!} procedure TIETextLayer.SizeToText(EnlargeOnly: Boolean = False); begin CopyToBitmapEx( fGlobalCacheBitmap, iMax( 1, Round( fResizedWidth )), iMax( 1, Round( fResizedHeight )), True, False, False, True, EnlargeOnly ); end; {!! TIETextLayer.ActivateEditor Declaration procedure ActivateEditor(); Description Activates editing of the layer text by the user (i.e. user can begin typing to change the text) Example // Display the text editor for the current layer if Layer is TIELineLayer TIELineLayer( ImageEnView1.CurrentLayer ).ActivateEditor() else if Layer is TIETextLayer TIETextLayer( ImageEnView1.CurrentLayer ).ActivateEditor(); See Also - !!} procedure TIETextLayer.ActivateEditor(); begin if assigned( fOwner ) then TImageEnView( fOwner ).LayersActivateTextEditor( GetIndex ); end; initialization fGlobalCacheBitmap := nil; finalization end.