(* 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 version 1056 Doc revision 1004 *) unit imageenview; {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$R-} {$Q-} interface {$I ie.inc} uses Windows, Messages, Graphics, Controls, Forms, Classes, SysUtils, StdCtrls, ExtCtrls, Contnrs, hyiedefs, iexBitmaps, imageenio, imageenproc, ieview, iexTransitions, hyieutils, iexRulers, iexLayers, ietextc {$ifdef FPC} ,lmessages {$endif} ; type {!! TIEGrip Declaration } TIEGrip = (ieNone, ieTopLeft, ieTopRight, ieBottomRight, ieBottomLeft, ieLeftSide, ieRightSide, ieTopSide, ieBottomSide, ieRotationCenter); {!!} {!! TIEFastDrawing Declaration TIEFastDrawing = (iefFast, iefDelayed, iefNormal); Description Item Description iefFast Layer draw quality is reduced to speed up display (only affects drawing) iefDelayed Fast drawing (iefFast) is used while rotating, moving or resizing layers. After a delay, layers are then drawn at normal quality (iefNormal) iefNormal Layers are drawn at normal quality
!!} TIEFastDrawing = (iefFast, iefDelayed, iefNormal); {!! TIEGridKind Declaration TIEGridKind = (iedgNone, iedgPixelGrid, iedgGuideLines); Description Item Description iedgNone No guide lines are shown iedgPixelGrid A grid is shown marking each pixel when the image is zoomed in (e.g. for pixel editing in an image editor) iedgGuideLines Guide lines are shown horizontally and vertically over the image (e.g. to help align objects when rotating)
!!} TIEGridKind = (iedgNone, iedgPixelGrid, iedgGuideLines); {!! TIEAlignLayers Declaration TIEAlignLayers = (ilaAlignToLeft, ilaAlignToRight, ilaAlignToTop, ilaAlignToBottom, ilaAlignToHorizontalCenter, ilaAlignToVerticalCenter, ilaAlignLeftEdges, ilaAlignRightEdges, ilaAlignTopEdges, ilaAlignBottomEdges, ilaAlignHorizontalCenters, ilaAlignVerticalCenters, ilaMatchWidth, ilaMatchHeight); Description Item Description ilaAlignToLeft Align selected layers to the left side of the image ilaAlignToRight Align selected layers to the right side of the image ilaAlignToTop Align selected layers to the top of the image ilaAlignToBottom Align selected layers to the bottom of the image ilaAlignToHorizontalCenter Align selected layers along the horizon of the image ilaAlignToVerticalCenter Align selected layers to the vertical center of the image ilaAlignLeftEdges Align selected layers to the edge of the left-most layer ilaAlignRightEdges Align selected layers to the edge of the right-most layer ilaAlignTopEdges Align selected layers to the edge of the top-most layer ilaAlignBottomEdges Align selected layers to the edge of the bottom-most layer ilaAlignHorizontalCenters Align selected layers to have the same horizontal center ilaAlignVerticalCenters Align selected layers to have the same vertical center ilaMatchWidth Resize all selected layers to the width of the widest layer ilaMatchHeight Resize all selected layers to the height of the tallest layer
!!} TIEAlignLayers = (ilaAlignToLeft, ilaAlignToRight, ilaAlignToTop, ilaAlignToBottom, ilaAlignToHorizontalCenter, ilaAlignToVerticalCenter, ilaAlignLeftEdges, ilaAlignRightEdges, ilaAlignTopEdges, ilaAlignBottomEdges, ilaAlignHorizontalCenters, ilaAlignVerticalCenters, ilaMatchWidth, ilaMatchHeight); {!! TIELayerOptions Declaration TIELayerOptions = set of (loAllowMultiSelect, loAutoSelectMask, loAutoUndoChangesByUser, loAutoUndoChangesByCode, loAutoPromptForImage, loFitToLayersWhenZooming, loAutoFixBorders, loAutoFixRotation, loDynamicCanvas); Description Options to control layer behavior: Value Description loAllowMultiSelect If enabled, users can select multiple layers by holding down the Shift key. Moving, resizing, rotation, and other methods will apply to all selected layers loAutoSelectMask If you have enabled a mask for a layer, then when selecting the layer the mask will also be selected (so that any resizing actions apply to the mask layer too) loAutoUndoChangesByUser If you have enabled , then changes to layers made by users (using layer interactions or layer TActions) will be saved to the undo stack loAutoUndoChangesByCode If you have enabled , then programmatic changes to layers will be saved to the undo stack. This applies to the methods: , , , , , , , , , , , , , , loAutoPromptForImage When setting to miCreateImageLayers, the user can drag select to create an If loAutoPromptForImage is enabled, then the user will be prompted to browse for an image file when after completing the selection. If the user cancels, the image layer is not added. loAutoFixBorders If enabled, will be called prior to rotation to removes any transparency around the edges of the image. loAutoFixRotation If enabled, will be called after rotation to lock in the rotation angle of image layers. loDynamicCanvas If enabled, ImageEn will align the view to the bounds of all layers (i.e. by ). You will be able to scroll to access layers that have been pushed beyond the bounds of Layer 0. However this may cause the view to scroll when moving layers around (so is best paired with =False). When not enabled, the view is aligned with Layer 0, and any layers pushed outside of the bounds of layer 0 may be inaccessible if they are off-screen.
Examples // Enable automatic mask selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoSelectMask ]; // Enable automatic undo for all image changes including layer changes ImageEnView1.Proc.AutoUndo := True; ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoUndoChangesByUser ]; // Disable multiple selection of layers ImageEnView1.LayerOptions := ImageEnView1.LayerOptions - [ loAutoSelectMask ]; // Allow users to create image layers. Prompt for an image file after selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoPromptForImage ]; ImageEnView1.MouseInteract := [ miCreateImageLayers ]; !!} TIELayerOptions = set of ( loAllowMultiSelect, // Multiple layers can be selected loAutoSelectMask, // When a layer is selected any mask associated with it is also selected loAutoUndoChangesByUser, // Add layer changes by user to undo stack if Auto-Undo is enabled for TImageEnView loAutoUndoChangesByCode, // Add layer changes by layer methods to undo stack if Auto-Undo is enabled for TImageEnView loAutoPromptForImage, // Prompt for an image file when creating an image layer loAutoFixBorders, // Automatically call LayersFixBorders loAutoFixRotation, // Automatically call LayersFixRotations loDynamicCanvas // Fix view to layer 0 ); {!! TViewChangeEvent Declaration TViewChangeEvent = procedure(Sender: TObject; Change: integer) of object; Description If Change = 0 the event is or modification. If Change = 1 the event is modification. Note: Zoom could also modify ViewX/Y. !!} TViewChangeEvent = procedure(Sender: TObject; Change: integer) of object; {!! TIEMediaFoundationNotifyEvent Declaration TIEMediaFoundationNotifyEvent = procedure(Sender: TObject; MediaFoundationObject: TObject; NotifyType: ) of object; Description Parameter Description Sender Sender object. For this is a object MediaFoundationObject Media foundation object. This could be a object NotifyType Notification type
!!} TIEMediaFoundationNotifyEvent = procedure(Sender: TObject; MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType) of object; {!! TIETextEditorEvent Declaration TIETextEditorEvent = procedure(Sender: TObject; Layer: integer; Editor: TObject) of object; Description Layer is the index of the layer being edited. Editor is a , which handles the editing operation for a or . !!} TIETextEditorEvent = procedure(Sender: TObject; Layer: integer; Editor: TObject) of object; {!! TIESmoothTask Declaration } TIESmoothTask = (iestScroll, iestZoom); {!!} {!! TIEFinishSmoothTaskEvent Declaration TIEFinishSmoothTaskEvent = procedure(Sender: TObject; Task: ) of object; Description Event called when a smooth task has finished (smooth scroll, smooth zoom, etc...). !!} TIEFinishSmoothTaskEvent = procedure(Sender: TObject; Task: TIESmoothTask) of object; {!! TViewChangingEvent Declaration type TViewChangingEvent = procedure(Sender: TObject; Change: integer; newValue: Double) of object; Description Parameter Description Change = 0 modification. Change = 1 modification. Change = 2 modification.
newValue contains the new value that will be set. Note: Zoom could also modify ViewX/Y. !!} TViewChangingEvent = procedure(Sender: TObject; Change: integer; newValue: double) of object; {!! TIEMouseInResizingGripEvent Declaration TIEMouseInResizingGripEvent = procedure(Sender: TObject; Grip: ) of object; !!} TIEMouseInResizingGripEvent = procedure(Sender: TObject; Grip: TIEGrip) of object; {!! TIEZoomEvent Declaration } TIEZoomEvent = procedure(Sender: TObject; var NewZoom: double) of object; {!!} {!! TIESpecialKeyEvent Declaration } TIESpecialKeyEvent = procedure(Sender: TObject; CharCode: word; Shift: TShiftState; var Handled: Boolean) of object; {!!} TIEScrollCommand = (iescPosition, iescBottom, iescTop, iescLineDown, iescLineUp, iescPageDown, iescPageUp); {!! TIEOnDrawCanvas Declaration } TIEOnDrawCanvas = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect) of object; {!!} {!! TIEOnDrawBackground Declaration } TIEOnDrawBackground = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; var Handled: boolean) of object; {!!} {!! TIEOnDrawPolygon Declaration } TIEOnDrawPolygon = procedure(Sender: TObject; polygon: Integer; point: Integer; Canvas: TCanvas; x, y: Integer) of object; {!!} {!! TIEWallpaperStyle Declaration TIEWallpaperStyle = (iewoNormal, iewoStretch, iewoTile); Description Value Description iewoNormal Draw the wallpaper image at the top left iewoStretch Stretch the wallpaper to the ImageEnView size iewoTile Tile the wallpaper over the background
Example // Tile a bitmap over the background ImageEnView1.WallpaperStyle := iewoTile; ImageEnView1.Wallpaper.LoadFromFile('D:\MyWallpaper.bmp'); !!} TIEWallpaperStyle = (iewoNormal, iewoStretch, iewoTile); {!! TIEMouseInteractItems Declaration TIEMouseInteractItems = (miZoom, miScroll, miSelect, miSelectPolygon, miSelectCircle, miSelectZoom, miSelectMagicWand, miSelectLasso, miMoveLayers, miResizeLayers, miRotateLayers, miMovingScroll, miCropTool, miCreateImageLayers, miCreateShapeLayers, miCreateLineLayers, miCreatePolylineLayers, miCreateTextLayers); Description What actions does the mouse perform: Value Description miZoom A left mouse click zooms into the image. A right click zooms out miScroll The image can be navigated by clicking with the left mouse button and dragging miSelect A rectangular area can be selected. Click and move the mouse to select the rectangle. miSelect excludes miScroll and miSelectXXX. Simultaneously holding down the Shift key allows the selection of multiple regions. The Alt Key forces the selection to maintain its aspect ratio miSelectZoom If the user selects an area, it will be automatically zoomed into (and become the new display view). Click and move the mouse to select the zoom rectangle miSelectPolygon A polygonal area can be selected. Click (and release) the left mouse button at each point of the polygon, or click and hold the left button and move to specify continuous irregular lines. Simultaneously holding down the Shift key allows the selection of multiple regions. Methods to terminate selection can be specified in miSelectCircle A circular/elliptical area can be selected. Click the left button and move the mouse (holding the Alt key will force a circular selection). Simultaneously holding down the Shift key allows the selection of multiple regions miSelectMagicWand Selects an irregular region of similar colors. Click the left mouse button upon a pixel and similar colors surrounding it are selected (see ). Simultaneously holding down the Shift key allows the selection of multiple regions miSelectLasso A polygonal area can be selected by continous movement. Click the left button and move the mouse to select a continuous irregular region miMoveLayers User can move layers miResizeLayers User can resize layers using grips miRotateLayers User can rotate layers using grips miMovingScroll Moving the mouse over the image (without requiring any clicking) will cause the image to automatically scroll (pan) (see ) miCropTool User can select a particular area of an image and discards the portions outside the chosen section (See ) miCreateImageLayers Click and move the mouse to create a * miCreateShapeLayers Click and move the mouse to create a * miCreateLineLayers Click and move the mouse to create a * miCreatePolylineLayers Click and move the mouse to create a * miCreateTextLayers Click and move the mouse to create a *
* Note: If you are unable to create layers on the background, ensure that ImageEnView1.Layers[0]. = False. Examples // Single left click zoom-in image, single right click zoom-out image, click and // drag scroll the image (if it is bigger than client area). ImageEnView1.MouseInteract := [ miZoom, miScroll ]; // Allow users to create image layers. Prompt for an image file after selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoPromptForImage ]; ImageEnView1.MouseInteract := [ miCreateImageLayers ]; // Allow user to move and resize layers (allow multiple layer selection and ensure masks are moved with layers) ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAllowMultiSelect, loAutoSelectMask ]; ImageEnView1.MouseInteract := [ miMoveLayers, miResizeLayers ]; A selected text layer with resize grips: // Allow user to rotate layers (allow multiple layer selection and ensure masks are moved with layers) ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAllowMultiSelect, loAutoSelectMask ]; ImageEnView1.MouseInteract := [ miRotateLayers ]; // Allow circular selections ImageEnView1.MouseInteract := [ miSelectCircle ]; // Allow the user to create, size and select red arrows ImageEnView1.MouseInteract := [ miCreateLineLayers, miMoveLayers, miResizeLayers ]; ImageEnView1.LayerDefaults.Clear(); ImageEnView1.LayerDefaults.Add( IELP_LineColor +'=clRed' ); ImageEnView1.LayerDefaults.Add( IELP_LineWidth +'=6' ); ImageEnView1.LayerDefaults.Add( IELP_LineShapeSize +'=20' ); ImageEnView1.LayerDefaults.Add( IELP_LineStartShape +'=1' ); ImageEnView1.LayerDefaults.Add( IELP_Rotate +'=235' ); See Also - - !!} TIEMouseInteractItems = ( miZoom, // Click-sx zoom-in / click-dx zoom-out miScroll, // Hand navigation miSelect, // Rectangular selection miSelectPolygon, // Polygonal selection miSelectCircle, // Circular selection miSelectZoom, // Zoom in rectangle miSelectMagicWand, // Magic Wand selection miSelectLasso, // Polygonal selection miMoveLayers, // Move layers miResizeLayers, // Resize layers miRotateLayers, // Rotate layers miMovingScroll, // Smooth moving scroll miCropTool, // Crop tool miCreateImageLayers, // Create TIEImageLayer miCreateShapeLayers, // Create TIEShapeLayer miCreateLineLayers , // Create TIELineLayer miCreatePolylineLayers, // Create TIEPolylineLayer miCreateTextLayers // Create TIETextLayer ); {!! TIEMouseInteract Declaration type TIEMouseInteract = set of ; !!} TIEMouseInteract = set of TIEMouseInteractItems; {!! TIEGestureOptions Description Options for ImageEn gesture support. Methods and Properties !!} TIEGestureOptions = class private fDisables: array of TIEGestureOptions; fEnabled: boolean; fInertia: boolean; fMultiplier: double; fSnapValues: boolean; fSnapDelta: double; procedure SetEnabled(Value: boolean); procedure AddDisables(Value: TIEGestureOptions); public {!! TIEGestureOptions.Enabled Declaration property Enabled: boolean; Description Enables/disables the gesture. !!} property Enabled: boolean read fEnabled write SetEnabled; {!! TIEGestureOptions.Inertia Declaration property Inertia: boolean; Description Whether the gesture supports "inertia". When inertia is enabled and a gesture is performed with sufficient speed then it will continue for a time even after the actual movement ends. !!} property Inertia: boolean read fInertia write fInertia; {!! TIEGestureOptions.Multiplier Declaration property Multiplier: double; Description Specifies a multiplier for the controlled viewer property. !!} property Multiplier: double read fMultiplier write fMultiplier; {!! TIEGestureOptions.SnapValues Declaration property SnapValues: boolean; Description If enabled, then values will change only in amounts specified by the . For example, when performing a small rotation of less than a of 90 degrees, it will "snap" to 90. !!} property SnapValues: boolean read fSnapValues write fSnapValues; {!! TIEGestureOptions.SnapDelta Declaration property SnapDelta: double; Description Specifies the amount to snap values by when is enabled. !!} property SnapDelta: double read fSnapDelta write fSnapDelta; end; {!! TIEGesturePanOptions Description Specify options for the Zoom gesture. Note: Inherites from the class. Methods and Properties !!} TIEGesturePanOptions = class(TIEGestureOptions) private fBoundingBox: TRect; fPanWithSingleFingerVertically: Boolean; fPanWithSingleFingerHorizontally: Boolean; public {!! TIEGesturePanOptions.BoundingBox Declaration property BoundingBox: TRect; Description Contains the minimum/maximum values for the left, top and right and bottom. !!} property BoundingBox: TRect read fBoundingBox write fBoundingBox; {!! TIEGesturePanOptions.PanWithSingleFingerVertically Declaration PanWithSingleFingerVertically: Boolean; Description Enables/disables vertical pans with one finger. Default: True !!} property PanWithSingleFingerVertically: Boolean read fPanWithSingleFingerVertically write fPanWithSingleFingerVertically; {!! TIEGesturePanOptions.PanWithSingleFingerHorizontally Declaration property PanWithSingleFingerHorizontally: Boolean; Description Enables/disables horizontal pans with one finger. Default: True !!} property PanWithSingleFingerHorizontally: Boolean read fPanWithSingleFingerHorizontally write fPanWithSingleFingerHorizontally; end; {!! TIEGestureZoomOptions Description Specifies options for the Zoom gesture. Note: Inherites from the class. Methods and Properties !!} TIEGestureZoomOptions = class(TIEGestureOptions) private fMax: double; fMin: double; public {!! TIEGestureZoomOptions.Max Declaration property Max: double; Description Specify the maximum allowed Zoom. !!} property Max: double read fMax write fMax; {!! TIEGestureZoomOptions.Min Declaration property Min: double; Description Specify the minimum allowed Zoom. !!} property Min: double read fMin write fMin; end; {!! TIEGestureLayerMoveOptions Description Specifies options for the layer movement gesture. Note: Inherites from the class. Methods and Properties !!} TIEGestureLayerMoveOptions = class(TIEGestureOptions) private fBoundingBox: TRect; public {!! TIEGestureLayerMoveOptions.BoundingBox Declaration property BoundingBox: TRect; Description Contains the minimum/maximum values for the left, top and right and bottom. !!} property BoundingBox: TRect read fBoundingBox write fBoundingBox; end; {!! TIEGestureLayerRotateOptions Description Specifies options for the layer rotation gesture. Note: Inherites from the class. Methods and Properties !!} TIEGestureLayerRotateOptions = class(TIEGestureOptions) private fMax: double; fMin: double; public {!! TIEGestureLayerRotateOptions.Max Declaration property Max: double; Description Specify the maximum allowed Zoom. !!} property Max: double read fMax write fMax; {!! TIEGestureLayerRotateOptions.Min Declaration property Min: double; Description Specify the minimum allowed Zoom. !!} property Min: double read fMin write fMin; end; {!! TIEViewerGestures Description TImageEnView supports native Windows gestures, allowing pan, zoom, layer rotation and movement. This class contains the properties to configure the gestures. Methods and Properties !!} TIEViewerGestures = class private fPan: TIEGesturePanOptions; fZoom: TIEGestureZoomOptions; fLayerRotate: TIEGestureLayerRotateOptions; fLayerMove: TIEGestureLayerMoveOptions; function GetEnabled(): boolean; public constructor Create(); destructor Destroy(); override; {!! TIEViewerGestures.Enabled Declaration property Enabled: boolean; (Read-only) Description Returns true whenever at least one gesture is enabled. !!} property Enabled: boolean read GetEnabled; {!! TIEViewerGestures.Pan Declaration property Pan: ; Description Allows enabling and configuration of the Pan (image scrolling) gesture. The Windows gesture to "Pan with inertia" is performed by "dragging 1 or 2 fingers". Note: The Pan and layer movement gestures are mutually exclusive (i.e. you cannot use both). !!} property Pan: TIEGesturePanOptions read fPan; {!! TIEViewerGestures.Zoom Declaration property Zoom: ; Description Allows enabling and configuration of the Zoom gesture. The Windows gesture of "Zoom" is performed by "moving two fingers apart/towards each other". !!} property Zoom: TIEGestureZoomOptions read fZoom; {!! TIEViewerGestures.LayerRotate Declaration property LayerRotate: ; Description Allows enabling and configuration of the Layer Rotation gesture. The Windows gesture of "Rotate" is performed by "moving two fingers in opposing directions or using one finger to pivot around another". !!} property LayerRotate: TIEGestureLayerRotateOptions read fLayerRotate; {!! TIEViewerGestures.LayerMove Declaration property LayerMove: ; Description Allows enabling and configuration of the Layer Movement gesture. The Windows gesture of "Pan with inertia" is performed by "dragging 1 or 2 fingers". Note: The Pan and layer movement gestures are mutually exclusive (i.e. you cannot use both). !!} property LayerMove: TIEGestureLayerMoveOptions read fLayerMove; end; {!! TIENavigatorOptions Declaration TIENavigatorOptions = set of (ienoMouseWheelZoom, ienoMarkOuter, ienoDontAssignNavBitmap, ienoDontPaintSrcBitmap, ienoDontRefreshSrcIfNavNotFocused); Description Value Description ienoMouseWheelZoom Zoom is possible with mouse-wheel ienoMarkOuter Marks as grayed non visible area ienoDontAssignNavBitmap Doesn't assign automatically navigator bitmap ienoDontPaintSrcBitmap Doesn't repaint source image on moving nav rect ienoDontRefreshSrcIfNavNotFocused Doesn't refresh main viewer when navigator isn't focused
!!} TIENavigatorOptions = set of (ienoMouseWheelZoom, ienoMarkOuter, ienoDontAssignNavBitmap, ienoDontPaintSrcBitmap, ienoDontRefreshSrcIfNavNotFocused); {!! TIESelectionBase Declaration } TIESelectionBase = ( iesbClientArea, // Select coordinates over client area (as they appear in the current view) iesbBitmap // Select coordinates over bitmap (as they relate to the bitmap regardless of view or zoom) ); {!!} {!! TIESelectionOptions Declaration TIESelectionOptions = set of ( iesoAnimated, iesoSizeable, iesoMoveable, iesoFilled, iesoCutBorders, iesoMarkOuter, iesoCanScroll, iesoSelectTranspLayers, iesoRightButtonSelectLayers, iesoRightButtonTerminatePolySelect, iesoDisableOneClickDeselect, iesoDisableNewSelection, iesoShowCenter, iesoAutoTerminatePolySelect, iesoAllowMoveByKeyboard); Description Value Description iesoAnimated Enable animation of the selection iesoSizeable Allow the user to resize the selection (with grips) iesoMoveable Allow the user to move the selection (with grips) iesoFilled The image within the selection is displayed with inverted colors iesoCutBorders The user is allowed to drag the selection outside the borders (the selection borders will be cut) iesoMarkOuter Areas of the image outside the selection are shown as grayed or with alpha blending (see ) iesoCanScroll Automatically scroll the image when selecting outside the visible area iesoSelectTranspLayers Allow transparent areas of a layer to be selectable iesoRightButtonSelectLayers Allow selection of layers with the right button (other than left button) iesoRightButtonTerminatePolySelect Allow polygon selection to be cancelled with the right mouse button iesoDisableOneClickDeselect Prevent the selection from being cleared when clicking outside the selection iesoDisableNewSelection Once a selection has been made (programatically using or by the user using ) then the user cannot make a new selection (though they can still move or resize the selection if iesoSizeable or iesoMoveable is specified) iesoShowCenter A cross shows the center of the rectangle, circle or polygon while making a selection iesoAutoTerminatePolySelect Polygon selection will be automatically cancelled when the user clicks close to the start of the selection (i.e. closes the polygon) iesoAllowMoveByKeyboard Allow rectangular selections and layers to be moved by the cursor keys (Hold Ctrl key to resize selections. Hold Shift to speed up movement)
!!} TIESelectionOptions = set of ( iesoAnimated, iesoSizeable, iesoMoveable, iesoFilled, iesoCutBorders, iesoMarkOuter, iesoCanScroll, iesoSelectTranspLayers, iesoRightButtonSelectLayers, iesoRightButtonTerminatePolySelect, iesoDisableOneClickDeselect, iesoDisableNewSelection, iesoShowCenter, iesoAutoTerminatePolySelect, iesoAllowMoveByKeyboard ); {!! TIESelOp Declaration TIESelOp = (iespReplace, iespAdd); Description iespReplace: replaces all previous selections. iespAdd: adds a new selection. !!} TIESelOp = (iespReplace, iespAdd); {!! TIEMagicWandMode Declaration TIEMagicWandMode=(iewInclusive, iewExclusive, iewGlobal); Description Value Description iewInclusive the selection is a closed polygon iewExclusive the selection includes only points that match the initial pixel, similar to a flood fill iewGlobal the selection includes all points that match the initial pixel, examining all pixels of the image
!!} TIEMagicWandMode = (iewInclusive, iewExclusive, iewGlobal); {!! TIELayerEvent Declaration TIELayerEvent = (ielSelected, ielMoved, ielResized, ielMoving, ielResizing, ielRotating, ielRotated, ielBeginResizing, ielBeginMoving, ielDeselected, ielEdited, ielBeginCreating, ielCreating, ielCreated, ielAction); Description Value Description ielSelected User selected the layer ielMoved User moved the layer ielResized User resized the layer ielMoving User is moving the layer ielResizing User is resizing the layer ielRotating User is rotating the layer ielRotated User rotated the layer ielBeginResizing User began to resize the layer (click down) ielBeginMoving User began to move the layer (click down) ielDeselected User deselected the layer ielEdited User edited the text of a layer ielBeginMoving User began creating a layer (click down) ielCreating User is creating a layer ielCreated User had created a new layer ielAction User has used an ImageEn Action that has changed the layers
!!} TIELayerEvent = (ielSelected, ielMoved, ielResized, ielMoving, ielResizing, ielRotating, ielRotated, ielBeginResizing, ielBeginMoving, ielDeselected, ielEdited, ielBeginCreating, ielCreating, ielCreated, ielAction); {!! TIELayerNotify Declaration TIELayerNotify = procedure(Sender: TObject; layer: integer; event:
) of object; Description layer is the layer index that is selected, moved or resized. event specifies the event type. Notes: - This event only occurs once for each change, even if multiple layers are selected. You should review the list of selected layers to determine which changed - To avoid incompatibility, events of ielBeginCreating and ielCreating do NOT occur unless IEIncludeDeprecatedInV6 has been undefined in ie.inc. If available, layer will return -1 Example // Log all resizing of layers procedure TfrmMain.IEView1LayerNotify(Sender: TObject; layer: integer; event: TIELayerEvent); var ALayer: TIELayer; i: Integer; sChangedLayers: string; begin if event = ielResized then begin sChangedLayers := ''; for i := 0 to IEView1.LayersCount - 1 do begin ALayer := IEView1.Layers[ I ]; if ( ALayer.Locked = False ) and ALayer.Selected then sChangedLayers := sChangedLayers + IntToStr( i ) +','; end; if sChangedLayers <> '' then begin SetLength( sChangedLayers, Length( sChangedLayers ) - 1 ); // Remove final comma memLog.Lines.Add( 'Layers Resized: ' + sChangedLayers ); end; end; end; !!} TIELayerNotify = procedure(Sender: TObject; layer: integer; event: TIELayerEvent) of object; {!! TIENewLayerEvent Declaration TIENewLayerEvent = procedure(Sender: TObject; LayerIdx: integer; LayerKind: ) of object; Description Occurs whenever a layer is added. It is useful to assign default properties to the layer. Both programmatic methods (e.g. using ) and user methods (e.g. using miCreateShapeLayers) trigger this event. LayerIdx is the index of the new layer. LayerKind is the kind of layer that was added. Note: will represent the new layer Examples procedure Tfmain.ImageEnView1NewLayer(Sender: TObject; LayerIdx: Integer; LayerKind: TIELayerKind); begin // Assign default properties for new objects case LayerKind of ielkPolyline : TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesExplosion, True ); ielkText : TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Double-click to edit text'; end; end; // Make new shape layer a red star procedure TfrmMain.ImageEnView1NewLayer(Sender: TObject; LayerIdx: integer; LayerKind: TIELayerKind); begin if LayerKind = ielkShape then begin TIEShapeLayer( ImageEnView1.CurrentLayer ).Shape := iesStar5; TIEShapeLayer( ImageEnView1.CurrentLayer ).FillColor := clRed; end; end; See Also - !!} TIENewLayerEvent = procedure(Sender: TObject; LayerIdx: integer; LayerKind: TIELayerKind) of object; {!! TIELayerMoveSizeEvent Declaration TIELayerMoveSizeEvent = procedure(Sender: TObject; layer: integer; event: ; var PosX, PosY, Width, Height: Double) of object; Description Value Description layer The layer index that is moved or resized (it will be -1 for ielCreating). event The event type (will be ielMoving, ielResizing or ielCreating). PosX, PosY The new left and top position of the layer Width, Height The new width and height of the layer
Example // Force all layers to be created at 200 x 200 procedure TfrmMain.ImageEnView1MoveSizeLayer(Sender: TObject; layer: integer; event: TIELayerEvent; var PosX, PosY, Width, Height: Double); begin if event = ielCreating then begin Width := 200; Height := 200; end; end; // Force all layers to be centered on the image horizon procedure TfMain.ImageEnView1MoveSizeLayer(Sender: TObject; layer: integer; event: TIELayerEvent; var PosX, PosY, Width, Height: Double); begin PosY := ( ImageEnView1.Layers[0].Height - Height ) / 2; end; !!} TIELayerMoveSizeEvent = procedure(Sender: TObject; layer: integer; event: TIELayerEvent; var PosX, PosY, Width, Height: Double) of object; {!! TIEVirtualKeyEvent Declaration TIEVirtualKeyEvent = procedure(Sender: TObject; VirtualKey: Dword; KeyData: Dword) of object; Description Event type for
event. Value Description VirtualKey Specifies the virtual key code (the same as wParam of WM_KEYWODN, WM_KEYUP, WM_SYSKEYDOWN and WM_SYSKEYUP) KeyData Specifies additional info about the key (the same as lParam of WM_KEYWODN, WM_KEYUP, WM_SYSKEYDOWN and WM_SYSKEYUP) KeyDown This is true on keydown, false on keyup
!!} TIEVirtualKeyEvent = procedure(Sender: TObject; VirtualKey: Dword; KeyData: Dword; KeyDown: Boolean) of object; {!! TIESetCursorEvent Declaration TIESetCursorEvent = procedure(Sender: TObject; var Cursor: TCursor) of object; Description Used by the
event. !!} TIESetCursorEvent = procedure(Sender: TObject; var Cursor: TCursor) of object; {!! TIEGestureFlags Declaration } TIEGestureFlags = set of (iegfBegin, iegfInertia, iegfEnd); {!!} {!! TIEGestureID Declaration } TIEGestureID = (iegiBegin, iegiEnd, iegiZoom, iegiPan, iegiRotate, iegiTwoFingerTap, iegiPressAndTap); {!!} {!! TIEImageEnGestureEvent Declaration TIEImageEnGestureEvent = procedure(Sender: TObject; Flags: ; ID: ; Location: TSmallPoint; Value: integer; InertiaX: integer; InertiaY: integer; PressAndTapDistance: integer; var Handled: boolean) of object; Description Used by the event. !!} TIEImageEnGestureEvent = procedure(Sender: TObject; Flags: TIEGestureFlags; ID: TIEGestureID; Location: TSmallPoint; Value: integer; InertiaX: integer; InertiaY: integer; PressAndTapDistance: integer; var Handled: boolean) of object; {!! TIERSOptions Declaration TIERSOptions = (iersNone, iersMoveToAdapt, iersSyncLayers); Description Value Description iersNone no adaption iersMoveToAdapt move the selection to fit inside the new size iersSyncLayers used to maintain the selection in the same position among layers
!!} TIERSOptions = (iersNone, iersMoveToAdapt, iersSyncLayers); {!! TIESoftCropMode Declaration TIESoftCropMode = (iesfNone, iesfAlphaBlend, iesfGrid, iesfAdd); Description Portion of layers that are outside the background layer are shown as: Value Description iesfNone Normal iesfAlphaBlend Partially transparent (to the level specified by ) iesfGrid Grayed (Grid matrix pattern) iesfAdd Color shifted/washed out (to the level specified by )
!!} TIESoftCropMode = (iesfNone, iesfAlphaBlend, iesfGrid, iesfAdd); {!! TIEGripShape Declaration } TIEGripShape = (iegsBox, iegsCircle); {!!} {!! TIEUpdateReason Declaration } TIEUpdateReason = (ieurDefault, ieurScrolled, ieurZoomed, ieurSelectionChanged, ieurComponentStuffChanged); {!!} {!! TIELayersResizeAspectRatio Declaration TIELayersResizeAspectRatio = (iearDisabled, iearALTKey, iearAlways, iearAlwaysOnCornerGrip, iearLayerDefaultOnCornerGrip); Description Value Description iearDisabled Doesn't maintain the aspect ratio even when pressing ALT or setting ) iearALTKey Maintains the aspect ratio only when pressing ALT or setting iearAlways The aspect ratio is always maintained (using any grips) iearAlwaysOnCornerGrip The aspect ratio is always maintained if the corner grips are used iearLayerDefaultOnCornerGrip If the layer has a preferred aspect ratio then dragging the corner grip will maintain the aspect ratio, for side grips and other layer types the aspect ratio is not maintained
!!} TIELayersResizeAspectRatio = (iearDisabled, iearALTKey, iearAlways, iearAlwaysOnCornerGrip, iearLayerDefaultOnCornerGrip); TIECropToolInteraction = class; // forward declaration ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TImageEnView {!! TImageEnView Declaration TImageEnView = class(); Description TImageEnView is an image container, viewer and editor. It supports zooming, scrolling, selections and layers. TImageEnView encapsulates a ( property) for loading/saving/acquisition and a ( property) component for image editing/processing (you do not need to add extra TImageEnIO and TImageEnProc components to your form). For rapid UI development a full set of actions is also available. Example // Setup with ImageEnView1 do begin LegacyBitmap := False; // Support bigger files and multithreading AutoShrink := True; // Make the image fit within the window BorderStyle := bsNone; // Normally don't require a 3D border ZoomFilter := rfFastLinear; // Use better quality drawing when the image is not 100%, Use rfFastLinear for best speed or rfLanczos3 for best quality MouseInteract := [miSelect]; // What action should the mouse do? end; // Display an image ImageEnView1.IO.LoadFromFile('C:\MyImage.jpg'); // Rotate the image ImageEnView1.Proc.Rotate(270, True); Methods and Properties Display Background Scrollbars Image Processing Input/Output Bitmap User Actions (Lock Aspect Ratio) Selections (Multiple selections) Alpha Channel (Transparency) Layers (Arrange) Also: Layer Loading and Layer Saving Animations and Transitions Navigator Animated Polygons Other Events !!} {$ifdef IEHASPLATFORMATTRIBUTE} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$endif} TImageEnView = class(TIEView) private fLegacyBitmap: boolean; // false=use TIEBitmap, true=use TBitmap fUseDrawDibDraw: boolean; // for same behavior of old versions set it to True fLCursor: TCursor; // this is default cursor fCursor: TCursor; // this is current cursor fWasScreenCursor : TCursor; // Store the screen's cursor for special handling on mouse down fOnImageChange: TNotifyEvent; fOnViewChange: TViewChangeEvent; fOnImageEnGesture: TIEImageEnGestureEvent; fOnFinishSmoothTask: TIEFinishSmoothTaskEvent; fOnViewChanging: TViewChangingEvent; fImageHorizAlignment: TIEHAlign; fImageVertAlignment: TIEVAlign; fZoomFilter: TResampleFilter; fActualZoomFilter: TResampleFilter; // ZoomFilter to use to display the current content fDelayZoomFilter: boolean; // if true enables fStable, delay zoom filter fBackgroundStyle: TIEBackgroundStyle; fMagicWandMaxFilter: boolean; // if true apply a max filter to the selection fMagicWandTolerance: integer; // 0..255 tolerance fMagicWandMode: TIEMagicWandMode; fRXScroll, fRYScroll: double; fDisplayGridKind: TIEGridKind; fDisplayGridLyr: integer; // layer where to display the grid (-1 = current, >= 0 specific layer) fHighlightedPixel: TPoint; fVScrollBarVisible, fHScrollBarVisible: boolean; fAniCounter: integer; fOnPaint: TNotifyEvent; fOnMouseInResizingGrip: TIEMouseInResizingGripEvent; fOnZoomIn, fOnZoomOut: TIEZoomEvent; fDelayDisplaySelection: boolean; fOnProgress: TIEProgressEvent; fOnFinishWork: TNotifyEvent; fOnAcquireBitmap: TIEAcquireBitmapEvent; fFullUpdateRequest: boolean; // true when Paint requires to repaint full image without cliprect, Paint event set to False fBlockPaint: boolean; fRectMoving: boolean; // true if we are moving a rectangle fDrawVersion: boolean; fOnDrawBackBuffer: TNotifyEvent; fOnLayerNotify: TIELayerNotify; fOnLayerMoveSize: TIELayerMoveSizeEvent; fOnLayerSelectionChange: TNotifyEvent; fOnNewLayer: TIENewLayerEvent; fSelectionAspectRatio: double; // -1 auto aspect , 0 = absolute (fSelectionAbsWidth, fSelectionAbsHeight), >0 specify aspect fSelectionAbsWidth: integer; fSelectionAbsHeight: integer; fOnSpecialKey: TIESpecialKeyEvent; fNavigator: TImageEnView; fNavigatorOptions: TIENavigatorOptions; fNavigatorInside: Boolean; fIsNavigator: Boolean; fNavigatorBackBuffer: TIEBitmap; fNavigatorActualRect: TRect; fUpdateInsideUpdate: Boolean; // true when Update call itself fInsideUpdate: Boolean; // true when it is inside Update fDelayTimer: Integer; fLyrResizingClientAreaBox: TRect; // ClientAreaBox when we begon resizing a layer fLyrResizingRotatedBox: array [0..3] of TPoint; // box coordinates when we begon resizing a rotated layer fZoomSelectionAspectRatio: Boolean; fMouseScrollRate: Double; fOnDrawPolygon: TIEOnDrawPolygon; fLayersRotationFilter: TIEAntialiasMode; fLayersRotationAntialias: Boolean; fLayersRotationUseFilterOnPreview: Boolean; fUpdate_MaskCache: Integer; // -1=update all, >-1 update only specified layer fLayersSelectConstrains: Boolean; fLayersResizeAspectRatio: TIELayersResizeAspectRatio; fLayersResizingAR: Double; // used when resizing layers fLayersFastDrawing: TIEFastDrawing; fLayersFastOutput: Boolean; // True if merge and other output operations should ignore anti-alias and other quality settings for layers fLayersCropped: boolean; fSelectionGridWidth: Integer; fSelectionGridHeight: Integer; fMarkOuterAlpha: Integer; fMarkOuterColor: TColor; fOnSetCursor: TIESetCursorEvent; // fLutLastZoomX: double; // last zoom used by CreateCoordConvLUT fLutLastZoomY: double; // last zoom used by CreateCoordConvLUT fLutLastFRX: integer; // last frx used by CreateCoordConvLUT fLutLastFRY: integer; // last fry used by CreateCoordConvLUT fLutLastMaxLayerWidth: integer; // fMaxLayerWidth used by CreateCoordConvLUT fLutLastMaxLayerHeight: integer; // fMaxLayerHeight used by CreateCoordConvLUT // handscroll fHSVX1, fHSVY1: integer; // view in mouse down // fo1x, fo1y, fo2x, fo2y: integer; frx, fry: integer; // fBitmapWidth, fBitmapHeight: integer; // monitoring bitmap size // transition effects fTransition: TIETransitionEffects; // effect engine fTransitionEffect: TIETransitionType; // transition type fTransitionDuration: integer; // transition duration ms fMinBitmapSize: Integer; // min bitmap size to make it displyed // {$IFDEF IEINCLUDEDIRECTSHOW} fOnDShowNewFrame: TNotifyEvent; fOnDShowEvent: TNotifyEvent; {$ENDIF} {$IFDEF IEINCLUDEMEDIAFOUNDATION} fOnMediaFoundationNotify: TIEMediaFoundationNotifyEvent; {$ENDIF} fFlatScrollBars: Boolean; fOnDrawBackground: TIEOnDrawBackground; fOnDrawCanvas: TIEOnDrawCanvas; fOldHandle: THandle; fOnDrawLayer: TIEDrawLayerEvent; fOnDrawLayerBox: TIEDrawLayerBoxEvent; fOnDrawLayerGrip: TIEDrawLayerGrip; fVisibleSelection: Boolean; fOffscreenPaint: Boolean; fFirstTimeSetCursor: Boolean; fLayersRotateStep: Integer; fLayersMergeFilter: TResamplefilter; // Wallpaper fWallpaper: TPicture; fWallpaperStyle: TIEWallpaperStyle; // setpixel replacement (due the Vista setpixel bug) fDrawPixelBitmap: TBitmap; fDrawPixelPtr: PRGB; // softcrop fSoftCrop: TIESoftCropMode; fSoftCropValue: Integer; // hints fEnableInteractionHints: Boolean; fInteractionHint: String; fInteractionHintX, fInteractionHintY: Integer; fInteractionHintMinText: String; // PostFrames support fields fPostFrames: TList; // a list of TIEPostFramesTarget objects // Play fPlaying: boolean; // true=play actived fPlayTimer: integer; // timer for playback of animated files (0=not allocated) fPlayLoop: boolean; // when True executes in loop fNeedUpdateLiveBackground : Boolean; // True when fLiveBackground needs to be filled fLiveBackground : TIEBitmap; // Show a background/wallpaper based on the current image // User interactions fUserInteractions: TObjectList; // Rulers fShowRulers: TRulerDirs; fRulerParams: TIEViewRulerParams; // Layer editing fEditingLayer: Integer; // the current layer for which a text editor is active fTextEditor: TIEEdit; // Component for editing the text of a TIETextLayer or TIELineLayer fOnTextEditorKeyDown: TKeyEvent; fOnActivateTextEditor: TIETextEditorEvent; fOnDeactivateTextEditor: TIETextEditorEvent; {$IFDEF UNITTESTING} fDebugUpdatedCount: Integer; // test for unexpected calls to Update(); {$ENDIF} fNextLayerPosition: Integer; // The next PosX and PosY for an added layer fModified: Boolean; // Returns true if the image or layers have changed since loading procedure RemovePostFrames(index: Integer); // procedure AniPolyFunc(Sender: TObject; UseLockPaint: boolean); procedure TimerEvent(Sender: TObject); procedure SetViewX(v: integer); procedure SetViewY(v: integer); procedure SetZoom(v: double); procedure SetZoomX(v: double); procedure SetZoomY(v: double); function GetSelX1: integer; function GetSelY1: integer; function GetSelX2: integer; function GetSelY2: integer; procedure SetCenter(value: boolean); function GetCenter(): Boolean; procedure SetImageHorizAlignment(value: TIEHAlign); procedure SetImageVertAlignment(value: TIEVAlign); function GetMouseInteract: TIEMouseInteract; function GetCropToolInteraction: TIECropToolInteraction; procedure SetBackgroundStyle(v: TIEBackgroundStyle); procedure DoSelectionChange; procedure DoSelectionChanging; procedure DoBeforeSelectionChange; procedure DoMouseInResizingGrip(Grip: TIEGrip); procedure DoMouseInSel; procedure DoZoomIn(var NewZoom: double); procedure DoZoomOut(var NewZoom: double); procedure SetSelectionOptions(v: TIESelectionOptions); function GetSelectedRect(): TIERectangle; function GetResizingGrip(x, y: integer; Shift: TShiftState): TIEGrip; function GetMovingGrip(x, y: integer; Shift: TShiftState): integer; function SelectResizeEx(grip: TIEGrip; newx, newy: integer; aspectratio: boolean): TIEGrip; function SelectMoveEx(fMoving, ox, oy: integer; cutBorders: Boolean): integer; function GetScrollBarsAlwaysVisible: boolean; procedure SetScrollBarsAlwaysVisible(v: boolean); {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (8/2/2016) function GetDisplayGrid(): boolean; procedure SetDisplayGrid(v: boolean); {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (21/2/2017) function GetAutoFixRotationBorders(): boolean; procedure SetAutoFixRotationBorders(v: boolean); {$endif} procedure SetDisplayGridKind(v: TIEGridKind); procedure SetDisplayGridLyr(v: integer); function GetTransitionRunning: boolean; function GetLayersCount: integer; procedure SetLayersCaching(v: integer); function GetLayer(idx: integer): TIELayer; procedure PaintSelection(OutBitmap: TBitmap); procedure PaintPixelGrid(OutBitmap: TBitmap); procedure PaintGuideLines(Canvas: TCanvas); procedure SetCursor(Value: TCursor); procedure SetDelayTimer(Value: integer); function GetDelayTimer: integer; procedure SetGradientEndColor(Value: TColor); procedure DoDrawVersion; procedure SetDrawVersion(v: boolean); procedure SetSelectionMaskDepth(value: integer); procedure MouseResizeLayer(clientlx, cliently: integer; AltPressed: Boolean); {$IFDEF IEINCLUDEDIRECTSHOW} procedure DShowNewFrame(var Message: TMessage); message IEM_NEWFRAME; procedure DShowEvent(var Message: TMessage); message IEM_EVENT; {$ENDIF} {$IFDEF IEINCLUDEMEDIAFOUNDATION} procedure MediaFoundationNotify(var Message: TMessage); message IEM_MEDIAFOUNDATION; {$ENDIF} procedure MouseSelectCircle(x, y: integer; Shift: TShiftState); procedure MouseSelectRectangle(x, y: integer; Shift: TShiftState); procedure SetSelectionAspectRatio(value: Double); function GetSavedSelectionsCount: Integer; {$ifdef IEINCLUDEFLATSB} procedure SetFlatScrollBars(Value: Boolean); {$endif} procedure SwapSelectionBase; procedure NavigatorSelectionChanging(Sender: TObject); procedure NavigatorMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); procedure SetNavigatorRect; function GetImageEnVersion: String; procedure SetImageEnVersion(Value: String); {$ifdef IEDOTNETVERSION} procedure WMContextMenu(var Message: TWMContextMenu); message WM_CONTEXTMENU; {$endif} procedure WMGestureNotify(var Msg: TIEWMGestureNotify); message IEWM_GESTURENOTIFY; procedure WMGesture(var Msg: TMessage); message IEWM_GESTURE; procedure SetOnTransitionStop(value: TNotifyEvent); function GetOnTransitionStop: TNotifyEvent; procedure SetOnTransitionStep(value: TIETransitionStepEvent); function GetOnTransitionStep: TIETransitionStepEvent; procedure SetTransitionTiming(value: TIETransitionTiming); function GetTransitionTiming: TIETransitionTiming; procedure SetWallpaper(Value: TPicture); procedure SetWallpaperStyle(Value: TIEWallpaperStyle); function AdjustRectToAspectRatio(ARect: TRect; TransitionActive: Boolean): TRect; procedure DoOnDrawPolygon(polygon: Integer; point: Integer; Canvas: TCanvas; x, y: Integer); function GetBackBuffer: TBitmap; procedure SetOnSaveUndo(value: TIESaveUndoEvent); function GetOnSaveUndo: TIESaveUndoEvent; procedure ZoomSelectionEx(AspectRatio: Boolean; FireDoZoomIn: Boolean); procedure SetSoftCrop(v: TIESoftCropMode); procedure SetSoftCropValue(v: Integer); procedure SetHighlightedPixel(v: TPoint); procedure SetOnTransitionPaint(const Value: TIEOnTransitionPaint); function GetOnTransitionPaint: TIEOnTransitionPaint; procedure SetSmoothScrollValue(v: Integer); procedure SetSmoothZoomValue(v: Integer); procedure SetupAniPolyTimer; procedure SetupTransition; procedure SetupDrawPixelBitmap; procedure TerminatePolySelection(shift: Boolean; removeLastPoint: Boolean); procedure DrawMarkOutNavigator(const rc: TRect); procedure SetHighlightedPixelColor(c: TColor); function GetSelectionGridSize(): Integer; procedure SetSelectionGridSize(value: Integer); procedure SetPlaying(const v: boolean); procedure StartPlayTimer; procedure StopPlayTimer; procedure DoImageEnGestureEvent(const GInfo: TIEGESTUREINFO; var Handled: boolean); virtual; function PerformRotateSnap(Value: double): double; function PerformLayerMoveSnap(Value: double): double; function PerformZoomSnap(Value: double): double; procedure SetLayerOptions(const Value: TIELayerOptions); function GetLayerDefaults() : TStringList; procedure SetLayersCropped(const Value: Boolean); function MultiSelectedLayersCount(): Integer; function MultiSelectedLayersList(): TIEArrayOfInteger; procedure SetDisplayStable(value: Boolean); procedure UpdateLiveBackground(Src: TIEBitmap); procedure SetShowRulers(const v: TRulerDirs); function GetOnRulerClick: TRulerClickEvent; function GetOnRulerGripClick: TRulerGripClickEvent; function GetOnRulerGripDblClick: TRulerGripClickEvent; function GetOnRulerGripPosChange: TRulerGripPosChangeEvent; procedure SetOnRulerClick(const Value: TRulerClickEvent); procedure SetOnRulerGripClick(const Value: TRulerGripClickEvent); procedure SetOnRulerGripDblClick(const Value: TRulerGripClickEvent); procedure SetOnRulerGripPosChange(const Value: TRulerGripPosChangeEvent); function fIEBitmap_Width(): Integer; function fIEBitmap_Height(): Integer; function GetModified(): Boolean; procedure SetModified(value: Boolean); protected // view and selections stabilization fDelayZoomTicks: integer; // initial fStable value (also available as public property) fDelayAniSelTicks: integer; // initial fStable2 value fStable: integer; // stability counter (0=stable) , decremented each AniPolyFunc fStable2: integer; // secondary stablity counter (for selections) // fUpdateReason: TIEUpdateReason; fUpdateBackBuffer: boolean; // if true draw fBackBuffer fBackBuffer: TIEBitmap; // back buffer fZoomX: double; // zoom percentage (starting at 1) fZoomY: double; // zoom percentage (starting at 1) fZoomD100X: double; // fZoomX/100 f100DZoomX: double; // 100/fZoomX fZoomD100Y: double; // fZoomX/100 f100DZoomY: double; // 100/fZoomX fHDrawDib: HDRAWDIB; // direct draw on the screen fScrollBars: TIEScrollStyle; fLockPaint: integer; // 0=paint locked fOffX, fOffY: integer; // start of view (for centered images) fExtX, fExtY: integer; // view extent fZZWW, fZZHH: integer; // size of zoomed bitmap fViewX, fViewY: integer; fUpdateLocked: integer; // 0=unlocked fBitmapInfoHeader256: TBitmapInfoHeader256; // used by DrawTo and PaintRect fAutoFit: boolean; fUpdateInvalidate: boolean; // if true (default) Update will call Invalidate fAutoStretch: boolean; fAutoShrink: boolean; // selections fSel: boolean; // True when the selection is active fPolySelecting: boolean; // True on polygonal selection fLassoSelecting: boolean; // True on polygonal and lasso selection fRectSelecting: boolean; // True on rectangular selection fCircSelecting: boolean; // True on circular selection fRectResizing: TIEGrip; // if <>ieNone we are resizing rectangular selection fSelectMoving: integer; // if >-1 selection moving fMMoveX, fMMoveY: integer; // used on fPolySelecting fHSX0, fHSY0: integer; // mouse down coordinates (clipped at bakcground layer) fHSX1, fHSY1: integer; // mouse down coordinates (clipped at current layer) fPredX, fPredY: integer; // last call to MouseMove coordinates fPredLX, fPredLY: integer; // last call to MouseMove coordinates (real coordinates) fMouseDownX, fMouseDownY: integer; // non clipped mouse down coordinates fHPolySel: pointer; // pointer to the current animated polygon fSelectionBase: TIESelectionBase; // coordinate system for selection (bitmap or client area) fSavedSelectionBase: TIESelectionBase; fOnSelectionChanging: TNotifyEvent; fOnSelectionChange: TNotifyEvent; fOnBeforeSelectionChange: TNotifyEvent; fOnMouseInSel: TNotifyEvent; fSelectionOptions: TIESelectionOptions; fStartingPolyCount: integer; // polycount at MouseDown time fSelectionMask: TIEMask; // selection mask fSelectionMaskDepth: integer; // selection mask depth fSelectionIntensity: integer; // must be 1 if fSelectionMaskDepth is 1, otherwise a value from 0 to 255 fSelColor1, fSelColor2: TColor; // selection colors fGripColor1, fGripColor2: TColor; // grip color fGripBrushStyle: TBrushStyle; fGripSize: integer; fGripShape: TIEGripShape; fExtendedGrips: boolean; fLyrGripColor1, fLyrGripColor2: TColor; fLyrGripBrushStyle: TBrushStyle; fLyrGripSize: integer; fLyrGripShape: TIEGripShape; fChessboardSize: integer; fChessboardBrushStyle: TBrushStyle; fChessboardColor2Customized: Boolean; fForceALTkey: boolean; fMouseMoveScrolling: boolean; // true if we are inside MouseMoveScroll fSavedSelection: TList; // list of saved selections fEnableShiftKey: boolean; // Enable/disable shift key to add multi selections fGradientEndColor: TColor; // animated polygons fAnimPoly: TList; // animated polygons list (TIEAnimPoly) fAnimPolyTimer: TTimer; // animation timer // smooth scroll fSmoothScrollTimer: TTimer; fSmoothScrollDestX, fSmoothScrollDestY: Integer; fSmoothScrollValue: Integer; // smooth zoom fSmoothZoomTimer: TTimer; fSmoothZoomDest: Double; fSmoothZoomValue: Integer; // fMouseInteract: TIEMouseInteract; fScrollBarsAlwaysVisible: boolean; // true if the scrollbars are always visible fVScrollBarParams: TIEScrollBarParams; fHScrollBarParams: TIEScrollBarParams; fMouseWheelParams: TIEMouseWheelParams; flx1, fly1, flx2, fly2: integer; // alpha channel fEnableAlphaChannel: boolean; // // encapsulated components fImageEnIO: TImageEnIO; fImageEnProc: TImageEnProc; // layers fLayers: TList; // list of TIELayer objects fLayersCurrent: integer; // 0=first layer fLayersRect: TIERectangle; // all layers coverage fLayerOptions: TIELayerOptions; fLayerDefaults: TStringList; // fLayersDrawBox: boolean; fLayersCaching: Integer; // 0 is no caching. -1 is cache all layers fMovingLayer: integer; // -1 no layers moving, >= 0 moving a layer fLayerMoved: Boolean; fRotatingLayer: integer; // -1 no layers rotating, >= 0 rotating layer fRotatingLayerValue: Double; fMovingRotationCenter: integer; // -1 no layers moving rotation center fLayerResizing: TIEGrip; // ieNone no layer grip fMovResRotLayerStarted: Boolean; // conversion LUT fGXScr2Bmp, fGYScr2Bmp: pintegerarray; // LUT used to convert screen based coordinate to bitmap fGXScr2BmpSize, fGYScr2BmpSize: Integer; // size of fGXScr2Bmp and fGYScr2Bmp LUTs fXScr2Bmp, fYScr2Bmp: pintegerarray; // LUT used to convert screen based coordinate to bitmap fXScr2BmpSize, fYScr2BmpSize: integer; // size of fXScr2Bmp and fYScr2Bmp LUTs fXBmp2Scr, fYBmp2Scr: pintegerarray; // LUT used to convert bitmap based coordinate to screen fGXBmp2Scr, fGYBmp2Scr: pintegerarray; // LUT used to convert bitmap based coordinate to screen fXBmp2ScrSize, fYBmp2ScrSize: integer; // size of fXBmp2Scr, fYBmp2Scr LUTs // fAutoCursors: Boolean; // If true (default) ImageEn handles mouse cursors // fOnSaveUndo: TIESaveUndoEvent; fOnVirtualKey: TIEVirtualKeyEvent; fLayerBoxPen: TPen; fHighlightedPixelColor: TColor; fImageSet : Boolean; // Becomes true once we set or assign an image // Gestures fGestures: TIEViewerGestures; fGestureStartValue: integer; fGestureStartX: integer; fGestureStartY: integer; fGestureBaseZoom: double; fGestureBaseViewX: integer; fGestureBaseViewY: integer; fGestureBaseRotate: double; fGestureBasePosX: integer; fGestureBasePosY: integer; // procedure CalcEdges(var LeftEdge, TopEdge, RightEdge, BottomEdge: integer; NoVertSB, NoHorizSB: boolean); procedure SetBackground(cl: TColor); override; procedure PolyDraw1; procedure SetScrollBars(v: TIEScrollStyle); virtual; procedure CreateHandle(); override; function GetOptimalZoom(CanStretch, CanShrink: Boolean): double; // cross platform events procedure DoSize; procedure DoVertScroll(command: TIEScrollCommand; Position: integer); procedure DoHorizScroll(command: TIEScrollCommand; Position: integer); procedure DoMouseWheelScroll(Delta: integer; mouseX, mouseY: integer; CtrlPressed: boolean); procedure DoDoubleClickEx(Shift: boolean); // platform specific events procedure WMSize(var Message: TWMSize); message WM_SIZE; procedure WMEraseBkgnd(var Message: TMessage); message WM_ERASEBKGND; procedure WMVScroll(var Message: TMessage); message WM_VSCROLL; procedure WMHScroll(var Message: TMessage); message WM_HSCROLL; procedure WMMouseWheel(var Message: TMessage); message WM_MOUSEWHEEL; procedure WMMouseHWheel(var Message: TMessage); message IEWM_MOUSEHWHEEL; function _CreatePalette: HPalette; function PaletteChanged(Foreground: Boolean): Boolean; {$ifndef FPC} override; {$endif} procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK; procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS; procedure CMWantSpecialKey(var Msg: TCMWantSpecialKey); message CM_WANTSPECIALKEY; procedure WMPaint(var Message: TWMPaint); message WM_PAINT; procedure IEMUpdate(var Message: TMessage); message IEM_UPDATE; procedure IEMProgress(var Message: TMessage); message IEM_PROGRESS; procedure IEMFinishWork(var Message: TMessage); message IEM_FINISHWORK; procedure CNKEYDOWN(var Message: TMessage); message CN_KEYDOWN; // we handle CN_ instead of WM_ to be sure key events arrive here procedure CNKEYUP(var Message: TMessage); message CN_KEYUP; // we handle CN_ instead of WM_ to be sure key events arrive here procedure WMSYSKEYDOWN(var Message: TMessage); message WM_SYSKEYDOWN; procedure WMSYSKEYUP(var Message: TMessage); message WM_SYSKEYUP; procedure WMTimer(var Message: TWMTimer); message WM_TIMER; // procedure RestoreCursor; procedure ShowSelectionEx(d: boolean); procedure HideSelectionEx(dd: boolean); function GetIdealComponentWidth: integer; function GetIdealComponentHeight: integer; function GetIdealImageWidth: integer; function GetIdealImageHeight: integer; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; function GetPolySel(idx: integer): TPoint; function GetPolySelCount: integer; procedure SetMouseInteract(v: TIEMouseInteract); virtual; procedure SetMouseWheelParams(v: TIEMouseWheelParams); procedure AnimPolygonAddPtEx(ap: pointer; x, y: integer); procedure AnimPolygonAddBreak(ap: pointer); procedure AnimPolygonRemoveLast(ap: pointer); procedure AnimPolygonRemoveLastPoint(ap: pointer); procedure AnimPolygonMove(ap: pointer; ox, oy: integer; max_x, max_y: integer; CutSel: boolean); procedure ViewChange(c: integer); virtual; procedure ViewChanging(c: integer; newValue: Double); virtual; procedure SetZoomFilter(v: TResampleFilter); procedure SubMouseMoveScroll(scx, scy: integer); virtual; procedure MouseMoveScroll(); function GetFBitmap: TBitmap; override; function GetIEBitmap: TIEBitmap; override; procedure SetVisibleSelection(vv: boolean); function GetVisibleSelection: boolean; function GetPolySelArray: PPointArray; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure AddSelPointEx(x, y: integer); procedure AddSelBreakEx; procedure SelectEx(x1, y1, x2, y2: integer; Op: TIESelOp; aspectratio: boolean; adjRect: Boolean); function GetClientWidth: integer; virtual; function GetClientWidthExRulers: integer; function GetClientHeight: integer; virtual; function GetClientHeightExRulers: integer; function HasParentWindow: boolean; virtual; procedure SetSelColor1(v: TColor); procedure SetSelColor2(v: TColor); function GetImageEnIO: TImageEnIO; function GetImageEnProc: TImageEnProc; procedure SetEnableAlphaChannel(v: boolean); procedure SetOnProgress(v: TIEProgressEvent); virtual; function GetOnFinishWork: TNotifyEvent; virtual; procedure SetOnFinishWork(v: TNotifyEvent); virtual; procedure SetOnAcquireBitmap(v: TIEAcquireBitmapEvent); virtual; function GetOnAcquireBitmap: TIEAcquireBitmapEvent; virtual; function GetOnProgress: TIEProgressEvent; virtual; function GetHasAlphaChannel: boolean; override; function GetAlphaChannel: TIEBitmap; override; function GetIsEmpty: boolean; virtual; function GetIsEmpty2: boolean; virtual; function RequiresScrollBars: boolean; procedure SetLayersCurrent(Value: integer); virtual; function SetLayersCurrentEx(Value: integer; bUserAction, bDeselectAll: Boolean; DoUpdate: Boolean = True): Boolean; procedure SelectMaskOfLayer(iLayerIndex: Integer; bSelect: Boolean; bUserAction: Boolean); procedure SyncBitmapToCurrentLayer(); function SyncLayers(): Boolean; function MouseChangingLayers(): Boolean; procedure SetLegacyBitmap(Value: boolean); virtual; procedure CreateCoordConvLUT; virtual; procedure CalcPaintCoords; virtual; procedure CalcPaintCoordsEx(var XSrc, YSrc, SrcWidth, SrcHeight: integer; var DstWidth, DstHeight: integer; tViewX, tViewY: integer); procedure UpdateLimits; virtual; function QuantizeViewX(vx: integer): integer; function QuantizeViewY(vy: integer): integer; procedure HideHorizScrollBar; procedure HideVertScrollBar; procedure SetSelectionIntensity(value: integer); procedure SetLayersDrawBox(value: boolean); procedure DoLayerNotify(layer: integer; event: TIELayerEvent); virtual; procedure SetTempCursor(Value: TCursor; bOnMouseDown : Boolean = False); function GetCurrentLayer: TIELayer; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure GetFitValueXY(var x, y: Double); function IsPointInsideLayer(x, y: Integer; layer: Integer): Boolean; procedure OnSmoothSetView(Sender: TObject); procedure StopSmoothScroll(); procedure OnSmoothZoom(Sender: TObject); procedure StopSmoothZoom(); procedure DrawSelectionGrid(x1, y1, x2, y2: Integer); virtual; procedure AfterDrawLayer(layerIndex: Integer; DestBitmap: TIEBitmap; const DestRect: TRect); virtual; procedure SetVisibleBitmapRect(ARect: TRect); function GetVisibleBitmapRect : TRect; function LayersAllowMultiSelect: Boolean; procedure MoveSelByKey(VKey: Word; ss: TShiftState); // user interactions function UserInteractions_MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; procedure UserInteractions_MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); function UserInteractions_MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; procedure UserInteractions_MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); function UserInteractions_MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; procedure UserInteractions_MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure UserInteractions_VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); procedure UserInteractions_Paint(const UpdateRect: TRect); {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (2015-12-15) function GetDPIX() : integer; function GetDPIY() : integer; procedure SetDPIX(dpiX: integer); virtual; procedure SetDPIY(dpiY: integer); virtual; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (8/11/2016) function GetLayersRotationDelayFilterOnPreview(): boolean; procedure SetLayersRotationDelayFilterOnPreview(value: Boolean); {$endif} procedure UpdateTextEditor(); procedure TextEditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure TextEditorOnChange(Sender: TObject); public fIEBitmapValid: Boolean; // Selected layer is an image (thus fIEBitmap can be used) fIEBitmap: TIEBitmap; // contains also the alpha channel fBitmap: TBitmap; constructor Create(Owner: TComponent); override; destructor Destroy; override; procedure Paint; override; procedure PaintToEx(ABitmap: TIEBitmap; UpdRect: PRect; drawBackground: Boolean; drawGadgets: Boolean); virtual; procedure GetRenderRectangles(var xDst, yDst, dxDst, dyDst: integer; var xSrc, ySrc, dxSrc, dySrc: integer); procedure GetMinViewXY(var mx, my: integer); procedure GetMaxViewXY(var mx, my: integer); procedure SetZoomNoUpdate(v: double); virtual; procedure SetZoomXNoUpdate(v: double); virtual; procedure SetZoomYNoUpdate(v: double); virtual; function GetFitValue(): double; procedure DrawBackgroundToCanvas(ACanvas: TCanvas; iWidth: Integer = -1; iHeight: Integer = -1); procedure MoveContentTo(Destination: TImageEnView); procedure SaveState(const FileName: String); overload; procedure SaveState(Stream: TStream); overload; procedure LoadState(const FileName: String); overload; procedure LoadState(Stream: TStream); overload; procedure ResetState(); // Selection procedure Select(x1, y1, x2, y2: integer; Op: TIESelOp = iespReplace); virtual; procedure SelectMagicWand(x, y: integer; Op: TIESelOp = iespReplace); procedure SelectColors(StartColor, FinalColor: TRGB; Op: TIESelOp = iespReplace); overload; procedure SelectColors(Color: TRGB; Op: TIESelOp = iespReplace); overload; procedure SelectColors(ColorIndex: integer; Op: TIESelOp = iespReplace); overload; procedure SelectNonAlpha(Op: TIESelOp = iespReplace); procedure SelectEllipse(CenterX, CenterY, Width, Height: integer; Op: TIESelOp = iespReplace); procedure SelectRoundRect(Left, Top, Right, Bottom, RoundWidth, RoundHeight: integer; Op: TIESelOp = iespReplace); procedure SelectCustom; procedure MoveSelection(MoveX, MoveY: integer; Sizing: Boolean = False); property SelectionAspectRatio: double read fSelectionAspectRatio write SetSelectionAspectRatio; procedure SetSelectionMarkOuterStyle(Alpha: Integer; Color: TColor); procedure SelectByGroupIndex(iGroupIndex: Integer; bSelect: Boolean; bUserAction: Boolean); {!! TImageEnView.SelectionAbsWidth Declaration property SelectionAbsWidth: Integer; Description Locks the selection to a specific width, when is 0. Example // we want a fixed selection of 100 x 100 pixels ImageEnView.SelectionAbsWidth := 100; ImageEnView.SelectionAbsHeight := 100; ImageEnView.SelectionAspectRatio := 0; See Also - - - !!} property SelectionAbsWidth: integer read fSelectionAbsWidth write fSelectionAbsWidth; {!! TImageEnView.SelectionAbsHeight Declaration property SelectionAbsHeight: Integer; Description Locks the selection to a specific height, when is 0. Example // we want a fixed selection of 100 x 100 pixels ImageEnView.SelectionAbsWidth := 100; ImageEnView.SelectionAbsHeight := 100; ImageEnView.SelectionAspectRatio := 0; See Also - - - !!} property SelectionAbsHeight: integer read fSelectionAbsHeight write fSelectionAbsHeight; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (21/2/2017) // Note: deprecated 'Use loAutoFixBorders of LayerOptions' property AutoFixRotationBorders: Boolean read GetAutoFixRotationBorders write SetAutoFixRotationBorders; {$ENDIF} procedure Deselect; property SelX1: integer read GetSelx1; property SelY1: integer read GetSely1; property SelX2: integer read GetSelx2; property SelY2: integer read GetSely2; procedure AddSelPoint(x, y: integer); virtual; procedure AddSelBreak; procedure DelLastSelPoint(); property PolySel[idx: integer]: TPoint read GetPolySel; property PolySelCount: integer read GetPolySelCount; property PolySelPoints: PPointArray read GetPolySelArray; property VisibleBitmapRect : TRect read GetVisibleBitmapRect write SetVisibleBitmapRect; property SmoothScrollValue: Integer read fSmoothScrollValue write SetSmoothScrollValue; property SmoothZoomValue: Integer read fSmoothZoomValue write SetSmoothZoomValue; {!! TImageEnView.Selected Declaration property Selected: boolean; Description Returns True if any portion of the image is selected. Selected is True after you have called the Select method. Selected is False after you have called method. If Selected is True, the properties , , , are valid. Read-only !!} property Selected: boolean read fSel; {!! TImageEnView.SelectedRect Declaration property SelectedRect: ; Description Returns current selected rectangle. If no selected exists returns the whole image rectangle. The coordinate has the same dimensions of the bitmap (i.e. it is not affected by and , values). You can programatically make a selection using the method. Read-only !!} property SelectedRect: TIERectangle read GetSelectedRect; property VisibleSelection: boolean read GetVisibleSelection write SetVisibleSelection; {!! TImageEnView.MagicWandMaxFilter Declaration property MagicWandMaxFilter: Boolean; Description Set to True to apply a maximum filter to the magic wand selection (remove the "black hole"). Default: False See Also - - - !!} property MagicWandMaxFilter: boolean read fMagicWandMaxFilter write fMagicWandMaxFilter; {!! TImageEnView.MagicWandTolerance Declaration property MagicWandTolerance: Integer; Description Specifies the color difference of original point and region point when using miSelectMagicWand. A low number selects colors of a very close match, whereas a higher value allows much broader color differences. Default: 15 See Also - - - !!} property MagicWandTolerance: integer read fMagicWandTolerance write fMagicWandTolerance; {!! TImageEnView.MagicWandMode Declaration property MagicWandMode: ; Description Specifies how magic wand selection works. Default: iewInclusive See Also - - - !!} property MagicWandMode: TIEMagicWandMode read fMagicWandMode write fMagicWandMode; function IsPointInsideSelection(x, y: integer): boolean; {!! TImageEnView.SelectionMask Declaration property SelectionMask: ; Description SelectionMask contains the current selection as a bit mask of 1 bit per pixel (zero is unselected, 1 is selected). Example // Excludes pixel 100,100 from selection ImageEnView1.SelectionMask.SetPixel(100, 100, 0); // To create a new selection using only SelectionMask (this select point 50,50 and 55,55) ImageEnView1.SelectionMask.SetPixel(50, 50, 1); ImageEnView1.SelectionMask.SetPixel(55, 55, 1); ImageEnView1.SelectCustom(); See Also - !!} property SelectionMask: TIEMask read fSelectionMask; procedure InvertSelection; procedure SetSelectedAreaAlpha(Alpha: integer); procedure SetSelectionGripStyle(GripColor1: TColor=clBlack; GripColor2: TColor=clWhite; GripBrushStyle: TBrushStyle=bsSolid; GripSize: integer=5; ExtendedGrips: boolean=true; Shape: TIEGripShape = iegsCircle); procedure GetSelectionGripStyle(var GripColor1: TColor; var GripColor2: TColor; var GripBrushStyle: TBrushStyle; var GripSize: integer; var ExtendedGrips: boolean; var Shape: TIEGripShape); procedure SetLayersGripStyle(GripColor1: TColor=clBlack; GripColor2: TColor=clWhite; GripBrushStyle: TBrushStyle=bsSolid; GripSize: integer=5; Shape: TIEGripShape = iegsCircle); procedure SetLayersBoxStyle(PenStyle: TPenStyle=psDot; PenMode: TPenMode=pmNot; PenWidth: Integer = 1; PenColor: TColor=clBlack); procedure ApplyBitmapToSelection(SrcBitmap: TBitmap; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); overload; procedure ApplyBitmapToSelection(SrcBitmap: TIEBitmap; MergeAlpha: Boolean = True; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); overload; procedure CopySelectionToBitmap(DestBitmap: TBitmap; FillBackground: Boolean = True); overload; procedure CopySelectionToBitmap(DestBitmap: TIEBitmap; FillBackground: Boolean = True); overload; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.0 procedure CopySelectionToIEBitmap(DestBitmap: TIEBitmap; FillBackground: Boolean=true); {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Use CopySelectionToBitmap instead - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} {$endif} procedure EndSelect; virtual; procedure SetSelectedPixelsColor(color: TRGB); procedure SetAlphaRangePixelsColor(alphaMin, alphaMax: integer; color: TRGB); procedure SaveSelectionToStream(Stream: TStream); function LoadSelectionFromStream(Stream: TStream; Options: TIERSOptions=iersMoveToAdapt): boolean; function MergeSelectionFromStream(Stream: TStream): boolean; procedure SaveSelectionToFile(const FileName: String); function LoadSelectionFromFile(const FileName: String; Options: TIERSOptions = iersMoveToAdapt): boolean; function MergeSelectionFromFile(const FileName: String): Boolean; function RestoreSelection(Remove: Boolean=true; Options: TIERSOptions = iersMoveToAdapt): boolean; procedure SaveSelection; function DiscardSavedSelection: boolean; property SavedSelectionsCount: Integer read GetSavedSelectionsCount; {!! TImageEnView.EnableShiftKey Declaration property EnableShiftKey: Boolean; Description Enables Shift key functionality (holding down the Shift key to insert multiple selections). Default: true !!} property EnableShiftKey: boolean read fEnableShiftKey write fEnableShiftKey; procedure LayersSizeAll(HorzSizing, VertSizing: Double; bSelectedOnly: Boolean = False; bFixSizes: Boolean = False; ScalePosition: Boolean = False); procedure LayersRotateAll(Value: Double; bSelectedOnly: Boolean = False; bFixRotations: Boolean = False); procedure LayersRepositionAll(MoveX, MoveY: Integer; SelectedOnly: Boolean = False; Sizing: Boolean = False); {!! TImageEnView.LayersRotationFilter Declaration property LayersRotationFilter: ; Description Specifies the rotation filter to use when layers rotation has completed. This is important to optimize the quality of rotated image layers. Note: You also need to set := True; Default: ierFast Example // Rotate the current layer 45 degrees clockwise at highest quality ImageEnView1.CurrentLayer.Rotate := -45; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; // Allow the user to free rotate layers at highest quality ImageEnView1.MouseInteract := [miRotateLayers]; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; See Also - - - !!} property LayersRotationFilter: TIEAntialiasMode read fLayersRotationFilter write fLayersRotationFilter; {!! TImageEnView.LayersRotationAntialias Declaration property LayersRotationAntialias: Boolean; Description Enables rotation anti-aliasing when layer rotation has completed (to improve their quality). Use to specify the anti-aliasing algorithm. Default: False Example // Rotate the current layer 45 degrees clockwise at highest quality ImageEnView1.CurrentLayer.Rotate := -45; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; // Allow the user to free rotate layers at highest quality ImageEnView1.MouseInteract := [miRotateLayers]; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; See Also - - - !!} property LayersRotationAntialias: Boolean read fLayersRotationAntialias write fLayersRotationAntialias; {!! TImageEnView.LayersRotationUseFilterOnPreview Declaration property LayersRotationUseFilterOnPreview: Boolean; Description Displays the user's rotation with the selected anti-alias effect immediately (i.e. before calling ). Note: Preview of large rotated images at high quality can be slow, so it is recommended that you also use . Default: False Example // Rotate the current layer 45 degrees clockwise at highest quality ImageEnView1.CurrentLayer.Rotate := -45; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; // Allow the user to free rotate layers at highest quality ImageEnView1.MouseInteract := [miRotateLayers]; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationFilter := ierBilinear; ImageEnView1.LayersRotationUseFilterOnPreview := true; ImageEnView1.LayersFastDrawing := iefDelayed; See Also - - - !!} property LayersRotationUseFilterOnPreview: boolean read fLayersRotationUseFilterOnPreview write fLayersRotationUseFilterOnPreview; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (8/11/2016) // Note: deprecated 'Use LayersFastDrawing' property LayersRotationDelayFilterOnPreview: boolean read GetLayersRotationDelayFilterOnPreview write SetLayersRotationDelayFilterOnPreview; {$endif} property SelectionMaskDepth: integer read fSelectionMaskDepth write SetSelectionMaskDepth; property SelectionIntensity: integer read fSelectionIntensity write SetSelectionIntensity; procedure MakeSelectionFeather(radius: double); // Animated polygons function AnimPolygonNew(VColor1, VColor2: TColor; VAnimated: boolean; VSizeable: boolean): pointer; procedure AnimPolygonDel(ap: pointer); procedure AnimPolygonAddPt(ap: pointer; x, y: integer); procedure AnimPolygonClear(ap: pointer); procedure AnimPolygonEnabled(ap: pointer; Value: Boolean); // Polygon process procedure CopyFromPolygon(Source: TBitmap; const Polygon: array of TPoint; PolygonLen: integer; const Position: TPoint); procedure CopyToPolygon(Dest: TBitmap; const Polygon: array of TPoint; PolygonLen: integer; const Position: TPoint); // Display procedure Update; override; {!! TImageEnView.UpdateReason Declaration property UpdateReason: ; Description Advises the reason for the next . This is used to optimize the Update() task. This property is restored to ieurDefault after Update() has executed. !!} property UpdateReason: TIEUpdateReason read fUpdateReason write fUpdateReason; procedure UpdateNoPaint; {!! TImageEnView.OffScreenPaint Declaration property OffScreenPaint: Boolean; Description When the component is not visible (i.e. Visible=False) the back buffer is not painted. If you need the back buffer to be paint correctly set OffScreenPaint to true. !!} property OffScreenPaint: Boolean read fOffscreenPaint write fOffscreenPaint; {!! TImageEnView.SelectionGridSize Declaration property SelectionGridSize: Integer; Description When this is not 1, a grid is drawn over rectangular selections with the column and row count of SelectionGridSize (e.g. if SelectionGridSize=3 then there will be three columns and rows within the selection box). The color of the grid is specified by . This property can be used in place of and . Default: 1 !!} property SelectionGridSize: Integer read GetSelectionGridSize write SetSelectionGridSize; {!! TImageEnView.SelectionGridWidth Declaration property SelectionGridWidth: Integer; Description When this is not 1, a grid is drawn over rectangular selections with the column count of SelectionGridWidth (e.g. if SelectionGridWidth=3 then there will be three columns within the selection box). The color of the grid is specified by . This property can be used in place of . Default: 1 See also: !!} property SelectionGridWidth: Integer read fSelectionGridWidth write fSelectionGridWidth; {!! TImageEnView.SelectionGridHeight Declaration property SelectionGridHeight: Integer; Description When this is not 1, a grid is drawn over rectangular selections with the row count of SelectionGridHeight (e.g. if SelectionGridHeight=3 then there will be three rows within the selection box). The color of the grid is specified by . This property can be used in place of . Default: 1 See also: !!} property SelectionGridHeight: Integer read fSelectionGridHeight write fSelectionGridHeight; procedure Fit(StretchSmall : Boolean = True); procedure FitToWidth; procedure FitToHeight; procedure Stretch; function GetIdealZoom: double; property ViewX: integer read fViewX write SetViewX; property ViewY: integer read fViewY write SetViewY; procedure CenterImage; procedure SetViewXY(x, y: integer); procedure SetViewXYSmooth(x, y: Integer); procedure SetZoomSmooth(Zoom: Double); property Zoom: double read fZoomX write SetZoom; property ZoomX: Double read fZoomX write SetZoomX; property ZoomY: Double read fZoomY write SetZoomY; procedure ZoomSelection(AspectRatio: Boolean=true); procedure ZoomAt(x, y: integer; ZoomVal: double; Center: Boolean=true); procedure ZoomIn; procedure ZoomOut; property ClientWidth read GetClientWidth; property ClientHeight read GetClientHeight; property IdealComponentWidth: integer read GetIdealComponentWidth; property IdealComponentHeight: integer read GetIdealComponentHeight; property IdealImageWidth: integer read GetIdealImageWidth; property IdealImageHeight: integer read GetIdealImageHeight; procedure LockPaint; override; function UnLockPaint: integer; override; function NPUnLockPaint: integer; override; {!! TImageEnView.LockPaintCount Declaration property LockPaintCount: Integer; (Read-only) Description Returns the lock painting state. 0=no lock, > 0 locking (the image will not be painted). increases LockPaintCount, decreases it. !!} property LockPaintCount: integer read fLockPaint; {!! TImageEnView.LockUpdateCount Declaration property LockUpdateCount: Integer; (Read-only) Description Returns the lock updating state. 0 = no lock, > 0 locking (the image will not be updated). increases LockUpdateCount, decreases it. !!} property LockUpdateCount: integer read fUpdateLocked; procedure DrawTo(Canvas: TCanvas); {!! TImageEnView.OffsetX Declaration property OffsetX: integer; (Read-only) Description Returns the horizontal position where the image has been drawn. If is iehLeft, OffsetX will be zero, whereas for iehCenter it will be (Control Width - Image Width) div 2. Note: This value only indicates the initial draw position for an image, it is not related to scrolling (unlike ). See Also - - - !!} property OffsetX: integer read fOffX; {!! TImageEnView.OffsetY Declaration property OffsetY: integer; (Read-only) Description Returns the vertical position where the image has been drawn. If is ievTop, OffsetY will be zero, whereas for ievCenter it will be (Control Height - Image Height) div 2. Note: This value only indicates the initial draw position for an image, it is not related to scrolling (unlike ). See Also - - - !!} property OffsetY: integer read fOffY; {!! TImageEnView.ExtentX Declaration property ExtentX: integer; (Read-only) Description Returns the width of the area used to show the current image (i.e. the width of the image as it appears onscreen). Example // Copy the actual view of ImageEnView1 as the current image ImageEnView2.Bitmap.Width := ImageEnView1.ExtentX; ImageEnView2.Bitmap.Height := ImageEnView1.ExtentY; ImageEnView1.DrawTo(ImageEnView2.Bitmap.Canvas); See Also - - - - !!} property ExtentX: integer read fExtX; {!! TImageEnView.ExtentY Declaration property ExtentY: integer; (Read-only) Description Returns the height of the area used to show the current image (i.e. the height of the image as it appears onscreen). Example // Copy the actual view of ImageEnView1 as the current image of ImageEnView2 ImageEnView2.Bitmap.Width := ImageEnView1.ExtentX; ImageEnView2.Bitmap.Height := ImageEnView1.ExtentY; ImageEnView1.DrawTo(ImageEnView2.Bitmap.Canvas); See Also - - - - !!} property ExtentY: integer read fExtY; {!! TImageEnView.ScrollBarsAlwaysVisible Declaration property ScrollBarsAlwaysVisible: Boolean; Description When the ScrollBarsAlwaysVisible property is True, the scrollbars specified in property will be displayed, even if when not required. !!} property ScrollBarsAlwaysVisible: boolean read GetScrollBarsAlwaysVisible write SetScrollBarsAlwaysVisible default false; {!! TImageEnView.VScrollBarParams Declaration property VScrollBarParams: ; Description The VScrollBarParams property allows an application to customize the vertical scrollbar behavior, including tracking (display refresh on mouse dragging), up/down buttons pixel scrolling, pagedown/up pixel scrolling. Example // disable tracking ImageEnView1.VScrollBarParams.Tracking := False; !!} property VScrollBarParams: TIEScrollBarParams read fVScrollBarParams; {!! TImageEnView.HScrollBarParams Declaration property HScrollBarParams: ; Description The HScrollBarParams property allows an application to customize the horizontal scroll bar behavior, including tracking (display refresh on mouse dragging), left/right buttons pixel scrolling, pageleft/pageright pixel scrolling. Example // disable tracking ImageEnView1.HScrollBarParams.Tracking := False; !!} property HScrollBarParams: TIEScrollBarParams read fHScrollBarParams; procedure UpdateRect(rclip: TRect); procedure PaintRect(const rc: TRect); procedure LockUpdate; procedure UnLockUpdate; procedure UnLockUpdateEx; property BackBuffer: TBitmap read GetBackBuffer; procedure SetNavigator(nav: TImageEnView; options: TIENavigatorOptions = []); {!! TImageEnView.IsNavigator Declaration property IsNavigator: Boolean; Description Returns true if this object is used as a navigator of another TImageEnView object. A navigator shows a selection that controls the zoom and scroll of the main control. See also: . !!} property IsNavigator: Boolean read fIsNavigator; property MinBitmapSize: Integer read fMinBitmapSize write fMinBitmapSize; procedure ChangeResolution(NewDPI: Integer; ResampleFilter: TResampleFilter=rfNone); // layers property LayersCount: integer read GetLayersCount; property LayersCurrent: integer read fLayersCurrent write SetLayersCurrent; function LayersAddEx(Kind: TIELayerKind; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0; SrcBitmap: TIEBitmap = nil; DoCopyBitmap: Boolean = true; DoSaveUndo: Boolean = False; AssignDefaults: Boolean = False; SelLayer: Boolean = True ): Integer; function LayersAdd(Kind: TIELayerKind = ielkImage): integer; overload; function LayersAdd(Width: Integer; Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB; PosX: Integer = -1; PosY: Integer = -1): Integer; overload; function LayersAdd(Bitmap: TIEBitmap; DoCopy: Boolean = true): integer; overload; function LayersAdd(FileName: WideString; PosX: Integer = -1; PosY: Integer = -1): Integer; overload; function LayersAdd(Shape: TIEShape; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0): Integer; overload; function LayersAdd(const Text: String; FontSize : Integer; FontColor : TColor; const FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1): Integer; overload; function LayersInsertEx(Position: Integer; Kind: TIELayerKind; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0; SrcBitmap: TIEBitmap = nil; DoCopyBitmap: Boolean = true; DoSaveUndo: Boolean = False; AssignDefaults: Boolean = False; SelLayer: Boolean = True ): Integer; procedure LayersInsert(Position: Integer; Kind: TIELayerKind = ielkImage); overload; procedure LayersInsert(Position: Integer; Width: Integer; Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB; PosX: Integer = -1; PosY: Integer = -1); overload; procedure LayersInsert(Position: Integer; Bitmap: TIEBitmap; DoCopy: Boolean = true); overload; procedure LayersInsert(Position: Integer; FileName: WideString; PosX: Integer = -1; PosY: Integer = -1); overload; procedure LayersInsert(Position: Integer; Shape: TIEShape; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0); overload; procedure LayersInsert(Position: Integer; const Text: String; FontSize : Integer; FontColor : TColor; const FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1); overload; procedure LayersRemoveEx(LyrIndex: Integer = -2; SaveUndo: Boolean = False); procedure LayersRemove(LyrIndex: Integer = -2); virtual; procedure LayersClear; procedure LayersMove(CurIndex, NewIndex: integer); procedure LayersMerge(Layer1, Layer2: integer; RemoveUpperLayer: Boolean = true); overload; procedure LayersMerge(LayerList: array of integer); overload; procedure LayersMerge(LayerList: TIEArrayOfInteger); overload; procedure LayersMerge(); overload; procedure LayersMergeTo(Layer1, Layer2: integer; Destination: TIEBitmap); procedure LayersDrawTo(Destination: TIEBitmap; AdjustBitmap: Boolean = True); procedure LayersSaveMergedTo(Destination: TIEBitmap; FastOutput: Boolean = False); overload; procedure LayersSaveMergedTo(const Filename: string; FastOutput: Boolean = False); overload; procedure LayersSaveMergedTo(const Stream: TStream; FileType: TIOFileType; FastOutput: Boolean = False); overload; procedure LayersMergeAll(AlphaCompositing: Boolean = False); procedure LayersCopyToAlpha(DestLayer: Integer); procedure LayersCropBackground(SelectedOnly: Boolean = False; FillAlpha: Integer = 255; AllowReduce: Boolean = True; AllowEnlarge : Boolean = True); procedure LayersActivateTextEditor(LayerIdx: integer); procedure LayersCancelEditor(SaveChanges: Boolean = True); function LayersCreateFromAlpha: Integer; function LayersCreateFromEdge(ScreenX, ScreenY: integer; Tolerance: integer; MaxFilter: boolean = False): integer; procedure LayersSetPropertiesEx(LayerIndex: integer; Props: TStrings; const PropName, Value: string; SaveUndo: Boolean; UndoMsg: string); procedure LayersSetProperties(LayerIndex: integer; Props: TStrings); overload; procedure LayersSetProperties(LayerIndex: integer; const PropName, Value: Variant); overload; property LayersCaching: integer read fLayersCaching write SetLayersCaching; property SoftCrop: TIESoftCropMode read fSoftCrop write SetSoftCrop; property SoftCropValue: Integer read fSoftCropValue write SetSoftCropValue; {!! TImageEnView.LayersRotateStep Declaration property LayersRotateStep: Integer; Description Sets the degree of each rotation step when the user rotates a layer and presses the Shift key. Default: 45 !!} property LayersRotateStep: Integer read fLayersRotateStep write fLayersRotateStep; {!! TImageEnView.LayersMergeFilter Declaration property LayersMergeFilter: ; Description Specifies the quality that is used when merging layers. It applies to: - - - - Note: Has no effect on image layers, if they have a custom Default: rfLanczos3 !!} property LayersMergeFilter: TResampleFilter read fLayersMergeFilter write fLayersMergeFilter; {!! TImageEnView.LayersSelectConstrains Declaration property LayersSelectConstrains: Boolean; Description If true, selection constraints are active, i.e. whether the layer itself can be selected is controlled at the layer level by . Default: True !!} property LayersSelectConstrains: Boolean read fLayersSelectConstrains write fLayersSelectConstrains; {!! TImageEnView.Layers Declaration property Layers[idx: Integer]: ; Description The Layers property provides access to properties related to a specified layer. Example // Set the opacity of the first layer to 0.5 (50%) ImageEnView.Layers[0].Opacity := 0.5; ImageEnView.Update; // Set the transparency of the first layer to 50 ImageEnView.Layers[0].Transparency := 50; ImageEnView.Update; // Hide layer 1 ImageEnView.Layers[1].Visible := False; ImageEnView.Update; // Create a magnify layer idx := ImageEnView.LayersAdd; with ImageEnView.Layers[idx] do begin Magnify.Enabled := true; Magnify.Rate := 2; // x2 magnification Width := 50; Height := 50; end; !!} property Layers[idx: integer]: TIELayer read GetLayer; property LayerOptions: TIELayerOptions read fLayerOptions write SetLayerOptions; property LayerDefaults: TStringList read GetLayerDefaults; property LayersList: TList read fLayers; {!! TImageEnView.LayersResizeAspectRatio Declaration property LayersResizeAspectRatio: ; Description Specifies whether ImageEn respects the aspect ratio of layers when resizing. Value Description iearDisabled Doesn't maintain the aspect ratio even when pressing ALT or setting ) iearALTKey Maintains the aspect ratio only when pressing ALT or setting iearAlways The aspect ratio is always maintained (using any grips) iearAlwaysOnCornerGrip The aspect ratio is always maintained if the corner grips are used iearLayerDefaultOnCornerGrip If the layer has a preferred aspect ratio then dragging the corner grip will maintain the aspect ratio, for side grips and other layer types the aspect ratio is not maintained
Default: iearALTKey Note: ImageEn will always enforce the aspect ratio if = true See Also - - - !!} property LayersResizeAspectRatio: TIELayersResizeAspectRatio read fLayersResizeAspectRatio write fLayersResizeAspectRatio; property LayersCropped: Boolean read fLayersCropped write SetLayersCropped; {!! TImageEnView.LayersFastDrawing Declaration property LayersFastDrawing: ; Description Improves the performance of layer rendering by delayed or disabling slow operations. Item Description iefFast Layer draw quality is reduced to speed up display (only affects drawing) iefDelayed Fast drawing (iefFast) is used while rotating, moving or resizing layers. After a delay, layers are then drawn at normal quality (iefNormal) iefNormal Layers are drawn at normal quality
When fast drawing is active: - Does not render
or - Zoom filters are not used for display ( and ) - is not rendered - Anti-alias filters are not used for rotation preview () Default: iefDelayed Note: LayersFastDrawing only affects what is displayed. It has no effect on the quality of the image when saved Examples // Use best display quality (even when manipulating layers) ImageEnView1.LayersFastDrawing := iefNormal; // Use best display quality, except when manipulating layers ImageEnView1.LayersFastDrawing := iefDelayed; // Best performance - always display layers at lower quality ImageEnView1.LayersFastDrawing := iefFast; // Allow changing of preview quality via a combo-box procedure Tfmain.cmbPreviewQualityChange(Sender: TObject); const _cmbPreviewQuality_Fast = 0; _cmbPreviewQuality_Delayed_Best = 1; _cmbPreviewQuality_Best = 2; begin // Seperate code to make it easier to understand if cmbPreviewQuality.ItemIndex = _cmbPreviewQuality_Fast then begin // FASTEST DISPLAY // Zoom filter ImageEnView1.ZoomFilter := rfNone; ImageEnView1.DelayZoomFilter := False; // Rotation anti-alias ImageEnView1.LayersRotationFilter := ierBicubic; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationUseFilterOnPreview := False; // Fast drawing ImageEnView1.LayersFastDrawing := iefFast; end else if cmbPreviewQuality.ItemIndex = _cmbPreviewQuality_Delayed_Best then begin // DELAYED HIGH QUALITY // Zoom filter ImageEnView1.ZoomFilter := rfLanczos3; ImageEnView1.DelayZoomFilter := True; // Rotation anti-alias ImageEnView1.LayersRotationFilter := ierBicubic; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationUseFilterOnPreview := True; // Fast drawing ImageEnView1.LayersFastDrawing := iefDelayed; end else begin // HIGH QUALITY // Zoom filter ImageEnView1.ZoomFilter := rfLanczos3; ImageEnView1.DelayZoomFilter := False; // Rotation anti-alias ImageEnView1.LayersRotationFilter := ierBicubic; ImageEnView1.LayersRotationAntialias := True; ImageEnView1.LayersRotationUseFilterOnPreview := True; // Fast drawing ImageEnView1.LayersFastDrawing := iefNormal; end; ImageEnView1.Update(); end; See Also - !!} property LayersFastDrawing: TIEFastDrawing read fLayersFastDrawing write fLayersFastDrawing; function LayersFastDrawingActive: Boolean; // Not exposed in doc index {!! TImageEnView.LayersFastOutput Declaration property LayersFastOutput: Boolean; Description Improves the performance of layer output operations, such as merging, by disabling anti-aliasing and other quality properties. Default: False Note: LayersFastOutput only affects output. Drawing is controlled by !!} property LayersFastOutput: Boolean read fLayersFastOutput write fLayersFastOutput; function MaxLayerWidth() : integer; function MaxLayerHeight() : integer; function LayersRect(SelOnly: Boolean = False; ExcludeLayer0: Boolean = False): TIERectangle; property LayersDrawBox: boolean read fLayersDrawBox write SetLayersDrawBox; function FindLayerAt(x, y: integer; SelectablesOnly: Boolean=true): integer; property CurrentLayer: TIELayer read GetCurrentLayer; procedure LayersSaveToStream(Stream: TStream; CompressionFormat: TIOFileType = -1; SelectedOnly: Boolean = False; ExcludeImageLayers: Boolean = False; SaveThumbnail: Boolean = False; ProgressEvent: TIEProgressEvent = nil); procedure LayersSaveToFile(const FileName: String; CompressionFormat: TIOFileType = -1); {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Use TImageEnIO.SaveToFileIEN instead - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} procedure LayersSelectAll(bIncludeLocked: Boolean = True); procedure LayersAlign(Alignment: TIEAlignLayers; Index: Integer = -2); function LayersSelCount(bCountBackgroundLayer: Boolean = True): Integer; procedure LayersDeselectAll(); procedure LayersGroup(bSelectedOnly: Boolean = True); procedure LayersConvertToImageLayersEx(LayerIdx: integer = -2; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False; DoSaveUndo: Boolean = False); procedure LayersConvertToImageLayers(LayerIdx: integer = -2; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False); procedure LayersUngroup(bSelectedOnly: Boolean = True); function LayersLoadFromStream(Stream: TStream; Append: Boolean = False; ProgressEvent: TIEProgressEvent = nil): Boolean; function LayersLoadFromFile(const FileName: String; Append: Boolean = False): Boolean; {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Use TImageEnIO.LoadFromFileIEN instead - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} function LayersCreateFromSelection: Integer; function LayersCreateFromClipboard: Integer; function LayersCreateFromFile(Filename : string = '') : integer; function LayersImport(const FileName: String; Stream: TStream = nil; FileFormat: TIOFileType = ioUnknown; Append: Boolean = False): Integer; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (23/11/16) function LayersCreateFromText(const Text : string; const sFontName : string; iFontSize : Integer; cFontColor : TColor; Style : TFontStyles; bAddShadow: boolean = False; iBlurRadius : Integer = 3; iShadowOffset : Integer = 2; Angle : Integer = 0; bAntiAlias : Boolean = true) : integer; {$ifdef IEWarningForDeprecated} deprecated {$ifdef IESupportDeprecatedDescription} 'Use TIETextLayer instead - http://imageen.com/help/Compatibility.html' {$endif}; {$endif} {$endif} procedure LayersFixSizes(layer: Integer = -1); procedure LayersFixRotations(layer: Integer = -1); procedure LayersFixBorders(layer: Integer = -1); // Other procedure SetExternalBitmap(bmp: TIEBitmap); property GradientEndColor: TColor read fGradientEndColor write SetGradientEndColor; property MouseCapture; procedure Assign(Source: TObject); reintroduce; virtual; procedure AssignSelTo(Dest: TPersistent); procedure ImageChange(); override; function YScr2Bmp(y: integer; CurrentLayer: Boolean = False): integer; function XScr2Bmp(x: integer; CurrentLayer: Boolean = False): integer; function YBmp2Scr(y: integer; CurrentLayer: Boolean = False): integer; function XBmp2Scr(x: integer; CurrentLayer: Boolean = False): integer; procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; property SelColor1: TColor read fSelColor1 write SetSelColor1 default clBlack; property SelColor2: TColor read fSelColor2 write SetSelColor2 default clWhite; procedure Clear; procedure ClearAll; procedure Blank; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (8/2/2016) // Note: deprecated 'Use DisplayGridKind instead' property DisplayGrid: boolean read GetDisplayGrid write SetDisplayGrid; {$endif} property DisplayGridLyr: integer read fDisplayGridLyr write SetDisplayGridLyr; property HighlightedPixel: TPoint read fHighlightedPixel write SetHighlightedPixel; property HighlightedPixelColor: TColor read fHighlightedPixelColor write SetHighlightedPixelColor; procedure SetInteractionHint(const Text: String; x, y: Integer; const minText: String); property ImageHorizAlignment: TIEHAlign read fImageHorizAlignment write SetImageHorizAlignment; property ImageVertAlignment: TIEVAlign read fImageVertAlignment write SetImageVertAlignment; procedure SetChessboardStyle(Size: integer = 16; BrushStyle: TBrushStyle = bsSolid; Color1: TColor = clNone_; Color2: TColor = clNone_); {!! TImageEnView.ForceALTkey Declaration property ForceALTkey: Boolean; Description Set ForceALTkey to True to emulate pressing the ALT key. When enabled (or the Alt key is pressed) the aspect ratio is maintained when making or modifying selections (or with vectorial objects for the component). Default: False !!} property ForceALTkey: boolean read fForceALTkey write fForceALTkey; {!! TImageEnView.DelayDisplaySelection Declaration property DelayDisplaySelection: Boolean Description When True, the selection is displayed with a delay. This allows you to quickly navigate the image (zoom and scroll) and once you have finished navigation the selection is displayed. !!} property DelayDisplaySelection: boolean read fDelayDisplaySelection write fDelayDisplaySelection; {!! TImageEnView.DelayZoomTime Declaration property DelayZoomTime: Integer; Description ImageEn has a timer that decrements a counter at each tick (you can set the tick delay using property). This timer controls the selection animation and the application of filters on scrolling (when is true). DelayZoomTime controls only the delay zoom filter application. Default: 4 (apply filter after 4 ticks since last scroll) !!} property DelayZoomTime: integer read fDelayZoomTicks write fDelayZoomTicks; property DelayTimer: integer read GetDelayTimer write SetDelayTimer; procedure CopyToBitmapWithAlpha(Dest: TBitmap; DestX, DestY: integer); property UseDrawDibDraw: boolean read fUseDrawDibDraw write fUseDrawDibDraw; function GetGripAt(x, y: integer): TIEGrip; procedure RemoveAlphaChannel(Merge: boolean = false); override; property IsEmpty: boolean read GetIsEmpty; property IsEmpty2: boolean read GetIsEmpty2; {!! TImageEnView.ZoomSelectionAspectRatio Declaration property ZoomSelectionAspectRatio: Boolean; Description This property is active when MouseInteract contains miSelectZoom. If true, the selected rectangle is adjusted to maintain the aspect ratio. Otherwise (false) the image loses the aspect ratio (ZoomX <> ZoomY and Zoom value is invalid) making it stretched inside the window. Default: True !!} property ZoomSelectionAspectRatio: Boolean read fZoomSelectionAspectRatio write fZoomSelectionAspectRatio; {!! TImageEnView.MouseScrollRate Declaration property MouseScrollRate: Double; Description If contains miScroll then MouseScrollRate specifies the relationship between mouse movement and image scrolling. Default: 1 (one mouse point is one pixel at 100%). Example // set double rate scroll ImageEnView1.MouseScrollRate := 2; ImageEnView1.MouseInteract := [miScroll]; !!} property MouseScrollRate: Double read fMouseScrollRate write fMouseScrollRate; // encapsulated components {!! TImageEnView.IO Declaration property IO: ; Description The IO property encapsulates the TImageEnIO component inside TImageEnView (The TImageEnIO component is automatically created the first time you access the IO property). provides all functionality for loading and saving images, and other I/O functions. Example // Load image into the ImageEnView ImageEnView1.IO.LoadFromFile('C:\Hello.jpeg'); // Retrieve an image from a Twain scanner and display in the ImageEnView ImageEnView1.IO.Acquire; !!} property IO: TImageEnIO read GetImageEnIO; {!! TImageEnView.Proc Declaration property Proc: ; Description Provides access to the TImageEnProc component inside TImageEnView (The TImageEnProc component is automatically created the first time you access the Proc property). provides functionality for editing and manipulating images, clipboard and analysis. Example // Invert the colors of the image in the ImageEnView ImageEnView1.Proc.Negative; !!} property Proc: TImageEnProc read GetImageEnProc; // transitions property TransitionRunning: boolean read GetTransitionRunning; procedure PrepareTransition; procedure RunTransition(Effect: TIETransitionType; Duration: integer); overload; procedure RunTransition(Effect: TIETransitionType; Duration: integer; PanZoomEffect : TIEPanZoomType; iZoomLevel : Integer; Smoothing: Integer = 96); overload; procedure RunTransition(Effect: TIETransitionType; Duration: integer; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean = True; Smoothing: Integer = 96); overload; procedure AbortTransition; {$ifdef IEIncludeDeprecatedInV4} // Deprecated prior to v4.3.1 // DEPRECATED: Use TImageEnProc.PrepareTransitionBitmaps/CreateTransitionBitmaps procedure PrepareTransitionBitmaps(OriginalBitmap, TargetBitmap : TBitmap; Effect : TIETransitionType; iWidth : Integer = -1; iHeight : Integer = -1); overload; {$ifdef IEWarningForDeprecated} deprecated; {$endif} procedure PrepareTransitionBitmaps(OriginalBitmap, TargetBitmap : TBitmap; Effect : TIETransitionType; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean = True; iWidth : Integer = -1; iHeight : Integer = -1); overload; {$ifdef IEWarningForDeprecated} deprecated; {$endif} procedure CreateTransitionBitmap(TransitionProgress : Single; DestBitmap : TBitmap); {$ifdef IEWarningForDeprecated} deprecated; {$endif} {$endif} property TransitionTiming: TIETransitionTiming read GetTransitionTiming write SetTransitionTiming; // post frames procedure BeginPostFrames(target: TImageEnView; delay: Integer; interval: Integer); procedure EndPostFrames(target: TImageEnView); // others undocumented procedure DrawLayerBox(ABitmap: TBitmap; idx: integer); procedure DrawLayerOuter(ABitmap: TBitmap; idx: Integer); procedure DrawLayerGrips(ABitmap: TBitmap; idx: integer); procedure DrawLayerRotationCenter(ABitmap: TBitmap; idx: integer); procedure CalcLayerGripCoords(layeridx: integer; var coords: array of TRect); function FindLayerGripAnySel(x, y: integer; bSetCurrent: Boolean = False): TIEGrip; function FindLayerGrip(x, y: integer): TIEGrip; function FindLayerGripDist(x, y: integer; var Distance: Double): TIEGrip; {!! TImageEnView.Gestures Declaration property Gestures: ; Description TImageEnView supports native Windows gestures: - Dragging the screen to pan an image - Pinching to zoom in - Reverse-pinching to zoom out - Layer rotation and movement ImageEn automatically handles the Windows gesture events, so adding gesture support to your applications requires only that you enable the relevant Gesture property. Demo Demos\Display\Gestures\Gestures.dpr Example // enable Pan (scroll) and Zoom gestures ImageEnView1.Gestures.Pan.Enabled := True; ImageEnView1.Gestures.Zoom.Enabled := True; !!} property Gestures: TIEViewerGestures read fGestures; // not: cannot stay in published section without an property editor {!! TImageEnView.RulerParams Declaration property RulerParams: ; Description Allows you to configure the properties of your rulers Demo Demos\Other\ImageEnViewRulers\ImageEnViewRulers.dpr Example // Show rulers in TImageEnView ImageEnView1.ShowRulers := [ rdHorizontal, rdVertical ]; // Set units to CM ImageEnView1.RulerParams.Units := ieruCentimeters; !!} property RulerParams: TIEViewRulerParams read fRulerParams; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (2015-12-15) // Since v6.2.2 these methods/properties are deprecated, and just point to IO.Params.DPI property DpiX: integer read GetDpiX write SetDPIX; property DpiY: integer read GetDpiY write SetDPIY; procedure SetDPI(dpiX, dpiY: integer); virtual; {$endif} property Modified: Boolean read GetModified write SetModified; property CropToolInteraction: TIECropToolInteraction read GetCropToolInteraction; property UserInteractions: TObjectList read fUserInteractions; published // Remove default so we can change this property later property LegacyBitmap: boolean read fLegacyBitmap write SetLegacyBitmap; property ZoomFilter: TResampleFilter read fZoomFilter write SetZoomFilter default rfNone; property ScrollBars: TIEScrollStyle read fScrollBars write SetScrollBars default ssBoth; {!! TImageEnView.OnViewChange Declaration property OnViewChange: ; Description Notifies of changes to , or . !!} property OnViewChange: TViewChangeEvent read fOnViewChange write fOnViewChange; {!! TImageEnView.OnImageEnGesture Declaration property OnImageEnGesture: ; Description Occurs whenever a gesture is handled by ImageEn. !!} property OnImageEnGesture: TIEImageEnGestureEvent read fOnImageEnGesture write fOnImageEnGesture; {!! TImageEnView.OnFinishSmoothTask Declaration property OnFinishSmoothTask: ; Description Notifies that a smooth task has finished (smooth scroll, smooth zoom, etc...). See Also - - !!} property OnFinishSmoothTask: TIEFinishSmoothTaskEvent read fOnFinishSmoothTask write fOnFinishSmoothTask; {!! TImageEnView.OnViewChanging Declaration property OnViewChanging: ; Description Notifies that , or is going to change. !!} property OnViewChanging: TViewChangingEvent read fOnViewChanging write fOnViewChanging; {!! TImageEnView.OnImageChange Declaration property OnImageChange: TNotifyEvent; Description Occurs after the image is modified using ( property) or ( property). If you are using multiple , then layer changes will also trigger OnImageChange. Note: calls after a modification which actuates OnImageChange. See Also - - - !!} property OnImageChange: TNotifyEvent read fOnImageChange write fOnImageChange; property SelectionOptions: TIESelectionOptions read fSelectionOptions write SetSelectionOptions default [iesoAnimated, iesoSizeable, iesoMoveable, iesoCanScroll, iesoAllowMoveByKeyboard]; property Center: boolean read GetCenter write SetCenter default true; property MouseInteract: TIEMouseInteract read GetMouseInteract write SetMouseInteract default []; {!! TImageEnView.AutoFit Declaration property AutoFit: Boolean; Description If AutoFit is True and the image is updated ( method) then is automatically called to make the image fit within the display area (stretch if it is smaller than the window, shrink if it is larger). This has the same effect as setting both and to true. Example procedure TForm1.chkAutoFitClick(Sender: TObject); begin ImageEnView1.AutoFit := chkAutoFit.Checked; if not chkAutoFit.Checked then ImageEnView1.Zoom := 100 else ImageEnView1.Fit(); end; See Also - loFitToLayersWhenZooming !!} property AutoFit: boolean read fAutoFit write fAutoFit default false; {!! TImageEnView.SelectionBase Declaration property SelectionBase: ; Description Specifies the meaning of coordinates used when creating a selection. If SelectionBase is iesbClientArea, then all coordinates depend upon the actual zoom and window view/scrolling (i.e. pixels on screen). Otherwise, if SelectionBase is iesbBitmap, then all coordinates refer to bitmap pixels. Default: iesbClientArea Note: Specify before creating a selection. It has no effect on existing selections. Examples // Select a 100 pixel square in the top left corner of the bitmap ImageEnView1.SelectionBase := iesbBitmap; ImageEnView1.Select(0, 0, 100, 100); // Select a 100 pixel square that is displayed in the top left corner of the ImageEnView window (100 x 100 pixels of screen area) ImageEnView1.SelectionBase := iesbClientArea; ImageEnView1.Select(0, 0, 100, 100); Note: When ImageEnView1.Zoom = 100, ImageEnView1.ViewX = 0 and ImageEnView1.ViewY = 0, then both the preceeding examples will provide the same result // Select 20% of the center of the screen const Selection_Size = 0.2; // 20% of screen area begin ImageEnView1.SelectionBase := iesbClientArea; ImageEnView1.Select(Trunc((0.5 - Selection_Size / 2) * ImageEnView1.ClientWidth), Trunc((0.5 - Selection_Size / 2) * ImageEnView1.ClientHeight), Trunc((0.5 + Selection_Size / 2) * ImageEnView1.ClientWidth), Trunc((0.5 + Selection_Size / 2) * ImageEnView1.ClientHeight)); end; See Also - - - - - !!} property SelectionBase: TIESelectionBase read fSelectionBase write fSelectionBase default iesbClientArea; property BackgroundStyle: TIEBackgroundStyle read fBackgroundStyle write SetBackgroundStyle default iebsSolid; {!! TImageEnView.OnSelectionChange Declaration property OnSelectionChange: TNotifyEvent; Description Occurs whenever the user finishes a change of the current selection. Methods such as or do not call the OnSelectionChange event. Example 1 // Real time copy of user selected region to ImageEnView2 component ImageEnView2.Clear; ImageEnView2.CopyFromPolygon(ImageEnView2.Bitmap, ImageEnView2.PolySelPoints^, ImageEnView2.PolySelCount, Point(0, 0)); // An enhancement of above example: Display the current user selection as zoomed in ImageEnView2 ImageEnView2.Clear; ImageEnView2.CopyFromPolygon(ImageEnView2.Bitmap, ImageEnView2.PolySelPoints^, ImageEnView2.PolySelCount, Point(0, 0)); ImageEnView2.Zoom := 200; Example 2 procedure Tfmain.ImageEnView1LayerSelectionChange(Sender: TObject); var bmp: TIEBitmap; begin // Show a preview in ImageEnView2 of the layer selected in ImageEnView1 bmp := ImageEnView2.IEBitmap; ImageEnView1.CurrentLayer.CopyToBitmap( bmp, ImageEnView2.IdealImageWidth, ImageEnView2.IdealImageWidth ); ImageEnView2.Update(); end; !!} property OnSelectionChange: TNotifyEvent read fOnSelectionChange write fOnSelectionChange; {!! TImageEnView.OnSelectionChanging Declaration property OnSelectionChanging: TNotifyEvent; Description Occurs whenever the user is modifying the current selection. Note: Methods such as or do not call the OnSelectionChanging event. Example // Show the user selection rect (MouseInteract includes miSelectZoom) procedure TForm.ImageEnVect1SelectionChanging(Sender: TObject); begin StatusBar.Panels[0].Text := '(' + IntToStr( ImageEnVect1.SelX1 ) + ',' + IntToStr( ImageEnVect1.SelY1 ) + '), ' + '(' + IntToStr( ImageEnVect1.SelX2 ) + ',' + IntToStr( ImageEnVect1.SelY2) + ')'; end; !!} property OnSelectionChanging: TNotifyEvent read fOnSelectionChanging write fOnSelectionChanging; {!! TImageEnView.OnMouseInSel Declaration property OnMouseInSel: TNotifyEvent; Description OnMouseInSel is called whenever the mouse is inside a selection or over its contours. !!} property OnMouseInSel: TNotifyEvent read fOnMouseInSel write fOnMouseInSel; {!! TImageEnView.DelayZoomFilter Declaration property DelayZoomFilter: Boolean Description If DelayZoomFilter is True, the zoom filter (which enhances the display quality) is only applied after a delay. This allows you to quickly navigate the image (zoom and scroll) and once the navigation has finished the image will be displayed at best quality. See Also - !!} property DelayZoomFilter: boolean read fDelayZoomFilter write fDelayZoomFilter default false; {!! TImageEnView.OnPaint Declaration property OnPaint: TNotifyEvent; Description OnPaint occurs whenever the component is redrawn. Use OnPaint to perform special processing when the component is redrawn. !!} property OnPaint: TNotifyEvent read fOnPaint write fOnPaint; property EnableAlphaChannel: boolean read fEnableAlphaChannel write SetEnableAlphaChannel default true; {!! TImageEnView.OnMouseInResizingGrip Declaration property OnMouseInResizingGrip: ; Description OnMouseInResizingGrip is called whenever the mouse moves over a grip and tells you which resizing grip is under the mouse position. !!} property OnMouseInResizingGrip: TIEMouseInResizingGripEvent read fOnMouseInResizingGrip write fOnMouseInResizingGrip; {!! TImageEnView.OnZoomIn Declaration property OnZoomIn: ; Description An OnZoomIn event occurs whenever the user zooms into the current image (increases its display size). You can programatically customize the zoom value by changing the NewZoom parameter. Example // Max zoom-in of 50% Procedure Tform1.ImageEnView1ZoomIn(Sender: TObject; var NewZoom: Double); Begin if NewZoom < 50 then NewZoom := 50; End; !!} property OnZoomIn: TIEZoomEvent read fOnZoomIn write fOnZoomIn; {!! TImageEnView.OnZoomOut Declaration property OnZoomOut: ; Description An OnZoomOut event occurs whenever the user zooms out of the current image (reduces its display size). You can programatically customize the zoom value by changing the NewZoom parameter. Example // Max zoom-out to 200% Procedure Tform1.ImageEnView1ZoomOut(Sender: TObject; var NewZoom: Double); Begin if NewZoom > 200 then NewZoom := 200; End; !!} property OnZoomOut: TIEZoomEvent read fOnZoomOut write fOnZoomOut; property OnProgress: TIEProgressEvent read GetOnProgress write SetOnProgress; property OnFinishWork: TNotifyEvent read GetOnFinishWork write SetOnFinishWork; property OnAcquireBitmap: TIEAcquireBitmapEvent read GetOnAcquireBitmap write SetOnAcquireBitmap; {!! TImageEnView.AutoStretch Declaration property AutoStretch: Boolean; Description When enabled the following display rules are used: - If an image is bigger than TImageEnView window it is displayed 100%; - If an image is smaller than TImageEnView window it is stretched to fit Example procedure TForm1.chkAutoStretchClick(Sender: TObject); begin ImageEnView1.AutoStretch := chkAutoStretch.Checked; if not chkAutoStretch.Checked then ImageEnView1.Zoom := 100 else ImageEnView1.Fit(); end; See Also - - - loFitToLayersWhenZooming !!} property AutoStretch: boolean read fAutoStretch write fAutoStretch default false; {!! TImageEnView.AutoShrink Declaration property AutoShrink: Boolean; Description When enabled the following display rules are used: - If an image is bigger than TImageEnView window it is shrunk to fit; - If an image is smaller than TImageEnView window it is displayed 100% Example procedure TForm1.chkAutoShrinkClick(Sender: TObject); begin ImageEnView1.AutoShrink := chkAutoShrink.Checked; if not chkAutoShrink.Checked then ImageEnView1.Zoom := 100 else ImageEnView1.Fit(); end; See Also - - - loFitToLayersWhenZooming !!} property AutoShrink: boolean read fAutoShrink write fAutoShrink default false; {!! TImageEnView.OnBeforeSelectionChange Declaration property OnBeforeSelectionChange: TNotifyEvent; Description OnBeforeSelectionChange occurs prior to the change of a selection. !!} property OnBeforeSelectionChange: TNotifyEvent read fOnBeforeSelectionChange write fOnBeforeSelectionChange; property DrawVersion: boolean read fDrawVersion write SetDrawVersion default false; {!! TImageEnView.OnDrawBackBuffer Declaration property OnDrawBackBuffer: TNotifyEvent; Description OnDrawBackBuffer provides access to the back buffer where ImageEn will draw the image (and layers) just before the paint event. You can draw on the by handling the OnDrawBackBuffer event to paint onto the Backbuffer canvas. is updated whenever is called. Example Procedure Form1OnDrawBackBuffer(Sender: TObject); Begin // Draw a red line on the back buffer With ImageEnView1.BackBuffer.Canvas do begin Pen.Color := clRed; MoveTo( 0, 0 ); LineTo( 100, 100 ); End; End; !!} property OnDrawBackBuffer: TNotifyEvent read fOnDrawBackBuffer write fOnDrawBackBuffer; {!! TImageEnView.OnLayerNotify Declaration property OnLayerNotify: ; Description Occurs whenever a layer is selected, moved or resized. This event only fires on user actions (not programatic changes). Example // Log all resizing of layers procedure TfrmMain.IEView1LayerNotify(Sender: TObject; layer: integer; event: TIELayerEvent); var ALayer: TIELayer; i: Integer; sChangedLayers: string; begin if event = ielResized then begin sChangedLayers := ''; for i := 0 to IEView1.LayersCount - 1 do begin ALayer := IEView1.Layers[ I ]; if ( ALayer.Locked = False ) and ALayer.Selected then sChangedLayers := sChangedLayers + IntToStr( i ) +','; end; if sChangedLayers <> '' then begin SetLength( sChangedLayers, Length( sChangedLayers ) - 1 ); // Remove final comma memLog.Lines.Add( 'Layers Resized: ' + sChangedLayers ); end; end; end; See Also - - - !!} property OnLayerNotify: TIELayerNotify read fOnLayerNotify write fOnLayerNotify; {!! TImageEnView.OnLayerMoveSize Declaration property OnLayerMoveSize: ; Description Occurs whenever a layer is moved or resized. This event only fires on user actions (not programatic changes). It will occur numerous times as the user moves the mouse. Allows the layer size and position to be controlled and adjusted. Example // Force all layers to be created at 200 x 200 procedure TfrmMain.ImageEnView1MoveSizeLayer(Sender: TObject; layer: integer; event: TIELayerEvent; var PosX, PosY, Width, Height: Double); begin if event = ielCreating then begin Width := 200; Height := 200; end; end; // Force all layers to be centered on the image horizon procedure TfMain.ImageEnView1MoveSizeLayer(Sender: TObject; layer: integer; event: TIELayerEvent; var PosX, PosY, Width, Height: Double); begin PosY := ( ImageEnView1.Layers[0].Height - Height ) / 2; end; See Also - - - - !!} property OnLayerMoveSize: TIELayerMoveSizeEvent read fOnLayerMoveSize write fOnLayerMoveSize; {!! TImageEnView.OnNewLayer Declaration property OnNewLayer: ; Description Occurs whenever a layer is added. It is useful to assign default properties to the layer. Both programmatic methods (e.g. using ) and user methods (e.g. using miCreateShapeLayers) trigger this event. LayerIdx is the index of the new layer. LayerKind is the kind of layer that was added. Notes: - will represent the new layer - You can also use to assign properties to new layers Examples procedure Tfmain.ImageEnView1NewLayer(Sender: TObject; LayerIdx: Integer; LayerKind: TIELayerKind); begin // Assign default properties for new objects case LayerKind of ielkImage : TIEImageLayer( ImageEnView1.CurrentLayer ).AspectRatioLocked := True; ielkPolyline : TIEPolylineLayer( ImageEnView1.CurrentLayer ).SetPoints( iesExplosion, True ); ielkText : TIETextLayer( ImageEnView1.CurrentLayer ).Text := 'Double-click to edit text'; end; end; // Make new shape layer a red star procedure TfrmMain.ImageEnView1NewLayer(Sender: TObject; LayerIdx: integer; LayerKind: TIELayerKind); begin if LayerKind = ielkShape then begin TIEShapeLayer( ImageEnView1.CurrentLayer ).Shape := iesStar5; TIEShapeLayer( ImageEnView1.CurrentLayer ).FillColor := clRed; end; end; See Also - - - - !!} property OnNewLayer: TIENewLayerEvent read fOnNewLayer write fOnNewLayer; {!! TImageEnView.OnLayerSelectionChange Declaration property OnLayerSelectionChange: TNotifyEvent; Description Occurs whenever a layer is selected or deselected. This event only fires on user actions (not programatic changes). A selected text layer: Example procedure TfrmMain.IEView1LayerSelectionChange(Sender: TObject); begin // Enable the cut and copy buttons if layer cut/copy is possible btnCut.Enabled := IEView1.Proc.CanCutFromClipboard( iecpLayer ); btnCopy.Enabled := IEView1.Proc.CanCopyFromClipboard( iecpLayer ); end; See Also - - !!} property OnLayerSelectionChange: TNotifyEvent read fOnLayerSelectionChange write fOnLayerSelectionChange; {!! TImageEnView.OnSpecialKey Declaration property OnSpecialKey: ; Description OnSpecialKey is called whenever a special key is pressed. Special keys are arrows, "Home", "End", etc. Notes: - OnSpecialKey is called twice for each key press (On key down and on key up). This is by Microsoft design. You can use GetKeyState to determine whether this is the on key down or on key up call - If you have problems receiving OnSpecialKey events, it is recommended that you place the TImageEnView (or its inherited components) on a TPanel instead of TForm Example // Allow the current layer to be moved using the Shift+Cursor keys procedure Tfmain.ImageEnView1SpecialKey(Sender: TObject; CharCode: Word; Shift: TShiftState; var Handled: Boolean); begin if ( ssShift in Shift ) and ( ImageEnView1.LayersCurrent > 0 ) then case CharCode of VK_LEFT : if IEIsKeyPressed( VK_LEFT ) then // Ensure this is a KeyDown call begin ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosX := ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosX - 10; ImageEnView1.Update; Handled := True; end; VK_RIGHT : if IEIsKeyPressed( VK_RIGHT ) then // Ensure this is a KeyDown call begin ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosX := ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosX + 10; ImageEnView1.Update; Handled := True; end; VK_UP : if IEIsKeyPressed( VK_UP ) then // Ensure this is a KeyDown call begin ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosY := ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosY - 10; ImageEnView1.Update; Handled := True; end; VK_DOWN : if IEIsKeyPressed( VK_DOWN ) then // Ensure this is a KeyDown call begin ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosY := ImageEnView1.Layers[ImageEnView1.LayersCurrent].PosY + 10; ImageEnView1.Update; Handled := True; end; end; end; !!} property OnSpecialKey: TIESpecialKeyEvent read fOnSpecialKey write fOnSpecialKey; property ImageEnVersion: String read GetImageEnVersion write SetImageEnVersion stored false; {!! TImageEnView.OnDrawBackground Declaration property OnDrawBackground: ; Description OnDrawBackground occurs whenever background needs to be painted. !!} property OnDrawBackground: TIEOnDrawBackground read fOnDrawBackground write fOnDrawBackground; {!! TImageEnView.OnDrawCanvas Declaration property OnDrawCanvas: ; Description OnDrawCanvas occurs whenever the component canvas is updated. !!} property OnDrawCanvas: TIEOnDrawCanvas read fOnDrawCanvas write fOnDrawCanvas; property Wallpaper: TPicture read fWallpaper write SetWallpaper; property WallpaperStyle: TIEWallpaperStyle read fWallpaperStyle write SetWallpaperStyle default iewoNormal; property OnTransitionStop: TNotifyEvent read GetOnTransitionStop write SetOnTransitionStop; property OnTransitionStep: TIETransitionStepEvent read GetOnTransitionStep write SetOnTransitionStep; property OnTransitionPaint: TIEOnTransitionPaint read GetOnTransitionPaint write SetOnTransitionPaint; {!! TImageEnView.OnDrawLayerBox Declaration property OnDrawLayerBox: ; Description Occurs when a layer box must be painted ( must be enabled). If you handle this event the default behavior is disabled. ABitmap is the destination bitmap and layer is the layer index that we are drawing. Use []. rectangle to get actual rectangle coordinates. See the ImageEditing\Layers demo for more details. Note: You can also use to customize the layer box style Example procedure Tfmain.ImageEnView1DrawLayerBox(Sender: TObject; ABitmap: TBitmap; layer: Integer); begin // a green line with ABitmap.Canvas do begin Pen.Style := psSolid; Pen.Width := 2; Pen.mode := pmCopy; Pen.Color := clGreen; Brush.Style := bsClear; with TIELayer(ImageEnView1.Layers[layer]).ClientAreaBox do Rectangle(Left-1, Top-1, Right+1, Bottom+1); end; end; !!} property OnDrawLayerBox: TIEDrawLayerBoxEvent read fOnDrawLayerBox write fOnDrawLayerBox; {!! TImageEnView.OnDrawLayer Declaration property OnDrawLayer: ; Description Occurs immediately after a layer is painted. Parameter Description Dest The destination bitmap (usually the back buffer) LayerIndex The layer index that we are drawing
Use
[]. rectangle to know actual rectangle coordinates. !!} property OnDrawLayer: TIEDrawLayerEvent read fOnDrawLayer write fOnDrawLayer; {!! TImageEnView.OnDrawLayerGrip Declaration property OnDrawLayerGrip: ; Description Occurs when a layer grip is painted. If you handle this event the default behavior is disabled. ABitmap is the destination bitmap and layer is the layer index that we are drawing. Rect specifies the actual grip rectangle. See the ImageEditing\Layers demo for more details. Example procedure Tfmain.ImageEnView1DrawLayerGrip(Sender: TObject; ABitmap: TBitmap; layer, grip: Integer; rect: TRect); begin with ABitmap.Canvas do begin Pen.Style := psSolid; Pen.Mode := pmCopy; Pen.Color := clGreen; Brush.Style := bsSolid; Brush.Color := $0000FF00; with rect do Ellipse(Left-1, Top-1, Right+1, Bottom+1); end; end; !!} property OnDrawLayerGrip: TIEDrawLayerGrip read fOnDrawLayerGrip write fOnDrawLayerGrip; {!! TImageEnView.OnDrawPolygon Declaration property OnDrawPolygon: ; Description OnDrawPolygon occurs whenever a polygon is painted. !!} property OnDrawPolygon: TIEOnDrawPolygon read fOnDrawPolygon write fOnDrawPolygon; property OnSaveUndo: TIESaveUndoEvent read GetOnSaveUndo write SetOnSaveUndo; property OnMouseWheel; property OnMouseWheelDown; property OnMouseWheelUp; property Anchors; property DragCursor; {$IFDEF IEINCLUDEDIRECTSHOW} {!! TImageEnView.OnDShowNewFrame Declaration property OnDShowNewFrame: TNotifyEvent; Description Occurs whenever a new frame is ready (when using the DirectShow functionality of TImageEnView). This event is active when you are using IO. and is True. Example procedure Tfmain.ImageEnView1DShowNewFrame(Sender: TObject); begin // copy current sample to ImageEnView bitmap ImageEnView1.IO.DShowParams.GetSample(ImageEnView1.IEBitmap); // refresh ImageEnView1 ImageEnView1.Update; end; !!} property OnDShowNewFrame: TNotifyEvent read fOnDShowNewFrame write fOnDShowNewFrame; {!! TImageEnView.OnDShowEvent Declaration property OnDShowEvent: TNotifyEvent; Description Occurs when one or more events are ready (when using the DirectShow functionality of TImageEnView). You should call .. until it returns false (no more events are available). Example procedure Tfmain.ImageEnView1DShowEvent; var event: Integer; begin while ImageEnView1.IO.DShowParams.GetEventCode(event) do case event of IEEC_COMPLETE: begin ... end of stream! end; end; end; !!} property OnDShowEvent: TNotifyEvent read fOnDShowEvent write fOnDShowEvent; {$ENDIF} {!! TImageEnView.OnSetCursor Declaration property OnSetCursor: ; Description OnSetCursor occurs whenever the mouse cursor needs to be changed. You can set your custom cursor by setting the Cursor parameter. This event may be called multiple times for the same cursor shape. !!} property OnSetCursor: TIESetCursorEvent read fOnSetCursor write fOnSetCursor; {$IFDEF IEINCLUDEMEDIAFOUNDATION} {!! TImageEnView.OnMediaFoundationNotify Declaration property OnMediaFoundationNotify: ; Description Occurs whenever Media Foundation sends a new frame or a notification to TImageEnView. Example // handler for TImageEnView.OnMediaFoundatioNotify event procedure TForm1.ImageEnVect1MediaFoundationNotify(Sender, MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType); var sample: TIEMFReceivedSample; begin if NotifyType = iemfnFRAME then // is this a frame? begin sample := ImageEnView1.IO.MediaFoundationSourceReader.GetNextSample(); // retrieve frame sample try sample.DecodeSample(ImageEnView1.IEBitmap); // convert frame sample to bitmap ImageEnView1.Update(); // update TImageEnView to show the new bitmap finally sample.Free(); // free the sample end; end; end; !!} property OnMediaFoundationNotify: TIEMediaFoundationNotifyEvent read fOnMediaFoundationNotify write fOnMediaFoundationNotify; {$ENDIF} {!! TImageEnView.OnVirtualKey Declaration property OnVirtualKey: ; Description Occurs whenever the component receives WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP or WM_SYSKEYUP message. !!} property OnVirtualKey: TIEVirtualKeyEvent read fOnVirtualKey write fOnVirtualKey; {!! TImageEnView.OnTextEditorKeyDown Declaration property OnTextEditorKeyDown: TKeyEvent; Description Occurs whenever a key is pressed when editing the text of a or . Example procedure TMainForm.ImageEnView1TextKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin // Make the Enter key cancel text input if Key = VK_Return then begin Key := 0; ImageEnView1.LayersCancelEditor( False ); end; end; !!} property OnTextEditorKeyDown: TKeyEvent read fOnTextEditorKeyDown write fOnTextEditorKeyDown; {!! TImageEnView.OnActivateTextEditor Declaration property OnActivateTextEditor: ; Description Occurs whenever a text editor is activated for a or . !!} property OnActivateTextEditor: TIETextEditorEvent read fOnActivateTextEditor write fOnActivateTextEditor; {!! TImageEnView.OnDeactivateTextEditor Declaration property OnDeactivateTextEditor: ; Description Occurs whenever a text editor is closed after editing of a or . !!} property OnDeactivateTextEditor: TIETextEditorEvent read fOnDeactivateTextEditor write fOnDeactivateTextEditor; {!! TImageEnView.EnableInteractionHints Declaration property EnableInteractionHints: Boolean; Description When true, mouse interaction hints are displayed to the user (rotation angle of a layer, position when moving, etc.). Default: True !!} property EnableInteractionHints: Boolean read fEnableInteractionHints write fEnableInteractionHints; // play property Playing: boolean read fPlaying write SetPlaying default false; {!! TImageEnView.PlayLoop Declaration property PlayLoop: boolean; Description Set to True to continuously loop playback of animated GIF and AVI files (when is enabled). Default: False !!} property PlayLoop: boolean read fPlayLoop write fPlayLoop default true; property Cursor: TCursor read fCursor write SetCursor default 1785; {$ifdef IEINCLUDEFLATSB} property FlatScrollBars: Boolean read fFlatScrollBars write SetFlatScrollBars default False; {$endif} property DisplayGridKind: TIEGridKind read fDisplayGridKind write SetDisplayGridKind default iedgNone; {!! TImageEnView.MouseWheelParams Declaration property MouseWheelParams: ; Description Properties to customize the behavior of the mouse wheel. Example // mouse wheel will scroll image of 15 % of component height ImageEnView1.MouseWheelParams.Action := iemwVScroll; ImageEnView1.MouseWheelParams.Variation := iemwPercentage; ImageEnView1.MouseWheelParams.value := 15; // mouse wheel will scroll image of 1 pixel ImageEnView1.MouseWheelParams.Action := iemwVScroll; ImageEnView1.MouseWheelParams.Variation := iemwAbsolute; ImageEnView1.MouseWheelParams.value := 1; Demo Demos\Other\MouseWheel\MouseWheelParams.dpr !!} property MouseWheelParams: TIEMouseWheelParams read fMouseWheelParams write SetMouseWheelParams; property ShowRulers: TRulerDirs read fShowRulers write SetShowRulers default []; {!! TImageEnView.AutoCursors Declaration property AutoCursors: Boolean; Description When AutoCursors is enabled ImageEn will automatically change the cursor when relevant: - crIEHandDrag when the mouse can be dragged (miScroll in TImageEnView.MouseInteract) - crIESizeNWSE/crIESizeNESW/crIESizeWE/crIESizeNS when resizing a layer - crIERotateSE/crIERotateNE/crIERotateSW/crIERotateNW when rotating a layer - crIESizeAll when moving a layer Default: True See Also - !!} property AutoCursors: Boolean read fAutoCursors write fAutoCursors default True; property OnRulerGripPosChange: TRulerGripPosChangeEvent read GetOnRulerGripPosChange write SetOnRulerGripPosChange; property OnRulerGripClick: TRulerGripClickEvent read GetOnRulerGripClick write SetOnRulerGripClick; property OnRulerGripDblClick: TRulerGripClickEvent read GetOnRulerGripDblClick write SetOnRulerGripDblClick; property OnRulerClick: TRulerClickEvent read GetOnRulerClick write SetOnRulerClick; property Align; property DragMode; property Enabled; property ParentShowHint; property PopupMenu; property ShowHint; property Visible; property TabOrder; property TabStop; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDrag; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnContextPopup; {$ifdef IEHASONGESTURE} property OnGesture; {$endif} end; // TImageEnView ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEUserInteraction // Base abstract class for user interactions TIEUserInteraction = class private fParent: TImageEnView; fEnabled: boolean; public constructor Create(Parent: TImageEnView); destructor Destroy(); override; // helpers function GetParent(): TImageEnView; property Enabled: boolean read fEnabled write fEnabled; procedure SetTempCursor(Value: TCursor); procedure RestoreCursor(); // methods to be implemented // MouseDownExclusive, MouseMoveExclusive and MouseUpExclusive are executed first and only if previous calls to the same methods of other objects are failed (result=false) // MouseDown, MouseMove, MouseUp are always executed after all MouseXXXXExclusive calls function MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; virtual; abstract; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual; abstract; function MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; virtual; abstract; procedure MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); virtual; abstract; function MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; virtual; abstract; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual; abstract; procedure VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); virtual; abstract; procedure Paint(const UpdateRect: TRect); virtual; abstract; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIECropToolInteraction TIECropToolInteractionState = (iectisUNSELECTED, iectisCREATING, iectisSELECTED, iectisTOP_LEFT_SIZE, iectisTOP_SIZE, iectisTOP_RIGHT_SIZE, iectisRIGHT_SIZE, iectisBOTTOM_RIGHT_SIZE, iectisBOTTOM_SIZE, iectisBOTTOM_LEFT_SIZE, iectisLEFT_SIZE, iectisMOVING, iectisROTATE); {!! TIECropToolInteractionMode Declaration } TIECropToolInteractionMode = (iectmRECTANGLE, iectmPERSPECTIVE); {!!} {!! TIECropToolOptions Declaration TIECropToolOptions = set of (iecoAllowResizing, iecoAllowRotating, iecoAllowMoving, iecoSideGripsRespectLocks, iecoSizeLocksAreMinimums); Description Value Description iecoAllowResizing The user can resize the crop selection by dragging the corner or side grips iecoAllowRotating The user can rotate the crop selection by dragging outside the corner grips iecoAllowMoving The user can move the crop selection by clicking within the selection area iecoSideGripsRespectLocks Determines whether the specified aspect ratio lock is enforced when dragging the side, top and bottom grips. If this option is not set then only the corner grips will respect the lock iecoSizeLocksAreMinimums If included, then the specified or are treated as minimum values, i.e. the user can make the selection larger than the specified values, but not smaller
Default: [iecoAllowResizing, iecoAllowRotating, iecoAllowMoving] Examples // Do not allow the user to resize the crop tool selection (i.e. only rotation and creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowResizing ]; // Do not allow the user to rotate the crop tool selection (i.e. only resizing and creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowRotating ]; // Do not allow the user to resize or rotate the crop tool selection (i.e. only creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowResizing, iecoAllowRotating ]; // we want a fixed aspect ratio of 4:3, which is enforced even if the user drags the side grips ImageEnView1.CropToolInteraction.LockAspectRatio := 4 / 3; ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options + [iecoSideGripsRespectLocks]; // Do not allow a selection smaller than 100x100 pixels ImageEnView1.CropToolInteraction.Options := [iecoSizeLocksAreMinimums]; ImageEnView1.CropToolInteraction.LockWidth := 100; ImageEnView1.CropToolInteraction.LockHeight := 100; !!} TIECropToolOptions = set of (iecoAllowResizing, iecoAllowRotating, iecoAllowMoving, iecoSideGripsRespectLocks, iecoSizeLocksAreMinimums); {!! TIECropToolInteraction Declaration TIECropToolInteraction = class(TIEUserInteraction); Description A class of TIEUserInteraction that is used to control interaction for the crop tool (when is miCropTool). The crop tool allows the user to select an area of the image to keep and then click "Enter" to apply the crop. The selection can also be rotated so the image is rotated and then cropped. In Crop Tool mode: - User can resize crop box by dragging grips - User can rotate crop by dragging outside grips - User can click "Enter" to enact the crop - User can click "Esc" to cancel the crop Rotated Crop Perspective Fix Example // Disable guide lines (on image thirds) ImageEnView1.CropToolInteraction.DrawGuides := False; // Make larger grips ImageEnView1.CropToolInteraction.GripSize := 12; // High quality cropping ImageEnView1.CropToolInteraction.AntialiasMode := ierBicubic; // Enable crop mode ImageEnView1.MouseInteract := [miCropTool]; // Enact crop (same as user clicking "Enter") ImageEnView1.CropToolInteraction.Crop(); // Cancel crop tool (same as user clicking "Esc") ImageEnView1.CropToolInteraction.Cancel(); Methods and Properties General Properties Selection (Same as rotating selection) (Same as resizing selection) Command Methods (Same as clicking "Esc") (Same as clicking "Enter") See Also - !!} TIECropToolInteraction = class(TIEUserInteraction) private // current state fScreenPolygon: TIE2DPointArray; // screen coordinates fBitmapPolygon: TIE2DPointArray; // bitmap coordinates fRotatedPolygon: TIE2DPointArray; // rotated polygon (screen coordinates) fRotation: double; fState: TIECropToolInteractionState; fMouseDownCoords: TPoint; fMouseDownScreenPolygon: TIE2DPointArray; // selected polygon at mousedown time fMouseDownRotation: double; fMouseDownRotatedPolygon: TIE2DPointArray; fGripRects: array [iectisTOP_LEFT_SIZE..iectisLEFT_SIZE] of array [0..1] of TPoint; fAspectRatio: double; fOptions: TIECropToolOptions; // visual appearance fGripSize: integer; fDrawGuides: boolean; // crop processing properties fAntialiasMode: TIEAntialiasMode; fMode: TIECropToolInteractionMode; fLockAspectRatio: double; // -1: No locking, >0: Locked to specific aspect fLockWidth, fLockHeight: Integer; // Lock selection to absolute sizes function GetGrip(x, y: integer): TIECropToolInteractionState; procedure Draw(Canvas: TCanvas); function ScreenToBitmap(const P: TIE2DPoint): TIE2DPoint; function BitmapToScreen(const P: TIE2DPoint): TIE2DPoint; procedure UpdateBitmapPolygon(); procedure UpdateScreenPolygon(); function GetRotatedBitmapPolygon(): TIE2DPointArray; procedure SetMode(const Value: TIECropToolInteractionMode); procedure AdjustAspectRatio(quad: TIE2DPointArray; grip: TIECropToolInteractionState); function GetSelected(): Boolean; procedure SetSelected(const Value: Boolean); public constructor Create(Parent: TImageEnView); // VISUAL APPEARANCE {!! TIECropToolInteraction.GripSize Declaration property GripSize: Integer; Description Specifies the size of the grips that appear around the crop selection (which can be dragged to enlarge). Note: You must call TImageEnView.Invalidate if you change this property when the crop selection is visible Default: 8 Example // Make larger grips ImageEnView1.CropToolInteraction.GripSize := 12; !!} property GripSize: integer read fGripSize write fGripSize; {!! TIECropToolInteraction.DrawGuides Declaration property DrawGuides: Boolean; Description Displays guide lines on the horizontal and vertical thirds of the crop selection. Note: You must call TImageEnView.Invalidate if you change this property when the crop selection is visible Default: True Example // Disable guide lines ImageEnView1.CropToolInteraction.DrawGuides := False; !!} property DrawGuides: boolean read fDrawGuides write fDrawGuides; {!! TIECropToolInteraction.LockAspectRatio Declaration property LockAspectRatio: Double; Description Allows the crop selection to be locked to a specific ratio, e.g. 0.75 for a 4:3 image or 1.77 for a 16:9 image If LockAspectRatio is -1, the aspect ratio is only locked when the user presses the ALT key If LockAspectRatio is >0, ImageEn locks the selection to the specified aspect ratio Note: By default, when dragging the side grips the aspect ratio is not enforced. Add iecoSideGripsRespectLocks to to force all grips to respect the ratio Example // we want standard behavior ImageEnView1.CropToolInteraction.LockAspectRatio := -1; // we want a fixed aspect ratio of 4:3 (standard landscape, i.e. height is 75% of width) ImageEnView1.CropToolInteraction.LockAspectRatio := 4 / 3; See Also - - - - !!} property LockAspectRatio: Double read fLockAspectRatio write fLockAspectRatio; {!! TIECropToolInteraction.LockWidth Declaration property LockWidth: Integer; Description Allows the width of the crop selection to be locked to a specific size. e.g. 200 pixels wide. Notes: - Values refer to bitmap pixels, not a screen dimension - Can be used independently of - if iecoSizeLocksAreMinimums is specified in , then this value is a minimum only - Has no effect if > 0 (unless iecoSizeLocksAreMinimums is used) Example // we want standard behavior ImageEnView1.CropToolInteraction.LockWidth := 0; ImageEnView1.CropToolInteraction.LockHeight := 0; // Lock the width to 500 pixels (but height can be changed) ImageEnView1.CropToolInteraction.LockAspectRatio := 0; ImageEnView1.CropToolInteraction.LockWidth := 500; ImageEnView1.CropToolInteraction.LockHeight := 0; // Lock width and height to half the image size ImageEnView1.CropToolInteraction.LockAspectRatio := 0; ImageEnView1.CropToolInteraction.LockWidth := ImageEnView1.IEBitmap.Width div 2; ImageEnView1.CropToolInteraction.LockHeight := ImageEnView1.IEBitmap.Height div 2; // Do not allow a selection smaller than 100x100 pixels ImageEnView1.CropToolInteraction.Options := [iecoSizeLocksAreMinimums]; ImageEnView1.CropToolInteraction.LockWidth := 100; ImageEnView1.CropToolInteraction.LockHeight := 100; See Also - - - - !!} property LockWidth: Integer read fLockWidth write fLockWidth; {!! TIECropToolInteraction.LockHeight Declaration property LockHeight: Integer; Description Allows the height of the crop selection to be locked to a specific size. e.g. 200 pixels high. Notes: - Values refer to bitmap pixels, not a screen dimension - Can be used independently of - if iecoSizeLocksAreMinimums is specified in , then this value is a minimum only - Has no effect if > 0 (unless iecoSizeLocksAreMinimums is used) Example // we want standard behavior ImageEnView1.CropToolInteraction.LockHeight := 0; ImageEnView1.CropToolInteraction.LockHeight := 0; // Lock the height to 500 pixels (but width can be changed) ImageEnView1.CropToolInteraction.LockAspectRatio := 0; ImageEnView1.CropToolInteraction.LockHeight := 500; ImageEnView1.CropToolInteraction.LockWidth := 0; // Lock width and height to half the image size ImageEnView1.CropToolInteraction.LockAspectRatio := 0; ImageEnView1.CropToolInteraction.LockWidth := ImageEnView1.IEBitmap.Width div 2; ImageEnView1.CropToolInteraction.LockHeight := ImageEnView1.IEBitmap.Height div 2; // Do not allow a selection smaller than 100x100 pixels ImageEnView1.CropToolInteraction.Options := [iecoSizeLocksAreMinimums]; ImageEnView1.CropToolInteraction.LockWidth := 100; ImageEnView1.CropToolInteraction.LockHeight := 100; See Also - - - - !!} property LockHeight: Integer read fLockHeight write fLockHeight; // CURRENT SELECTION {!! TIECropToolInteraction.BitmapPolygon Declaration property BitmapPolygon: ; (Read-only) Description Returns the area of the image the user has selected for cropping. Note: - BitmapPolygon does not consider the - BitmapPolygon is an array [0..3] of type, . Item 0 is Top-Left, item 1 is Top-Right, item 2 is Bottom-Right and item 3 is Bottom-Left Example // Show the size of the selection while resizing procedure TForm1.ImageEnView1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if ImageEnView1.MouseCapture then // selection being made or altered with ImageEnView1.CropToolInteraction do Caption := 'Selection: ' + IntToStr( abs( Round( BitmapPolygon[2].X - BitmapPolygon[0].X ))) + ' x ' + IntToStr( abs( Round( BitmapPolygon[2].Y - BitmapPolygon[0].Y ))); end; See Also - - - !!} {$ifdef IESUPPORTPROPERTYOFARRAYTYPE} property BitmapPolygon: TIE2DPointArray read fBitmapPolygon; {$endif} property RotatedBitmapPolygon: TIE2DPointArray read GetRotatedBitmapPolygon; procedure SetBitmapPolygon(Rect: TRect); {!! TIECropToolInteraction.ScreenPolygon Declaration property ScreenPolygon: ; (Read-only) Description Returns the area of the image the user has selected for cropping, using screen coordinates. Note: ScreenPolygon is an array [0..3] of type, . Item 0 is Top-Left, item 1 is Top-Right, item 2 is Bottom-Right and item 3 is Bottom-Left !!} {$ifdef IESUPPORTPROPERTYOFARRAYTYPE} property ScreenPolygon: TIE2DPointArray read fScreenPolygon; {$endif} {!! TIECropToolInteraction.RotatedPolygon Declaration property RotatedPolygon: ; (Read-only) Description Returns the area of the image the user has selected for cropping with support for rotation (returning the four corners of the rotated polygon) See Also - - - !!} {$ifdef IESUPPORTPROPERTYOFARRAYTYPE} property RotatedPolygon: TIE2DPointArray read fRotatedPolygon; {$endif} {!! TIECropToolInteraction.Rotation Declaration property Rotation: Double; Description The rotation the user has applied to the crop selection (degrees counter-clockwise). This is the programatic equivalent of the user dragging outside the grips of the crop tool selection. Note: You must call TImageEnView.Invalidate if you change this property when the crop selection is visible Example // Change rotation to 45 deg. CCW ImageEnView1.CropToolInteraction.Rotation := 45; ImageEnView1.Invalidate(); !!} property Rotation: double read fRotation write fRotation; // OTHER PROPERTIES {!! TIECropToolInteraction.AntialiasMode Declaration property AntialiasMode: ; Description Specifies the quality of a rotated crop. Default: ierFast Example // High quality cropping ImageEnView1.CropToolInteraction.AntialiasMode := ierBicubic; !!} property AntialiasMode: TIEAntialiasMode read fAntialiasMode write fAntialiasMode; property Mode: TIECropToolInteractionMode read fMode write SetMode; {!! TIECropToolInteraction.Options Declaration property Options: ; Description Options that control the behaviour of the crop tool. Value Description iecoAllowResizing The user can resize the crop selection by dragging the corner or side grips iecoAllowRotating The user can rotate the crop selection by dragging outside the corner grips iecoAllowMoving The user can move the crop selection by clicking within the selection area iecoSideGripsRespectLocks Determines whether the specified aspect ratio lock is enforced when dragging the side, top and bottom grips. If this option is not set then only the corner grips will respect the lock iecoSizeLocksAreMinimums If included, then the specified or are treated as minimum values, i.e. the user can make the selection larger than the specified values, but not smaller
Default: [iecoAllowResizing, iecoAllowRotating, iecoAllowMoving] Examples // Do not allow the user to resize the crop tool selection (i.e. only rotation and creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowResizing ]; // Do not allow the user to rotate the crop tool selection (i.e. only resizing and creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowRotating ]; // Do not allow the user to resize or rotate the crop tool selection (i.e. only creation would be allowed) ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options - [ iecoAllowResizing, iecoAllowRotating ]; // we want a fixed aspect ratio of 4:3, which is enforced even if the user drags the side grips ImageEnView1.CropToolInteraction.LockAspectRatio := 4 / 3; ImageEnView1.CropToolInteraction.Options := ImageEnView1.CropToolInteraction.Options + [iecoSideGripsRespectLocks]; // Do not allow a selection smaller than 100x100 pixels ImageEnView1.CropToolInteraction.Options := [iecoSizeLocksAreMinimums]; ImageEnView1.CropToolInteraction.LockWidth := 100; ImageEnView1.CropToolInteraction.LockHeight := 100; See Also - - - !!} property Options: TIECropToolOptions read fOptions write fOptions; property Selected: Boolean read GetSelected write SetSelected; // commands procedure Refresh(); procedure Cancel(); procedure Crop(); // abstract methods implementation function MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; function MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; override; procedure MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); override; function MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); override; procedure Paint(const UpdateRect: TRect); override; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIECreateLayerInteraction TIECreateLayerInteraction = class(TIEUserInteraction) private // current state fScreenPt1: TIE2DPoint; // screen coordinates fScreenPt2: TIE2DPoint; // screen coordinates fMouseDownCoords: TPoint; fLayerKind: TIELayerKind; fCreatingRect: Boolean; // False until we commence creation of hte rect // visual appearance fLockAspectRatio: double; // -1: No locking, >0: Locked to specific aspect fLockWidth, fLockHeight: Integer; // Lock selection to absolute sizes procedure Draw(Canvas: TCanvas); function GetSelX(): Integer; function GetSelY(): Integer; function GetSelWidth(): Integer; function GetSelHeight(): Integer; public constructor Create(Parent: TImageEnView); property LockAspectRatio: Double read fLockAspectRatio write fLockAspectRatio; property LockWidth: Integer read fLockWidth write fLockWidth; property LockHeight: Integer read fLockHeight write fLockHeight; property LayerKind: TIELayerKind read fLayerKind write fLayerKind; property SelX: Integer read GetSelX; property SelY: Integer read GetSelY; property SelWidth: Integer read GetSelWidth; property SelHeight: Integer read GetSelHeight; procedure SetSel(X, Y, Width, Height: Integer); procedure Enact(); procedure Cancel(); procedure Refresh(); // abstract methods implementation function MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; function MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; override; procedure MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); override; function MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); override; procedure Paint(const UpdateRect: TRect); override; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function _IsRectangle(p: PPointArray; n: integer): boolean; procedure IEDrawBackground(ComponentState: TComponentState; Canvas: TCanvas; Bitmap: TBitmap; fBackgroundStyle: TIEBackgroundStyle; fBackground: TColor; DestX, DestY, Width, Height: integer; x1, y1, x2, y2: integer; fChessboardSize: integer; fChessboardBrushStyle: TBrushStyle; fChessboardColor2Customized: Boolean; fGradientEndColor: TColor; Wallpaper: TPicture; WallpaperStyle: TIEWallpaperStyle; LiveBackground: TIEBitmap); function IELayersLoadHeaderFromStream(Stream: TStream; out Header: TLayerHeader; out Width: Integer; out Height: Integer; out Description: Widestring; var Thumbnail: TIEBitmap; LoadThumb: Boolean = True ): Boolean; const // consts used by IEN_Send_To_Back = -9; IEN_Send_Backward = -8; IEN_Bring_Forward = -7; IEN_Bring_To_Front = -6; // Consts used by LayersFixBorders, LayersFixRotations, LayersFixSizes, LayersMove, etc. LYR_ALL_LAYERS = -1; LYR_SELECTED_LAYERS = -2; // ImageEn embedded cursors crIEZoomOut = TCursor(1778); crIEZoomIn = TCursor(1779); crIEThickCross2 = TCursor(1780); crIEEraser = TCursor(1781); crIEHandDrag = TCursor(1782); crIEPencil = TCursor(1783); crIECross = TCursor(1784); crIECrossSight = TCursor(1785); crIESizeNWSE = TCursor(1786); crIESizeNS = TCursor(1787); crIESizeNESW = TCursor(1788); crIESizeWE = TCursor(1789); crIESizeAll = TCursor(1790); crIECrossSightPlus = TCursor(1791); crIECrossSightMinus = TCursor(1792); crIEThickCross = TCursor(1793); crIEThickCrossPlus = TCursor(1794); crIECrossSightMinus2 = TCursor(1795); crIECrossSightMinus3 = TCursor(1796); crIEBrush = TCursor(1797); crIEEyeDropper3 = TCursor(1798); crIEPaintFill = TCursor(1799); crIEStamp = TCursor(1800); crIECrop = TCursor(1801); crIECrossSmallPlus = TCursor(1802); crIESmallArrow = TCursor(1803); crIEMultipleArrow = TCursor(1804); crIEEyeDropper2 = TCursor(1805); crIEEyeDropper = TCursor(1806); crIECut = TCursor(1807); crIESelectArrow = TCursor(1808); crIEPen = TCursor(1809); crIEBigZoomPlusMinus = TCursor(1810); crIERotateNE = TCursor(1811); crIERotateSW = TCursor(1812); crIERotateNW = TCursor(1813); crIERotateSE = TCursor(1814); procedure IEInitialize_imageenview; procedure IEFinalize_imageenview; implementation uses iexThemes, math, NeurQuant, ievect, iegdiplus, iesettings, iexCanvasUtils {$ifdef IEUSEVCLZLIB}, zlib{$else}, iezlib{$endif} {$IfDef UNICODE}, AnsiStrings {$EndIf} {$ifdef IEINCLUDEDIRECTSHOW} , ieds {$endif} {$ifdef IEINCLUDEFLATSB} , flatsb {$endif} {$IFDEF IEINCLUDEMEDIAFOUNDATION} , iemmf {$ENDIF} {$ifdef IEVISION} , ievision {$endif} {$ifdef IEHASTYPES} , Types {$endif} ; {$R IMRES.RES} {$R-} type // animated polygons item // note: this item is replicated in ievect also TIEAnimPoly = record Poly: PPointArray; // coordinates PolyCount: integer; // vertex count PolyCapacity: integer; // memory capacity Color1: TColor; // Color 1 Color2: TColor; // Color 2 // Animated: boolean; // Animated AniFt: integer; // frame counter C1: integer; // DDA counter Canvas: TCanvas; // destination canvas RX1, RY1, RX2, RY2: integer; // bounds of the polygon Enabled: boolean; // if True show the polygon Sizeable: boolean; // shows and use resizing grips ShowCenter: Boolean; // draw a cross to show center of the polygon DrawPixelPtr: PRGB; // to replace SetPixel DrawPixelBitmap: TBitmap; // to replace SetPixel end; PIEAnimPoly = ^TIEAnimPoly; // Initialize (load) cursors procedure InitCursors; const imcur = 1777; curnum = 37; curname: array[1..curnum] of string = ( 'ZOOMMENO', // 1778 'ZOOMPIU', // 1779 'CROCE', // 1780 'GOMMA', // 1781 'MANO', // 1782 'PENNA', // 1783 'CROCE1', // 1784 'CROCE3', // 1785 // default 'MOVE2', // 1786 'MOVEY', // 1787 'MOVE1', // 1788 'MOVEX', // 1789 'MOVE', // 1790 'CROCE3+', // 1791 'CROCE3-', // 1792 'CROCE2', // 1793 'CROCE2+', // 1794 'CROCE2-', // 1795 'CROCE2-', // 1796 (FREE ENTRY) '1795', // 1797 '1796', // 1798 '1797', // 1799 '1798', // 1800 '1799', // 1801 '1800', // 1802 '1801', // 1803 '1802', // 1804 '1803', // 1805 '1803', // 1806 (FREE ENTRY) '1805', // 1807 '1806', // 1808 '1807', // 1809 '1808', // 1810 'ROT1', // 1811 'ROT2', // 1812 'ROT3', // 1813 'ROT4' // 1814 ); var q: integer; begin for q := 1 to curnum do Screen.Cursors[imcur + q] := LoadCursor(sysinit.hinstance, PChar(curname[q])); end; ///////////////////////////////////////////////////////////////////////////////////// constructor TImageEnView.Create(Owner: TComponent); begin LockUpdate; fOffscreenPaint := false; fGXScr2Bmp := nil; fGYScr2Bmp := nil; fGXScr2BmpSize := 0; fGYScr2BmpSize := 0; fGXBmp2Scr := nil; fGYBmp2Scr := nil; fXScr2BmpSize := 0; fYScr2BmpSize := 0; fXBmp2ScrSize := 0; fYBmp2ScrSize := 0; fXScr2Bmp := nil; fYScr2Bmp := nil; fXBmp2Scr := nil; fYBmp2Scr := nil; fBitmapWidth := 0; fBitmapHeight := 0; fUpdateReason := ieurDefault; fWasScreenCursor := crNone; fImageEnIO := nil; fImageEnProc := nil; {$IFDEF IEIncludeDeprecatedInV4} fLegacyBitmap := True; fBitmap := TBitmap.create; fBitmap.PixelFormat := pf24bit; {$IFNDEF OCXVERSION} fBitmap.Width := Width; fBitmap.Height := Height; {$ENDIF} {$ELSE} fLegacyBitmap := False; fBitmap := nil; {$ENDIF} inherited Create(Owner); {$ifdef IEVISION} if (csDesigning in ComponentState) then begin // design mode, unload ievision IEFinalize_ievision(); end; {$endif} IEGDIPLoadLibrary(); fIEBitmapValid := True; fIEBitmap := TIEBitmap.Create; fIEBitmap.fOwner := Self; {$IFDEF IEIncludeDeprecatedInV4} fIEBitmap.EncapsulateTBitmap(fBitmap, true); {$ELSE} fIEBitmap.Location := ieFile; fIEBitmap.Allocate( 1, 1, ie24RGB ); {$ENDIF} fLayersRect.x := 0; fLayersRect.y := 0; fLayersRect.width := fIEBitmap.Width; fLayersRect.height := fIEBitmap.Height; fUpdateInsideUpdate := false; fInsideUpdate := false; // layers fLayers := TList.Create; fLayers.Add(TIEImageLayer.Create(self, fIEBitmap, true)); with TIEImageLayer(fLayers[0]) do begin VisibleBox := false; Locked := true; end; fLayersCurrent := 0; fDrawPixelBitmap := nil; fDrawPixelPtr := nil; fOnSetCursor := nil; fOldHandle := 0; fAutoCursors := assigned(Owner); fTransition := nil; fTransitionEffect := iettNone; fTransitionDuration := 1000; fVScrollBarVisible := false; fHScrollBarVisible := false; fScrollBarsAlwaysVisible := false; fRXScroll := 1; fRYScroll := 1; fSelectionOptions := [iesoAnimated, iesoSizeable, iesoMoveable, iesoCanScroll, iesoAllowMoveByKeyboard]; fOnViewChange := nil; fOnFinishSmoothTask := nil; fOnViewChanging := nil; fOnImageEnGesture := nil; fOnImageChange := nil; fOnDrawLayer := nil; fOnDrawLayerBox := nil; fOnDrawLayerGrip := nil; fDelayZoomFilter := false; fZoomFilter := rfNone; fActualZoomFilter := rfNone; fUpdateBackBuffer := true; fFullUpdateRequest := true; ZeroMemory(@fBitmapInfoHeader256, sizeof(TBitmapInfoHeader256)); fMouseInteract := []; fLockPaint := 0; fHDrawDib := IEDrawDibOpen; {$ifndef IEDOTNETVERSION} if Owner <> nil then {$endif} InitCursors; fFirstTimeSetCursor := true; fCursor := crIECrossSight; fLCursor := fCursor; fScrollBars := ssBoth; fZoomX := 100; fZoomY := 100; fZoomD100X := fZoomX / 100; f100DZoomX := 100 / fZoomX; fZoomD100Y := fZoomY / 100; f100DZoomY := 100 / fZoomY; Height := 105; Width := 105; fOffX := 0; fOffY := 0; fExtX := 0; fExtY := 0; fImageHorizAlignment := iehCenter; fImageVertAlignment := ievCenter; fPolySelecting := False; fLassoSelecting := False; fRectSelecting := False; fCircSelecting := False; fRectResizing := ieNone; fSelectMoving := -1; fSel := false; fAnimPoly := TList.Create; fAnimPolyTimer := nil; fDelayTimer := -20; // maximum 20% of cpu for selections fHPolySel := PIEAnimPoly(AnimPolygonNew(clBlack, clWhite, True, True)); if not (csDesigning in ComponentState) then begin fBackBuffer := TIEBitmap.Create(10, 10, ie24RGB); // back buffer fBackBuffer.Location := ieTBitmap; HideSelectionEx(false); end; fUpdateInvalidate := true; fSelectionBase := iesbClientArea; fSavedSelectionBase := fSelectionBase; fBackgroundStyle := iebsSolid; fOnSelectionChange := nil; fOnSelectionChanging := nil; fOnBeforeSelectionChange := nil; fMagicWandMaxFilter := false; fMagicWandMode := iewInclusive; fMagicWandTolerance := 15; fOnMouseInSel := nil; fOnMouseInResizingGrip := nil; fOnZoomIn := nil; fOnZoomOut := nil; fOnVirtualKey := nil; fDisplayGridKind := iedgNone; fDisplayGridLyr := -1; fVScrollBarParams := TIEScrollBarParams.Create; fHScrollBarParams := TIEScrollBarParams.Create; fMouseWheelParams := TIEMouseWheelParams.Create( iemwZoom ); fSelectionMaskDepth := 1; fSelectionIntensity := 1; fSelectionMask := TIEMask.Create; fSelectionMask.AllocateBits(fIEBitmap.Width, fIEBitmap.Height, fSelectionMaskDepth); fAniCounter := 0; SelColor1 := clBlack; SelColor2 := clWhite; fGripColor1 := clBlack; fGripColor2 := $00BAFFFF; fGripBrushStyle := bsSolid; fGripSize := 5; fGripShape := iegsCircle; fExtendedGrips := true; fLyrGripColor1 := clBlack; fLyrGripColor2 := $00BAFFFF; fLyrGripBrushStyle := bsSolid; fLyrGripSize := 5; fLyrGripShape := iegsCircle; fChessboardSize := 16; fChessboardBrushStyle := bsSolid; fChessboardColor2Customized := False; fOnPaint := nil; fOnProgress := nil; fOnFinishWork := nil; fOnAcquireBitmap := nil; fForceALTkey := false; fEnableAlphaChannel := true; fDelayDisplaySelection := true; fAutoStretch := false; fAutoShrink := false; fBlockPaint := false; fRectMoving := false; fMouseMoveScrolling := false; fSavedSelection := TList.Create; fEnableShiftKey := true; fDelayZoomTicks := 4; fDelayAniSelTicks := 2; fLutLastZoomX := -1; fLutLastZoomY := -1; fLutLastFRX := -1; fLutLastFRY := -1; fLutLastMaxLayerWidth := -1; fLutLastMaxLayerHeight := -1; fGradientEndColor := clBtnShadow; fUseDrawDibDraw := false; // for same behavior of old versions set it to True fDrawVersion := false; UnLockUpdate; fOnDrawBackBuffer := nil; fLayersDrawBox := false; fLayersCaching := 0; fMovingLayer := -1; fLayerMoved := false; fRotatingLayer := -1; fRotatingLayerValue := 0; fMovingRotationCenter := -1; fLayerResizing := ieNone; fMovResRotLayerStarted := false; fEditingLayer := -1; fOnLayerNotify := nil; fOnLayerSelectionChange := nil; {$IFDEF IEINCLUDEDIRECTSHOW} fOnDShowNewFrame := nil; fOnDShowEvent := nil; {$ENDIF} {$IFDEF IEINCLUDEMEDIAFOUNDATION} fOnMediaFoundationNotify := nil; {$ENDIF} fOnTextEditorKeyDown := nil; fOnActivateTextEditor := nil; fOnDeactivateTextEditor := nil; fSelectionAspectRatio := -1; fSelectionAbsWidth := 100; fSelectionAbsHeight := 100; fOnSpecialKey := nil; fFlatScrollBars := false; fNavigator := nil; fNavigatorInside := false; fIsNavigator := false; fMinBitmapSize := 2; fOnDrawBackground := nil; fOnDrawCanvas := nil; {$ifdef IEDOTNETVERSION} // wallpaper created on request when under DOTNET fWallpaper := nil; {$else} fWallpaper := TPicture.Create; {$endif} fWallpaperStyle := iewoNormal; fZoomSelectionAspectRatio := true; fMouseScrollRate := 1; fVisibleSelection := true; fOnDrawPolygon := nil; fOnSaveUndo := nil; fSoftCrop := iesfNone; fSoftCropValue := 60; fInteractionHint := ''; fEnableInteractionHints := true; fLayersRotationFilter := ierFast; fLayersRotationAntialias := false; fLayersRotationUseFilterOnPreview := false; fLayersRotateStep := 45; fLayersSelectConstrains := true; fLayersMergeFilter := rfLanczos3; fUpdate_MaskCache := -1; fSmoothScrollTimer := nil; fSmoothScrollValue := 8; fSmoothZoomTimer := nil; fSmoothZoomValue := 8; fHighlightedPixel := Point(-1, -1); fPostFrames := TList.Create; fSelectionGridWidth := 1; fSelectionGridHeight := 1; fNavigatorOptions := []; fNavigatorBackBuffer := nil; fNavigatorActualRect := Rect(0, 0, 0, 0); fMarkOuterAlpha := -1; fMarkOuterColor := clWhite; fLayerDefaults := nil; fLayerOptions := [ loAllowMultiSelect, loAutoUndoChangesByUser, loAutoPromptForImage, loAutoFixBorders ]; fLayersResizeAspectRatio := iearALTKey; fLayersFastDrawing := iefDelayed; fLayersFastOutput := False; fLayerBoxPen := TPen.Create; fLayerBoxPen.Style := psDot; fLayerBoxPen.Mode := pmNot; fLayerBoxPen.Width := 1; fHighlightedPixelColor := clRed; fPlayTimer := 0; fPlayLoop := true; fImageSet := False; fNeedUpdateLiveBackground := True; fLiveBackground := nil; fGestures := TIEViewerGestures.Create(); fIEBitmap.Modified := False; fModified := False; fTextEditor := nil; fShowRulers := []; fRulerParams := TIEViewRulerParams.Create( Self ); fUserInteractions := TObjectList.Create(); // add default user interactions plugins fUserInteractions.Add( TIECropToolInteraction.Create(self) ); fUserInteractions.Add( TIECreateLayerInteraction.Create(self) ); end; procedure TImageEnView.CreateHandle(); begin inherited; end; destructor TImageEnView.Destroy; var i: integer; begin IECleanupLayers(); FreeAndNil(fUserInteractions); // free post frames while fPostFrames.Count > 0 do RemovePostFrames(0); FreeAndNil(fPostFrames); FreeAndNil( fRulerParams ); FreeAndNil( fGestures ); FreeAndNil( fTextEditor ); FreeAndNil(fSmoothScrollTimer); FreeAndNil(fSmoothZoomTimer); SyncLayers(); // Without this, in rare situation you will get an exception if current layer fBitmap points to a bitmap that no longer exists (e.g. an external bitmap that has been destroyed). Fixed known causes of this issue, but do not remove this line in case there are other instances FreeAndNil(fTransition); if assigned(fNavigator) then SetNavigator(nil); if assigned(fImageEnIO) then FreeAndNil(fImageEnIO); if assigned(fImageEnProc) then FreeAndNil(fImageEnProc); if not (csDesigning in ComponentState) then begin // free double buffer FreeAndNil(fBackBuffer); end; FreeAndNil(fAnimPolyTimer); for i := 0 to fAnimPoly.Count-1 do begin freemem(PIEAnimPoly(fAnimPoly[i])^.Poly); // free vertex array freemem(PIEAnimPoly(fAnimPoly[i])); // free TIEAnimPoly structure end; FreeAndNil(fAnimPoly); IEDrawDibClose(fHDrawDib); FreeAndNil(fVScrollBarParams); FreeAndNil(fHScrollBarParams); FreeAndNil(fMouseWheelParams); FreeAndNil(fSelectionMask); FreeAndNil(fLayerDefaults); // free layers (frees also fIEBitmap and fBitmap) for i := 0 to fLayers.Count - 1 do TIELayer(fLayers[i]).Free; FreeAndNil(fLayers); // deleted by previous loop fBitmap := nil; fIEBitmap := nil; fIEBitmapValid := False; for i := 0 to fSavedSelection.Count-1 do TObject(fSavedSelection[i]).Free; FreeAndNil(fSavedSelection); if fGXScr2Bmp <> nil then freemem(fGXScr2Bmp); if fGYScr2Bmp <> nil then freemem(fGYScr2Bmp); if fGXBmp2Scr <> nil then freemem(fGXBmp2Scr); if fGYBmp2Scr <> nil then freemem(fGYBmp2Scr); fGXScr2Bmp := nil; fGYScr2Bmp := nil; fGXScr2BmpSize := 0; fGYScr2BmpSize := 0; fGXBmp2Scr := nil; fGYBmp2Scr := nil; fXScr2BmpSize := 0; fYScr2BmpSize := 0; fXBmp2ScrSize := 0; fYBmp2ScrSize := 0; FreeAndNil(fLayerBoxPen); FreeAndNil(fWallpaper); FreeAndNil(fDrawPixelBitmap); FreeAndNil( fLiveBackground ); if assigned(fNavigatorBackBuffer) then fNavigatorBackBuffer.Free; IEGDIPUnLoadLibrary(); inherited; end; procedure TImageEnView.SetupAniPolyTimer; begin if not assigned(fAnimPolyTimer) then begin fAnimPolyTimer := TTimer.Create(nil); fAnimPolyTimer.enabled := false; fAnimPolyTimer.Interval := 210; fAnimPolyTimer.OnTimer := TimerEvent; end; end; procedure TImageEnView.SetupTransition; begin if not assigned(fTransition) then fTransition := TIETransitionEffects.Create( Self ); end; procedure TImageEnView.SetupDrawPixelBitmap; begin if not assigned(fDrawPixelBitmap) then begin fDrawPixelBitmap := TBitmap.Create; fDrawPixelBitmap.Width := 1; fDrawPixelBitmap.Height := 1; fDrawPixelBitmap.PixelFormat := pf24bit; fDrawPixelPtr := PRGB(fDrawPixelBitmap.Scanline[0]); end; end; {!! TImageEnView.Background Declaration property Background: TColor; Description Specifies the background color, which is shown in the unoccupied area of the window (when the current image is smaller than the ImageEnView). This color is used also in geometric processing (such as rotation) to fill blank areas. If you change the background color after the component has been created (at runtime) , you won't see the change because the bitmap overlaps the background. For this reason, to change background color at runtime you must: - empty Layer1 bitmap: ImageEnView.Blank; ImageEnView.Background := clRed; - or fill the bitmap using the color you want: ImageEnView.Proc.Fill(clRed); Note: This value may be overridden if is enabled. Default: clBtnFace Example // Rotate of 30 degrees and fill blank spaces with clBlack color ImageEnView1.Background := clBlack; ImageEnView1.Proc.Rotate(30, False); See Also - !!} procedure TImageEnView.SetBackground(cl: TColor); begin inherited SetBackground(cl); if csDesigning in ComponentState then Clear; UpdateReason := ieurComponentStuffChanged; Update; UpdateReason := ieurComponentStuffChanged; ImageChange; if (csDesigning in ComponentState) then Paint; end; procedure TImageEnView.DoSize; begin if assigned(fTransition) and fTransition.Running then fTransition.stop; fNeedUpdateLiveBackground := True; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.ScrollBars Declaration property ScrollBars: TScrollType; Description ScrollBars determines whether the TImageEnView control displays scroll bars (they are only shown if they are needed unless is true). Value Description ssNone The control has no scroll bars ssHorizontal The control has a single scroll bar on the bottom edge when needed ssVertical The control has a single scroll bar on the right edge when needed ssBoth The control has a scroll bar on both the bottom and right edges when needed
!!} procedure TImageEnView.SetScrollBars(v: TIEScrollStyle); begin fScrollBars := v; if (fScrollBars <> ssVertical) and (fScrollBars <> ssBoth) then IEShowScrollBar(handle, SB_VERT, false, fFlatScrollBars); if (fScrollBars <> ssHorizontal) and (fScrollBars <> ssBoth) then IEShowScrollBar(handle, SB_HORZ, false, fFlatScrollBars); UpdateReason := ieurComponentStuffChanged; Update; end; // Stable = False: Delay full quality display // Stable = True: Display at normal quality procedure TImageEnView.SetDisplayStable(Value: Boolean); begin if Value then begin fStable2 := 0; if fStable > 0 then begin fStable := 0; Update(); end; end else begin if (fDelayZoomFilter) and (fZoomFilter <> rfNone) and ((fZoomX <> 100) or (fZoomY <> 100)) then fStable := fDelayZoomTicks; fStable2 := fDelayAniSelTicks; end; end; {!! TImageEnView.Zoom Declaration property Zoom: double; Description Use the Zoom property to zoom in or out of the image. The image itself is not modified, only its display size changes. Zoom is expressed as a percentage of its native size, i.e. 100 is normal size, values less than 100 decrease the display size and values greater than 100 increase the display size. Note: Zoom will have no effect if
, or are enabled. See Also - - - - Example // Half size: a 200x200 pixel image is displayed at a size of 100x100 ImageEnView.Zoom := 50; // Double size: a 200x200 pixel image is displayed at a size of 400x400 ImageEnView.Zoom := 200; // floating point zoom ImageEnView.Zoom := 30.25; !!} procedure TImageEnView.SetZoomNoUpdate(v: double); var zz: double; minX, minY: integer; maxX, maxY: integer; x, y: integer; begin StopSmoothScroll(); zz := v / 100; x := GetClientWidthExRulers shr 1; x := trunc(round((x + fViewX - fOffX) * (f100DZoomX)) * zz - x); y := GetClientHeightExRulers shr 1; y := trunc(round((y + fViewY - fOffY) * (f100DZoomY)) * zz - y); fZoomX := v; fZoomD100X := fZoomX / 100; f100DZoomX := 100 / fZoomX; fZoomY := v; fZoomD100Y := fZoomY / 100; f100DZoomY := 100 / fZoomY; // Center image when scrollbars showed the first time GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewX := ilimit(x, minX, maxX); fViewY := ilimit(y, minY, maxY); end; procedure TImageEnView.SetZoom(v: double); begin StopSmoothScroll(); ViewChanging(2, v); if (v > 0) and ((v <> fZoomX) or (v <> fZoomY)) then begin SetDisplayStable( False ); LockPaint; if assigned(fNavigator) then fNavigator.LockPaint; SetZoomNoUpdate(v); UpdateReason := ieurZoomed; Update; // initial update UpdateReason := ieurZoomed; Update; // final update (without this scroll-bars aren't updated well) CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT NPUnLockPaint; if assigned(fNavigator) then fNavigator.NPUnLockPaint; Paint; ViewChange(1); end; end; procedure TImageEnView.SetZoomXNoUpdate(v: double); var zz: double; minX, minY: integer; maxX, maxY: integer; x: integer; begin StopSmoothScroll(); zz := v / 100; x := GetClientWidthExRulers shr 1; x := trunc(round((x + fViewX - fOffX) * (f100DZoomX)) * zz - x); GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewX := ilimit(x, minX, maxX); fZoomX := v; fZoomD100X := fZoomX / 100; f100DZoomX := 100 / fZoomX; end; {!! TImageEnView.ZoomX Declaration property ZoomX: Double; Description ZoomX specifies the horizontal Zoom. Using this property (and/or ZoomY) you lose the image aspect ratio and some functions, which require aspect ratio, may not work properly. Setting ZoomX and ZoomY to the same value is equivalent to setting . See Also - - !!} procedure TImageEnView.SetZoomX(v: double); begin StopSmoothScroll(); ViewChanging(2, v); if (v > 0) and (v <> fZoomX) then begin SetDisplayStable( False ); LockPaint; SetZoomXNoUpdate(v); UpdateReason := ieurZoomed; Update; // initial update UpdateReason := ieurZoomed; Update; // final update (without this scroll-bars aren't updated well) CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT NPUnLockPaint; Paint; ViewChange(1); end; end; procedure TImageEnView.SetZoomYNoUpdate(v: double); var zz: double; minX, minY: integer; maxX, maxY: integer; y: integer; begin StopSmoothScroll(); zz := v / 100; y := GetClientHeightExRulers shr 1; y := trunc(round((y + fViewY - fOffY) * (f100DZoomY)) * zz - y); GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewY := ilimit(y, minX, maxY); fZoomY := v; fZoomD100Y := fZoomY / 100; f100DZoomY := 100 / fZoomY; end; {!! TImageEnView.ZoomY Declaration property ZoomY: Double; Description ZoomY specifies the vertical zoom. Using this property (and/or ZoomX) you lose the image aspect ratio and some functions, which require aspect ratio, may not work properly. Setting and ZoomY to the same value is equivalent to setting . See Also - - !!} procedure TImageEnView.SetZoomY(v: double); begin StopSmoothScroll(); ViewChanging(2, v); if (v > 0) and (v<>fZoomY) then begin SetDisplayStable( False ); LockPaint; SetZoomYNoUpdate(v); UpdateReason := ieurZoomed; Update; // initial update UpdateReason := ieurZoomed; Update; // final update (without this scroll-bars aren't updated well) CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT NPUnLockPaint; Paint; ViewChange(1); end; end; // TODO: Unused method // creates a palette for the current bitmap type tpal = record palVersion: word; palNumEntries: word; PaletteEntry: array[0..255] of TPALETTEENTRY; end; plogpalette = ^tlogpalette; function TImageEnView._CreatePalette: HPalette; var pa: tpal; pp: array[0..255] of TRGB; q: integer; qt: TIEQuantizer; begin qt := TIEQuantizer.Create(fIEBitmap, pp, 256); for q := 0 to 255 do begin pa.PaletteEntry[q].peRed := pp[q].r; pa.PaletteEntry[q].peGreen := pp[q].g; pa.PaletteEntry[q].peBlue := pp[q].b; pa.PaletteEntry[q].peFlags := 0; end; pa.palVersion := $300; pa.palNumEntries := 256; FreeAndNil(qt); result := CreatePalette(plogpalette(@pa)^); end; {!! TImageEnView.IdealComponentWidth Declaration property IdealComponentWidth: integer; (Read-only) Description Returns the width that the TImageEnView component should be to exactly fit the current image. Example // Resize ImageEnView to fully contain Carlotta.jpg ImageEnView.LoadFromFile('C:\Carlotta.jpg'); ImageEnView1.Width := ImageEnView1.IdealComponentWidth; ImageEnView1.Height := ImageEnView1.IdealComponentHeight; See Also - loFitToLayersWhenZooming - !!} // ideal horizontal component size function TImageEnView.GetIdealComponentWidth: integer; var z1: integer; begin z1 := trunc( fZoomX * MaxLayerWidth() / 100 ); // new width of the bitmap result := z1 + 1; if ( fScrollBars = ssHorizontal ) or ( fScrollBars = ssBoth ) or ( fShowRulers <> [] ) then inc(result, width - GetClientWidthExRulers); end; {!! TImageEnView.IdealComponentHeight Declaration property IdealComponentHeight: integer; (Read-only) Description Returns the height that the TImageEnView component should be to exactly fit the current image. Example // Resize ImageEnView to fully contains Carlotta.jpg ImageEnView.LoadFromFile('C:\Carlotta.jpg'); ImageEnView1.Width := ImageEnView1.IdealComponentWidth; ImageEnView1.Height := ImageEnView1.IdealComponentHeight; See Also - loFitToLayersWhenZooming - !!} function TImageEnView.GetIdealComponentHeight: integer; var z2: integer; begin z2 := trunc(fZoomY * MaxLayerHeight() / 100 ); // new height of the bitmap result := z2 + 1; if ( fScrollBars = ssHorizontal ) or ( fScrollBars = ssBoth ) or ( fShowRulers <> [] ) then inc(result, height - GetClientHeightExRulers); end; {!! TImageEnView.IdealImageWidth Declaration property IdealImageWidth: integer; (Read-only) Description Returns the width that an image should be to fill the entire TImageEnView without requiring a scrollbar Example procedure Tfmain.ImageEnView1LayerSelectionChange(Sender: TObject); var bmp: TIEBitmap; begin // Show a preview in ImageEnView2 of the layer selected in ImageEnView1 bmp := ImageEnView2.IEBitmap; ImageEnView1.CurrentLayer.CopyToBitmap( bmp, ImageEnView2.IdealImageWidth, ImageEnView2.IdealImageWidth ); ImageEnView2.Update(); end; See Also - !!} function TImageEnView.GetIdealImageWidth: integer; var edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, true, true ); Result := ( Width - edgeLeft - edgeRight ) end; {!! TImageEnView.IdealImageHeight Declaration property IdealImageHeight: integer; (Read-only) Description Returns the width that an image should be to fill the entire TImageEnView without requiring a scrollbar Example procedure Tfmain.ImageEnView1LayerSelectionChange(Sender: TObject); var bmp: TIEBitmap; begin // Show a preview in ImageEnView2 of the layer selected in ImageEnView1 bmp := ImageEnView2.IEBitmap; ImageEnView1.CurrentLayer.CopyToBitmap( bmp, ImageEnView2.IdealImageWidth, ImageEnView2.IdealImageWidth ); ImageEnView2.Update(); end; See Also - !!} function TImageEnView.GetIdealImageHeight: integer; var edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, true, true ); Result := ( Height - edgeTop - edgeBottom ); end; procedure TImageEnView.DoMouseWheelScroll(Delta: integer; mouseX, mouseY: integer; CtrlPressed: boolean); var zDelta, nPos, xTmp: integer; dPos: double; dir: integer; mx, my: Integer; begin if (fMouseWheelParams.Action = iemwNone) or fAutoFit then exit; zDelta := Delta; if zDelta > 0 then dir := -1 else dir := 1; if fMouseWheelParams.InvertDirection then dir := -1 * dir; case fMouseWheelParams.Action of iemwVScroll: begin GetMaxViewXY(mx, my); case fMouseWheelParams.Variation of iemwAbsolute: // bitmap based if CtrlPressed or ((mx > 0) and (my = 0)) then begin // horizontal nPos := fViewX + dir * fMouseWheelParams.Value * imax(trunc(fZoomD100X), 1); SetViewX(nPos); end else begin // vertical nPos := fViewY + dir * fMouseWheelParams.Value * imax(trunc(fZoomD100Y), 1); SetViewY(nPos); end; iemwPercentage: // client based if CtrlPressed or ((mx > 0) and (my = 0)) then begin // horizontal xTmp := imax(round(GetClientWidthExRulers * fMouseWheelParams.Value / 100), 1); nPos := fViewX + dir * xTmp; SetViewX(nPos); end else begin // vertical xTmp := imax(round(GetClientHeightExRulers * fMouseWheelParams.Value / 100), 1); nPos := fViewY + dir * xTmp; SetViewY(nPos); end; end; end; iemwZoom, iemwZoomView: begin dPos := fZoomX; case fMouseWheelParams.Variation of iemwAbsolute: dPos := fZoomX + dir * fMouseWheelParams.Value; iemwPercentage: dPos := fZoomX + imax(round(fZoomX * fMouseWheelParams.Value / 100), 1) * dir; end; if (dPos > fZoomX) then DoZoomIn(dPos); if (dPos < fZoomX) then DoZoomOut(dPos); if fMouseWheelParams.ZoomPosition = iemwCenter then SetZoom(dPos) else ZoomAt(mouseX, mouseY, dPos, false); end; iemwNavigate: begin if dir < 0 then IO.Seek(ieioSeekPrior) else IO.Seek(ieioSeekNext); end; end; end; // Position is valid on when command is iescPosition procedure TImageEnView.DoVertScroll(command: TIEScrollCommand; Position: integer); var nPos: integer; mx, my: integer; begin nPos := 0; case command of iescPosition: nPos := Position; iescBottom: begin GetMaxViewXY( mx, my ); nPos := my; end; iescTop: begin GetMinViewXY( mx, my ); nPos := my; end; iescLineDown: if fVScrollBarParams.LineStep = -1 then nPos := fViewY + imax(trunc(fZoomD100Y), 1) else nPos := fViewY + fVScrollBarParams.LineStep * imax(trunc(fZoomD100Y), 1); iescLineUp: if fVScrollBarParams.LineStep = -1 then nPos := fViewY - imax(trunc(fZoomD100Y), 1) else nPos := fViewY - fVScrollBarParams.LineStep * imax(trunc(fZoomD100Y), 1); iescPageDown: if fVScrollBarParams.PageStep = -1 then nPos := fViewY + GetClientHeightExRulers else nPos := fViewY + fVScrollBarParams.PageStep * imax(trunc(fZoomD100Y), 1); iescPageUp: if fVScrollBarParams.PageStep = -1 then nPos := fViewY - GetClientHeightExRulers else nPos := fViewY - fVScrollBarParams.PageStep * imax(trunc(fZoomD100Y), 1); end; SetViewY(nPos); end; // Position is valid on when command is scPosition procedure TImageEnView.DoHorizScroll(command: TIEScrollCommand; Position: integer); var nPos: integer; mx, my: integer; begin nPos := 0; case command of iescPosition: nPos := Position; iescBottom: begin GetMaxViewXY( mx, my ); nPos := mx; end; iescTop: begin GetMinViewXY( mx, my ); nPos := mx; end; iescLineDown: if fHScrollBarParams.LineStep = -1 then nPos := fViewX + imax(trunc(fZoomD100X), 1) else nPos := fViewX + fHScrollBarParams.LineStep * imax(trunc(fZoomD100X), 1); iescLineUp: if fHScrollBarParams.LineStep = -1 then nPos := fViewX - imax(trunc(fZoomD100X), 1) else nPos := fViewX - fHScrollBarParams.LineStep * imax(trunc(fZoomD100X), 1); iescPageDown: if fHScrollBarParams.PageStep = -1 then nPos := fViewX + GetClientWidthExRulers else nPos := fViewX + fHScrollBarParams.PageStep * imax(trunc(fZoomD100X), 1); iescPageUp: if fHScrollBarParams.PageStep = -1 then nPos := fViewX - GetClientWidthExRulers else nPos := fViewX - fHScrollBarParams.PageStep * imax(trunc(fZoomD100X), 1); end; SetViewX(nPos); end; procedure TImageEnView.WMVScroll(var Message: TMessage); var cmd: TIEScrollCommand; pos: integer; begin inherited; pos := 0; case Message.WParamLo of SB_THUMBTRACK, SB_THUMBPOSITION: begin if (not fVScrollBarParams.Tracking) and (Message.WParamLo = SB_THUMBTRACK) then exit; cmd := iescPosition; pos := round( Message.WParamHi * fRYScroll ); // "round" to avoid scrolling with a single click end; SB_BOTTOM: cmd := iescBottom; SB_TOP: cmd := iescTop; SB_LINEDOWN: cmd := iescLineDown; SB_LINEUP: cmd := iescLineUp; SB_PAGEDOWN: cmd := iescPageDown; SB_PAGEUP: cmd := iescPageUp; else begin cmd := iescPosition; pos := fViewY; end; end; DoVertScroll(cmd, pos); end; procedure TImageEnView.WMHScroll(var Message: TMessage); var cmd: TIEScrollCommand; pos: integer; begin inherited; pos := 0; case Message.WParamLo of SB_THUMBTRACK, SB_THUMBPOSITION: begin if (not fHScrollBarParams.Tracking) and (Message.WParamLo = SB_THUMBTRACK) then exit; cmd := iescPosition; pos := round( Message.WParamHi * fRXScroll ); // "round" to avoid scrolling with a single click end; SB_BOTTOM: cmd := iescBottom; SB_TOP: cmd := iescTop; SB_LINEDOWN: cmd := iescLineDown; SB_LINEUP: cmd := iescLineUp; SB_PAGEDOWN: cmd := iescPageDown; SB_PAGEUP: cmd := iescPageUp; else begin cmd := iescPosition; pos := fViewX; end; end; DoHorizScroll(cmd, pos); end; procedure TImageEnView.WMMouseWheel(var Message: TMessage); var pt: TPoint; begin inherited; pt.x := smallint(Message.LParamLo); pt.y := smallint(Message.LParamHi); pt := ScreenToClient(pt); DoMouseWheelScroll(smallint($FFFF and (Message.wParam shr 16)), pt.x, pt.y, GetKeyState(VK_CONTROL) < 0); end; procedure TImageEnView.WMMouseHWheel(var Message: TMessage); begin inherited; end; // double click - end of polygonal selection procedure TImageEnView.WMLButtonDblClk(var Message: TWMLButtonDblClk); begin inherited; DoDoubleClickEx((MK_SHIFT and Message.Keys) <> 0); end; procedure TImageEnView.WMKillFocus(var Msg: TWMKillFocus); begin inherited; invalidate; end; procedure TImageEnView.WMSetFocus(var Msg: TWMSetFocus); begin inherited; invalidate; end; procedure TImageEnView.WMPaint(var Message: TWMPaint); begin {$IFDEF IEINCLUDEDIRECTSHOW} if assigned(fImageEnIO) and assigned(fImageEnIO.DShowParams) and fImageEnIO.DShowParams.RenderVideo and (fImageEnIO.DShowParams.State<>gsStopped) then fImageEnIO.DShowParams.RepaintVideo(handle, Canvas.Handle); {$ENDIF} inherited; end; procedure TImageEnView.IEMUpdate(var Message: TMessage); begin Update; end; procedure TImageEnView.IEMProgress(var Message: TMessage); begin if assigned(fOnProgress) then fOnProgress(self, Message.wParam); end; procedure TImageEnView.IEMFinishWork(var Message: TMessage); begin if assigned(fOnFinishWork) then fOnFinishWork(self); end; procedure TImageEnView.WMSize(var Message: TWMSize); begin inherited; if not fInsideUpdate then DoSize; end; procedure TImageEnView.WMEraseBkgnd(var Message: TMessage); begin Message.Result := 0; end; {!! TImageEnView.SetViewXY Declaration procedure SetViewXY(x, y: integer); Description Sets and in one step to change the displayed portion of the image (programatic scroll). !!} procedure TImageEnView.SetViewXY(x, y: integer); var minX, minY: integer; maxX, maxY: integer; lviewx, lviewy: integer; begin ViewChanging(0, x); ViewChanging(1, y); lviewx := fViewX; lviewy := fViewY; if (x = fViewX) and (y = fViewY) then exit; GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewX := ilimit(x, minX, maxX); fViewY := ilimit(y, minY, maxY); if (fViewX = lviewx) and (fViewY = lviewy) then exit; SetDisplayStable( False ); fUpdateBackBuffer := true; fFullUpdateRequest := true; Paint; ViewChange(0); if fSel then AniPolyFunc(self, true); if (fScrollBars = ssHorizontal) or (fScrollBars = ssBoth) then IESetScrollPos(Handle, SB_HORZ, trunc(fViewX / fRXScroll), true, fFlatScrollBars); if (fScrollBars = ssVertical) or (fScrollBars = ssBoth) then IESetScrollPos(Handle, SB_VERT, trunc(fViewY / fRYScroll), true, fFlatScrollBars); end; {!! TImageEnView.ViewX Declaration property ViewX: integer; Description ViewX and specify the top-left of the image that is visible in the TImageEnView component window. Use ViewX/Y to programatically scroll images bigger than the TImageEnView. Example ImageEnView1.ViewX := 20; // View from column 20 of bitmap (i.e. first 20 pixels on the left of the image will no longer be visible) ImageEnView1.Zoom := 200; // zoom image to 200% ImageEnView1.ViewX := 20; // view from column 40 of bitmap (i.e. first 40 pixels on the left of the image will no longer be visible) See Also - - - - !!} procedure TImageEnView.SetViewX(v: integer); var minX, minY: integer; maxX, maxY: integer; lviewx: Integer; begin ViewChanging(0, v); if v = fViewX then exit; lviewx := fViewX; GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewX := ilimit(v, minX, maxX); if fViewX=lviewx then exit; SetDisplayStable( False ); fUpdateBackBuffer := true; fFullUpdateRequest := true; paint; ViewChange(0); if fSel then AniPolyFunc(self, true); if (fScrollBars = ssHorizontal) or (fScrollBars = ssBoth) then IESetScrollPos(Handle, SB_HORZ, trunc(fViewX / fRXScroll), true, fFlatScrollBars); end; {!! TImageEnView.ViewY Declaration property ViewY: integer; Description and ViewY specify the top-left of the image that is visible in the TImageEnView component window. Use ViewX/Y to programatically scroll images bigger than the TImageEnView. Example ImageEnView1.ViewX := 20; // View from column 20 of bitmap (i.e. first 20 pixels on the left of the image will no longer be visible) ImageEnView1.Zoom := 200; // zoom image to 200% ImageEnView1.ViewX := 20; // view from column 40 of bitmap (i.e. first 40 pixels on the left of the image will no longer be visible) See Also - - - - !!} procedure TImageEnView.SetViewY(v: integer); var minX, minY: integer; maxX, maxY: integer; lviewy: Integer; begin ViewChanging(1, v); if v = fViewY then exit; lviewy := fViewY; GetMinViewXY(minX, minY); GetMaxViewXY(maxX, maxY); fViewY := ilimit(v, minY, maxY); if fViewY = lviewy then exit; SetDisplayStable( False ); fUpdateBackBuffer := true; fFullUpdateRequest := true; paint; ViewChange(0); if fSel then AniPolyFunc(self, true); if (fScrollBars = ssVertical) or (fScrollBars = ssBoth) then IESetScrollPos(Handle, SB_VERT, trunc(fViewY / fRYScroll), true, fFlatScrollBars); end; {!! TImageEnView.GetMaxViewXY Declaration procedure GetMaxViewXY(var mx, my: integer); Description Returns the maximum values for and (which will fill the mx and my vars). I.e. this is the maximum that the image can be programatically scrolled. !!} procedure TImageEnView.GetMaxViewXY(var mx, my: integer); var zx, zy: integer; begin if fZoomX <> fZoomY then begin zx := trunc(fLayersRect.width * fZoomD100X); // new bitmap width (zoom) zy := trunc(fLayersRect.height * fZoomD100Y); // new bitmap height (zoom) if zx > (GetClientWidthExRulers + 10) then // this avoids cutting last right/bottom pixel zx := trunc((fLayersRect.width + 1) * fZoomD100X); // new bitmap width (zoom) if zy > (GetClientHeightExRulers + 10) then // this avoids cutting last right/bottom pixel zy := trunc((fLayersRect.height + 1) * fZoomD100Y); // new bitmap height (zoom) mx := 0; my := 0; if (zx > 0) and (zy > 0) then begin mx := zx - GetClientWidthExRulers; my := zy - GetClientHeightExRulers; if (mx < 0) or (XScr2Bmp( mx, False ) = 0) then mx := 0; if (my < 0) or (YScr2Bmp( my, False ) = 0) then my := 0; if zx <= Width - fRulerParams.RulerAreaLeft - fRulerParams.RulerAreaRight then mx := 0; if zy <= Height - fRulerParams.RulerAreaTop - fRulerParams.RulerAreaBottom then my := 0; end; end else begin zx := trunc(fLayersRect.width * fZoomD100X); // new bitmap width (zoom) zy := trunc(fLayersRect.height * fZoomD100Y); // new bitmap height (zoom) if ((zx > (GetClientWidthExRulers + 10)) or (zy > (GetClientHeightExRulers + 10))) and (ScrollBars <> ssNone) then begin // this is to avoid removing the last right/bottom pixel zx := trunc((fLayersRect.width + 1) * fZoomD100X); // new bitmap width (zoom) zy := trunc((fLayersRect.height + 1) * fZoomD100Y); // new bitmap height (zoom) end; mx := 0; my := 0; if (zx > 0) and (zy > 0) then begin mx := zx - GetClientWidthExRulers; my := zy - GetClientHeightExRulers; if (mx < 0) or (XScr2Bmp( mx, False ) = 0) then mx := 0; if (my < 0) or (YScr2Bmp( my, False ) = 0) then my := 0; if ( zx <= Width - fRulerParams.RulerAreaLeft - fRulerParams.RulerAreaRight ) and ( zy <= Height - fRulerParams.RulerAreaTop - fRulerParams.RulerAreaBottom ) then begin mx := 0; my := 0; end; end; end; end; // At this time always returns 0,0, because scrolling is not possible outside Layer 0 procedure TImageEnView.GetMinViewXY(var mx, my: integer); begin mx := 0; my := 0; end; function TImageEnView.PaletteChanged(Foreground: Boolean): Boolean; begin {$IFNDEF OCXVERSION} if assigned(application) and assigned(application.mainform) and assigned(application.mainform.canvas) then begin if IEDrawDibRealize(fHDrawDib, application.mainform.canvas.handle, false) > 0 then invalidate; end else invalidate; {$ELSE} invalidate; {$ENDIF} result := true; end; // makes an event OnImageChange {!! TImageEnView.ImageChange Declaration procedure ImageChange; virtual; Description Generates an event and sets to true. !!} procedure TImageEnView.ImageChange(); begin inherited; fModified := True; if assigned(fOnImageChange) then fOnImageChange(self); fNeedUpdateLiveBackground := True; StartPlayTimer; if ( fImageSet = False ) and ( UpdateReason <> ieurComponentStuffChanged ) and ( fLayersCurrent = 0 ) then if ((csReading in ComponentState) or (csDesigning in ComponentState) or (csLoading in ComponentState)) = False then fImageSet := True; end; {!! TImageEnView.Clear Declaration procedure Clear; Description Fills the current image with the color. Comparison of Methods Method Description Fills the current image with the background color and removes the alpha channel Calls and resets the image size to 1 x 1 Removes all of the layers Resets the image (calling ) and removes all layers (calling )
Example // Clear the image ImageEn1.Background := clWhite; ImageEn1.Clear; // Clear the top-most layer ImageEnView1.LayersCurrent := ImageEnView1.LayersCount - 1; ImageEnView1.Clear; See Also - - !!} procedure TImageEnView.Clear; begin if fIEBitmapValid then fIEBitmap.Fill(Background); RemoveAlphaChannel(false); Update; ImageChange(); end; {!! TImageEnView.ClearAll Declaration procedure ClearAll; Description Removes all content from the control, by removing all layers (with ) and resetting the background image (with ). Comparison of Methods Method Description Fills the current image with the background color and removes the alpha channel Calls and resets the image size to 1 x 1 Removes all of the layers Resets the image (calling ) and removes all layers (calling )
Example ImageEn1.ClearAll; See Also - - - !!} procedure TImageEnView.ClearAll; begin LockUpdate; LayersClear; Blank; UnlockUpdate; end; {!! TImageEnView.Blank Declaration procedure Blank; Description Resets the image size to 1x1 (Width x Height). Note: Blank also calls Comparison of Methods Method Description Fills the current image with the background color and removes the alpha channel Calls and resets the image size to 1 x 1 Removes all of the layers Resets the image (calling ) and removes all layers (calling )
Example ImageEnView1.IO.LoadFromFile('image.tif'); // Load image ... ImageEnView1.Blank; // free memory See Also - - - !!} procedure TImageEnView.Blank; begin StopPlayTimer; if assigned(fTransition) and fTransition.Running then fTransition.stop; if fIEBitmapValid then begin fIEBitmap.Width := 1; fIEBitmap.Height := 1; end; Clear; fImageSet := False; end; {!! TImageEnView.IsEmpty Declaration property IsEmpty: Boolean; Description Returns True if the size of the image is less than 2 x 2 pixels. Also, see which returns true if an image has not been assigned or loaded. !!} function TImageEnView.GetIsEmpty: boolean; begin result := True; if fIEBitmapValid then Result := (fIEBitmap.Width < 2) and (fIEBitmap.Height < 2); end; {!! TImageEnView.IsEmpty2 Declaration property IsEmpty2 : boolean; Description Returns True if the image is empty, i.e. no image has been assigned or loaded. Also, see which returns true if the image is less than 2 x 2 pixels. !!} function TImageEnView.GetIsEmpty2: boolean; var bBackgroundOnly: Boolean; brgb, irgb: TRGB; begin Result := True; if fIEBitmapValid = False then exit; if fImageSet and ( fLayersCurrent = 0 ) then Result := False else if (fIEBitmap.Width > 1) and (fIEBitmap.Height > 1) then begin irgb := fIEBitmap.Pixels[0, 0]; brgb := TColor2TRGB(TColor(fBackground)); bBackgroundOnly := (fIEBitmap.Width = Width) and (fIEBitmap.Height = Height) and (irgb.r = brgb.r) and (irgb.g = brgb.g) and (irgb.b = brgb.b); Result := bBackgroundOnly; end; end; function TImageEnView.GetSelectedRect(): TIERectangle; begin if Selected then result := IERectangle(SelX1, SelY1, SelX2 - SelX1 + 1, SelY2 - SelY1 + 1) else if fIEBitmapValid then result := IERectangle(0, 0, fIEBitmap.Width, fIEBitmap.Height) else result := IERectangle(0, 0, 0, 0) end; {!! TImageEnView.SelX1 Declaration property SelX1: integer; (Read-only) Description Returns the top-left X (column) coordinate of the selected area. The value is a coordinate of the Bitmap itself, i.e. it is independent of scrolling ( and ) and (e.g. you will get the same result whether the zoom is 50% or 100%). Note: - The selected area can be specified using - You can convert the returned value to a screen value using Example // Enlarge the selection by ten pixels on all sides With ImageEnView1 do begin SelectionBase := iesbBitmap; Select( SelX1 - 10, SelY1 - 10, SelX2 - 10, SelY2 - 10 ); End; See Also - - - - - - - - !!} function TImageEnView.GetSelX1: integer; begin if fPolySelecting or fRectSelecting or fCircSelecting or (fRectResizing <> ieNone) or fRectMoving then result := PIEAnimPoly(fHPolySel)^.rx1 else result := fSelectionMask.X1; end; {!! TImageEnView.SelY1 Declaration property SelY1: integer; (Read-only) Description Returns the top-left Y (row) coordinate of the selected area. The value is a coordinate of the Bitmap itself, i.e. it is independent of scrolling ( and ) and (e.g. you will get the same result whether the zoom is 50% or 100%). Note: - The selected area can be specified using - You can convert the returned value to a screen value using Example // Enlarge the selection by ten pixels on all sides With ImageEnView1 do begin SelectionBase := iesbBitmap; Select( SelX1 - 10, SelY1 - 10, SelX2 - 10, SelY2 - 10 ); End; See Also - - - - - - - - !!} function TImageEnView.GetSelY1: integer; begin if fPolySelecting or fRectSelecting or fCircSelecting or (fRectResizing <> ieNone) or fRectMoving then result := PIEAnimPoly(fHPolySel)^.ry1 else result := fSelectionMask.Y1; end; {!! TImageEnView.SelX2 Declaration property SelX2: integer; (Read-only) Description Returns bottom-right X (column) coordinate of the selected area. The value is a coordinate of the Bitmap itself, i.e. it is independent of scrolling ( and ) and (e.g. you will get the same result whether the zoom is 50% or 100%). Note: - The selected area can be specified using - You can convert the returned value to a screen value using Example // Enlarge the selection by ten pixels on all sides With ImageEnView1 do begin SelectionBase := iesbBitmap; Select( SelX1 - 10, SelY1 - 10, SelX2 - 10, SelY2 - 10 ); End; See Also - - - - - - - - !!} function TImageEnView.GetSelX2: integer; begin if fPolySelecting or fRectSelecting or fCircSelecting or (fRectResizing <> ieNone) or fRectMoving then result := PIEAnimPoly(fHPolySel)^.rx2 - 1 else result := fSelectionMask.X2; end; {!! TImageEnView.SelY2 Declaration property SelY2: integer; (Read-only) Description Returns the bottom-right Y (row) coordinate of the selected area. The value is a coordinate of the Bitmap itself, i.e. it is independent of scrolling ( and ) and (e.g. you will get the same result whether the zoom is 50% or 100%). Note: - The selected area can be specified using - You can convert the returned value to a screen value using Example // Enlarge the selection by ten pixels on all sides With ImageEnView1 do begin SelectionBase := iesbBitmap; Select( SelX1 - 10, SelY1 - 10, SelX2 - 10, SelY2 - 10 ); End; See Also - - - - - - - - !!} function TImageEnView.GetSelY2: integer; begin if fPolySelecting or fRectSelecting or fCircSelecting or (fRectResizing <> ieNone) or fRectMoving then result := PIEAnimPoly(fHPolySel)^.ry2 - 1 else result := fSelectionMask.Y2; end; {!! TImageEnView.XBmp2Scr Declaration function XBmp2Scr(x: Integer; CurrentLayer: Boolean): Integer; Description The XBmp2Scr and methods convert a bitmap coordinate to the window coordinate (considering the Zoom and View status). x and y are bitmap coordinates. These methods are useful to select a bitmap region independently from the , and properties. x is a bitmap coordinate. If CurrentLayer is true, then x is assumed to be a coordinate of the current layer. If false, y is a coordinate of the background layer (layer 0). Note: To convert a coordinate of a non-current layer, you can use TImageEnView.Layers[]. Demo Demos\Other\PixelView\PixelView.dpr Example // Select rect 10,10,100,100 of bitmap ImageEnView1.Zoom(300); x1 := XBmp2Scr(10); y1 := YBmp2Scr(10); x2 := XBmp2Scr(100); y2 := YBmp2Scr(100); ImageEnView1.Select( x1, y1, x2, y2); // Select rect 10,10,100,100 of the window ImageEnView1.Select(10, 10, 100, 100) See Also - - - !!} function TImageEnView.XBmp2Scr(x: integer; CurrentLayer: Boolean): integer; var xx: integer; begin if CurrentLayer then result := self.CurrentLayer.ConvXBmp2Scr(x) else begin xx := x - fo1x; if (xx < 0) or (xx >= fXBmp2ScrSize) then // approximated value result := round(fOffX + (x + round((-QuantizeViewX(fViewX)) * f100DZoomX)) * fZoomD100X) else result := fOffX + fXBmp2Scr[xx]; end; end; {!! TImageEnView.YBmp2Scr Declaration function YBmp2Scr(y: Integer; CurrentLayer: Boolean): Integer; Description The YBmp2Scr and methods convert a bitmap coordinate to the window coordinate (considering the Zoom and View status). x and y are bitmap coordinates. These methods are useful to select a bitmap region independently from the , and properties. y is a bitmap coordinate. If CurrentLayer is true, then y is assumed to be a coordinate of the current layer. If false, y is a coordinate of the background layer (layer 0). Note: To convert a coordinate of a non-current layer, you can use TImageEnView.Layers[]. Demo Demos\Other\PixelView\PixelView.dpr Example // Select rect 10, 10, 100, 100 of bitmap ImageEnView1.Zoom(300); x1 := XBmp2Scr(10); y1 := YBmp2Scr(10); x2 := XBmp2Scr(100); y2 := YBmp2Scr(100); ImageEnView1.Select( x1, y1, x2, y2); // Select rect 10,10,100,100 of the window ImageEnView1.Select(10, 10, 100, 100) See Also - - - !!} function TImageEnView.YBmp2Scr(y: integer; CurrentLayer: Boolean): integer; var yy: integer; begin if CurrentLayer then result := self.CurrentLayer.ConvYBmp2Scr(y) else begin yy := y - fo1y; if (yy < 0) or (yy >= fYBmp2ScrSize) then begin // approximated value result := round(fOffY + (y + round((-QuantizeViewY(fViewY)) * f100DZoomY)) * fZoomD100Y); end else result := fOffY + fYBmp2Scr[yy]; end; end; {!! TImageEnView.XScr2Bmp Declaration function XScr2Bmp(x: integer; CurrentLayer: Boolean): integer; Description The XScr2Bmp and methods convert a window coordinate to the corresponding bitmap coordinate (considering and , status). x is a window coordinate. If CurrentLayer is true, then the result will be a coordinate relative to the current layer. If false, it will be a coordinate relative to the background layer (layer 0). Notes: - The result may be negative or greater than the bitmap width if x is beyond the displayed image's boundaries - To convert a coordinate of a non-current layer, use TImageEnView.Layers[]. Demo Demos\Other\PixelView\PixelView.dpr Example // X and Y are MOUSE coordinates bx := ImageEnView1.XScr2Bmp( X, False ); by := ImageEnView1.YScr2Bmp( Y, False ); // now bx and by are Bitmap coordinates (of ImageEnView1.Bitmap) See Also - - - - !!} function TImageEnView.XScr2Bmp(x: integer; CurrentLayer: Boolean): integer; var xx: integer; begin if CurrentLayer then result := self.CurrentLayer.ConvXScr2Bmp(x) else begin xx := x - fOffX; if (xx < 0) or (xx >= fXScr2BmpSize) then // approximated value result := trunc((x - fOffX) * f100DZoomX + fo1x) else result := fXScr2Bmp[xx]; end; end; {!! TImageEnView.YScr2Bmp Declaration function YScr2Bmp(y: integer; CurrentLayer: Boolean): integer; Description The XScr2Bmp and methods convert a window coordinate to the corresponding bitmap coordinate (considering and , status). y is a window coordinate. If CurrentLayer is true, then the result will be a coordinate relative to the current layer. If false, it will be a coordinate relative to the background layer (layer 0). Notes: - The result may be negative or greater than the bitmap height if y is beyond the displayed image's boundaries - To convert a coordinate of a non-current layer, use TImageEnView.Layers[]. Demo Demos\Other\PixelView\PixelView.dpr Example // X and Y are MOUSE coordinates bx := ImageEnView1.XScr2Bmp( X, False ); by := ImageEnView1.YScr2Bmp( Y, False ); // now bx and by are Bitmap coordinates (of ImageEnView1.Bitmap) See Also - - - - !!} function TImageEnView.YScr2Bmp(y: integer; CurrentLayer: Boolean): integer; var yy: integer; begin if CurrentLayer then result := self.CurrentLayer.ConvYScr2Bmp(y) else begin yy := y - fOffY; if (yy < 0) or (yy >= fYScr2BmpSize) then // approximated value result := trunc((y - fOffY) * f100DZoomY + fo1y) else result := fYScr2Bmp[yy]; end; end; {!! TImageEnView.GetIdealZoom Declaration function TImageEnView.GetIdealZoom: Double; Description Returns the best zoom value to stretch the image to fit within the component. Note: If the image is empty, result will be zero. Example // Both the following code snippets will have the same result ImageEnView.Zoom := ImageEnView.GetIdealZoom; // or ImageEnView.Fit; See Also - loFitToLayersWhenZooming !!} function TImageEnView.GetIdealZoom: double; begin result := 0; if ( MaxLayerWidth() <> 0 ) and ( MaxLayerHeight() <> 0 ) then Result := dmin(Width / ( MaxLayerWidth() / 100 ), Height / ( MaxLayerHeight() / 100 )); end; procedure TImageEnView.CalcEdges(var LeftEdge, TopEdge, RightEdge, BottomEdge: integer; NoVertSB, NoHorizSB: boolean); var edgeX, edgeY: Integer; begin case fBackgroundStyle of iebsCropped: begin edgeX := IEGlobalSettings().edgeX; edgeY := IEGlobalSettings().edgeY; end; iebsCropShadow: begin edgeX := 5; edgeY := 5; end; iebsSoftShadow: begin edgeX := 9; edgeY := 9; end; else begin if NoVertSB then begin if BorderStyle=bsNone then edgeX := 0 else if Ctl3D then edgeX := IEGlobalSettings().edgeX else edgeX := IEGlobalSettings().BorderX; end else edgeX := (Width - GetClientWidth) div 2; if NoHorizSB then begin if BorderStyle=bsNone then edgeY := 0 else if Ctl3D then edgeY := IEGlobalSettings().edgeY else edgeY := IEGlobalSettings().BorderY; end else edgeY := (Height - GetClientHeight) div 2; end; end; LeftEdge := edgeX + fRulerParams.RulerAreaLeft; TopEdge := edgeY + fRulerParams.RulerAreaTop; RightEdge := edgeX + fRulerParams.RulerAreaRight; BottomEdge := edgeY + fRulerParams.RulerAreaBottom; end; procedure TImageEnView.GetFitValueXY(var x, y: double); var edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, true, true ); x := ( Width - edgeLeft - edgeRight ) / ( MaxLayerWidth() / 100 ); y := ( Height - edgeTop - edgeBottom ) / ( MaxLayerHeight() / 100 ); end; function TImageEnView.GetFitValue(): double; var x, y: double; begin GetFitValueXY( x, y); Result := dmin(x, y); end; {!! TImageEnView.Fit Declaration procedure Fit(StretchSmall : Boolean = True); Description This method adjusts so that the image fits within the client area of the component (while respecting the aspect ratio). If StretchSmall is false, then images that are smaller than the window are shown 1:1 (i.e. are not zoomed more than 100%). Example // Display the entire image (including outlying layers) within the view ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loFitToLayersWhenZooming ]; ImageEnView1.Fit( False ); See Also - - - loFitToLayersWhenZooming - !!} procedure TImageEnView.Fit(StretchSmall : Boolean = True); var dZoom : double; begin if ( MaxLayerWidth() > 1 ) and ( MaxLayerHeight() > 1 ) then begin HideHorizScrollBar; HideVertScrollBar; dZoom := GetFitValue(); if ( StretchSmall = False ) and ( dZoom > 100 ) then dZoom := 100; Zoom := dZoom; end; end; {!! TImageEnView.Stretch Declaration procedure Stretch; Description This method sets and values to stretch the image to fit within the component borders. Note: Using this method you will lose the image aspect ratio and some functions, which require aspect ratio, may not work properly. See Also - - - - loFitToLayersWhenZooming !!} procedure TImageEnView.Stretch; var x, y: Double; begin if ( MaxLayerWidth() > 1 ) and ( MaxLayerHeight() > 1 ) then begin HideHorizScrollBar; HideVertScrollBar; GetFitValueXY(x, y); LockPaint; ZoomX := x; ZoomY := y; UnlockPaint; HideHorizScrollBar; HideVertScrollBar; end; end; {!! TImageEnView.FitToWidth Declaration procedure FitToWidth; Description FitToWidth adjust the image display size () so that it fits within the width of the control window. See Also - - - loFitToLayersWhenZooming - !!} procedure TImageEnView.FitToWidth; var edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, false, true ); if ( MaxLayerWidth() > 1 ) and ( MaxLayerHeight() > 1 ) then begin LockPaint; Zoom := ( Width - edgeLeft - edgeRight ) / ( MaxLayerWidth() / 100 ); Zoom := ( GetClientWidthExRulers ) / ( MaxLayerWidth() / 100 ); // second time needed for scrollbars UnLockPaint; end; end; {!! TImageEnView.FitToHeight Declaration procedure FitToHeight; Description FitToHeight adjust the image display size () so that it fits within the height of the control window. See Also - - - loFitToLayersWhenZooming - !!} procedure TImageEnView.FitToHeight; var edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, true, false ); if ( MaxLayerWidth() > 1 ) and ( MaxLayerHeight() > 1 ) then begin LockPaint; Zoom := ( Height - edgeTop - edgeBottom ) / ( MaxLayerHeight() / 100 ); Zoom := ( GetClientHeightExRulers ) / ( MaxLayerHeight() / 100 ); // second time needed for scrollbars UnLockPaint; end; end; function TImageEnView.GetOptimalZoom(CanStretch, CanShrink: Boolean): double; var bitmapW, bitmapH, ieviewW, ieviewH: integer; edgeLeft, edgeTop, edgeRight, edgeBottom: integer; begin result := 100; CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, False, False ); bitmapW := MaxLayerWidth(); bitmapH := MaxLayerHeight(); ieviewW := GetClientWidth - edgeLeft - edgeRight; ieviewH := GetClientHeight - edgeTop - edgeBottom; if ( ieviewW < 1 ) or ( ieviewH < 1 ) or ( bitmapW < 2 ) or ( bitmapH < 2 ) then exit; try if bitmapH / ieviewH < bitmapW / ieviewW then begin // width is important if bitmapW > ieviewW then begin if CanShrink = False then result := 100 else result := GetFitValue(); end else begin if CanStretch = False then result := 100 else result := GetFitValue(); end; end else begin // height is important if bitmapH > ieviewH then begin if CanShrink = False then result := 100 else result := GetFitValue(); end else begin if CanStretch = False then result := 100 else result := GetFitValue(); end; end; // if wider than high except end; end; // makes a zoom inside the selected area {!! TImageEnView.ZoomSelection Declaration procedure ZoomSelection(AspectRatio: Boolean); Description The ZoomSelection method zooms to a rectangular area specified with Select method. If AspectRatio is true then the zoom respects the aspect ratio of the image, otherwise the image area is stretched to match the size of the component. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.ZoomSelection; // fill client area (if possible) with rectangle 10,10,100,100 !!} procedure TImageEnView.ZoomSelection(AspectRatio: Boolean); begin ZoomSelectionEx(AspectRatio, false); end; procedure TImageEnView.ZoomSelectionEx(AspectRatio: Boolean; FireDoZoomIn: Boolean); var dx, dy: integer; x1, y1: integer; cx, cy: integer; zx, zy: double; zm: Double; begin if fSel then begin dx := Selx2 - Selx1 + 1; dy := Sely2 - Sely1 + 1; x1 := SelX1; y1 := SelY1; if (x1 < 0) or (y1 < 0) or (dx < 2) or (dy < 2) then exit; Deselect; zm := dmin(Width / (dx / 100), Height / (dy / 100)); // zoom with aspect ratio if FireDoZoomIn then DoZoomIn(zm); if AspectRatio then begin Zoom := zm; end else begin ZoomX := Width / (dx / 100); ZoomY := Height / (dy / 100); end; zx := ZoomX / 100; zy := ZoomY / 100; x1 := trunc(x1 * zx); dx := trunc(dx * zx); y1 := trunc(y1 * zy); dy := trunc(dy * zy); cy := (GetClientHeightExRulers - dy) div 2; cx := (GetClientWidthExRulers - dx) div 2; SetViewXY(x1 - cx, y1 - cy); end; end; // called by "initialization" procedure InitImageEnView; begin with IEGlobalSettings().GridPen do begin Mode := pmNot; Style := psSolid; Width := 1; end; end; {!! TImageEnView.LockPaint Declaration procedure LockPaint; Description The LockPaint method increases the lock counter's value. The ImageEnView window will not be repainted while > 0. See also: . Example ImageEnView1.LockPaint; ImageEnView1.ViewX := 10; ImageEnView1.ViewY := 20; ImageEnView1.Zoom := 300; ImageEnView1.UnLockPaint; !!} // Inc fLockPaint counter procedure TImageEnView.LockPaint; begin inc(fLockPaint); end; {!! TImageEnView.UnlockPaint Declaration function UnlockPaint: integer; Description Use the UnlockPaint method to decrease the lock counter's value. The ImageEnView window will not be repainted while > 0. If calling UnlockPaint resets to zero then the method is automatically called. Returns the lock count. See also: Example ImageEnView1.LockPaint; ImageEnView1.ViewX := 10; ImageEnView1.ViewY := 20; ImageEnView1.Zoom := 300; ImageEnView1.UnLockPaint; !!} // Dec fLockPaint counter // return current fLockPaint value (after Dec) // Call Update if fLockPaint = 0 function TImageEnView.UnLockPaint: integer; begin if fLockPaint > 0 then dec(fLockPaint); if fLockPaint = 0 then Update; result := fLockPaint; end; // Dec fLockPaint counter // return current fLockPaint value (after Dec) function TImageEnView.NPUnLockPaint: integer; begin if fLockPaint > 0 then dec(fLockPaint); result := fLockPaint; end; {!! TImageEnView.ZoomAt Declaration procedure ZoomAt(x, y: integer; ZoomVal: double; Center: Boolean=true); Description Zooms by the percentage specified by ZoomVal. If the optional Center parameter if False, the zooming center is x, y, otherwise (the default) it is the center of image. !!} // zoom to ZoomVal at x,y coordinates (client area coordinates) procedure TImageEnView.ZoomAt(x, y: integer; ZoomVal: double; Center: Boolean); var zz: double; bx, by: Integer; w2, h2: Integer; begin if assigned(fNavigator) then fNavigator.LockPaint; ViewChanging(2, x); ViewChanging(2, y); LockPaint; bx := XScr2Bmp( x, False ); by := YScr2Bmp( y, False ); Zoom := ZoomVal; // fire ViewChange(1) event zz := Zoom / 100; w2 := GetClientWidthExRulers div 2; h2 := GetClientHeightExRulers div 2; if Center then SetViewXY(trunc(bx * zz - w2), trunc(by * zz - h2)) // fire ViewChange(0) event else SetViewXY(trunc(bx*zz - x +Zoom/100), trunc(by*zz - y+Zoom/100)); // fire ViewChange(0) event UnLockPaint; CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT if assigned(fNavigator) then begin fNavigator.NPUnLockPaint; SetNavigatorRect; // 3.0.4 (27/07/2009 14:18) end; end; {!! TImageEnView.ZoomIn Declaration procedure ZoomIn; Description Provides a convenient method to handle clicking of a "Zoom In" button. Each time ZoomIn is called it increases the zoom by a logical step, e.g. 50 to 75, 75 to 100, etc. It also includes "Fit to Window" as one of the steps. Note: ZoomIn will have no effect if , or are enabled. See Also - - !!} procedure TImageEnView.ZoomIn; begin Zoom := GetNextZoomValue(Zoom, True, GetIdealZoom); end; {!! TImageEnView.ZoomOut Declaration procedure ZoomOut; Description Provides as a convenient method to handle clicking of a "Zoom Out" button. Each time ZoomOut is called it decreases the zoom by a logical step, e.g. 100 to 75, 75 to 50, etc. It also includes "Fit to Window" as one of the steps. Note: ZoomOut will have no effect if , or are enabled. See Also - - !!} procedure TImageEnView.ZoomOut; begin Zoom := GetNextZoomValue(Zoom, False, GetIdealZoom); end; {!! TImageEnView.DrawTo Declaration procedure DrawTo(Canvas: TCanvas); Description This method draws the current view to the specified Canvas. Note: The background is not painted, and the image has an up-left alignment. Example // draw in ImageEn2 all what is displayed in ImageEnView1 ImageEnView1.DrawTo(ImageEnView2.Bitmap.Canvas); ImageEnView2.Update; !!} procedure TImageEnView.DrawTo(Canvas: TCanvas); begin Canvas.CopyRect(Rect(0, 0, frx, fry), fBackBuffer.Canvas, Rect(fOffX, fOffY, fOffX + frx, fOffY + fry)); end; function TImageEnView.HasParentWindow: boolean; begin result := (GetParentForm(self) <> nil) or (ParentWindow <> 0); end; {!! TImageEnView.UpdateNoPaint Declaration procedure UpdateNoPaint; Description The Update method refreshes the TImageEnView component view with the current state of the image. You must call or UpdateNoPaint() whenever the or property is modified by your code. Unlike , UpdateNoPaint doesn't paint the image, just refreshes the bitmap data. !!} procedure TImageEnView.UpdateNoPaint; begin try fBlockPaint := true; Update; finally fBlockPaint := false; end; end; function TImageEnView.RequiresScrollBars: boolean; var maxX, maxY: integer; begin GetMaxViewXY(maxX, maxY); result := (maxX > 0) or (maxY > 0); end; procedure TImageEnView.HideHorizScrollBar; begin if fHScrollBarVisible then begin fHScrollBarVisible := false; IEShowScrollBar(handle, SB_HORZ, false, fFlatScrollBars); end; end; procedure TImageEnView.HideVertScrollBar; begin if fVScrollBarVisible then begin fVScrollBarVisible := false; IEShowScrollBar(handle, SB_VERT, false, fFlatScrollBars); end; end; // Update the fLiveBackground image which stores the background to draw when BackgroundStyle = iebsBlurredBitmap procedure TImageEnView.UpdateLiveBackground(Src: TIEBitmap); const Opacity_Level = 0.75; // Background in 75% opaque Blur_Radius = 8; // Background is blurred with a radius of 8 var aRect: TRect; DestRect : TIERectangle; begin fNeedUpdateLiveBackground := False; try if not assigned( fLiveBackground ) then fLiveBackground := TIEBitmap.create; fLiveBackground.Clear; if ( Src = nil ) or ( Src.IsEmpty ) then exit; fLiveBackground.Allocate( ClientWidth, ClientHeight ); fLiveBackground.Fill( GetThemeColor( ietpControlBackground, fBackground )); aRect := GetImageRectWithinArea( Src.Width, Src.Height, fLiveBackground.Width, fLiveBackground.Height, 0, 0, True, True, True, True, 0, _fmFillRect_WithOverlap ); DestRect := IERectangle( aRect ); Src.RenderToTIEBitmapEx( fLiveBackground, DestRect.X, DestRect.Y, DestRect.Width, DestRect.Height, 0, 0, Src.Width, Src.Height, True, 255, rfNone, ielNormal, Opacity_Level ); _IEGBlur(fLiveBackground, Blur_Radius, nil, nil); except if assigned( fLiveBackground ) then fLiveBackground.Clear; end; end; {!! TImageEnView.Update Declaration procedure Update; Description The Update method refreshes the TImageEnView component view with the current state of the image and redraws the client area. You must call or UpdateNoPaint() whenever the or property is modified by your code. Update is called automatically when an image processing or I/O operation is executed. Example // Draw a rectangle on the image and show it ImageEnView1.Bitmap.Canvas.Rectangle(5, 5, 100, 100); ImageEnView1.Update; !!} procedure TImageEnView.Update; var max_x, max_y: integer; lClientWidth, lClientHeight: integer; bb: boolean; i: Integer; newZoom: double; begin if fUpdateLocked <> 0 then exit; if (csDesigning in ComponentState) then exit; if (ComponentState <> []) and (ComponentState <> [csDesigning]) and (ComponentState <> [csFreeNotification]) then exit; {$IFDEF UNITTESTING} inc( fDebugUpdatedCount ); {$ENDIF} fInsideUpdate := true; try if fNeedUpdateLiveBackground and ( BackgroundStyle = iebsBlurredImage ) then UpdateLiveBackground( Layers[0].Bitmap ); // empty layer mask caches for i := 0 to fLayers.Count-1 do if (fUpdate_MaskCache = -1) or (fUpdate_MaskCache=i) then FreeAndNil( TIELayer(fLayers[i]).fCachedLayerMask ); fUpdate_MaskCache := -1; // check layers sizes SyncLayers(); if (fAutoStretch or fAutoShrink or fAutoFit) and ( MaxLayerWidth() <> 0 ) and ( MaxLayerHeight() <> 0 ) then begin ViewChanging(2, fZoomX); NewZoom := GetOptimalZoom( fAutoStretch or fAutoFit, fAutoShrink or fAutoFit); if NewZoom < 1 then NewZoom := 1; SetZoomNoUpdate(newZoom); CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT ViewChange(1); // to avoid flickering fStable := 0; fStable2 := 0; end; // check bitmap size changes if fIEBitmapValid and ((fBitmapWidth <> fIEBitmap.Width) or (fBitmapHeight <> fIEBitmap.Height)) then begin fBitmapWidth := fIEBitmap.Width; fBitmapHeight := fIEBitmap.Height; if (fSelectionMask.Width <> fIEBitmap.Width) or (fSelectionMask.Height <> fIEBitmap.Height) then begin if fSel then begin fSelectionMask.Resize(fIEBitmap.Width, fIEBitmap.Height); fSelectionMask.SyncFull; fSelectionMask.SyncRect; end else fSelectionMask.AllocateBits(fIEBitmap.Width, fIEBitmap.Height, fSelectionMaskDepth); end; if fIEBitmap.HasAlphaChannel and ((fIEBitmap.AlphaChannel.Width <> fIEBitmap.Width) or (fIEBitmap.AlphaChannel.Height <> fIEBitmap.Height)) then begin fIEBitmap.AlphaChannel.Allocate(fIEBitmap.Width, fIEBitmap.Height, ie8g); fIEBitmap.AlphaChannel.Fill(255); end; end; if not HandleAllocated then exit; if not (csDesigning in ComponentState) and (HasParentWindow) then begin // Save client sizes because the scrollbar changes the client area, then we must recall Update (recursive call) lClientWidth := GetClientWidth; lClientHeight := GetClientHeight; // bb := false; GetMaxViewXY(max_x, max_y); if fViewX > max_x then begin ViewChanging(0, max_x); fViewX := max_x; bb := true; end; if fViewY > max_y then begin ViewChanging(1, max_y); fViewY := max_y; bb := true; end; if bb then ViewChange(0); try if HasParentWindow and ((fScrollBars = ssHorizontal) or (fScrollBars = ssBoth)) then begin if max_x > 0 then begin // we need horizontal scroll bar fHScrollBarVisible := true; fRXScroll := (max_x + GetClientWidthExRulers) / 65536; IESetScrollBar(Handle, SB_HORZ, 0, 65535, trunc(GetClientWidthExRulers / fRXScroll), trunc(fViewX / fRXScroll), true, fFlatScrollBars); IEEnableScrollBar(Handle, SB_HORZ, ESB_ENABLE_BOTH, fFlatScrollBars); IEShowScrollBar(handle, SB_HORZ, true, fFlatScrollBars); end else if fScrollBarsAlwaysVisible then begin // the scroll bar is always visible fHScrollBarVisible := true; IEEnableScrollBar(Handle, SB_HORZ, ESB_DISABLE_BOTH, fFlatScrollBars); IEShowScrollBar(handle, SB_HORZ, true, fFlatScrollBars); end else begin // we don't need the horizontal scroll bar HideHorizScrollBar; end; end; if HasParentWindow and ((fScrollBars = ssVertical) or (fScrollBars = ssBoth)) then begin if max_y > 0 then begin // we need vertical scroll bar fVScrollBarVisible := true; fRYScroll := (max_y + GetClientHeightExRulers) / 65536; IESetScrollBar(Handle, SB_VERT, 0, 65535, trunc(GetClientHeightExRulers / fRYScroll), trunc(fViewY / fRYScroll), true, fFlatScrollBars); IEEnableScrollBar(Handle, SB_VERT, ESB_ENABLE_BOTH, fFlatScrollBars); IEShowScrollBar(handle, SB_VERT, true, fFlatScrollBars); end else if fScrollBarsAlwaysVisible then begin // the scroll bar is always visible fVScrollBarVisible := true; IEEnableScrollBar(Handle, SB_VERT, ESB_DISABLE_BOTH, fFlatScrollBars); IEShowScrollBar(handle, SB_VERT, true, fFlatScrollBars); end else begin // we don't need the vertical scroll bar HideVertScrollBar; end; end; except end; if ((lClientWidth <> GetClientWidth) or (lClientHeight <> GetClientHeight)) and not fUpdateInsideUpdate then begin fUpdateInsideUpdate := true; Update; // recursive, see above fUpdateInsideUpdate := false; end; end; UpdateLimits; // Update Rulers fRulerParams.Update( False ); UpdateTextEditor(); fUpdateBackBuffer := true; fFullUpdateRequest := true; if HasParentWindow and (fBlockPaint = false) and fUpdateInvalidate then invalidate; if assigned(fNavigator) and (fNavigator.fLockPaint = 0)then begin if fUpdateReason = ieurDefault then fNavigator.Update; SetNavigatorRect; end; finally fUpdateReason := ieurDefault; fInsideUpdate := false; end; end; procedure TImageEnView.UpdateLimits; var cw, ch: Integer; begin cw := GetClientWidthExRulers; ch := GetClientHeightExRulers; fZZWW := round(fLayersRect.width * fZoomD100X); // new Bitmap width fZZHH := round(fLayersRect.height * fZoomD100Y); // new Bitmap height fOffX := 0; fOffY := 0; if not (csDesigning in ComponentState) then begin fExtX := imin( fZZWW, cw ); // width of target bitmap fExtY := imin( fZZHH, ch ); // height of target bitmap case fImageHorizAlignment of //iehLeft: iehCenter: if fExtX < cw then fOffX := ( cw - fExtX ) div 2 - fLayersRect.X else fOffX := - fLayersRect.X; iehRight: if fExtx < cw then fOffX := imin( cw - fZZWW, cw - fRulerParams.RulerAreaRight); end; case fImageVertAlignment of //ievTop: ievCenter: if fExty < ch then fOffY := ( ch - fExtY ) div 2 - fLayersRect.Y else fOffY := - fLayersRect.Y; ievBottom: if fExty < ch then fOffY := imin( ch - fZZHH, ch - fRulerParams.RulerAreaBottom ); end; end else begin fExtX := imin(fZZWW, Width); fExtY := imin(fZZHH, Height); end; inc( fOffX, fRulerParams.RulerAreaLeft ); inc( fOffY, fRulerParams.RulerAreaTop ); end; {!! TImageEnView.Center Declaration property Center: boolean; Description If Center is True, the image is displayed in the center of the ImageEnViews client area. Default: True, which is equivalent to = iehCenter and = ievCenter. See Also - - !!} procedure TImageEnView.SetCenter(value: boolean); begin if value then begin ImageHorizAlignment := iehCenter; ImageVertAlignment := ievCenter; end else begin ImageHorizAlignment := iehLeft; ImageVertAlignment := ievTop; end; end; function TImageEnView.GetCenter(): Boolean; begin result := (ImageHorizAlignment = iehCenter) and (ImageVertAlignment = ievCenter); end; {!! TImageEnView.ImageHorizAlignment Declaration property ImageHorizAlignment: ; Description Specifies where to align horizontally the image inside the component. Default: iehCenter See Also - - !!} procedure TImageEnView.SetImageHorizAlignment(value: TIEHAlign); begin if value <> fImageHorizAlignment then begin fImageHorizAlignment := value; UpdateReason := ieurScrolled; Update(); end; end; {!! TImageEnView.ImageVertAlignment Declaration property ImageVertAlignment: ; Description Specifies where to align vertically the image inside the component. Default: ievCenter See Also - - !!} procedure TImageEnView.SetImageVertAlignment(value: TIEVAlign); begin if value <> fImageVertAlignment then begin fImageVertAlignment := value; UpdateReason := ieurScrolled; Update(); end; end; procedure TImageEnView.SetMouseWheelParams(v: TIEMouseWheelParams); begin fMouseWheelParams.Assign( v ); end; procedure TImageEnView.SetMouseInteract(v: TIEMouseInteract); var exclusiveSelection : Boolean; layerSelection: Boolean; layerKind: TIELayerKind; procedure _MakeSelExclusive(value: TIEMouseInteractItems); var createLayerOp: Boolean; begin if not ( value in v ) then exit; createLayerOp := value in [ miCreateImageLayers, miCreateShapeLayers, miCreateLineLayers, miCreatePolylineLayers, miCreateTextLayers ]; if not (value in fMouseInteract) then begin v := v - [miScroll, miSelect, miSelectPolygon, miSelectCircle, miSelectZoom, miSelectMagicWand, miSelectLasso, miCropTool, miRotateLayers, miCropTool, miCreateImageLayers, miCreateShapeLayers, miCreateLineLayers, miCreatePolylineLayers, miCreateTextLayers ]; if not createLayerOp then v := v - [ miRotateLayers, miMoveLayers, miResizeLayers ] else if miRotateLayers in v then v := v - [ miMoveLayers, miResizeLayers ] else v := v - [ miRotateLayers ]; v := v + [value]; exclusiveSelection := True; end; if createLayerOp then begin layerSelection := True; case value of miCreateImageLayers : layerKind := ielkImage; miCreateShapeLayers : layerKind := ielkShape; miCreateLineLayers : layerKind := ielkLine; miCreatePolylineLayers : layerKind := ielkPolyline; miCreateTextLayers : layerKind := ielkText; end; end; end; begin if v <> fMouseInteract then begin if fPolySelecting and (miSelectPolygon in fMouseInteract) then begin AnimPolygonRemoveLastPoint(fHPolySel); fSelectionMask.Empty; EndSelect; fPolySelecting := False; invalidate; end; RestoreCursor(); // Items that need exclusive dragging over image exclusiveSelection := False; layerSelection := False; _MakeSelExclusive( miScroll ); _MakeSelExclusive( miSelect ); _MakeSelExclusive( miSelectPolygon ); _MakeSelExclusive( miSelectCircle ); _MakeSelExclusive( miSelectLasso ); _MakeSelExclusive( miSelectZoom ); _MakeSelExclusive( miCreateImageLayers ); _MakeSelExclusive( miCreateShapeLayers ); _MakeSelExclusive( miCreateLineLayers ); _MakeSelExclusive( miCreatePolylineLayers ); _MakeSelExclusive( miCreateTextLayers ); if exclusiveSelection then begin { // } end else if (miZoom in v) and not (miZoom in fMouseInteract) then // miZoom v := v - [miSelectPolygon, miSelectMagicWand] else if (miSelectMagicWand in v) and not (miSelectMagicWand in fMouseInteract) then // miSelectMagicWand v := v - [miSelect, miScroll, miSelectCircle, miSelectZoom, miZoom, miSelectPolygon, miSelectLasso, miMoveLayers, miResizeLayers, miRotateLayers, miCropTool] else if (miRotateLayers in v) then // miRotateLayers v := v - [miSelect, miScroll, miSelectCircle, miSelectZoom, miSelectPolygon, miSelectLasso, miSelectMagicWand, miResizeLayers, miCropTool] else if (miMoveLayers in v) then // miMoveLayers begin v := v - [miSelect, miScroll, miSelectCircle, miSelectZoom, miSelectPolygon, miSelectLasso, miSelectMagicWand, miCropTool]; if miResizeLayers in v then v := v-[miRotateLayers]; end else if (miResizeLayers in v) then // miResizeLayers v := v - [miSelect, miScroll, miSelectCircle, miSelectZoom, miZoom, miSelectPolygon, miSelectLasso, miSelectMagicWand, miRotateLayers, miCropTool] else if (miCropTool in v) then // miCropTool begin v := v - [miSelectPolygon, miSelectCircle, miScroll, miSelectZoom, miSelectMagicWand, miSelectLasso, miMoveLayers, miResizeLayers, miRotateLayers]; end; (fUserInteractions[fUserInteractions.FindInstanceOf(TIECropToolInteraction)] as TIECropToolInteraction).Enabled := miCropTool in v; // Layer Creation (fUserInteractions[fUserInteractions.FindInstanceOf(TIECreateLayerInteraction)] as TIECreateLayerInteraction).Enabled := layerSelection; (fUserInteractions[fUserInteractions.FindInstanceOf(TIECreateLayerInteraction)] as TIECreateLayerInteraction).LayerKind := layerKind; if miRotateLayers in fMouseInteract then begin // We were rotating... if not (miRotateLayers in v) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations // exiting from rotation mode? Anyway fix rotations. end else if loAutoFixBorders in fLayerOptions then LayersFixBorders; // entering rotation mode, fix borders end; fMouseInteract := v; Update(); end; end; // track mouse move for polygonal selection procedure TImageEnView.PolyDraw1; var x, y: integer; begin if fPolySelecting and (not fLassoSelecting) then begin canvas.pen.mode := pmNot; canvas.pen.width := 1; canvas.pen.style := psSolid; with PIEAnimPoly(fHPolySel)^ do if PolyCount > 0 then begin canvas.moveto(fMMoveX, fMMoveY); x := XBmp2Scr( Poly^[PolyCount - 1].x, True ); y := YBmp2Scr( Poly^[PolyCount - 1].y, True ); canvas.lineto(x, y); end; end; end; procedure TImageEnView.DrawMarkOutNavigator(const rc: TRect); var dx, dy: integer; begin if not assigned(fNavigatorBackBuffer) then begin fNavigatorBackBuffer := TIEBitmap.Create(GetClientWidth, GetClientHeight, ie24RGB); fNavigatorBackBuffer.Location := ieTBitmap; end; if (fNavigatorBackBuffer.Width <> GetClientWidth) or (fNavigatorBackBuffer.Height <> GetClientHeight) then fNavigatorBackBuffer.Resize(GetClientWidth, GetClientHeight); with rc do begin dx := imin(right - left, GetClientWidth); dy := imin(bottom - top, GetClientHeight); BitBlt(fNavigatorBackBuffer.Canvas.Handle, left, top, dx, dy, fBackBuffer.Canvas.Handle, left, top, SRCCOPY); with CurrentLayer.DrawingInfo do IEDrawGrayedOut(fNavigatorBackBuffer.Canvas, XDst, YDst, WidthDst, HeightDst, fNavigatorActualRect.Left, fNavigatorActualRect.Top, fNavigatorActualRect.Right, fNavigatorActualRect.Bottom); BitBlt(Canvas.Handle, left, top, dx, dy, fNavigatorBackBuffer.Canvas.Handle, left, top, SRCCOPY); end; end; {!! TImageEnView.PaintRect Declaration procedure PaintRect(const rc: TRect); Description PaintRect repaints only the rectangle rc without waiting for the Windows Paint message. Example // this code paints an image (width=50 height=50) at bitmap coordinates 10,10 ImageEnView1.Bitmap.Canvas.Draw(10, 10, MyBitmap); // map the bitmap coordinates to view coordinates (rc is a TRect type) With ImageEnView1 do rc := rect( XBmp2Scr(10), YBmp2Scr(10), XBmp2Scr(10+50), YBmp2Scr(10+50) ); ImageEnView1.UpdateRect(rc); // update internal ImageEn state ImageEnView1.PaintRect(rc); // paint the changes on the screen !!} procedure TImageEnView.PaintRect(const rc: TRect); var dx, dy: integer; ur: TRect; {$IFDEF IEDEBUG} t1: dword; {$ENDIF} begin if (not HasParentWindow) and (not fOffscreenPaint) then exit; {$IFDEF IEDEBUG} t1 := gettickcount; {$ENDIF} // prepare the back buffer if (fBackBuffer.Width <> GetClientWidth) or (fBackBuffer.Height <> GetClientHeight) then begin fBackBuffer.Allocate(GetClientWidth, GetClientHeight, ie24RGB); fUpdateBackBuffer := true; end; // draw on the back buffer if fUpdateBackBuffer then begin ur := rc; PaintToEx(fBackBuffer, @ur, true, true); if assigned(fOnDrawBackBuffer) then fOnDrawBackBuffer(self); fUpdateBackBuffer := false; end; // draw the back buffer to the canvas with fBitmapInfoHeader256 do begin biSize := sizeof(TBitmapInfoHeader); biWidth := GetClientWidth; biHeight := GetClientHeight; biPlanes := 1; if fBackBuffer.PixelFormat = ie1g then begin biBitCount := 1; Palette[1].rgbRed := 255; Palette[1].rgbGreen := 255; Palette[1].rgbBlue := 255; end else biBitCount := 24; biCompression := BI_RGB; end; {$IFDEF IEINCLUDEDIRECTSHOW} if assigned(fImageEnIO) and assigned(fImageEnIO.DShowParams) and fImageEnIO.DShowParams.RenderVideo and (fImageEnIO.DShowParams.State<>gsStopped) then with CurrentLayer.DrawingInfo do ExcludeClipRect(Canvas.Handle, XDst, YDst, XDst+WidthDst, YDst+HeightDst); {$ENDIF} with rc do begin dx := imin(right - left, GetClientWidth); dy := imin(bottom - top, GetClientHeight); if (fUseDrawDibDraw or (IEGlobalSettings().SystemColors <= 8)) and not IEGlobalSettings().IsRemoteSession then // drawdibdraw. Good for dithering in system with <=256 colors IEDrawDibDraw(fHDrawDib, Canvas.Handle, left, top, dx, dy, PBitmapInfoHeader(@fBitmapInfoHeader256)^, fBackBuffer.Scanline[fBackBuffer.Height - 1], left, top, dx, dy, 0) else begin // new mode if (IEGlobalSettings().SystemColors < 24) and not IEGlobalSettings().IsRemoteSession then begin // dithering needed (for example display with 16bit depth need dithering) SetStretchBltMode(Canvas.Handle, HALFTONE); StretchBlt(Canvas.Handle, left, top, dx, dy, fBackBuffer.Canvas.Handle, left, top, dx, dy, SRCCOPY); end else begin // no dithering needed (fastest way) if fIsNavigator and (ienoMARKOUTER in fNavigatorOptions) then DrawMarkOutNavigator(rc) else BitBlt(Canvas.Handle, left, top, dx, dy, fBackBuffer.Canvas.Handle, left, top, SRCCOPY); end; end; end; {$IFDEF IEDEBUG} //OutputDebugString(PAnsiChar('PaintRect: '+IEIntToStr(gettickcount-t1)+' ms')); {$ENDIF} if fPolySelecting then PolyDraw1; UserInteractions_Paint(rc); if (fOldHandle<>0) and (fOldHandle<>Handle) then IO.RecreatedTImageEnViewHandle; fOldHandle := Handle; end; procedure TImageEnView.DoDrawVersion; var x, y: integer; ss: string; begin with Canvas do begin Font.Name := 'Arial'; Font.Height := 13; Font.Color := clBlack; Brush.style := bsSolid; Brush.Color := clWhite; ss := 'ImageEn Version ' + string(IEMAINVERSION) + ' - ' + IntToStr(IEMAINDATEDD) + '/' + IntToStr(IEMAINDATEMM) + '/' + IntToStr(IEMAINDATEYY); x := ClientWidth - TextWidth(ss) - fRulerParams.RulerAreaRight; y := ClientHeight - TextHeight(ss) - fRulerParams.RulerAreaBottom; TextOut(x, y, ss); end; end; procedure TImageEnView.Paint; var rc: TRect; {$IFDEF IEINCLUDEDIRECTSHOW} x1, y1, nw, nh: Integer; zw, zh: Double; {$ENDIF} begin {$ifdef IEDEBUG} OutputDebugString('TImageEnView.Paint'); {$endif} try if (not HandleAllocated) or ((not HasParentWindow) or (GetClientWidth = 0) or (GetClientHeight = 0)) and not fOffscreenPaint then exit; // environment not ready if csDesigning in ComponentState then begin // draws only the background IEDrawBackground(ComponentState, Canvas, nil, fBackgroundStyle, GetThemeColor( ietpControlBackground, fBackground ), 0, 0, Width, Height, 0, 0, 0, 0, fChessboardSize, fChessboardBrushStyle, fChessboardColor2Customized, GetThemeColor( ietpControlBackgroundGradientEnd, fGradientEndColor ), fWallpaper, fWallpaperStyle, fLiveBackground); end else begin if fLockPaint = 0 then begin // ready to draw if fFullUpdateRequest then rc := Rect(0, 0, GetClientWidth, GetClientHeight) else begin rc := Canvas.ClipRect; if (rc.Right = 0) or (rc.bottom = 0) then begin rc.Right := GetClientWidth; rc.Bottom := GetClientHeight; end; end; // Exclude Rulers rc.Left := imax( rc.Left , fRulerParams.RulerAreaLeft ); rc.Top := imax( rc.Top , fRulerParams.RulerAreaTop ); rc.Right := imin( rc.Right , GetClientWidth() - fRulerParams.RulerAreaRight ); rc.Bottom := imin( rc.Bottom, GetClientHeight() - fRulerParams.RulerAreaBottom ); PaintRect(rc); PaintGuideLines( Canvas ); if Assigned(fOnDrawCanvas) then fOnDrawCanvas(self, Canvas, Rect(0, 0, GetClientWidth, GetClientHeight)); end; fFullUpdateRequest := False; if not fRectMoving then AniPolyFunc(self, false); if assigned(fOnPaint) then OnPaint(self); end; except {$IFDEF IEDEBUG} on E:Exception do OutputDebugStringA(PAnsiChar( '[Paint] ' + e.message + #13#10 )); {$ENDIF} end; if fDrawVersion then DoDrawVersion; // Draw rulers if fLockPaint = 0 then fRulerParams.Paint( Canvas ); if (fInteractionHint <> '') and (fEnableInteractionHints) then IEDrawHint2(Canvas, fInteractionHintX, fInteractionHintY, fInteractionHint, fInteractionHintMinText); {$IFDEF IEINCLUDEDIRECTSHOW} // synchronize directshow video rendering with current layer if assigned(fImageEnIO) and assigned(fImageEnIO.DShowParams) and fImageEnIO.DShowParams.RenderVideo and (fImageEnIO.DShowParams.State<>gsStopped) then begin with CurrentLayer.DrawingInfo do begin // Ensure an image layer is active if ( fLayersCurrent > -1 ) and ( Layers[ fLayersCurrent ].Kind <> ielkImage ) then SetLayersCurrent( 0 ); // Base layer always image fImageEnIO.DShowParams.GetVideoRenderNativeSize(nw, nh); if (nw > 0) and (nh > 0) and (CurrentLayer.Bitmap.Width > 0) and (CurrentLayer.Bitmap.Height > 0) then begin zw := CurrentLayer.Bitmap.Width / nw; zh := CurrentLayer.Bitmap.Height / nh; x1 := trunc(XSrc/zw); y1 := trunc(YSrc/zh); nw := trunc(WidthSrc/zw); nh := trunc(HeightSrc/zh); fImageEnIO.DShowParams.SetVideoRenderRect( Rect(x1, y1, x1+nw, y1+nh), Rect(XDst, YDst, XDst+WidthDst, YDst+HeightDst) ); end; end; end; {$ENDIF} if fAutoCursors and fFirstTimeSetCursor then begin SetCursor( Cursor ); fFirstTimeSetCursor := false; end; end; procedure TImageEnView.TerminatePolySelection(shift: Boolean; removeLastPoint: Boolean); begin if removeLastPoint then AnimPolygonRemoveLastPoint(fHPolySel); if (not shift) or (not fEnableShiftKey) then fSelectionMask.Empty; EndSelect; UpdateReason := ieurSelectionChanged; Update; fPolySelecting := False; DoSelectionChange; end; procedure TImageEnView.DoDoubleClickEx(Shift: boolean); begin if fPolySelecting and (not fLassoSelecting) then TerminatePolySelection(Shift, true); end; procedure TImageEnView.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); begin inherited; {$IFNDEF OCXVERSION} if (csReading in ComponentState) or (csDesigning in ComponentState) or (csLoading in ComponentState) then if fIEBitmapValid then begin fIEBitmap.Width := Width; fIEBitmap.Height := Height; Clear; end; {$ENDIF} end; {!! TImageEnView.PolySelPoints Declaration property PolySelPoints: ; Description PolySelPoints returns the current selection as a pointer to an array of TPoint. Example // Copies current selection to ImageEnView2. Then enhance contrast of ImageEnView2 and copy back to ImageEnView1 (in some selection). ImageEnView2.CopyFromPolygon(ImageEnView1.Bitmap, ImageEnView2.PolySelPoints^, ImageEnView2.PolySelCount, Point(0, 0)); ImageEnView2.Proc.Contrast(30); ImageEnView2.CopyToPolygon(ImageEnView1.Bitmap, ImageEnView1.PolySelPoints^, ImageEnView1.PolySelCount, Point(0, 0)); ImageEnView1.Update; !!} function TImageEnView.GetPolySelArray: PPointArray; begin result := PIEAnimPoly(fHPolySel)^.Poly; end; {!! TImageEnView.PolySel Declaration property PolySel[idx: Integer]: TPoint; (Read-only) Description Returns the idx point of the current polygonal selection. The point is specified in bitmap coordinates. Example var MyPolySelArray: array of TPoint; I: Integer; begin // Create an array of TPoints of the polygon selection in a TImageEnView SetLength( MyPolySelArray, ImageEnView1.PolySelCount ); for I := 0 to ImageEnView1.PolySelCount - 1 do MyPolySelArray[ I ] := ImageEnView1.PolySel[ I ]; end; See Also - - - !!} function TImageEnView.GetPolySel(idx: integer): TPoint; begin result := Point(0, 0); with PIEAnimPoly(fHPolySel)^ do if (idx >= 0) and (idx <= PolyCount) then begin if Poly^[idx].X = IESELBREAK then result := Poly^[idx] // break code else result := Point(Poly^[idx].X, Poly^[idx].Y); end; end; {!! TImageEnView.PolySelCount Declaration property PolySelCount: Integer; (Read-only) Description Returns the points number of the current polygonal selection (size of array). Example var MyPolySelArray: array of TPoint; I: Integer; begin // Create an array of TPoints of the polygon selection in a TImageEnView SetLength( MyPolySelArray, ImageEnView1.PolySelCount ); for I := 0 to ImageEnView1.PolySelCount - 1 do MyPolySelArray[ I ] := ImageEnView1.PolySel[ I ]; end; See Also - - !!} function TImageEnView.GetPolySelCount: integer; begin result := PIEAnimPoly(fHPolySel)^.PolyCount; end; {!! TImageEnView.Deselect Declaration procedure Deselect; Description This method removes current selection. After Deselect is called, the property will be false. !!} procedure TImageEnView.Deselect; begin if fSel then begin fSel := false; HideSelectionEx(true); end; AnimPolygonClear(fHPolySel); fSelectionMask.Empty; fSel := false; fPolySelecting := false; fLassoSelecting := false; fRectSelecting := False; fCircSelecting := False; fRectResizing := ieNone; fSelectMoving := -1; RestoreCursor; UpdateReason := ieurSelectionChanged; Update; end; {!! TImageEnView.Select Declaration procedure Select(x1, y1, x2, y2: integer; Op: = iespReplace); virtual; Description This method selects a portion of the image. The selected area will be outlined with an animated rectangle. If is iesbClientArea (default) all coordinates depend on actual zoom and scrolling. If SelectionBase is iesbBitmap, all coordinates refer to bitmap pixels. Parameter Description x1 Top-left horizontal position y1 Top-left vertical position x2 Bottom-right horizontal position. Last column not selected y2 Bottom-right vertical position. Last row not selected Op Selection operation (add or replace selection). If Op is iespReplace, Select replaces all previous selections. If Op is iespAdd, Select adds a new selection
x2, y2 represent the right/bottom margin (not selected). To select an area of 1x1 pixels we need to select using 0,0,1,1 (the column 1 and the row 1 aren't selected). Example // Increase contrast of bitmap rectangle (0,0,49,49) ImageEnView1.SelectionBase := iesbBitmap; ImageEnView1.Select(0, 0, 50, 50); ImageEnView1.Proc.Contrast(10); ImageEnView1.Deselect; // Enlarge the selection by ten pixels on all sides With ImageEnView1 do begin SelectionBase := iesbBitmap; Select( SelX1 - 10, SelY1 - 10, SelX2 - 10, SelY2 - 10 ); End; See Also -
- - - - - - - - !!} // x2,y2 represent the right/bottom margin (not selected) // to select an area of 1x1 pixels we need to select using 0,0,1,1 (the column 1 and the // row 1 aren't selected) procedure TImageEnView.Select(x1, y1, x2, y2: integer; Op: TIESelOp); begin if fIsNavigator then LockPaint; SelectEx(x1, y1, x2, y2, Op, false, false); if Op = iespReplace then fSelectionMask.Empty; EndSelect; if not fIsNavigator then // 3.0.3: to speed-up scrolling when navigator has a ZoomFilter fUpdateBackBuffer := true; if fIsNavigator then begin NPUnLockPaint; AniPolyFunc(self, true); Paint; AniPolyFunc(self, true); end else Paint; end; {!! TImageEnView.SelectEllipse Declaration procedure SelectEllipse(CenterX, CenterY, Width, Height: Integer; Op: = iespReplace); Description SelectEllipse makes an elliptical selection, centered at CenterX and CenterY, and with size specified by Width and Height. Op specifies whether to add a new selection (iespAdd) or replace the current one (iespReplace). Example ImageEnView.SelectEllipse( 100, 100, 20, 20 ); !!} procedure TImageEnView.SelectEllipse(CenterX, CenterY, Width, Height: integer; Op: TIESelOp); var dx, dy, p, g, xx, yy: integer; begin if fSelectionBase = iesbClientArea then begin CenterX := XScr2Bmp( CenterX, True ); CenterY := YScr2Bmp( CenterY, True ); Width := trunc(Width * f100DZoomX); Height := trunc(Height * f100DZoomY); end; if (Width <= 0) or (Height <= 0) then exit; fSel := true; if (Op = iespAdd) and (PIEAnimPoly(fHPolySel)^.PolyCount > 0) then AnimPolygonAddBreak(fHPolySel) else begin AnimPolygonClear(fHPolySel); end; dx := Width div 2; dy := Height div 2; p := trunc(2 * pi * imin(dx, dy)) shr 2; if p < 3 then p := 3; for g := 0 to p - 1 do begin xx := round(CenterX + cos((2 * pi / p) * g) * dx); yy := round(CenterY + sin((2 * pi / p) * g) * dy); xx := imax(0, imin(fIEBitmap_Width, xx)); yy := imax(0, imin(fIEBitmap_Height, yy)); AnimPolygonAddPtEx(fHPolySel, xx, yy); end; if Op = iespReplace then fSelectionMask.Empty; EndSelect; fUpdateBackBuffer := true; Paint; ShowSelectionEx(true); end; {!! TImageEnView.SelectRoundRect Declaration procedure SelectRoundRect(Left, Top, Right, Bottom, RoundWidth, RoundHeight: integer; Op: = iespReplace); Description Creates a rounded selection. Left, Top, Right, Bottom are the rectangle coordinates. RoundWidth and RoundHeight specify the size of the rounding (in pixels). Op specifies whether to add a new selection (iespAdd) or replace the current one (iespReplace). Example ImageEnView1.SelectRoundRect(100, 100, 250, 250, 20, 20); !!} procedure TImageEnView.SelectRoundRect(Left, Top, Right, Bottom, RoundWidth, RoundHeight: integer; Op: TIESelOp); var nsteps: Integer; ptr: ppointarray; i: Integer; xrect: TRect; procedure AddPt(xx, yy: Integer); begin xx := imax(0, imin(fIEBitmap_Width, xx)); yy := imax(0, imin(fIEBitmap_Height, yy)); AnimPolygonAddPtEx(fHPolySel, xx, yy); end; begin if fSelectionBase = iesbClientArea then begin Left := XScr2Bmp( Left, True ); Top := YScr2Bmp( Top, True ); Right := XScr2Bmp( Right, True ); Bottom := YScr2Bmp( Bottom, True ); RoundWidth := trunc(RoundWidth * f100DZoomX); RoundHeight := trunc(RoundHeight * f100DZoomY); end; fSel := true; if (Op = iespAdd) and (PIEAnimPoly(fHPolySel)^.PolyCount > 0) then AnimPolygonAddBreak(fHPolySel) else AnimPolygonClear(fHPolySel); xrect := rect(Left, Top, Right, Bottom); nsteps := RoundWidth * RoundHeight; getmem(ptr, sizeof(TPoint) * nsteps); try // top-left round IEBezier2D4Controls(Point(xrect.Left, xrect.Top+RoundHeight), xrect.TopLeft, Point(xrect.Left+RoundWidth, xrect.Top), Point(xrect.Left+RoundWidth, xrect.Top), ptr, nsteps); for i := 0 to nsteps-1 do AddPt( ptr[i].x, ptr[i].y ); // top-right round IEBezier2D4Controls(Point(xrect.Right, xrect.Top+RoundHeight), Point(xrect.Right, xrect.Top), Point(xrect.Right-RoundWidth, xrect.Top), Point(xrect.Right-RoundWidth, xrect.Top), ptr, nsteps); for i := nsteps-1 downto 0 do AddPt( ptr[i].x, ptr[i].y ); // bottom-right round IEBezier2D4Controls(Point(xrect.Right, xrect.Bottom-RoundHeight), Point(xrect.Right, xrect.Bottom), Point(xrect.Right-RoundWidth, xrect.Bottom), Point(xrect.Right-RoundWidth, xrect.Bottom), ptr, nsteps); for i := 0 to nsteps-1 do AddPt( ptr[i].x, ptr[i].y ); // bottom-left round IEBezier2D4Controls(Point(xrect.Left, xrect.Bottom-RoundHeight), Point(xrect.Left, xrect.Bottom), Point(xrect.Left+RoundWidth, xrect.Bottom), Point(xrect.Left+RoundWidth, xrect.Bottom), ptr, nsteps); for i := nsteps-1 downto 0 do AddPt( ptr[i].x, ptr[i].y ); finally freemem(ptr); end; if Op = iespReplace then fSelectionMask.Empty; EndSelect; fUpdateBackBuffer := true; Paint; ShowSelectionEx(true); end; procedure AdjustRectangle(var x1, y1, x2, y2: Integer; Width, Height: Integer); begin if x1<0 then begin x2 := x2-x1; x1 := 0; end; if y1<0 then begin y2 := y2-y1; y1 := 0; end; if x2>=Width then begin x1 := x1-(x2-Width+1); x2 := Width-1; end; if y2>=Height then begin y1 := y1-(y2-Height+1); y2 := Height-1; end; end; // x2, y2 represent the right/bottom margin (not selected) // to select an area of 1x1 pixels we need to select using 0, 0, 1, 1 (the column 1 and the // row 1 aren't selected) // IT DO NOT CALL "EndSelect" // if adjRect is true, move the rectangle to make it inside the bitmap procedure TImageEnView.SelectEx(x1, y1, x2, y2: integer; Op: TIESelOp; aspectratio: boolean; adjRect: Boolean); begin if (x1 = x2) or (y1 = y2) then exit; if fSelectionBase = iesbClientArea then begin x1 := XScr2Bmp( x1, True ); y1 := YScr2Bmp( y1, True ); x2 := XScr2Bmp( x2, True ); y2 := YScr2Bmp( y2, True ); end; fSel := true; if (Op = iespAdd) and (PIEAnimPoly(fHPolySel)^.PolyCount > 0) then AnimPolygonAddBreak(fHPolySel) else begin AnimPolygonClear(fHPolySel); end; if (Op = iespReplace) then fSelectionMask.Empty; if aspectratio and (fSelectionAspectRatio = -1) then y2 := round(x2 - x1 + 1 + y1 - 1) else if fSelectionAspectRatio > 0 then begin y2 := y1 + round((x2 - x1) * fSelectionAspectRatio); if y2 >= fIEBitmap_Height then x2 := round( (fIEBitmap_Height-1-y1+x1*fSelectionAspectRatio)/fSelectionAspectRatio ); if y2 < 0 then x2 := round( (0-y1+x1*fSelectionAspectRatio)/fSelectionAspectRatio ); end; if adjRect then AdjustRectangle(x1, y1, x2, y2, fIEBitmap_Width, fIEBitmap_Height); OrdCor(x1, y1, x2, y2); x1 := imax(0, imin(fIEBitmap_Width - 1, x1)); y1 := imax(0, imin(fIEBitmap_Height - 1, y1)); x2 := imax(0, imin(fIEBitmap_Width - 0, x2)); y2 := imax(0, imin(fIEBitmap_Height - 0, y2)); AnimPolygonAddPtEx(fHPolySel, x1, y1); AnimPolygonAddPtEx(fHPolySel, x2, y1); AnimPolygonAddPtEx(fHPolySel, x2, y2); AnimPolygonAddPtEx(fHPolySel, x1, y2); ShowSelectionEx(true); end; {!! TImageEnView.SelectCustom Declaration procedure SelectCustom; Description Call SelectCustom after you have specified a pixmap of selected pixels of the image. To select a pixmap use methods like . Example // only pixels at 10,10 and 15,15 are selected ImageEnView.SelectionMask.SetPixel(10, 10, 1); ImageEnView.SelectionMask.SetPixel(15, 15, 1); ImageEnView.SelectCustom(); See Also - !!} procedure TImageEnView.SelectCustom; begin fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; {!! TImageEnView.SelectMagicWand Declaration procedure SelectMagicWand(x, y: Integer; Op: ); Description SelectMagicWand selects an irregular region that has similar colors. Parameter Description x Starting horizontal coordiante y Starting vertical coordinate Op If Op is iespReplace the region replaces the existing selection, otherwise if Op is iespAdd, the region is appended to the existing selection
Example ImageEnView1.SelectMagicWand(10, 10, iespReplace); !!} procedure TImageEnView.SelectMagicWand(x, y: integer; Op: TIESelOp); var points: TIEArrayOfTPoint; q: integer; xx, yy: integer; begin SetLength(points, 0); if fSelectionBase = iesbClientArea then begin x := XScr2Bmp( x, True ); y := YScr2Bmp( y, True ); end; if (fIEBitmapValid = False) or (x < 0) or (x > fIEBitmap.Width) or (y < 0) or (y > fIEBitmap.Height) then exit; case fMagicWandMode of iewInclusive: begin points := IEMakeMagicWandPoints(fIEBitmap, x, y, fMagicWandMaxFilter, fMagicWandTolerance); if length(points) > 0 then begin fSel := true; if (Op = iespAdd) and (PIEAnimPoly(fHPolySel)^.PolyCount > 0) then AnimPolygonAddBreak(fHPolySel) else begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; for q := 0 to length(points) - 1 do begin xx := imin(imax(0, points[q].x), fIEBitmap.Width); yy := imin(imax(0, points[q].y), fIEBitmap.Height); AnimPolygonAddPtEx(fHPolySel, xx, yy); end; if Op = iespReplace then fSelectionMask.Empty; EndSelect; ShowSelectionEx(true); end; end; iewExclusive: begin if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; _MakeMagicWandPointsEx(fIEBitmap, x, y, fMagicWandMaxFilter, fMagicWandTolerance, fSelectionMask, fSelectionIntensity); fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); end; iewGlobal: begin if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; _MakeMagicWandPointsEx2(fIEBitmap, x, y, fMagicWandTolerance, fSelectionMask, fSelectionIntensity); fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); end; end; fUpdateBackBuffer := true; Paint; end; {!! TImageEnView.SelectColors Declaration procedure SelectColors(StartColor, FinalColor:
; Op: = iespReplace); procedure SelectColors(Color: ; Op: = iespReplace); procedure SelectColors(ColorIndex: integer; Op: = iespReplace); Description Selects all colors inside the range StartColor up to FinalColor, or specific color or a color index. If Op is iespReplace the region replaces the existing selection, otherwise if Op is iespAdd, the region is appended to the existing selection. Third overload accepts ColorIndex, which is the index of a color in image colormap: the bitmat pixelformat must be ie8p (palette). Example // select from 200,200,200 to 255,255,255 ImageEnView1.SelectColors(CreateRGB(200, 200, 200), CreateRGB(255, 255, 255)); // select only color 255,0,0 (pure red) ImageEnView1.SelectColors(CreateRGB(255, 0, 0)); // select color index 5 of a paletted bitmap (ie8p) ImageEnView1.SelectColors(5); See Also - - - - !!} procedure TImageEnView.SelectColors(StartColor, FinalColor: TRGB; Op: TIESelOp); var i, j: integer; ww, hh: integer; r1, g1, b1, r2, g2, b2: byte; p_rgb: PRGB; begin if fIEBitmapValid = False then exit; if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; r1 := StartColor.r; g1 := StartColor.g; b1 := StartColor.b; r2 := FinalColor.r; g2 := FinalColor.g; b2 := FinalColor.b; ww := fIEBitmap.Width; hh := fIEBitmap.Height; case fIEBitmap.PixelFormat of ie24RGB: begin for i := 0 to hh - 1 do begin p_rgb := fIEBitmap.ScanLine[i]; for j := 0 to ww - 1 do begin with p_rgb^ do if (r >= r1) and (g >= g1) and (b >= b1) and (r <= r2) and (g <= g2) and (b <= b2) then fSelectionMask.SetPixel(j, i, fSelectionIntensity); inc(p_rgb); end; end; end; else begin for i := 0 to hh - 1 do for j := 0 to ww - 1 do with fIEBitmap.Pixels[j, i] do if (r >= r1) and (g >= g1) and (b >= b1) and (r <= r2) and (g <= g2) and (b <= b2) then fSelectionMask.SetPixel(j, i, fSelectionIntensity); end; end; fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; procedure TImageEnView.SelectColors(Color: TRGB; Op: TIESelOp); var i, j: integer; ww, hh: integer; rr, gg, bb: byte; p_rgb: PRGB; begin if fIEBitmapValid = False then exit; if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; rr := Color.r; gg := Color.g; bb := Color.b; ww := fIEBitmap.Width; hh := fIEBitmap.Height; case fIEBitmap.PixelFormat of ie24RGB: begin for i := 0 to hh - 1 do begin p_rgb := fIEBitmap.ScanLine[i]; for j := 0 to ww - 1 do begin with p_rgb^ do if (r = rr) and (g = gg) and (b = bb) then fSelectionMask.SetPixel(j, i, fSelectionIntensity); inc(p_rgb); end; end; end; else begin for i := 0 to hh - 1 do for j := 0 to ww - 1 do with fIEBitmap.Pixels[j, i] do if (r = rr) and (g = gg) and (b = bb) then fSelectionMask.SetPixel(j, i, fSelectionIntensity); end; end; fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; procedure TImageEnView.SelectColors(ColorIndex: integer; Op: TIESelOp); var i, j: integer; ww, hh: integer; begin if ( fIEBitmapValid = False ) or ( fIEBitmap.PixelFormat <> ie8p ) then exit; if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; ww := fIEBitmap.Width; hh := fIEBitmap.Height; for i := 0 to hh - 1 do for j := 0 to ww - 1 do if fIEBitmap.Pixels_ie8[j, i] = ColorIndex then fSelectionMask.SetPixel(j, i, fSelectionIntensity); fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; {!! TImageEnView.SelectNonAlpha Declaration procedure SelectNonAlpha(Op: = iespReplace); Description Selects all pixels based on the alpha channel. Pixels of Alpha value 0 will be unselected, 255 will be selected, and 1 - 254 partially selected. If Op is iespReplace the region replaces the existing selection, otherwise if Op is iespAdd, the region is appended to the existing selection. Example // Load a transparent PNG file and select the non-alpha pixels ImageEnView1.IO.LoadFromFile( 'D:\Transparent.png' ); ImageEnView1.SelectNonAlpha(); See Also - !!} procedure TImageEnView.SelectNonAlpha(Op: TIESelOp = iespReplace); var i, j: integer; ww, hh: integer; begin if ( fIEBitmapValid = False ) or ( fEnableAlphaChannel = False ) then exit; if (Op = iespReplace) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Empty; end; ww := fIEBitmap.AlphaChannel.Width; hh := fIEBitmap.AlphaChannel.Height; for i := 0 to hh - 1 do for j := 0 to ww - 1 do fSelectionMask.SetPixel( j, i, fIEBitmap.AlphaChannel.Pixels_ie8[ j, i ]); fSel := not fSelectionMask.IsEmpty; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; procedure AdjustRectWithRatio(var x1, y1, x2, y2: Integer; lx1, ly1, lx2, ly2: Integer; Width, Height: Integer; z: Double); begin z := 1/z; if y2>=Height then x2 := round( (Height-1-y1+x1*z)/z ) else if y1<0 then x1 := round( (-y2+0+x2*z)/z ) else if x2>=Width then y2 := round( y1+(Width-1-x1)*z ) else if x1<0 then y1 := round( y2-(x2-0)*z ); end; // Resize selection // newx, newy: new point in client coords // return new grip if changed function TImageEnView.SelectResizeEx(grip: TIEGrip; newx, newy: integer; aspectratio: boolean): TIEGrip; var x1, y1, x2, y2, w, h: integer; z: double; begin z := 1; result := grip; with PIEAnimPoly(fHPolySel)^ do if _IsRectangle(Poly, PolyCount) then begin newx := XScr2Bmp( newx, True ); newy := YScr2Bmp( newy, True ); if aspectratio then begin w := flx2 - flx1 + 1; h := fly2 - fly1 + 1; if h = 0 then exit; if fSelectionAspectRatio>0 then z := 1/fSelectionAspectRatio else z := w / h; case grip of ieTopLeft: // left-top while true do begin newy := round((-flx2 + newx - 1 + z * fly2 + z) / z); if newy >= 0 then break; inc(newx); end; ieTopRight: // right-top while true do begin newy := round((-newx + flx1 - 1 + z * fly2) / z); if newy >= 0 then break; dec(newx); end; ieBottomRight: // right-bottom newy := round((newx - flx1 + 1 + z * fly1 - z) / z); ieBottomLeft: // left-bottom while true do begin newy := round((flx2 - newx + 1 + fly1 * z + z) / z); if newy<=fIEBitmap_Height then break; inc(newx); end; ieLeftSide: // left side begin while true do begin newy := round((-flx2 + newx - 1 + z * fly2 + z) / z); if newy >= 0 then break; inc(newx); end; grip := ieTopLeft; end; ieRightSide: // right side begin newy := round((newx - flx1 + 1 + z * fly1 - z) / z); grip := ieBottomRight; end; ieTopSide: // top side begin while true do begin newx := round(-z * fly2 + z * newy - z + flx2 + 1); if newx >= 0 then break; inc(newy); end; grip := ieTopLeft; end; ieBottomSide: // bottom side begin while true do begin newx := round(z * newy - z * fly1 + z + flx1 - 1); if newx<=fIEBitmap_Width then break; dec(newy); end; grip := ieBottomRight; end; end; end; if (grip = ieTopRight) or (grip = ieBottomRight) or (grip = ieRightSide) then inc(newx); if (grip = ieBottomRight) or (grip = ieBottomLeft) or (grip = ieBottomSide) then inc(newy); x1 := RX1; y1 := RY1; x2 := RX2; y2 := RY2; case grip of ieTopLeft, ieBottomLeft, ieLeftSide: // left begin x1 := newx; if x1 = x2 then dec(x1); end; ieTopRight, ieBottomRight, ieRightSide: // right begin x2 := newx; if x1 = x2 then inc(x2); end; end; case grip of ieTopLeft, ieTopRight, ieTopSide: // top begin y1 := newy; if y1 = y2 then dec(y1); end; ieBottomRight, ieBottomLeft, ieBottomSide: // bottom begin y2 := newy; if y1 = y2 then inc(y2); end; end; if x1 > x2 then begin if (result = ieTopLeft) then result := ieTopRight // from left-top to right-top else if (result = ieBottomLeft) then result := ieBottomRight // from left-bottom to right-bottom else if (result = ieTopRight) then result := ieTopLeft // from right-top to left-top else if (result = ieBottomRight) then result := ieBottomLeft // from right-bottom to left-bottom else if (result = ieLeftSide) then result := ieRightSide // from left side to right side else if (result = ieRightSide) then result := ieLeftSide; // from right side to left side end; if y1 > y2 then begin if (result = ieTopRight) then result := ieBottomRight // from right-top to right-bottom else if (result = ieTopLeft) then result := ieBottomLeft // from left-top to left-bottom else if (result = ieBottomRight) then result := ieTopRight // from right-bottom to right-top else if (result = ieBottomLeft) then result := ieTopLeft // from left-bottom to left-top else if (result = ieTopSide) then result := ieBottomSide // from top side to bottom side else if (result = ieBottomSide) then result := ieTopSide; // from bottom side to top side end; AnimPolygonClear(fHPolySel); OrdCor(x1, y1, x2, y2); if aspectratio then AdjustRectWithRatio(x1, y1, x2, y2, flx1, fly1, flx2, fly2, fIEBitmap_Width, fIEBitmap_Height, z); x1 := imax(0, imin(fIEBitmap_Width, x1)); y1 := imax(0, imin(fIEBitmap_Height, y1)); x2 := imax(0, imin(fIEBitmap_Width, x2)); y2 := imax(0, imin(fIEBitmap_Height, y2)); OrdCor(x1, y1, x2, y2); AnimPolygonAddPtEx(fHPolySel, x1, y1); AnimPolygonAddPtEx(fHPolySel, x2, y1); AnimPolygonAddPtEx(fHPolySel, x2, y2); AnimPolygonAddPtEx(fHPolySel, x1, y2); ShowSelectionEx(true); end; end; // Move selection // fMoving must be 0 // ox, oy are moving offsets function TImageEnView.SelectMoveEx(fMoving, ox, oy: integer; cutBorders: Boolean): integer; begin result := fMoving; with PIEAnimPoly(fHPolySel)^ do fRectMoving := _IsRectangle(Poly, PolyCount); if not fRectMoving then begin fSelectionMask.TranslateBitmap(ox, oy, cutBorders); // modify ox and oy end else begin fSelectionMask.Empty; // moving a rectangle, full handled by AnimPolygonMove end; if (ox = 0) and (oy = 0) then exit; AnimPolygonMove(fHPolySel, ox, oy, fIEBitmap_Width, fIEBitmap_Height, cutBorders); AniPolyFunc(self, true); if fIsNavigator then begin Paint; AniPolyFunc(self, true); end; end; {!! TImageEnView.MoveSelection Declaration procedure MoveSelection(MoveX, MoveY: Integer; Sizing: Boolean = False); Description Moves the current selection by the specified horizontal and vertical offsets. If Sizing is true then selection is resized (top-left position does not move). Example // Move the selection up and left 5 pixels ImageEnView.MoveSelection( -5, -5 ); // Enlarge the selection vertically and horizontally by 10 pixels ImageEnView.MoveSelection( 10, 10 ); !!} procedure TImageEnView.MoveSelection(MoveX, MoveY: integer; Sizing: Boolean = False); var prevSelectionBase: TIESelectionBase; begin if Sizing then begin // SIZING // allows to work when SelectionBase is iesbClientArea prevSelectionBase := fSelectionBase; fSelectionBase := iesbBitmap; // watch for sels less than 1 if MoveX < -1 * (SelX2 - SelX1 - 1) then MoveX := -1 * (SelX2 - SelX1 - 1); if MoveY < -1 * (SelY2 - SelY1 - 1) then MoveY := -1 * (SelY2 - SelY1 - 1); // Note: Sizing will probably fail if Offset is small and aspect ratio is enforced Select( SelX1, SelY1, SelX2 + MoveX + 1, SelY2 + MoveY + 1, iespReplace ); fSelectionBase := prevSelectionBase; end else begin // MOVING SelectMoveEx(0, MoveX, MoveY, iesoCutBorders in fSelectionOptions); EndSelect; end; end; {!! TImageEnView.AddSelPoint Declaration procedure AddSelPoint(x, y: Integer); Description AddSelPoint adds a point to the current polygonal selection. If is iesbClientArea (default), all coordinates depend upon actual zoom and scrolling. Otherwise, if SelectionBase is iesbBitmap all coordinates refer to bitmap pixels. Use to terminate selection by code. Example // Create a polygon selection from an array of TPoints for I := Low( MyPolySelArray ) to High( MyPolySelArray ) do ImageEnView1.AddSelPoint( MyPolySelArray[ I ].x, MyPolySelArray[ I ].y ); ImageEnView1.EndSelect(); See Also - - - !!} // add a point to current selection // To deselect use Deselect procedure TImageEnView.AddSelPoint(x, y: integer); begin AddSelPointEx(x, y); fUpdateBackBuffer := true; Paint; end; // Same as AddSelPoint // add a point to current selection // To deselect use Deselect // DO NOT CALL "EndSelect" procedure TImageEnView.AddSelPointEx(x, y: integer); begin if fSelectionBase = iesbClientArea then begin x := XScr2Bmp( x, True ); y := YScr2Bmp( y, True ); x := imax(0, imin(fIEBitmap_Width, x)); y := imax(0, imin(fIEBitmap_Height, y)); end; AnimPolygonAddPt(fHPolySel, x, y); ShowSelectionEx(true); end; {!! TImageEnView.DelLastSelPoint Declaration procedure DelLastSelPoint(); Description Removes the last inserted selection point. Example // Pressing ESC removes last polygon point (when MouseInteract = [miSelectPolygon]) procedure TForm1.ImageEnVect1KeyPress(Sender: TObject; var Key: Char); begin if key = #27 then ImageEnView1.DelLastSelRegion(); end; !!} procedure TImageEnView.DelLastSelPoint(); begin if PIEAnimPOly(fHPolySel)^.PolyCount > 1 then begin AnimPolygonRemoveLastPoint(fHPolySel); fUpdateBackBuffer := true; Paint; end; end; {!! TImageEnView.AddSelBreak Declaration procedure AddSelBreak; Description AddSelBreak ends the current selection and begins a new selection. !!} // add a "break" to insert a new selection procedure TImageEnView.AddSelBreak; begin AddSelBreakEx; end; // add a "break" to insert a new selection // DO NOT CALL "EndSelect" procedure TImageEnView.AddSelBreakEx; begin if PIEAnimPoly(fHPolySel)^.PolyCount > 0 then AnimPolygonAddBreak(fHPolySel); end; // Show current selection // d=true : draw now // d=false : draw at next timer tick procedure TImageEnView.ShowSelectionEx(d: boolean); begin PIEAnimPoly(fHPolySel)^.Enabled := True; if d then AniPolyFunc(self, true); end; // Hides current selection // dd=true : remove selection performing a Paint // dd=false : do not remove selection now procedure TImageEnView.HideSelectionEx(dd: boolean); begin PIEAnimPoly(fHPolySel)^.Enabled := False; if dd and (fLockPaint = 0) then Paint; end; procedure TImageEnView.SetVisibleSelection(vv: boolean); begin fVisibleSelection := vv; if vv then ShowSelectionEx(true) else HideSelectionEx(true); UpdateReason := ieurSelectionChanged; Update; end; {!! TImageEnView.VisibleSelection Declaration property VisibleSelection: Boolean; Description When true the current selection is displayed. This property is still valid when the selection is hidden. !!} function TImageEnView.GetVisibleSelection: boolean; begin result := fVisibleSelection; end; {!! TImageEnView.SelectionOptions Declaration property SelectionOptions: ; Description Provides access to selection behavior options. Default: SelectionOptions = [iesoAnimated, iesoSizeable, iesoMoveable, iesoCanScroll, iesoAllowMoveByKeyboard]; !!} procedure TImageEnView.SetSelectionOptions(v: TIESelectionOptions); begin fSelectionOptions := v; with PIEAnimPoly(fHPolySel)^ do begin Animated := iesoAnimated in fSelectionOptions; Sizeable := iesoSizeable in fSelectionOptions; ShowCenter := iesoShowCenter in fSelectionOptions; end; UpdateReason := ieurSelectionChanged; Update; end; // reset vertex number of the animated polygon "ap" {!! TImageEnView.AnimPolygonClear Declaration procedure AnimPolygonClear(ap: pointer); Description Removes all points of the specified polygon. !!} procedure TImageEnView.AnimPolygonClear(ap: pointer); begin with PIEAnimPOly(ap)^ do begin freemem(Poly); GetMem(Poly, 0); PolyCount := 0; PolyCapacity := 0; end; if fLockPaint = 0 then Paint; end; // Removes last added sub-polygon procedure TImageEnView.AnimPolygonRemoveLast(ap: pointer); var q: integer; begin with PIEAnimPoly(ap)^ do for q := PolyCount - 1 downto 0 do if (Poly^[q].x = IESELBREAK) or (q = 0) then begin PolyCount := q; if PolyCount = 0 then AnimPolygonClear(ap) else if fLockPaint = 0 then Paint; break; end; end; // removes last point procedure TImageEnView.AnimPolygonRemoveLastPoint(ap: pointer); begin with PIEAnimPoly(ap)^ do begin dec(PolyCount); while (PolyCount > 0) and (Poly^[PolyCount - 1].x = IESELBREAK) do dec(PolyCount); end; end; // Add a "break" in the animated polygon procedure TImageEnView.AnimPolygonAddBreak(ap: pointer); var tmp: PPointArray; begin with PIEAnimPoly(ap)^ do begin if PolyCount = PolyCapacity then begin PolyCapacity := imax(PolyCapacity*2, PolyCount+1); GetMem(tmp, sizeof(TPoint) * PolyCapacity); if PolyCount > 0 then begin CopyMemory(tmp, Poly, sizeof(TPoint) * PolyCount); FreeMem(Poly); end; Poly := tmp; end; if (PolyCount > 0) and (Poly^[PolyCount - 1].x = IESELBREAK) then exit; Poly^[PolyCount] := Point(IESELBREAK, IESELBREAK); inc(PolyCount); end; end; // add a vertex to animated polygon "ap", doesn't paint procedure TImageEnView.AnimPolygonAddPtEx(ap: pointer; x, y: integer); var tmp: PPointArray; begin // add a point with PIEAnimPoly(ap)^ do begin if PolyCount = PolyCapacity then begin PolyCapacity := imax(PolyCapacity*2, PolyCount+1); GetMem(tmp, sizeof(TPoint) * PolyCapacity); if PolyCount > 0 then begin CopyMemory(tmp, Poly, sizeof(TPoint) * PolyCount); FreeMem(Poly); end; Poly := tmp; end; Poly^[PolyCount] := Point(x, y); inc(PolyCount); // calc rectangle if PolyCount = 2 then begin // only two points RX1 := Poly^[0].x; RY1 := Poly^[0].y; RX2 := Poly^[1].x; RY2 := Poly^[1].y; OrdCor(RX1, RY1, RX2, RY2); end else if PolyCount > 2 then begin // more than two points (R__ are already valid) RX1 := imin(RX1, x); RY1 := imin(RY1, y); RX2 := imax(RX2, x); RY2 := imax(RY2, y); end; end; fSel := true; end; procedure TImageEnView.AnimPolygonEnabled(ap: pointer; Value: Boolean); begin with PIEAnimPoly(ap)^ do Enabled := Value; AniPolyFunc(self, true); end; // move the polygon procedure TImageEnView.AnimPolygonMove(ap: pointer; ox, oy: integer; max_x, max_y: integer; CutSel: boolean); var q: integer; {} procedure LimitOXOY; begin with PIEAnimPoly(ap)^ do begin if (ox + RX1) < 0 then dec(ox, (ox + RX1)); if (ox + RX2) >= max_x then dec(ox, (ox + RX2 - max_x + 0)); if (oy + RY1) < 0 then dec(oy, (oy + RY1)); if (oy + RY2) >= max_y then dec(oy, (oy + RY2 - max_y + 0)); end; end; {} begin if (ox = 0) and (oy = 0) then exit; if fLockPaint = 0 then Paint; with PIEAnimPoly(ap)^ do begin if not CutSel then begin LimitOXOY; if RX1 + ox >= max_x then exit; if RY1 + oy >= max_y then exit; if RX2 + ox <= 0 then exit; if RY2 + oy <= 0 then exit; end else begin if RX1 + ox >= max_x then LimitOXOY; if RY1 + oy >= max_y then LimitOXOY; if RX2 + ox <= 0 then LimitOXOY; if RY2 + oy <= 0 then LimitOXOY; end; RX1 := ilimit(RX1 + ox, 0, max_x); RY1 := ilimit(RY1 + oy, 0, max_y); RX2 := ilimit(RX2 + ox, 0, max_x); RY2 := ilimit(RY2 + oy, 0, max_y); for q := 0 to PolyCount - 1 do with Poly^[q] do if x <> IESELBREAK then begin x := ilimit(x + ox, 0, max_x); y := ilimit(y + oy, 0, max_y); end; end; end; {!! TImageEnView.AnimPolygonAddPt Declaration procedure AnimPolygonAddPt(ap: pointer; x, y: Integer); Description Adds a new point to the polygon ap. x, y are the point coordinates (bitmap based). !!} // add a vertex to the polygon "ap" // x and y are bitmap based coordinate procedure TImageEnView.AnimPolygonAddPt(ap: pointer; x, y: integer); begin AnimPolygonAddPtEx(ap, x, y); if fLockPaint = 0 then Paint; end; {!! TImageEnView.AnimPolygonNew Declaration function TImageEnView.AnimPolygonNew(VColor1, VColor2: TColor; VAnimated: Boolean; VSizeable: Boolean): pointer; Description Creates a new animated polygon. VColor1 and VColor2 specify the two colors of animation. Set VAnimated to True to animate the polygon Set VSizeable to True to allow resizing of the polygon. Returns an index of the new polygon. !!} // Create a new animated polygon // return the polygon handle function TImageEnView.AnimPolygonNew(VColor1, VColor2: TColor; VAnimated: boolean; VSizeable: boolean): pointer; var pp: PIEAnimPoly; begin getmem(pp, sizeof(TIEAnimPoly)); fAnimPoly.Add(pp); with pp^ do begin PolyCount := 0; PolyCapacity := 0; getmem(Poly, 0); Color1 := VColor1; Color2 := VColor2; Animated := VAnimated; Sizeable := VSizeable; ShowCenter := False; AniFt := 0; if not (csDesigning in ComponentState) then Canvas := self.Canvas; Enabled := True; RX1 := 0; RY1 := 0; RX2 := 0; RY2 := 0; end; if (fAnimPoly.Count = 1) and not (csDesigning in ComponentState) {$ifndef IEDOTNETVERSION} and (assigned(Owner) or (ParentWindow <> 0)) {$endif} then begin SetupDrawPixelBitmap; SetupAniPolyTimer; fAnimPolyTimer.Enabled := True; end; pp^.DrawPixelPtr := fDrawPixelPtr; pp^.DrawPixelBitmap := fDrawPixelBitmap; result := pp; end; {!! TImageEnView.AnimPolygonDel Declaration procedure AnimPolygonDel(ap: pointer); Description Removes the animated polygon ap (value returned from ). !!} // removes the animated polygon "ap" procedure TImageEnView.AnimPolygonDel(ap: pointer); begin if ap <> nil then begin freemem(PIEAnimPoly(ap)^.Poly); freemem(PIEAnimPoly(ap)); fAnimPoly.Delete(fAnimPoly.IndexOf(pointer(ap))); if (fAnimPoly.Count = 0) and assigned(fAnimPolyTimer) then fAnimPolyTimer.Enabled := False; if fLockPaint = 0 then Paint; end; end; // this makes selection animated procedure TImageEnView.TimerEvent(Sender: TObject); begin AniPolyFunc(Sender, true); end; procedure TImageEnView.DoOnDrawPolygon(polygon: Integer; point: Integer; Canvas: TCanvas; x, y: Integer); begin if assigned(fOnDrawPolygon) then fOnDrawPolygon(self, polygon, point, Canvas, x, y); end; function TImageEnView.GetSelectionGridSize(): Integer; begin result := imax( fSelectionGridWidth, fSelectionGridHeight ); end; procedure TImageEnView.SetSelectionGridSize(value: Integer); begin fSelectionGridWidth := value; fSelectionGridHeight := value; end; procedure TImageEnView.DrawSelectionGrid(x1, y1, x2, y2: Integer); var i: Integer; p: Integer; begin if (fSelectionGridWidth > 1) or (fSelectionGridHeight > 1) then begin OrdCor(x1, y1, x2, y2); Canvas.Pen.Color := IEGlobalSettings().SelectionGridColor; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Style := psSolid; for i := 1 to fSelectionGridHeight-1 do begin // horizontal lines p := trunc( i*(y2-y1)/fSelectionGridHeight ); Canvas.MoveTo(x1, y1 + p); Canvas.LineTo(x2, y1 + p); end; for i := 1 to fSelectionGridWidth-1 do begin // vertical lines p := trunc( i*(x2-x1)/fSelectionGridWidth ); Canvas.MoveTo(x1 + p, y1); Canvas.LineTo(x1 + p, y2); end; end; end; procedure LineDDAProc(x, y: integer; self: PIEAnimPoly); stdcall; begin with self^ do begin // Due to SetPixel bug on Vista - on Window Classic theme if Assigned(DrawPixelPtr) then begin if C1 < 4 then DrawPixelPtr^ := TColor2TRGB(Color1) else if C1 < 7 then DrawPixelPtr^ := TColor2TRGB(Color2) else begin // fC1=6 DrawPixelPtr^ := TColor2TRGB(Color2); C1 := -1; end; Canvas.Draw(x, y, DrawPixelBitmap); inc(C1); end; end; end; // Draw the selection procedure TImageEnView.AniPolyFunc(Sender: TObject; UseLockPaint: boolean); const Target_Size = 22; procedure DrawGrip(iec: TIECanvas; x1, y1, x2, y2: Integer); begin case fGripShape of iegsBox: iec.Rectangle(x1, y1, x2, y2); iegsCircle: iec.Ellipse(x1, y1, x2, y2); end; end; var q, p: integer; pp: PIEAnimPoly; x1, y1, x2, y2: integer; lbreak: TPoint; grx1, gry1, grx2, gry2: integer; xanimated: boolean; xtime: Dword; invisible: Boolean; iec: TIECanvas; rxWidth, ryHeight: Integer; begin if (not HasParentWindow) or (not fVisibleSelection) then exit; xanimated := false; for q := 0 to fAnimPoly.Count - 1 do begin pp := PIEAnimPoly(fAnimPoly[q]); with pp^ do if Enabled then begin if Animated then xanimated := true; if Animated and (not fRectSelecting) and (not fPolySelecting) and (not fCircSelecting) and (Sender is TTimer) and (fRectResizing = ieNone) and (fSelectMoving < 0) then begin inc(AniFt); if AniFt >= 10 then AniFt := 0; inc(fAniCounter); end; with Canvas.ClipRect do invisible := (Left = 0) and (Top = 0) and (Right = 0) and (Bottom = 0); if (not invisible) and (fLockPaint = 0) and ((Canvas.LockCount = 0) or (not UseLockPaint)) and (not fMouseMoveScrolling) then begin // draw grips if Sizeable and _IsRectangle(Poly, PolyCount) and (not fRectSelecting) and (fSelectMoving = -1) then begin iec := TIECanvas.Create(Canvas, true, true); with iec do begin Brush.Style := fGripBrushStyle; Brush.Color := fGripColor2; Pen.Color := fGripColor1; grx1 := 10000000; gry1 := grx1; gry2 := -1000000; grx2 := gry2; for p := 0 to PolyCount - 1 do begin if Poly^[p].x <> IESELBREAK then begin x1 := XBmp2Scr( Poly^[p].x, True ); y1 := YBmp2Scr( Poly^[p].y, True ); DrawGrip(iec, x1 - fGripSize, y1 - fGripSize, x1 + fGripSize, y1 + fGripSize); if x1 < grx1 then grx1 := x1; if y1 < gry1 then gry1 := y1; if x1 > grx2 then grx2 := x1; if y1 > gry2 then gry2 := y1; end; end; if fExtendedGrips then begin x1 := (grx2 + grx1) div 2; y1 := (gry2 + gry1) div 2; DrawGrip(iec, x1 - fGripSize, gry1 - fGripSize, x1 + fGripSize, gry1 + fGripSize); DrawGrip(iec, grx1 - fGripSize, y1 - fGripSize, grx1 + fGripSize, y1 + fGripSize); DrawGrip(iec, grx2 - fGripSize, y1 - fGripSize, grx2 + fGripSize, y1 + fGripSize); DrawGrip(iec, x1 - fGripSize, gry2 - fGripSize, x1 + fGripSize, gry2 + fGripSize); end; end; iec.Free; DrawSelectionGrid(grx1, gry1, grx2, gry2); end; // end draw grips if (pp = fHPolySel) and (not fSelectionMask.IsEmpty) and (fRectResizing = ieNone) and (not fRectSelecting) and (not fCircSelecting) and (not fPolySelecting) and (not fRectMoving) then begin // draw selection if (not fDelayDisplaySelection) or (fStable2 = 0) then begin xtime := GetTickCount; with CurrentLayer.DrawingInfo do fSelectionMask.DrawOutline(Canvas, XDst, YDst, WidthDst, HeightDst, XSrc, YSrc, WidthSrc, HeightSrc, fAniCounter, fSelColor1, fSelColor2, @fNavigatorActualRect); xtime := GetTickCount - xtime; if (fDelayTimer<0) and (assigned(Owner) or (ParentWindow<>0)) then begin SetupAniPolyTimer; fAnimPolyTimer.Interval := imax(210, trunc(xtime*100/(-fDelayTimer))); end; end; end else begin C1 := AniFt; Canvas.pen.mode := pmCopy; // draw user polygon or building selection if PolyCount > 0 then begin if _IsRectangle(Poly, PolyCount) then begin // this is a rectangle x1 := XBmp2Scr( Poly^[0].x, True ); y1 := YBmp2Scr( Poly^[0].y, True ); x2 := XBmp2Scr( Poly^[2].x, True ) - 1; y2 := YBmp2Scr( Poly^[2].y, True ) - 1; fNavigatorActualRect := Rect(x1, y1, x2, y2); // 3.0.4: rectangular selection painted here to avoid grips missalignment LineDDA(x1, y1, x2, y1, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, 1, Canvas, x2, y1); LineDDA(x2, y1, x2, y2, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, 2, Canvas, x2, y2); LineDDA(x2, y2, x1, y2, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, 3, Canvas, x1, y2); LineDDA(x1, y1, x1, y2, @LineDDAProc, NativeInt(pp)); if fRectSelecting or fRectMoving then DrawSelectionGrid(x1, y1, x2, y2); DoOnDrawPolygon(q, 0, Canvas, x1, y1); end else begin // this is a polygon lbreak := Poly^[0]; p := 1; while p < PolyCount do begin if Poly^[p].x = IESELBREAK then begin // closes sub-polygon x1 := XBmp2Scr( Poly^[p - 1].x, True ); y1 := YBmp2Scr( Poly^[p - 1].y, True ); x2 := XBmp2Scr( lbreak.x, True ); y2 := YBmp2Scr( lbreak.y, True ); LineDDA(x1, y1, x2, y2, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, p-1, Canvas, x1, y1); inc(p); lbreak := Poly^[p]; end else begin x1 := XBmp2Scr( Poly^[p - 1].x, True ); y1 := YBmp2Scr( Poly^[p - 1].y, True ); x2 := XBmp2Scr( Poly^[p].x, True ); y2 := YBmp2Scr( Poly^[p].y, True ); LineDDA(x1, y1, x2, y2, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, p-1, Canvas, x1, y1); end; inc(p); end; // closes last sub-polygon if (not fPolySelecting) then begin x1 := XBmp2Scr( Poly^[PolyCount - 1].x, True ); y1 := YBmp2Scr( Poly^[PolyCount - 1].y, True ); x2 := XBmp2Scr( lbreak.x, True ); y2 := YBmp2Scr( lbreak.y, True ); LineDDA(x1, y1, x2, y2, @LineDDAProc, NativeInt(pp)); DoOnDrawPolygon(q, p-1, Canvas, x1, y1); end; end; // Polygon, not rectange // Draw a small cross to show the center of the current selection rxWidth := XBmp2Scr( rx2, True ) - XBmp2Scr( rx1, True ); ryHeight := YBmp2Scr( ry2, True ) - YBmp2Scr( ry1, True ); if ShowCenter and ( PolyCount > 1 ) and ( rxWidth > 0 ) and ( ryHeight > 0 ) then begin LineDDA( XBmp2Scr( rx1, True ) + rxWidth div 2 - Target_Size div 2, YBmp2Scr( ry1, True ) + ryHeight div 2, XBmp2Scr( rx1, True ) + rxWidth div 2 + Target_Size div 2, YBmp2Scr( ry1, True ) + ryHeight div 2, @LineDDAProc, NativeInt ( pp )); LineDDA( XBmp2Scr( rx1, True ) + rxWidth div 2, YBmp2Scr( ry1, True ) + ryHeight div 2 - Target_Size div 2, XBmp2Scr( rx1, True ) + rxWidth div 2, YBmp2Scr( ry1, True ) + ryHeight div 2 + Target_Size div 2, @LineDDAProc, NativeInt( pp )); end; end; end; end; end; // end of polygon "enabled" end; if (assigned(Owner) or (ParentWindow <> 0)) then begin SetupAniPolyTimer; if (fStable = 0) and (fStable2 = 0) and (not xanimated) then fAnimPolyTimer.Enabled := false else if (fAnimPolyTimer.Enabled = false) then fAnimPolyTimer.Enabled := true; end; if fStable > 0 then begin dec(fStable); if fStable = 0 then Update; end; if fStable2 > 0 then dec(fStable2); end; {!! TImageEnView.GetGripAt Declaration function GetGripAt(x, y: Integer): ; Description Returns the selection grip at mouse position specified by x, y (or ieNone if a grip is not found). !!} function TImageEnView.GetGripAt(x, y: integer): TIEGrip; var p, x1, y1, x2, y2: integer; begin result := ieNone; with PIEAnimPoly(fHPolySel)^ do if Enabled and Sizeable and _IsRectangle(Poly, PolyCount) and not fRectSelecting then begin // try grips for p := 0 to PolyCount - 1 do begin if Poly^[p].x <> IESELBREAK then begin x1 := XBmp2Scr( Poly^[p].x, True ); y1 := YBmp2Scr( Poly^[p].y, True ); if IEPointInRect(x, y, x1 - fGripSize, y1 - fGripSize, x1 + fGripSize, y1 + fGripSize) then begin result := TIEGrip(p + 1); break; end; end; end; if result = ieNone then begin // try sides x1 := XBmp2Scr( RX1, True ); y1 := YBmp2Scr( RY1, True ); x2 := XBmp2Scr( RX2, True ); y2 := YBmp2Scr( RY2, True ); if _DistPoint2Seg(x, y, x1, y1, x1, y2) < 3 then result := ieLeftSide // left else if _DistPoint2Seg(x, y, x2, y1, x2, y2) < 3 then result := ieRightSide // right else if _DistPoint2Seg(x, y, x1, y1, x2, y1) < 3 then result := ieTopSide // top else if _DistPoint2seg(x, y, x1, y2, x2, y2) < 3 then result := ieBottomSide; // bottom end; end; end; // Return the grip on position x,y // ieNone if none or Shift is pressed function TImageEnView.GetResizingGrip(x, y: integer; Shift: TShiftState): TIEGrip; begin if (ssShift in Shift) then result := ieNone else result := GetGripAt(x, y); end; // return 0 if x,y is inside selection and shift is not pressed // -1 otherwise function TImageEnView.GetMovingGrip(x, y: integer; Shift: TShiftState): integer; begin result := -1; if (not (ssShift in Shift)) and (not fSelectionMask.IsEmpty) and (not fRectSelecting) and (not fPolySelecting) and (not fCircSelecting) and fSelectionMask.IsPointInside( XScr2Bmp( x, True ), YScr2Bmp( y, True )) and (iesoMoveable in fSelectionOptions) then result := 0; end; function TImageEnView.UserInteractions_MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; var i: integer; begin result := false; for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled and (fUserInteractions[i] as TIEUserInteraction).MouseDownExclusive(Button, Shift, X, Y) then begin result := true; break; end; end; procedure TImageEnView.UserInteractions_MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i: integer; begin for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled then (fUserInteractions[i] as TIEUserInteraction).MouseDown(Button, Shift, X, Y); end; procedure TImageEnView.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i: integer; inLayerX, inLayerY: integer; bDisableNewSelections: Boolean; bDeselect: Boolean; {$IFNDEF OCXVERSION} ParForm: TCustomForm; {$ENDIF} begin inherited; {$IFDEF OCXVERSION} SetFocus; {$ELSE} ParForm := GetParentForm(Self); if (ParForm<>nil) and (ParForm.Visible) and CanFocus then SetFocus; {$ENDIF} if (Button = mbRight) and (ssLeft in Shift) then // right button pressed exit; fLayerMoved := false; bDisableNewSelections := (iesoDisableNewSelection in fSelectionOptions) and (Selected = True); if fDelayZoomFilter then fActualZoomFilter := rfNone; fSavedSelectionBase := fSelectionBase; fSelectionBase := iesbClientArea; fHSX0 := ilimit(X, fOffX, fOffX + fExtX); fHSY0 := ilimit(Y, fOffY, fOffY + fExtY); inLayerX := ilimit( X, CurrentLayer.ClientAreaBox.Left, CurrentLayer.ClientAreaBox.Right + 1 ); inLayerY := ilimit( Y, CurrentLayer.ClientAreaBox.Top, CurrentLayer.ClientAreaBox.Bottom + 1 ); fMouseDownX := X; fMouseDownY := Y; fPredLX := X; fPredLY := Y; fPredX := inLayerX; fPredY := inLayerY; fHSX1 := inLayerX; fHSY1 := inLayerY; fHSVX1 := ViewX; fHSVY1 := ViewY; fMMoveX := inLayerX; fMMoveY := inLayerY; fStartingPolyCount := PIEAnimPoly(fHPolySel)^.PolyCount; if ( fEditingLayer >= 0 ) and ( Button = mbLeft ) then begin LayersCancelEditor(); end; if not UserInteractions_MouseDownExclusive(Button, Shift, X, Y) then begin if (Button = mbLeft) and ((miSelectPolygon in fMouseInteract) or (miSelectLasso in fMouseInteract)) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations; DoBeforeSelectionChange; fSelectMoving := GetMovingGrip(inLayerX, inLayerY, Shift); if (fSelectMoving = -1) and (bDisableNewSelections = False) then begin if (ssAlt in Shift) or fForceALTkey then with PIEAnimPoly(fHPolySel)^ do if (PolyCount > 0) and (Poly^[PolyCount - 1].x <> IESELBREAK) then _CastPolySelCC(Poly^[PolyCount - 1].x - fViewX + fOffX, Poly^[PolyCount - 1].y - fViewY + fOffY, inLayerX, inLayerY); if (not fPolySelecting) then begin if (ssShift in Shift) and (fEnableShiftKey) then AddSelBreakEx else if (iesoDisableOneClickDeselect in fSelectionOptions) = False then DeSelect; end; AddSelPointEx(inLayerX, inLayerY); fPolySelecting := true; fLassoSelecting := miSelectLasso in fMouseInteract; DoSelectionChanging; end; end else if (Button = mbLeft) and (miSelect in fMouseInteract) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations; DoBeforeSelectionChange; fRectResizing := GetResizingGrip(X, Y, Shift); if fRectResizing = ieNone then fSelectMoving := GetMovingGrip(X, Y, Shift); if (fRectResizing = ieNone) and (fSelectMoving = -1) and (bDisableNewSelections = False) then begin // new rectangular selection fRectSelecting := True; if (fSelectionAspectRatio = 0) then begin // fixed selection MouseSelectRectangle(inLayerX, inLayerY, Shift); end; DoSelectionChanging; end; if fRectResizing <> ieNone then with PIEAnimPoly(fHPolySel)^ do begin flx1 := RX1; flx2 := RX2; fly1 := RY1; fly2 := RY2; end; end else if (Button = mbLeft) and (miSelectZoom in fMouseInteract) then begin fRectSelecting := True; DoSelectionChanging; if miSelectZoom in fMouseInteract then SaveSelection; end else if (Button = mbLeft) and (miSelectCircle in fMouseInteract) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations; DoBeforeSelectionChange; fSelectMoving := GetMovingGrip(inLayerX, inLayerY, Shift); if (fSelectMoving = -1) and (bDisableNewSelections = False) then begin fCircSelecting := True; ShowSelectionEx(false); if (fSelectionAspectRatio = 0) then begin // fixed selection MouseSelectCircle(inLayerX, inLayerY, Shift); end; DoSelectionChanging; end; end else if (Button = mbLeft) and (miSelectMagicWand in fMouseInteract) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations; DoBeforeSelectionChange; fSelectMoving := GetMovingGrip(inLayerX, inLayerY, Shift); end else if ((Button = mbLeft) or ((Button=mbRight) and (iesoRightButtonSelectLayers in fSelectionOptions))) and (((miMoveLayers in fMouseInteract) or (miResizeLayers in fMouseInteract) or (miRotateLayers in fMouseInteract))) then begin fMovResRotLayerStarted := false; if miResizeLayers in fMouseInteract then fLayerResizing := FindLayerGripAnySel( X, Y, True ) else fLayerResizing := ieNone; if (fLayerResizing <> ieNone) then begin if loAutoFixRotation in fLayerOptions then LayersFixRotations; with TIELayer(fLayers[fLayersCurrent]) do begin fLyrResizingClientAreaBox := ClientAreaBox; for i := 0 to 3 do fLyrResizingRotatedBox[i] := DrawingInfo.RotatedDest[i]; end; DoLayerNotify(fLayersCurrent, ielBeginResizing); end; if (fLayerResizing = ieNone) and ((miMoveLayers in fMouseInteract) or (miRotatelayers in fMouseInteract)) then begin if (miRotateLayers in fMouseInteract) and (FindLayerGrip(X, Y) = ieRotationCenter) then // begin rotation center moving fMovingRotationCenter := LayersCurrent else begin if (miRotateLayers in fMouseInteract) and (LayersCurrent > -1) and CurrentLayer.SupportsFeature(ielfRotation) and ( CurrentLayer.Locked = False ) and ( not IsPointInsideLayer(X, Y, LayersCurrent )) then begin // start rotating current layer fRotatingLayer := LayersCurrent; fRotatingLayerValue := CurrentLayer.Rotate; if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; end else begin // begin layer moving fMovingLayer := FindLayerAt(X, Y); // Have they double clicked a text layer? if ( fMovingLayer > -1 ) and ( ssDouble in Shift ) and ( Layers[ fMovingLayer ].SupportsFeature( ielfTextEditing )) then begin fEditingLayer := fMovingLayer; fMovingLayer := -1; LayersActivateTextEditor( fEditingLayer ); end; // Deselect all layers if ( fMovingLayer = -1 ) and ( fEditingLayer = -1 ) and ( not ( ssShift in Shift )) then begin if LayersAllowMultiSelect then begin LayersDeselectAll; DoLayerNotify(fLayersCurrent, ielDeselected); end else // Select background layer if SetLayersCurrentEx( 0, True, False ) then DoLayerNotify( fLayersCurrent, ielSelected ); end; // Deselect current layer? if ( fMovingLayer > -1 ) and ( LayersAllowMultiSelect ) and ( Layers[ fMovingLayer ].fSelected ) and ( ssShift in Shift ) then begin Layers[ fMovingLayer ].fSelected := False; DoLayerNotify(fMovingLayer, ielDeselected); SelectByGroupIndex( Layers[ fMovingLayer ].GroupIndex, False, True ); SelectMaskOfLayer( fMovingLayer, False, True ); fMovingLayer := -1; Update; end; if fMovingLayer > -1 then begin bDeselect := NOT ( Layers[ fMovingLayer ].fSelected or ( ssShift in Shift )); if SetLayersCurrentEx( fMovingLayer, True, bDeselect ) then DoLayerNotify(fLayersCurrent, ielSelected); DoLayerNotify(fLayersCurrent, ielBeginMoving); if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; end; if (fMovingLayer > -1) and (not TIELayer(fLayers[fLayersCurrent]).Locked) then SetTempCursor(crIESizeAll, true); end; end; end; end; end; // warning, does not follow the previous if..then...else UserInteractions_MouseDown(Button, Shift, X, Y); // Rulers fRulerParams.HandleMouseDown( Button, Shift, X, Y ); if (Button = mbLeft) and (miScroll in fMouseInteract) and RequiresScrollBars then SetTempCursor(crIEHandDrag, True); fSelectionBase := fSavedSelectionBase; end; // Called by MouseMoveScroll, when it is scrolled the view (ViewXY) // of scx and scy pixels. procedure TImageEnView.SubMouseMoveScroll(scx, scy: integer); begin dec(fMMoveX, scx); dec(fMMoveY, scy); dec(fPredX, scx); dec(fPredY, scy); dec(fPredLX, scx); dec(fPredLY, scy); end; // calls SubMouseMoveScroll method // scroll if the mouse is out of the component procedure TImageEnView.MouseMoveScroll(); var pt: Tpoint; scx, scy, lvx, lvy: integer; begin if MouseChangingLayers() then exit; fMouseMoveScrolling := true; try repeat // calc movement GetCursorPos(pt); pt := ScreenToClient(pt); if pt.x < fOffX then scx := pt.x - fOffX else if pt.x > (fOffX + fExtX - 1) then scx := pt.x - (fOffX + fExtX - 1) else scx := 0; if pt.y < fOffY then scy := pt.y - fOffY else if pt.y > (fOffY + fExtY - 1) then scy := pt.y - (fOffY + fExtY - 1) else scy := 0; if (scx = 0) and (scy = 0) then break; lvx := fViewX; lvy := fViewY; SetViewXY(fViewX + scx, fViewY + scy); if (lvx = fViewX) and (lvy = fViewY) then break; dec(lvx, fViewX); dec(lvy, fViewY); inc(fHSX1, lvx); inc(fHSY1, lvy); inc(fHSX0, lvx); inc(fHSY0, lvy); SubMouseMoveScroll(scx, scy); until false; finally fMouseMoveScrolling := false; end; end; {!! TImageEnView.LayersRepositionAll Declaration procedure LayersRepositionAll(MoveX, MoveY: Integer; SelectedOnly: Boolean = False; Sizing: Boolean = False); Description Updates and of all layers (or just selected if SelectedOnly = True) to move them to a new position. If Sizing is true then Layer is resized (top-left position does not move). These consts are also for MoveX: 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
These consts are also MoveY: 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
Note: Use
to resize layers by percentage Examples // Move all layers 50 pixels up and left ImageEnView1.LayersRepositionAll( -50, -50 ); // Move selected layers 100 pixels down ImageEnView1.LayersRepositionAll( 0, 100, true ); // Enlarge all layers vertically and horizontally by 10 pixels ImageEnView.LayersRepositionAll( 10, 10, False, True ); // Center all layers in the middle of the image ImageEnView1.LayersRepositionAll( IELayer_Pos_HCenter, IELayer_Pos_VCenter ); See Also - - - !!} procedure TImageEnView.LayersRepositionAll(MoveX, MoveY: Integer; SelectedOnly: Boolean = False; Sizing: Boolean = False); var ALayer: TIELayer; i: Integer; doMoveX: Integer; doMoveY: Integer; begin if ( MoveX = 0 ) and ( MoveY = 0 ) then exit; for i := 0 to LayersCount - 1 do begin // Moving ALayer ALayer := TIELayer( fLayers[ I ]); if ( aLayer.Locked = False ) and (( SelectedOnly = False ) or aLayer.Selected ) then begin doMoveX := MoveX; doMoveY := MoveY; if Sizing then begin // SIZING // Do not allow smaller than 1 if doMoveX < -1 * aLayer.Width + 1 then doMoveX := -1 * aLayer.Width + 1; if doMoveY < -1 * aLayer.Height + 1 then doMoveY := -1 * aLayer.Height + 1; aLayer.Width := aLayer.Width + doMoveX; aLayer.Height := aLayer.Height + doMoveY; end else begin // MOVING aLayer.PosX := aLayer.PosX + doMoveX; aLayer.PosY := aLayer.PosY + doMoveY; end; end; end; Update; end; {!! TImageEnView.LayersRotateAll Declaration procedure LayersRotateAll(Value: Double; bSelectedOnly: Boolean = False; bFixRotations: Boolean = False); Description Rotates all layers (or just selected if bSelectedOnly = True) by the specified angle (negative or positive degrees counter-clockwise). This method updates . If bFixRotations = True, then is called to finalize the rotation of the layer and improve quality. Examples // Rotate all layers 45° clockwise ImageEnView1.LayersRotateAll( 315 ); // Rotate selected layers 90° clockwise ImageEnView1.LayersRotateAll( 270, true ); See Also - - !!} procedure TImageEnView.LayersRotateAll(Value: Double; bSelectedOnly: Boolean = False; bFixRotations: Boolean = False); var ALayer: TIELayer; i: Integer; begin if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then begin if bFixRotations then Proc.SaveUndo( IEMsg( IEMsg_RotateLayers ), ieuObjectsAndLayers, True, IEOP_ROTATELAYER ) else Proc.SaveUndo( IEMsg( IEMsg_RotateLayers ), ieuLayer, True, IEOP_ROTATELAYER ); end; for i := 0 to LayersCount - 1 do begin // Rotating ALayer ALayer := TIELayer( fLayers[ I ]); if ( aLayer.Locked = False ) and (( bSelectedOnly = False ) or aLayer.Selected ) then ALayer.Rotate := ALayer.Rotate + Value; end; if bFixRotations then begin if bSelectedOnly then LayersFixRotations( LYR_SELECTED_LAYERS ) else LayersFixRotations( LYR_ALL_LAYERS ); end else Update(); end; {!! TImageEnView.LayersSizeAll Declaration procedure LayersSizeAll(HorzSizing, VertSizing: Double; bSelectedOnly: Boolean = False; bFixSizes: Boolean = False; ScalePosition: Boolean = False); Description Scales the and values for all layers (or just selected if bSelectedOnly = True). HorzSizing and VertSizing are percentage values, so 2 will double the layer size, and 0.5 will halve it. If bFixSizes = True, then is called to resample the layer to the new sizes. If ScalePosition is True, then and are scaled to keep their position relative to other layers (best if also scaling the background layer). If False the layer is centered after scaling (best when only scaling some layers). Note: To size by pixels rather than scale, see Examples // Halve the size of all layers ImageEnView1.LayersSizeAll( 0.5, 0.5, False, False, True ); // Increase the size of selected layers by 25% ImageEnView1.LayersSizeAll( 1.25, 1.25, True ); See Also - - !!} procedure TImageEnView.LayersSizeAll(HorzSizing, VertSizing: Double; bSelectedOnly: Boolean = False; bFixSizes: Boolean = False; ScalePosition: Boolean = False); var aLayer: TIELayer; lw, lh: Double; i: Integer; begin for i := 0 to LayersCount - 1 do begin aLayer := TIELayer( fLayers[ I ]); if ( aLayer.Locked = False ) and (( bSelectedOnly = False ) or aLayer.Selected ) then begin lw := aLayer.Width; lh := aLayer.Height; if HorzSizing = 0 then aLayer.WidthD := 1 else aLayer.WidthD := dmax( 1, lw * HorzSizing ); if VertSizing = 0 then aLayer.HeightD := 1 else aLayer.HeightD := dmax( 1, lh * VertSizing ); if ( aLayer.WidthD > 1 ) and ( lw > 1 ) then begin if ScalePosition then aLayer.PosX := Round( aLayer.PosX * HorzSizing) else if ( HorzSizing < 0.1 ) or ( HorzSizing > 0.1 ) then // Avoid "wild" movements when scrolling up from very small sizes aLayer.fPosX := aLayer.fPosX + ( lw - aLayer.WidthD ) / 2; end; if ( aLayer.HeightD > 1 ) and ( lh > 1 ) then begin if ScalePosition then aLayer.PosY := Round( aLayer.PosY * VertSizing) else if ( VertSizing < 0.1 ) or ( VertSizing > 0.1 ) then // Avoid "wild" movements when scrolling up from very small sizes aLayer.fPosY := aLayer.fPosY + ( lh - aLayer.HeightD ) / 2; end; end; end; if bFixSizes then begin if bSelectedOnly then LayersFixSizes( LYR_SELECTED_LAYERS ) else LayersFixSizes( LYR_ALL_LAYERS ); end; ImageChange(); Update(); end; procedure TImageEnView.MouseResizeLayer(clientlx, cliently: integer; AltPressed: Boolean); var w, h, lw, lh: Double; lx, ly: integer; layer: TIELayer; plx, ply: Integer; lr: TIEGrip; aspectratio: Boolean; i: Integer; lxp, lyp: Double; // Percentage to resize layer in each dimension BaseX, BaseY: Double; BaseR, BaseB: Double; NewR, NewB: Double; newPosX, newPosY, newWidthD, newHeightD: Double; begin layer := CurrentLayer; lx := XScr2Bmp( clientlx, False ); ly := YScr2Bmp( cliently, False ); plx := XScr2Bmp( fPredLX, False ); ply := YScr2Bmp( fPredLY, False ); lr := fLayerResizing; if layer.AspectRatioLocked then aspectratio := True else case fLayersResizeAspectRatio of iearALTKey: aspectratio := AltPressed; iearAlways: aspectratio := true; iearAlwaysOnCornerGrip: aspectratio := (lr = ieTopLeft) or (lr = ieTopRight) or (lr = ieBottomRight) or (lr = ieBottomLeft); iearLayerDefaultOnCornerGrip: aspectratio := ((lr = ieTopLeft) or (lr = ieTopRight) or (lr = ieBottomRight) or (lr = ieBottomLeft)) and (layer.PreferredAspectRatio <> 0); else // iearDisabled (suppress warning) aspectratio := false; end; if aspectratio then case lr of ieTopLeft: // left-top begin ly := YScr2Bmp( trunc( ( clientlx - fLyrResizingClientAreaBox.Left ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Top, False ); end; ieTopRight: // right-top begin ly := YScr2Bmp( trunc( ( -clientlx + fLyrResizingClientAreaBox.Right ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Top, False ); end; ieBottomRight: // right-bottom begin ly := YScr2Bmp( trunc( ( clientlx - fLyrResizingClientAreaBox.Left ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Top, False ); end; ieBottomLeft: // left-bottom begin ly := YScr2Bmp( trunc( ( -clientlx + fLyrResizingClientAreaBox.Left ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Bottom, False ); end; ieLeftSide: // left side begin ly := YScr2Bmp( trunc( ( -clientlx + fLyrResizingClientAreaBox.Left ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Bottom, False ); lr := ieBottomLeft; end; ieRightSide: // right side begin ly := YScr2Bmp( trunc( ( clientlx - fLyrResizingClientAreaBox.Left ) * fLayersResizingAR ) + fLyrResizingClientAreaBox.Top, False ); lr := ieBottomRight; end; ieTopSide: // top side begin lx := XScr2Bmp( trunc( ( cliently - fLyrResizingClientAreaBox.Top ) / fLayersResizingAR ) + fLyrResizingClientAreaBox.Left, False ); lr := ieTopLeft; end; ieBottomSide: // bottom side begin lx := XScr2Bmp( trunc( ( cliently - fLyrResizingClientAreaBox.Top ) / fLayersResizingAR ) + fLyrResizingClientAreaBox.Left, False ); lr := ieBottomRight; end; else end; w := layer.Width; h := layer.Height; BaseX := layer.fPosX; BaseR := layer.fPosX + w; BaseY := layer.fPosY; BaseB := layer.fPosY + h; // Get resize percentage - Horizontal lxp := 1; try case lr of ieTopLeft : lxp := w / ( w + ( layer.fPosX - lx )); ieTopRight : lxp := w / ( lx - layer.fPosX ); ieBottomRight : lxp := w / ( lx - XScr2Bmp( fLyrResizingClientAreaBox.Left, False )); ieBottomLeft : lxp := w / ( w + ( layer.fPosX - lx )); ieLeftSide : lxp := w / ( w - ( lx - plx )); ieRightSide : lxp := w / ( w - ( -lx + plx )); end; except lxp := 1; end; // Get resize percentage - Vertical lyp := 1; try case lr of ieTopLeft : lyp := h / ( h + ( layer.fPosY - ly )); ieTopRight : lyp := h / ( h + ( layer.fPosY - ly )); ieBottomRight : lyp := h / ( ly - YScr2Bmp( fLyrResizingClientAreaBox.Top, False )); ieBottomLeft : lyp := h / ( ly - YScr2Bmp( fLyrResizingClientAreaBox.Top, False )); ieTopSide : lyp := h / ( h + ( layer.fPosY - ly )); ieBottomSide : lyp := h / ( h - ( -ly + ply )); end; except lyp := 1; end; for i := 0 to LayersCount - 1 do begin Layer := TIELayer( fLayers[ I ]); if ( Layer.Locked = False ) and Layer.Selected then begin lw := layer.Width; lh := layer.Height; if lxp = 0 then newWidthD := 1 else newWidthD := dmax( 1, lw / lxp ); if lyp = 0 then newHeightD := 1 else newHeightD := dmax( 1, lh / lyp ); newPosX := layer.fPosX; newPosY := layer.fPosY; if ( newWidthD > 1 ) and ( lw > 1 ) and (( lxp < 0.1 ) or ( lxp > 0.1 )) then // Avoid "wild" movements when scrolling up from very small sizes if lr in [ ieTopLeft, ieLeftSide, ieBottomLeft ] then begin NewR := BaseR - (( BaseR - ( newPosX + lw )) / lxp ); newPosX := NewR - newWidthD; end else begin newPosX := BaseX + (( newPosX - BaseX ) / lxp ); end; if ( newHeightD > 1 ) and ( lh > 1 ) and (( lyp < 0.1 ) or ( lyp > 0.1 )) then // Avoid "wild" movements when scrolling up from very small sizes if lr in [ ieTopLeft, ieTopSide, ieTopRight ] then begin NewB := BaseB - (( BaseB - ( newPosY + lh )) / lyp ); newPosY := NewB - newHeightD; end else begin newPosY := BaseY + (( newPosY - BaseY ) / lyp ); end; if assigned( fOnLayerMoveSize ) then fOnLayerMoveSize( Self, i, ielResizing, newPosX, newPosY, newWidthD, newHeightD ); layer.fPosX := newPosX; layer.fPosY := newPosY; layer.WidthD := newWidthD; layer.HeightD := newHeightD; if not aspectratio then fLayersResizingAR := layer.Height / layer.Width; end; end; ImageChange(); end; procedure TImageEnView.MouseSelectCircle(x, y: integer; Shift: TShiftState); var dx, dy, p, g: integer; xx, yy: integer; begin MouseMoveScroll; if (fSelectionAspectRatio = 0) then begin // fixed selection dx := round(fSelectionAbsWidth * fZoomD100X) div 2; dy := round(fSelectionAbsHeight * fZoomD100Y) div 2; fHSX1 := x; fHSY1 := y; x := x + dx; y := y + dy; end; if (ssShift in Shift) and (fEnableShiftKey) then begin if fStartingPolyCount <> PIEAnimPoly(fHPolySel)^.PolyCount then AnimPolygonRemoveLast(fHPolySel); AddSelBreakEx; end else AnimPolygonClear(fHPolySel); if ((ssAlt in Shift) or fForceALTkey) and (fSelectionAspectRatio = -1) then begin // circle (pressing ALT) dx := imax(abs(fHSX1 - X), abs(fHSY1 - Y)); dy := dx; end else if fSelectionAspectRatio>0 then begin dx := imax(abs(fHSX1 - X), abs(fHSY1 - Y)); dy := round(dx * fSelectionAspectRatio); end else begin dx := abs(fHSX1 - X); dy := abs(fHSY1 - Y); end; dx := trunc(dx * f100DZoomX); dy := trunc(dy * f100DZoomY); p := trunc(2 * pi * imin(dx, dy)); if p < 50 then p := 50; for g := 0 to p - 1 do begin xx := round( XScr2Bmp( fHSX1, True ) + cos((2 * pi / p) * g) * dx); yy := round( YScr2Bmp( fHSY1, True ) + sin((2 * pi / p) * g) * dy); xx := imax(0, imin(fIEBitmap_Width, xx)); yy := imax(0, imin(fIEBitmap_Height, yy)); AnimPolygonAddPtEx(fHPolySel, xx, yy); end; AniPolyFunc(self, true); DoSelectionChanging; end; procedure TImageEnView.MouseSelectRectangle(x, y: integer; Shift: TShiftState); var dx, dy: integer; begin MouseMoveScroll; if (fSelectionAspectRatio = 0) then begin dx := round(fSelectionAbsWidth * fZoomD100X) div 2; dy := round(fSelectionAbsHeight * fZoomD100Y) div 2; fHSx1 := x - dx; fHsy1 := y - dy; x := x + dx - 1; y := y + dy - 1; end; if (ssShift in Shift) and (fEnableShiftKey) then begin if fStartingPolyCount <> PIEAnimPoly(fHPolySel)^.PolyCount then AnimPolygonRemoveLast(fHPolySel); SelectEx(fHSx1, fHSy1, x, y, iespAdd, (ssAlt in Shift) or fForceALTkey, not(iesoSizeable in fSelectionOptions) ) end else SelectEx(fHSx1, fHSy1, x, y, iespReplace, (ssAlt in Shift) or fForceALTkey, not(iesoSizeable in fSelectionOptions) ); DoSelectionChanging; end; function TImageEnView.UserInteractions_MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; var i: integer; begin result := false; for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled and (fUserInteractions[i] as TIEUserInteraction).MouseMoveExclusive(Shift, X, Y, Captured) then begin result := true; break; end; end; procedure TImageEnView.UserInteractions_MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); var i: integer; begin for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled then (fUserInteractions[i] as TIEUserInteraction).MouseMove(Shift, X, Y, Captured); end; procedure TImageEnView.MouseMove(Shift: TShiftState; X, Y: Integer); procedure _MoveSelLayers(iMoveX, iMoveY: Integer); var aLayer: TIELayer; i: Integer; newPosX, newPosY, newWidthD, newHeightD: Double; begin if ( iMoveX = 0 ) and ( iMoveY = 0 ) then exit; for i := 0 to LayersCount - 1 do begin // Moving aLayer aLayer := TIELayer( fLayers[ I ]); if ( aLayer.Locked = False ) and aLayer.Selected then begin newPosX := aLayer.PosX - iMoveX; newPosY := aLayer.PosY - iMoveY; newWidthD := aLayer.WidthD; newHeightD := aLayer.HeightD; if assigned( fOnLayerMoveSize ) then fOnLayerMoveSize( Self, i, ielMoving, newPosX, newPosY, newWidthD, newHeightD ); aLayer.fPosX := newPosX; aLayer.fPosY := newPosY; aLayer.WidthD := newWidthD; aLayer.HeightD := newHeightD; end; end; ImageChange(); end; procedure _RotateSelLayers(Value: Double; bSnapToStep: Boolean); var aLayer: TIELayer; i: Integer; begin for i := 0 to LayersCount - 1 do begin // Rotating aLayer aLayer := TIELayer( fLayers[ I ]); if ( aLayer.Locked = False ) and ( aLayer.Selected or ( i = fRotatingLayer )) then begin if bSnapToStep then aLayer.Rotate := trunc( Value / fLayersRotateStep ) * fLayersRotateStep else aLayer.Rotate := Value; end; end; end; var inLayerX, inLayerY: integer; grip: TIEGrip; ii: integer; layer: TIELayer; cx, cy: Integer; dx, dy: Double; max_x, max_y: Integer; ox, oy: Integer; begin inherited; fSavedSelectionBase := fSelectionBase; fSelectionBase := iesbClientArea; inLayerX := ilimit( X, CurrentLayer.ClientAreaBox.Left, CurrentLayer.ClientAreaBox.Right + 1 ); inLayerY := ilimit( Y, CurrentLayer.ClientAreaBox.Top, CurrentLayer.ClientAreaBox.Bottom + 1 ); if not UserInteractions_MouseMoveExclusive(Shift, X, Y, MouseCapture) then begin if MouseCapture then begin // inside Mouse Capture if miScroll in fMouseInteract then begin // panning SetViewXY(fHSVX1 - trunc((X - fMouseDownX)*fMouseScrollRate), fHSVY1 - trunc((Y - fMouseDownY)*fMouseScrollRate) ); // 3.0.2 end else if fRectResizing <> ieNone then begin // resize rectangular selection MouseMoveScroll; fRectResizing := SelectResizeEx(fRectResizing, inLayerX, inLayerY, (ssAlt in Shift) or fForceALTkey or (fSelectionAspectRatio>0)); DoSelectionChanging; end else if fSelectMoving > -1 then begin // move selection if iesoCanScroll in fSelectionOptions then MouseMoveScroll; fSelectMoving := SelectMoveEx(fSelectMoving, XScr2Bmp( inLayerX, True ) - XScr2Bmp( fPredX, True ), YScr2Bmp( inLayerY, True ) - YScr2Bmp( fPredY, True ), iesoCutBorders in fSelectionOptions); DoSelectionChanging; end else if fRectSelecting then begin // select rectangle MouseSelectRectangle(inLayerX, inLayerY, Shift); end else if fPolySelecting then begin // select polygon MouseMoveScroll; Paint; PolyDraw1; AnimPolygonAddPtEx( fHPolySel, XScr2Bmp( inLayerX, True ), YScr2Bmp( inLayerY, True )); AniPolyFunc(self, true); DoSelectionChanging; end else if fCircSelecting then begin // select circle MouseSelectCircle(inLayerX, inLayerY, Shift); end else if (fMovingLayer > -1) then begin // Moving a layer layer := TIELayer(fLayers[fMovingLayer]); if not layer.Locked then begin if not fMovResRotLayerStarted and Proc.AutoUndo and ( loAutoUndoChangesByUser in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_MoveLayers ), ieuLayer, True, IEOP_MOVELAYER ); fMovResRotLayerStarted := true; MouseMoveScroll; ox := Layer.PosX + ( XScr2Bmp(X, False ) - XScr2Bmp(fPredLX, False )); oy := Layer.PosY + ( YScr2Bmp(Y, False ) - YScr2Bmp(fPredLY, False )); fLayerMoved := ( ox <> layer.PosX ) or ( oy <> layer.PosY ) or fLayerMoved; _MoveSelLayers( layer.PosX - ox, layer.PosY - oy ); SetInteractionHint('X=' + IntToStr( Layer.PosX ) + ' Y=' + IntToStr( Layer.PosY ), X, Y, 'X=000 Y=000'); fUpdate_MaskCache := fMovingLayer; if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; Update; if fLayerMoved then DoLayerNotify(fLayersCurrent, ielMoving); end; end else if fMovingRotationCenter > -1 then begin // moving rotation center layer := TIELayer(fLayers[fMovingRotationCenter]); layer.RotateCenterX := layer.ConvXScr2Bmp(X) / layer.OriginalWidth; layer.RotateCenterY := layer.ConvYScr2Bmp(Y) / layer.OriginalHeight; SetInteractionHint('X='+IntToStr(trunc(layer.RotateCenterX*layer.Width)) + ' Y='+IntToStr(trunc(layer.RotateCenterY*layer.Height)), X, Y, 'X=000 Y=000'); fUpdate_MaskCache := fMovingRotationCenter; if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; Update; end else if (fRotatingLayer > -1) then begin // Rotating a layer layer := TIELayer(fLayers[fRotatingLayer]); if not layer.Locked then begin if not fMovResRotLayerStarted and Proc.AutoUndo and ( loAutoUndoChangesByUser in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_RotateLayers ), ieuFullLayer, True, IEOP_ROTATELAYER ); fMovResRotLayerStarted := true; dx := ((XScr2Bmp( X, False ) - XScr2Bmp( fPredLX, False ))) / 4; dy := ((YScr2Bmp( Y, False ) - YScr2Bmp( fPredLY, False ))) / 4; cx := XBmp2Scr( trunc( CurrentLayer.RotateCenterX * CurrentLayer.OriginalWidth ), True ); cy := YBmp2Scr( trunc( CurrentLayer.RotateCenterY * CurrentLayer.OriginalHeight ), True ); if X > cx then dy := -dy; if Y < cy then dx := -dx; fRotatingLayerValue := fRotatingLayerValue + dx + dy; _RotateSelLayers( fRotatingLayerValue, ssShift in Shift ); SetInteractionHint(IEFloatToStrS(layer.Rotate)+'°', X, Y, '0000°'); fUpdate_MaskCache := fRotatingLayer; if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; Update; DoLayerNotify(fLayersCurrent, ielRotating); end; end else if (fLayerResizing <> ieNone) and (not CurrentLayer.Locked) then begin // Resizing a layer if not fMovResRotLayerStarted and Proc.AutoUndo and ( loAutoUndoChangesByUser in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_ResizeLayers ), ieuLayer, True, IEOP_RESIZELAYER ); if not fMovResRotLayerStarted then fLayersResizingAR := CurrentLayer.Height / CurrentLayer.Width; fMovResRotLayerStarted := true; MouseMoveScroll; MouseResizeLayer(X, Y, (ssAlt in Shift) or fForceALTkey); SetInteractionHint(IntToStr(CurrentLayer.Width)+' x '+IntToStr(CurrentLayer.Height), X, Y, '0000 x 0000'); fUpdate_MaskCache := fLayersCurrent; if fLayersFastDrawing = iefDelayed then fStable := fDelayZoomTicks; Update; DoLayerNotify(fLayersCurrent, ielResizing); end; // out of Mouse Capture end else if fPolySelecting and not (fLassoSelecting) then begin PolyDraw1; if (ssAlt in Shift) or fForceALTkey then with PIEAnimPoly(fHPolySel)^ do if (PolyCount > 0) and (Poly^[PolyCount - 1].x <> IESELBREAK) then _CastPolySelCC(Poly^[PolyCount - 1].x - fViewX + fOffX, Poly^[PolyCount - 1].y - fViewY + fOffY, inLayerX, inLayerY); fMMoveX := inLayerX; fMMoveY := inLayerY; PolyDraw1; DoSelectionChanging; end else if (miSelect in fMouseInteract) or (miSelectPolygon in fMouseInteract) or (miSelectCircle in fMouseInteract) or (miSelectMagicWand in fMouseInteract) or (miSelectLasso in fMouseInteract) then begin grip := GetResizingGrip(X, Y, Shift); DoMouseInResizingGrip(grip); if grip = ieNone then begin ii := GetMovingGrip(X, Y, Shift); if ii > -1 then // moving cursor SetTempCursor(crIESizeAll) else begin // default cursor if (ssShift in Shift) and fEnableShiftKey then begin case cursor of crIECrossSight : SetTempCursor(crIECrossSightPlus); crIEThickCross : SetTempCursor(crIEThickCrossPlus); end; end else RestoreCursor; end; end else begin // resizing cursors case grip of ieTopLeft, ieBottomRight: SetTempCursor(crIESizeNWSE); ieTopRight, ieBottomLeft: SetTempCursor(crIESizeNESW); ieLeftSide, ieRightSide: SetTempCursor(crIESizeWE); ieTopSide, ieBottomSide: SetTempCursor(crIESizeNS); end; end; end else if (miRotateLayers in fMouseInteract) then begin // layers rotation. Rotate only the currently selected layer. if IsPointInsideLayer(X, Y, fLayersCurrent) then RestoreCursor else if ( fLayersCurrent > -1 ) and CurrentLayer.SupportsFeature( ielfRotation ) and ( CurrentLayer.Locked = False ) then begin cx := XBmp2Scr( trunc(CurrentLayer.RotateCenterX * CurrentLayer.OriginalWidth), True ); cy := YBmp2Scr( trunc(CurrentLayer.RotateCenterY * CurrentLayer.OriginalHeight), True ); if (X < cx) and (Y < cy) then SetTempCursor(crIERotateSE) else if (X < cx) and (Y > cy) then SetTempCursor(crIERotateNE) else if (X > cx) and (Y < cy) then SetTempCursor(crIERotateSW) else if (X > cx) and (Y > cy) then SetTempCursor(crIERotateNW); end; end else if ((miResizeLayers in fMouseInteract) or (miMoveLayers in fMouseInteract)) then begin grip := ieNone; if (miResizeLayers in fMouseInteract) then begin if LayersAllowMultiSelect then grip := FindLayerGripAnySel(X, Y) else if TIELayer(fLayers[fLayersCurrent]).Locked = False then grip := FindLayerGrip(X, Y); end; if grip = ieNone then begin ii := FindLayerAt(X, Y); if (ii > -1) and (not TIELayer(fLayers[ii]).Locked) and (miMoveLayers in fMouseInteract) then // moving cursor SetTempCursor(crIESizeAll) else // default cursor RestoreCursor; end else begin // resizing cursors case grip of ieTopLeft, ieBottomRight : SetTempCursor(crIESizeNWSE); ieTopRight, ieBottomLeft : SetTempCursor(crIESizeNESW); ieLeftSide, ieRightSide : SetTempCursor(crIESizeWE); ieTopSide, ieBottomSide : SetTempCursor(crIESizeNS); end; end; end; end; UserInteractions_MouseMove(Shift, X, Y, MouseCapture); // Rulers if fRulerParams.HandleMouseMove( Shift, X, Y ) then SetTempCursor( crDefault ); if (miMovingScroll in fMouseInteract) and ((fPredLx <> X) or (fPredLy <> Y)) and not MouseCapture then begin GetMaxViewXY(max_x, max_y); cx := trunc( (imax(imin(ClientWidth -1, X), 0)/(ClientWidth )-0.02) * 1.05 * (max_x) ); cy := trunc( (imax(imin(ClientHeight-1, Y), 0)/(ClientHeight)-0.02) * 1.05 * (max_y) ); SetViewXYSmooth( cx, cy ); end; if fSelectionMask.IsPointInside( XScr2Bmp( inLayerX, True ), YScr2Bmp( inLayerY, True )) then DoMouseInSel; fMMoveX := inLayerX; fMMoveY := inLayerY; fSelectionBase := fSavedSelectionBase; fPredX := inLayerX; fPredY := inLayerY; fPredLx := X; fPredLy := Y; end; {!! TImageEnView.IsPointInsideSelection Declaration function IsPointInsideSelection(x, y: Integer): Boolean; Description IsPointInsideSelection returns true if the point specified with x, y is inside the current selection. If is iesbClientArea (default) all coordinates depend on the zoom and image view (scrolling). !!} function TImageEnView.IsPointInsideSelection(x, y: integer): boolean; begin if fSelectionBase = iesbClientArea then begin x := XScr2Bmp( x, True ); y := YScr2Bmp( y, True ); end; result := fSelectionMask.IsPointInside(x, y); end; function TImageEnView.UserInteractions_MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; var i: integer; begin result := false; for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled and (fUserInteractions[i] as TIEUserInteraction).MouseUpExclusive(Button, Shift, X, Y) then begin result := true; break; end; end; procedure TImageEnView.UserInteractions_MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i: integer; begin for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled then (fUserInteractions[i] as TIEUserInteraction).MouseUp(Button, Shift, X, Y); end; procedure TImageEnView.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); const NUMSCALES = 8; scales: array[1..NUMSCALES] of integer = (2, 5, 10, 25, 33, 50, 75, 100); Poly_Select_Near_Region = 3; // how close the end point must be near the first point of a poly selection to automatically close it var w, sl: integer; d: double; inLayerX, inLayerY: integer; callselectionchange: boolean; bDeselect: Boolean; begin inherited; fInteractionHint := ''; callselectionchange := false; inLayerX := ilimit( x, CurrentLayer.ClientAreaBox.Left, CurrentLayer.ClientAreaBox.Right + 1 ); inLayerY := ilimit( y, CurrentLayer.ClientAreaBox.Top, CurrentLayer.ClientAreaBox.Bottom + 1 ); fSavedSelectionBase := fSelectionBase; fSelectionBase := iesbClientArea; d := 0; if not UserInteractions_MouseUpExclusive(Button, Shift, X, Y) then begin if (miZoom in fMouseInteract) and (fHSx1 = x) and (fHSy1 = y) and not IsEmpty then begin if Button = mbLeft then begin if (miScroll in fMouseInteract) then RestoreCursor; // zoom-in (MOUSE LEFT) if Zoom < 100 then begin for w := 1 to NUMSCALES do if scales[w] > Zoom then begin d := scales[w]; break; end; end else d := Zoom + 100; DoZoomIn(d); if (d <> fZoomX) or (d<>fZoomY) then ZoomAt(x, y, d, false) end else if (Button = mbRight) then begin // zoom-out (MOUSE RIGHT) if Zoom < 200 then begin d := 2; for w := NUMSCALES downto 1 do if scales[w] < Zoom then begin d := scales[w]; break; end; end else d := Zoom - 100; DoZoomOut(d); if (d <> fZoomX) or (d<>fZoomY) then ZoomAt(x, y, d, false); end; fPolySelecting := false; end else if (Button = mbLeft) and (miScroll in fMouseInteract) and RequiresScrollBars then begin // set "view", free by MouseCapture SetViewXY(fHSVX1 - trunc((x - fMouseDownX)*fMouseScrollRate), fHSVY1 - trunc((y - fMouseDownY)*fMouseScrollRate)); // 3.0.2 RestoreCursor; end else if (Button = mbLeft) and (miSelectZoom in fMouseInteract) then begin ZoomSelectionEx(fZoomSelectionAspectRatio, true); fRectSelecting := false; RestoreSelection(true, iersMoveToAdapt); end else if (Button = mbLeft) and (miSelect in fMouseInteract) then begin if (fHSX1 = inLayerX) and (fHSY1 = inLayerY) and (fRectResizing = ieNone) and (fSelectMoving = -1) then begin if fSel and ((iesoDisableOneClickDeselect in fSelectionOptions) = False) then begin DeSelect; callselectionchange := true; end; end else begin if fRectSelecting or (fRectResizing <> ieNone) then begin if (not (ssShift in Shift)) or (not fEnableShiftKey) then fSelectionMask.Empty; EndSelect; end; fRectSelecting := false; fRectResizing := ieNone; fSelectMoving := -1; callselectionchange := true; if fIsNavigator then invalidate else begin UpdateReason := ieurSelectionChanged; Update; end; end; end else if (Button = mbLeft) and (miSelectCircle in fMouseInteract) then begin if (fHSX1 = inLayerX) and (fHSY1 = inLayerY) and (fSelectMoving = -1) and (fSelectionAspectRatio <> 0) then begin if (iesoDisableOneClickDeselect in fSelectionOptions) = False then DeSelect end else begin if fCircSelecting then begin if (not (ssShift in Shift)) or (not fEnableShiftKey) then fSelectionMask.Empty; EndSelect; end; fCircSelecting := False; fSelectMoving := -1; callselectionchange := true; UpdateReason := ieurSelectionChanged; Update; end; end else if (Button = mbLeft) and (miSelectLasso in fMouseInteract) then begin if (fHSX1 = inLayerX) and (fHSY1 = inLayerY) and (fSelectMoving = -1) then begin if (iesoDisableOneClickDeselect in fSelectionOptions) = False then DeSelect end else begin if fLassoSelecting then begin if (not (ssShift in Shift)) or (not fEnableShiftKey) then fSelectionMask.Empty; EndSelect; end; fLassoSelecting := false; fPolySelecting := false; fSelectMoving := -1; callselectionchange := true; UpdateReason := ieurSelectionChanged; Update; end; end else if (Button = mbLeft) and (miSelectPolygon in fMouseInteract) then begin if (fSelectMoving > -1) then begin fSelectMoving := -1; callselectionchange := true; end; UpdateReason := ieurSelectionChanged; Update; end else if (Button = mbLeft) and (miSelectMagicWand in fMouseInteract) then begin if fSelectMoving > -1 then begin fSelectMoving := -1; callselectionchange := true; end else if NOT ((iesoDisableNewSelection in fSelectionOptions) and Selected) then begin SetTempCursor(crHourGlass); if (ssShift in Shift) and fEnableShiftKey then SelectMagicWand(x, y, iespAdd) else SelectMagicWand(x, y, iespReplace); RestoreCursor; callselectionchange := true; end; UpdateReason := ieurSelectionChanged; Update; end; end; UserInteractions_MouseUp(Button, Shift, X, Y); // Rulers fRulerParams.HandleMouseUp( Button, Shift, X, Y ); if Button = mbLeft then begin if fRectMoving then begin fSelectionMask.Empty; EndSelect; fRectMoving := false; end; if fMovingLayer > -1 then begin fMovingLayer := -1; RestoreCursor; if fLayerMoved then DoLayerNotify(fLayersCurrent, ielMoved); fLayerMoved := false; If SyncLayers() and Center then Update() else invalidate; end; if fRotatingLayer > -1 then begin fRotatingLayer := -1; if (fHSX1 <> inLayerX) or (fHSY1 <> inLayerY) then DoLayerNotify(fLayersCurrent, ielRotated); If SyncLayers() and Center then Update() else invalidate; end else if (fMovingRotationCenter > -1) then begin fMovingRotationCenter := -1; end; if (miRotateLayers in fMouseInteract) and (fHSX1 = inLayerX) and (fHSY1 = inLayerY) then begin // just select a layer sl := FindLayerAt(X, Y); // Deselect current layer? if ( sl > -1 ) and ( LayersAllowMultiSelect ) and ( Layers[ sl ].fSelected ) and ( ssShift in Shift ) then begin Layers[ sl ].fSelected := False; DoLayerNotify( sl, ielDeselected ); SelectByGroupIndex( Layers[ sl ].GroupIndex, False, True ); SelectMaskOfLayer( sl, False, True ); sl := -1; Update; end; if sl > -1 then begin bDeselect := NOT ( Layers[ sl ].fSelected or ( ssShift in Shift )); if SetLayersCurrentEx( sl, True, bDeselect ) then DoLayerNotify(fLayersCurrent, ielSelected); end; end; if fLayerResizing <> ieNone then begin fLayerResizing := ieNone; if (fHSX1 <> inLayerX) or (fHSY1 <> inLayerY) then DoLayerNotify(fLayersCurrent, ielResized); if ( Layers[ fLayersCurrent ] is TIELineLayer ) and ( TIELineLayer( Layers[ fLayersCurrent ] ).AutoSize ) then TIELineLayer( Layers[ fLayersCurrent ] ).SizeToFit(); SyncLayers(); Update; // needed to update magnify-resized layer end; fSelectMoving := -1; fRectResizing := ieNone; fRectSelecting := false; fCircSelecting := false; fLassoSelecting := false; if callselectionchange then DoSelectionChange; end; if ( Button = mbRight ) and ( iesoRightButtonTerminatePolySelect in fSelectionOptions ) then TerminatePolySelection( ssShift in Shift, false ) else if ( Button = mbLeft ) and ( iesoAutoTerminatePolySelect in fSelectionOptions ) and ( GetPolySelCount > 1 ) and ( Abs( XScr2Bmp( X, True ) - GetPolySel( 0 ).X ) < Poly_Select_Near_Region ) and ( Abs( YScr2Bmp( Y, True ) - GetPolySel( 0 ).Y ) < Poly_Select_Near_Region ) then TerminatePolySelection( ssShift in Shift, false ); if fZoomFilter <> fActualZoomFilter then begin fActualZoomFilter := fZoomFilter; Update; end; fSelectionBase := fSavedSelectionBase; end; // Called whenever the zoom or viewx/y changes. // It calls fOnViewChange procedure TImageEnView.ViewChange(c: integer); begin fRulerParams.Update( False ); UpdateTextEditor(); if assigned(fOnViewChange) then fOnViewChange(self, c); if assigned(fNavigator) then SetNavigatorRect; end; procedure TImageEnView.ViewChanging(c: integer; newValue: double); begin if assigned(fOnViewChanging) then fOnViewChanging(self, c, newValue); end; // draw background on Width and Height area procedure IEDrawBackground(ComponentState: TComponentState; Canvas: TCanvas; Bitmap: TBitmap; fBackgroundStyle: TIEBackgroundStyle; fBackground: TColor; DestX, DestY, Width, Height: integer; x1, y1, x2, y2: integer; fChessboardSize: integer; fChessboardBrushStyle: TBrushStyle; fChessboardColor2Customized: Boolean; fGradientEndColor: TColor; Wallpaper: TPicture; WallpaperStyle: TIEWallpaperStyle; LiveBackground: TIEBitmap); const BS: array[iebsSolid..iebsDiagCross] of TBrushStyle = (bsSolid, bsHorizontal, bsVertical, bsFDiagonal, bsBDiagonal, bsCross, bsDiagCross); var x, y, i1, i2: integer; b1, b2: boolean; rc: TRect; px: PRGB; c: array [0..1] of TRGB; hh: Integer; begin with Canvas do case fBackgroundStyle of iebsGradient: IEDrawGradient(Rect(DestX, DestY, width + DestX, height + DestY), Canvas.handle, fBackground, fGradientEndColor, true); iebsSolid..iebsDiagCross: begin Brush.Color := fBackground; Brush.Style := BS[fBackgroundStyle]; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); end; iebsChessBoard, iebsPhotoLike: begin if fBackgroundStyle = iebsPhotoLike then begin IEDrawBackground(ComponentState, Canvas, Bitmap, iebsSolid, $B0B0B0, DestX, DestY, Width, Height, x1, y1, x2, y2, fChessboardSize, fChessboardBrushStyle, fChessboardColor2Customized, fGradientEndColor, Wallpaper, WallpaperStyle, LiveBackground); Canvas.Pen.Color := clBlack; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Width := 1; Canvas.Pen.Style := psSolid; Canvas.Brush.Style := bsClear; Canvas.Rectangle(x1-1, y1-1, x2+1, y2+1); DestX := x1; DestY := y1; Width := x2-x1; Height := y2-y1; end; if (Bitmap <> nil) and (fChessboardBrushStyle = bsSolid) and (Bitmap.PixelFormat = pf24bit) then begin c[0] := TColor2TRGB( fBackground ); if fChessboardColor2Customized then c[1] := TColor2TRGB( fGradientEndColor ) else c[1] := TColor2TRGB( not fBackground ); b1 := false; i2 := 0; hh := Bitmap.Height; for y := DestY to DestY+Height-1 do begin b2 := b1; if y<0 then px := Bitmap.Scanline[0] else if y>=hh then px := Bitmap.Scanline[hh-1] else px := Bitmap.Scanline[y]; inc(px, DestX); i1 := 0; for x := 0 to Width-1 do begin px^ := c[integer(b2)]; if i1=fChessboardSize then begin b2 := not b2; i1 := 0; end; inc(i1); inc(px); end; if i2=fChessboardSize then begin b1 := not b1; i2 := 0; end; inc(i2); end; end else begin Brush.Style := fChessboardBrushStyle; y := DestY; b1 := false; while y < Height + DestY do begin b2 := b1; b1 := not b1; x := DestX; while x < Width + DestX do begin if b2 then Brush.Color := fBackground else if fChessboardColor2Customized then Brush.Color := fGradientEndColor else Brush.Color := not fBackground; b2 := not b2; FillRect(rect(x, y, imin(x + fChessboardSize, DestX + Width), imin(y + fChessboardSize, DestY + Height))); inc(x, fChessboardSize); end; inc(y, fChessboardSize); end; end; end; iebsDiagonals: begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); Pen.Color := not fBackground; Pen.Style := psSolid; moveto(DestX, DestY); lineto(Width + DestX, Height + DestY); moveto(Width + DestX, DestY); lineto(DestX, Height + DestY); end; iebsCropped: begin if (csDesigning in ComponentState) then begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); end else begin Brush.Color := clBtnFace; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); if ((x2 - x1) > 1) and ((y2 - y1) > 1) then begin rc := rect(x1 - IEGlobalSettings().EdgeX, y1 - IEGlobalSettings().EdgeY, x2 + IEGlobalSettings().EdgeX, y2 + IEGlobalSettings().EdgeY); {$IFDEF IEHASTHEMING} if IEStyleServices_Enabled then begin Canvas.Pen.Color := clGray; Canvas.Pen.Mode := pmCopy; Canvas.Pen.Width := 1; Canvas.Pen.Style := psSolid; Canvas.Brush.Style := bsClear; Canvas.Rectangle(x1-1, y1-1, x2+1, y2+1); end else {$ENDIF} DrawEdge(Canvas.Handle, rc, EDGE_SUNKEN, BF_RECT); end; end; end; iebsCropShadow: begin if (csDesigning in ComponentState) then begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); end else begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); if ((x2 - x1) > 1) and ((y2 - y1) > 1) then begin IERightShadow(Canvas, Bitmap, x2, y1, x2 + 5, y2 + 3, iestSmooth1, fBackground); IEBottomShadow(Canvas, Bitmap, x1, y2, x2 + 4, y2 + 5, iestSmooth1, fBackground); end; end; end; iebsSoftShadow: begin if (csDesigning in ComponentState) then begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); end else begin if assigned(Bitmap) then begin Brush.Color := fBackground; Brush.Style := bsSolid; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); if ((x2 - x1) > 1) and ((y2 - y1) > 1) then IERectShadow(Bitmap, x1, y1, x2, y2, fBackground); end; end; end; iebsBlurredImage: if assigned( LiveBackground ) and not LiveBackground.IsEmpty then LiveBackground.DrawToCanvas( Canvas, 0, 0 ) else begin Brush.Color := fBackground; FillRect(rect(DestX, DestY, Width + DestX, Height + DestY)); end; end; // Draw wallpaper if assigned(Wallpaper) and assigned(Wallpaper.Graphic) then case WallpaperStyle of iewoNormal : Canvas.Draw( 0, 0, Wallpaper.Graphic ); iewoStretch : Canvas.StretchDraw( rect( 0, 0, Width, Height ), Wallpaper.Graphic ); iewoTile : TileBitmapOntoCanvas( Canvas, Width, Height, Wallpaper.Graphic ); end; end; // fo1x, fo1y, fo2x, fo2y , frx, fry procedure TImageEnView.CalcPaintCoordsEx(var XSrc, YSrc, SrcWidth, SrcHeight: integer; var DstWidth, DstHeight: integer; tViewX, tViewY: integer); var rr: double; begin XSrc := 0; SrcWidth := 0; YSrc := 0; SrcHeight := 0; if fZZWW <> 0 then begin rr := fLayersRect.width / fZZWW; XSrc := round(QuantizeViewX(tViewX) * rr); SrcWidth := round(fExtx * rr); if (XSrc + SrcWidth) > fLayersRect.width then dec(SrcWidth); end; if fZZHH <> 0 then begin rr := fLayersRect.height / fZZHH; YSrc := round(QuantizeViewY(tViewY) * rr); SrcHeight := round(fExty * rr); if (YSrc + SrcHeight) > fLayersRect.height then dec(SrcHeight); end; if fZoomX > 100 then begin DstWidth := trunc(SrcWidth * fZoomD100X); if (DstWidth < fExtX) and (XSrc + SrcWidth + 1 <= fLayersRect.width) then begin inc(SrcWidth); DstWidth := trunc(SrcWidth * fZoomD100X); end; end else DstWidth := fExtX; if fZoomY > 100 then begin DstHeight := trunc(SrcHeight * fZoomD100Y); if (DstHeight < fExtY) and (YSrc + SrcHeight + 1 <= fLayersRect.height) then begin inc(SrcHeight); DstHeight := trunc(SrcHeight * fZoomD100Y); end; end else DstHeight := fExtY; end; procedure TImageEnView.CalcPaintCoords; begin CalcPaintCoordsEx(fo1x, fo1y, fo2x, fo2y, frx, fry, fViewX, fViewY); end; {!! TImageEnView.ZoomFilter Declaration property ZoomFilter: ; Description Specifies the filter to apply when the image is not displayed at normal size (i.e. is not 100). It improves the quality of the image display. For fastest display the ZoomFilter should be set to rfNone (default), but better quality is achieved with a filter such as rfLancoz3. Default: rfNone Demo Demos\Display\ZoomFilter\ZoomFilter.dpr Example // Performs a 400% quality zoom ImageEnView1.ZoomFilter := rfFastLinear; ImageEnView1.Zoom := 400; !!} procedure TImageEnView.SetZoomFilter(v: TResampleFilter); begin if fZoomFilter <> v then begin fZoomFilter := v; fActualZoomFilter := v; Update; end; end; {!! TImageEnView.Assign Declaration procedure Assign(Source: TObject); reintroduce; overload; Description Copy the content of a TBitmap, , or to the current control. Example // Copy content from another TImageEnView, including layers and IO params ImageEnView1.Assign(ImageEnView2); // Copy only the image of another TImageEnView ImageEnView1.Assign(ImageEnView2.IEBitmap); See Also - !!} procedure TImageEnView.Assign(Source: TObject); var si: TImageEnView; i: Integer; iLayerID: Integer; begin if Source = nil then Clear else if Source is TImageEnView then begin si := (Source as TImageEnView); LockUpdate(); // Disable navigator SetNavigator(nil); fBackground := si.fBackground; // IO Params IO.Params.Assign( si.IO.Params ); // Layers LayersClear; for i := 0 to si.LayersCount - 1 do begin if i > 0 then // layer 0 already is here, no need to create iLayerID := LayersAddEx( si.Layers[i].Kind, 0, 0 ) else iLayerID := 0; Layers[ iLayerID ].Assign( si.Layers[i] ); // here bitmaps are also copied end; // Vect objects if (Source is TImageEnVect) and (Self is TImageEnVect) then (Source as TImageEnVect).CopyAllObjectsTo(Self as TImageEnVect); UnlockUpdate; ImageChange(); // Navigator if si.IsNavigator then SetNavigator(si.fNavigator); end else if Source is TBitmap then begin // Ensure an image layer is active if ( fLayersCurrent > -1 ) and ( Layers[ fLayersCurrent ].Kind <> ielkImage ) then SetLayersCurrent( 0 ); // Base layer always image fIEBitmap.CopyFromTBitmap(source as TBitmap); if (fIEBitmap.PixelFormat <> ie1g) and (fIEBitmap.PixelFormat <> ie24RGB) then fIEBitmap.PixelFormat := ie24RGB; Update; ImageChange; end else if Source is TIEBitmap then begin // Ensure an image layer is active if ( fLayersCurrent > -1 ) and ( Layers[ fLayersCurrent ].Kind <> ielkImage ) then SetLayersCurrent( 0 ); // Base layer always image fIEBitmap.Assign(Source); Update; ImageChange; end; end; // ret True if the polygon is a rectangle // "n" is the number of vertex function _IsRectangle(p: PPointArray; n: integer): boolean; var q: integer; vv: boolean; // vv=false (x equals) vv=true (y equals) begin result := false; if (n = 4) then begin if (p^[3].x = p^[0].x) and (p^[3].y <> p^[0].y) then vv := true else if (p^[3].x <> p^[0].x) and (p^[3].y = p^[0].y) then vv := false else exit; for q := 0 to 2 do if (p^[q].x = p^[q + 1].x) and (p^[q].y <> p^[q + 1].y) and (not vv) then vv := true else if (p^[q].x <> p^[q + 1].x) and (p^[q].y = p^[q + 1].y) and vv then vv := false else exit; result := true; end; end; {!! TImageEnView.MouseInteract Declaration property MouseInteract: ; Description Specify which mouse activities are performed when the user interacts with the ImageEnView component with the mouse. Note: Multiple interactions can be specified, but activities that are not mutually compatible will be excluded Examples // Single left click zoom-in image, single right click zoom-out image, click and // drag scroll the image (if it is bigger than client area). ImageEnView1.MouseInteract := [ miZoom, miScroll ]; // Allow users to create image layers. Prompt for an image file after selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoPromptForImage ]; ImageEnView1.MouseInteract := [ miCreateImageLayers ]; // Allow user to move and resize layers (allow multiple layer selection and ensure masks are moved with layers) ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAllowMultiSelect, loAutoSelectMask ]; ImageEnView1.MouseInteract := [ miMoveLayers, miResizeLayers ]; A selected text layer with resize grips: // Allow user to rotate layers (allow multiple layer selection and ensure masks are moved with layers) ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAllowMultiSelect, loAutoSelectMask ]; ImageEnView1.MouseInteract := [ miRotateLayers ]; // Allow circular selections ImageEnView1.MouseInteract := [ miSelectCircle ]; // Allow the user to create, size and select red arrows ImageEnView1.MouseInteract := [ miCreateLineLayers, miMoveLayers, miResizeLayers ]; ImageEnView1.LayerDefaults.Clear(); ImageEnView1.LayerDefaults.Add( IELP_LineColor +'=clRed' ); ImageEnView1.LayerDefaults.Add( IELP_LineWidth +'=6' ); ImageEnView1.LayerDefaults.Add( IELP_LineShapeSize +'=20' ); ImageEnView1.LayerDefaults.Add( IELP_LineStartShape +'=1' ); ImageEnView1.LayerDefaults.Add( IELP_Rotate +'=235' ); Demos Demos\FullApps\PhotoEn3\ImageEx.dpr Demos\Display\SoftPan\SoftPan.dpr Demos\ImageEditing\RotateLayers\RotateLayers.dpr Demos\ImageEditing\Layers_AllTypes\Layers.dpr See Also - - !!} function TImageEnView.GetMouseInteract: TIEMouseInteract; begin result := fMouseInteract; end; {!! TImageEnView.CropToolInteraction Declaration property CropToolInteraction: ; Description Provides access to the methods and properties of the class, which is used when is miCropTool. The crop tool allows the user to select an area of the image to keep and then click "Enter" to apply the crop. The selection can also be rotated so the image is rotated and then cropped. In Crop Tool mode: - User can resize crop box by dragging grips - User can rotate crop by dragging outside grips - User can click "Enter" to enact the crop - User can click "Esc" to cancel the crop Rotated Crop Perspective Fix Demo Demos\ImageEditing\CropTool\CropTool.dpr Example // Disable guide lines (on image thirds) ImageEnView1.CropToolInteraction.DrawGuides := False; // Make larger grips ImageEnView1.CropToolInteraction.GripSize := 12; // High quality cropping ImageEnView1.CropToolInteraction.AntialiasMode := ierBicubic; // Enable crop mode ImageEnView1.MouseInteract := [miCropTool]; // Enact crop (same as user clicking "Enter") ImageEnView1.CropToolInteraction.Crop(); // Cancel crop tool (same as user clicking "Esc") ImageEnView1.CropToolInteraction.Cancel(); !!} function TImageEnView.GetCropToolInteraction: TIECropToolInteraction; begin Result := fUserInteractions[ fUserInteractions.FindInstanceOf( TIECropToolInteraction )] as TIECropToolInteraction; end; {!! TImageEnView.BackgroundStyle Declaration property BackgroundStyle: ; Description Specifies the style of the image background (the region of the ImageEnView window that is not filled by the image). Example ImageEnView1.BackgroundStyle := iebsPhotoLike; See Also - - - - !!} procedure TImageEnView.SetBackgroundStyle(v: TIEBackgroundStyle); begin fBackgroundStyle := v; invalidate; UpdateReason := ieurComponentStuffChanged; Update; end; procedure TImageEnView.DoSelectionChanging; begin SwapSelectionBase; if Assigned(fOnSelectionChanging) then OnSelectionChanging(self); SwapSelectionBase; end; procedure TImageEnView.DoSelectionChange; begin if Assigned(fOnSelectionChange) then OnSelectionChange(self); end; procedure TImageEnView.DoBeforeSelectionChange; begin SwapSelectionBase; if Assigned(fOnBeforeSelectionChange) then OnBeforeSelectionChange(self); SwapSelectionBase; end; {!! TImageEnView.CopyFromPolygon Declaration procedure CopyFromPolygon(Source: TBitmap; const Polygon: array of TPoint; PolygonLen: Integer; const Position: TPoint); Description CopyFromPolygon copies a region (Polygon) of source bitmap to current image. CopyFromPolygon enlarges current bitmap when needed. Parameter Description Source Source bitmap Polygon Array of polygon vertexes (pixel coordinates related to Source bitmap) PolygonLen Number of vertexes in polygon Position Destination point (pixel coordinate related to current image). The destination point is the top-left side of the rectangle that encloses source polygon
Example // Copies current selected area of ImageEnView1 to ImageEnView2 at position 0, 0 ImageEnView2.CopyFromPolygon(ImageEnView1.Bitmap, ImageEnView1.PolySelPoints^, ImageEnView1.PolySelCount, Point(0, 0)); // Copies the rect 0, 0, 100, 100 in ImageEnView2 at position 0, 0 ImageEnView2.CopyFromPolygon(ImageEnView1.Bitmap, [Point(0, 0), Point(100, 0), Point(100, 100), Point(0, 100)], 4, Point(0, 0)); // Copies current selection to ImageEnView2. Then enhance contrast of ImageEnView2 and copy back to ImageEnView1 (in some selection). ImageEnView2.CopyFromPolygon(ImageEnView1.Bitmap, ImageEnView2.PolySelPoints^, ImageEnView2.PolySelCount, Point(0, 0)); ImageEnView2.Proc.Contrast(30); ImageEnView2.CopyToPolygon(ImageEnView1.Bitmap, ImageEnView1.PolySelPoints^, ImageEnView1.PolySelCount, Point(0, 0)); ImageEnView1.Update; !!} // Copy the polygon Polygon of Source in Position of fBitmap procedure TImageEnView.CopyFromPolygon(Source: TBitmap; const Polygon: array of TPoint; PolygonLen: integer; const Position: TPoint); begin _CopyPolygonToPoint(Source, @Polygon, PolygonLen, fBitmap, Position); Update; end; {!! TImageEnView.CopyToPolygon Declaration procedure CopyToPolygon(Dest: TBitmap; const Polygon: array of TPoint; PolygonLen: Integer; const Position: TPoint); Description CopyToPolygon copies a region (Polygon) of current image inside Dest bitmap. Polygon is an array of TPoint (pixel coordinates related to Dest bitmap) and PolygonLen is the number of point in Polygon. Position is the source point (pixel coordinate related to current image). The source point is the top-left side of the rectangle that encloses destination polygon. CopyToPolygon enlarges destination bitmap when needed. Example // Copies current selection to ImageEnView2. Then enhance contrast of ImageEnView2 and copy back to ImageEnView1 (in some selection). ImageEnView2.CopyFromPolygon(ImageEnView1.Bitmap, ImageEnView2.PolySelPoints^, ImageEnView2.PolySelCount, Point(0, 0)); ImageEnView2.Proc.Contrast(30); ImageEnView2.CopyToPolygon(ImageEnView1.Bitmap, ImageEnView1.PolySelPoints^, ImageEnView1.PolySelCount, Point(0, 0)); ImageEnView1.Update; !!} // copy the rect at Position of fBitmap in Polygon of Dest procedure TImageEnView.CopyToPolygon(Dest: TBitmap; const Polygon: array of TPoint; PolygonLen: integer; const Position: TPoint); begin _CopyPointToPolygon(fBitmap, @Polygon, PolygonLen, Dest, Position); end; function TImageEnView.GetScrollBarsAlwaysVisible: boolean; begin result := fScrollBarsAlwaysVisible; end; procedure TImageEnView.SetScrollBarsAlwaysVisible(v: boolean); begin fScrollBarsAlwaysVisible := v; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.DisplayGridKind Declaration property DisplayGridKind:
; Description Enables the display of helper lines over the image. Item Description iedgNone No guide lines are shown iedgPixelGrid A grid is shown marking each pixel when the image is zoomed in (e.g. for pixel editing in an image editor) iedgGuideLines Guide lines are shown horizontally and vertically over the image (e.g. to help align objects when rotating)
Examples // Draw a grid to show pixels when we zoom above 500% IEGlobalSettings().GridPen.Color := clSilver; IEGlobalSettings().GridPen.Style := psSolid; IEGlobalSettings().GridPen.Mode := pmNot; IEGlobalSettings().MinZoomDisplayGrid := 500; ImageEnView1.DisplayGridKind := iedgPixelGrid; // Enable guide lines to help line up images when manually rotating IEGlobalSettings().GridPen.Color := clSilver; IEGlobalSettings().GridPen.Style := psDot; IEGlobalSettings().GridPen.Mode := pmCopy; IEGlobalSettings().GuidelineCount := 4; ImageEnView1.DisplayGridKind := iedgGuideLines; See Also -
- - - - !!} procedure TImageEnView.SetDisplayGridKind(v: TIEGridKind); begin fDisplayGridKind := v; UpdateReason := ieurComponentStuffChanged; Update; end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (8/2/2016) function TImageEnView.GetDisplayGrid(): boolean; begin Result := fDisplayGridKind <> iedgNone; end; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (8/2/2016) procedure TImageEnView.SetDisplayGrid(v: boolean); begin if not v then DisplayGridKind := iedgNone else if DisplayGridKind = iedgNone then DisplayGridKind := iedgPixelGrid; end; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (21/2/2017) function TImageEnView.GetAutoFixRotationBorders(): boolean; begin Result := loAutoFixBorders in fLayerOptions; end; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (21/2/2017) procedure TImageEnView.SetAutoFixRotationBorders(v: boolean); begin if v then fLayerOptions := fLayerOptions + [ loAutoFixBorders ] else fLayerOptions := fLayerOptions - [ loAutoFixBorders ] end; {$endif} {!! TImageEnView.DisplayGridLyr Declaration property DisplayGridLyr: Integer; Description Specifies where to draw the grid if is iedgPixelGrid. -1 : current layer (default behavior) >= 0 : specific layer See Also - - - - !!} procedure TImageEnView.SetDisplayGridLyr(v: integer); begin fDisplayGridLyr := v; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.ShowRulers Declaration property ShowRulers: ; Description Specify whether rulers are shown on the TImageEnView. Rulers show the current position of the cursor and can include optional grips to mark the position of other objects. Use to configure the ruler properties. Default: [] (No rulers) Demo Demos\Other\ImageEnViewRulers\ImageEnViewRulers.dpr Example // Show rulers in TImageEnView ImageEnView1.ShowRulers := [ rdHorizontal, rdVertical ]; // Set units to CM ImageEnView1.RulerParams.Units := ieruCentimeters; !!} procedure TImageEnView.SetShowRulers(const v: TRulerDirs); begin if fShowRulers <> v then begin fShowRulers := v; UpdateReason := ieurComponentStuffChanged; fRulerParams.Update( False ); // May not be called in Update below, due to start up or design tiem Update; end; end; procedure TImageEnView.KeyDown(var Key: Word; Shift: TShiftState); begin inherited; if (ssShift in Shift) and fEnableShiftKey then begin case cursor of crIECrossSight : SetTempCursor(crIECrossSightPlus); crIEThickCross : SetTempCursor(crIEThickCrossPlus); end; end; if ( Key = VK_F2 ) and ( fLayersCurrent > -1 ) and ( Layers[ fLayersCurrent ].SupportsFeature( ielfTextEditing )) then begin LayersActivateTextEditor( fLayersCurrent ); end; end; procedure TImageEnView.KeyUp(var Key: Word; Shift: TShiftState); begin inherited; if (not (ssShift in Shift)) and fEnableShiftKey then begin RestoreCursor; end; end; procedure TImageEnView.KeyPress(var Key: Char); begin inherited; end; {!! TImageEnView.EndSelect Declaration procedure EndSelect; Description Terminates a selection specified by code using the and methods. Example ImageEnView1.AddSelPoint(0, 0); ImageEnView1.AddSelPoint(100, 100); ImageEnView1.AddSelPoint(50, 50); ImageEnView1.EndSelect; !!} // finalize selection (update fSelectionMask) procedure TImageEnView.EndSelect; begin fSelectionMask.DrawPolygon(fSelectionIntensity, PIEAnimPoly(fHPolySel)^.Poly, PIEAnimPoly(fHPolySel)^.PolyCount); // update mask if fSelectionMask.IsEmpty then begin // empty selection fSel := false; AnimPolygonClear(fHPolySel); end; end; function TImageEnView.GetClientWidth: integer; begin if fOffscreenPaint then result := Width else if HasParentWindow and HandleAllocated then result := inherited ClientWidth else result := 50; end; function TImageEnView.GetClientWidthExRulers: integer; begin if fOffscreenPaint then result := Width else if HasParentWindow and HandleAllocated then result := inherited ClientWidth - fRulerParams.RulerAreaLeft - fRulerParams.RulerAreaRight else result := 50; end; function TImageEnView.GetClientHeight: integer; begin if fOffscreenPaint then result := Height else if HasParentWindow and HandleAllocated then result := inherited Clientheight else result := 50; end; function TImageEnView.GetClientHeightExRulers: integer; begin if fOffscreenPaint then result := Height else if HasParentWindow and HandleAllocated then result := inherited Clientheight - fRulerParams.RulerAreaLeft - fRulerParams.RulerAreaRight else result := 50; end; {!! TImageEnView.SelColor1 Declaration property SelColor1: TColor Description SelColor1 and set the two colors of the animated selection polygon. !!} procedure TImageEnView.SetSelColor1(v: TColor); begin PIEAnimPoly(fHPolySel)^.Color1 := v; fSelColor1 := v; end; {!! TImageEnView.SelColor2 Declaration property SelColor2: TColor Description and SelColor2 set the two colors of the animated selection polygon. !!} procedure TImageEnView.SetSelColor2(v: TColor); begin PIEAnimPOly(fHPolySel)^.Color2 := v; fSelColor2 := v; end; function TImageEnView.GetImageEnIO: TImageEnIO; begin if not assigned(fImageEnIO) then begin fImageEnIO := TImageEnIO.Create(self); fImageEnIO.AttachedImageEn := self; fImageEnIO.OnProgress := fOnProgress; fImageEnIO.OnFinishWork := fOnFinishWork; fImageEnIO.OnAcquireBitmap := fOnAcquireBitmap; end; result := fImageEnIO; end; function TImageEnView.GetImageEnProc: TImageEnProc; begin if not assigned(fImageEnProc) then begin fImageEnProc := TImageEnProc.Create(self); fImageEnProc.AttachedImageEn := self; fImageEnProc.OnProgress := fOnProgress; fImageEnProc.OnFinishWork := fOnFinishWork; fImageEnProc.OnSaveUndo := fOnSaveUndo; end; result := fImageEnProc; end; {!! TImageEnView.OnProgress Declaration property OnProgress: ; Description The OnProgress event is called when image processing or input/output operations are executed. If you are using it to update a progress bar then you can reset it in the event. Note: To determine what type of work is in progress, check the class of the Sender, e.g. if Sender is TImageEnIO then MainForm.Caption := format( 'IO Task Progress: %d%%', [ per ]) else if Sender is TImageEnProc then MainForm.Caption := format( 'Processing Task Progress: %d%%', [ per ]); Example // An example showing seperate progress display for I/O operations and processing operations procedure TMainForm.ImageEnView1Progress(Sender: TObject; per: Integer); begin // I/O PROGRESS if Sender is TImageEnIO then begin IOProgressBar.Position := per; IOProgressBar.Visible := True; end else // IMAGE PROCESSING PROGRESS if Sender is TImageEnProc then begin ProcProgressBar.Position := per; ProcProgressBar.Visible := True; end end; // Hide the progress bar procedure TMainForm.ImageEnView1FinishWork(Sender: TObject); begin // I/O PROGRESS if Sender is TImageEnIO then IOProgressBar.Visible := False else // IMAGE PROCESSING PROGRESS if Sender is TImageEnProc then ProcProgressBar.Visible := False; end; !!} function TImageEnView.GetOnProgress: TIEProgressEvent; begin result := fOnProgress; end; procedure TImageEnView.SetOnProgress(v: TIEProgressEvent); begin fOnProgress := v; if assigned(fImageEnIO) then fImageEnIO.OnProgress := v; if assigned(fImageEnProc) then fImageEnProc.OnProgress := v; end; {!! TImageEnView.OnAcquireBitmap Declaration property OnAcquireBitmap: ; Description Occurs whenever a new bitmap is acquired during an acquisition. Parameter Description Sender Will be either a TImageEnIO or TImageEnMIO control ABitmap A object that contains the acquired image DpiX, DpiY Tne DPI of the acquired image Handled Has no effect when acquiring via a TImageEnView/TImageEnIO
!!} function TImageEnView.GetOnAcquireBitmap: TIEAcquireBitmapEvent; begin result := fOnAcquireBitmap; end; procedure TImageEnView.SetOnAcquireBitmap(v: TIEAcquireBitmapEvent); begin fOnAcquireBitmap := v; if assigned(fImageEnIO) then fImageEnIO.OnAcquireBitmap := v; end; {!! TImageEnView.OnFinishWork Declaration property OnFinishWork: TNotifyEvent; Description Occurs whenever an image processing or input/output task terminates. It is always called after so is useful to reset a progress bar. Note: To determine what type of work has finished, check the class of the Sender, e.g. if Sender is TImageEnIO then ShowMessage( 'IO Task has finished' ) else if Sender is TImageEnProc then ShowMessage( 'Processing Task has finished' ) else ShowMessage( 'Unexpected result!' ) Example // An example showing seperate progress display for I/O operations and processing operations procedure TMainForm.ImageEnView1Progress(Sender: TObject; per: Integer); begin // I/O PROGRESS if Sender is TImageEnIO then begin IOProgressBar.Position := per; IOProgressBar.Visible := True; end else // IMAGE PROCESSING PROGRESS if Sender is TImageEnProc then begin ProcProgressBar.Position := per; ProcProgressBar.Visible := True; end end; // Hide the progress bar procedure TMainForm.ImageEnView1FinishWork(Sender: TObject); begin // I/O PROGRESS if Sender is TImageEnIO then IOProgressBar.Visible := False else // IMAGE PROCESSING PROGRESS if Sender is TImageEnProc then ProcProgressBar.Visible := False; end; !!} function TImageEnView.GetOnFinishWork: TNotifyEvent; begin result := fOnFinishWork; end; procedure TImageEnView.SetOnFinishWork(v: TNotifyEvent); begin fOnFinishWork := v; if assigned(fImageEnIO) then fImageEnIO.OnFinishWork := v; if assigned(fImageEnProc) then fImageEnProc.OnFinishWork := v; end; {!! TImageEnView.TransitionRunning Declaration property TransitionRunning: Boolean; Description TransitionRunning is True whenever a transition effect is being displayed. See Also - - - !!} function TImageEnView.GetTransitionRunning: boolean; begin result := assigned(fTransition) and fTransition.Running; end; {!! TImageEnView.PrepareTransition Declaration procedure PrepareTransition; Description PrepareTransition must be called prior to running a transition effect. It copies the currently displayed image to an internal buffer, which allows you to change current image (load, update, etc.) before starting the transition with . Example // Show a transition effect from the image already loaded in AImageEnView to our new image, Pic2.jpg AImageEnView.PrepareTransition; // Prepare the transition AImageEnView.IO.LoadFromFile('C:\Pic2.jpg'); // Load the new image (though it won't yet display) AImageEnView.RunTransition(iettRandompoints, 500); // Start display of the transition effect See Also - - - !!} procedure TImageEnView.PrepareTransition; var iebmp: TIEBitmap; begin if (GetClientWidth = 0) or (GetClientHeight = 0) then exit; SetupTransition; fTransition.SetSizes(ClientWidth, ClientHeight); iebmp := TIEBitmap.Create; try iebmp.EncapsulateTBitmap(fTransition.SourceShot, false); PaintToEx(iebmp, nil, true, true); finally iebmp.free; end; end; {!! TImageEnView.RunTransition Declaration procedure RunTransition(Effect : ; Duration : integer); overload; procedure RunTransition(Effect : ; Duration : integer; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean; Smoothing: Integer = 96); overload; procedure RunTransition(Effect : ; Duration : integer; PanZoomEffect : ; iZoomLevel : Integer; Smoothing: Integer = 96); overload; Description RunTransition starts the transition using Effect and Duration parameters. Effect specifies the effect. Duration specifies the duration of the transition in milliseconds. If effect is iettPanZoom then use one of the overloaded versions. Pan-Zoom Overload 1: Value Description StartRect The starting rectangle of an iettPanZoom transition (specified in bitmap points) EndRect The ending rectangle of an iettPanZoom transition (specified in bitmap points) bMaintainAspectRatio StartRect and EndRect will be automatically adjusted to ensure the image appears with the correct aspect ratio Smoothing In order to reduce the "jumpiness" of pan zoom effects, transition frames are alpha blended. A low value will improve smoothness, but increase blurriness. A high value will improve clarity, but increase jumpiness. Typical range is 64 - 196. 255 means no alpha blending
Pan-Zoom Overload 2: Value Description PanZoomEffect One of ImageEn's built-in Pan Zoom effects iZoomLevel If the specified PanZoomEffect is a "Zoom" type, then this specifies the maximum amount to zoom in, e.g. 20% Smoothing In order to reduce the "jumpiness" of pan zoom effects, transition frames are alpha blended. A low value will improve smoothness, but increase blurriness. A high value will improve clarity, but increase jumpiness. Typical range is 64 - 196. 255 means no alpha blending
iettShreddedFromLeft iettCubeRotateFromTop2 Demos Demos\Display\Transitions\Transitions.dpr Demos\Display\PanZoomEffects\PanZoomEffects.dpr Example // Transition from Image1.jpg to Image2.jpg with "Randon Points" transition ImageEnView1.IO.LoadFromFile('D:\image1.jpg'); // Load initial image ImageEnView1.PrepareTransition; // Prepare the transition ImageEnView1.IO.LoadFromFile('D:\image2.jpg'); // Load the next image (but does not display it) ImageEnView1.RunTransition(iettRandompoints, 500); // Execute the transition // Pan from the top-left corner of the image to the bottom-right (Image is 600 x 800) ImageEnView1.PrepareTransition; ImageEnView1.IO.LoadFromFile('D:\image.jpg'); ImageEnView1.RunTransition(iettPanZoom, 2000, // 2 second transition Rect(0, 0, 300, 400), // Top-left quarter Rect(300, 400, 600, 800), // Bottom-right quarter True); // Automatically adjust starting and ending rect to ensure the transition does not distort the image // Pan from the top-left corner of the image to the bottom-right ImageEnView1.PrepareTransition; ImageEnView1.IO.LoadFromFile('D:\image.jpg'); ImageEnView1.RunTransition(iettPanZoom, 2000, // 2 second transition iepzPanTopLeftToBottomRight, 20); See Also -
- - !!} procedure TImageEnView.RunTransition(Effect: TIETransitionType; duration: integer); var iebmp: TIEBitmap; begin if (GetClientWidth = 0) or (GetClientHeight = 0) then exit; // Select base layer SetLayersCurrent( 0 ); SetupTransition; if (duration < 1) then duration := 1; fTransitionEffect := Effect; fTransitionDuration := duration; fTransition.Transition := fTransitionEffect; fTransition.Duration := fTransitionDuration; fTransition.Background := GetThemeColor( ietpControlBackground, Background ); iebmp := TIEBitmap.Create; try iebmp.EncapsulateTBitmap(fTransition.TargetShot, false); PaintToEx(iebmp, nil, true, true); finally iebmp.free; end; fTransition.FullImage := fIEBitmap; fTransition.Run(true); // Now adjust the display to match the end position of the transition if Effect = iettPanZoom then VisibleBitmapRect := fTransition.EndRect; fTransitionEffect := iettNone; end; procedure TImageEnView.RunTransition(Effect: TIETransitionType; Duration: integer; PanZoomEffect : TIEPanZoomType; iZoomLevel : Integer; Smoothing: Integer = 96); var StartRect, EndRect : TRect; begin // Select base layer SetLayersCurrent( 0 ); GetPanZoomEffectStartEndRects(ClientWidth, ClientHeight, fIEBitmap.Width, fIEBitmap.Height, PanZoomEffect, iZoomLevel, StartRect, EndRect); RunTransition(Effect, Duration, StartRect, EndRect, True, Smoothing); end; procedure TImageEnView.RunTransition(Effect: TIETransitionType; Duration: integer; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean = True; Smoothing: Integer = 96); begin SetupTransition; if bMaintainAspectRatio then begin fTransition.StartRect := AdjustRectToAspectRatio( StartRect, True ); fTransition.EndRect := AdjustRectToAspectRatio( EndRect, True ); end else begin fTransition.StartRect := StartRect; fTransition.EndRect := EndRect; end; fTransition.Smoothing := Smoothing; RunTransition( Effect, Duration ); end; {$ifdef IEIncludeDeprecatedInV4} // Deprecated prior to v4.3.1 // DEPRECATED: Use TImageEnProc.PrepareTransitionBitmaps/CreateTransitionBitmaps procedure TImageEnView.PrepareTransitionBitmaps(OriginalBitmap, TargetBitmap : TBitmap; Effect : TIETransitionType; iWidth : Integer = -1; iHeight : Integer = -1); begin // Select base layer SetLayersCurrent( 0 ); SetupTransition; fTransition.Transition := Effect; fTransition.FullImage := fIEBitmap; fTransition.Background := GetThemeColor( ietpControlBackground, Background ); if Effect = iettPanZoom then begin fIEBitmap.assign(OriginalBitmap); fTransition.PrepareBitmap(OriginalBitmap, OriginalBitmap); end else begin fTransition.PrepareBitmap(OriginalBitmap, TargetBitmap); end; if iWidth > 0 then fTransition.SetSizes(iWidth, iHeight); end; {$endif} {$ifdef IEIncludeDeprecatedInV4} {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED OFF} {$ENDIF} // Deprecated prior to v4.3.1 // DEPRECATED: Use TImageEnProc.PrepareTransitionBitmaps/CreateTransitionBitmaps procedure TImageEnView.PrepareTransitionBitmaps(OriginalBitmap, TargetBitmap : TBitmap; Effect : TIETransitionType; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean = True; iWidth : Integer = -1; iHeight : Integer = -1); begin // Select base layer SetLayersCurrent( 0 ); SetupTransition; if bMaintainAspectRatio then begin fTransition.StartRect := AdjustRectToAspectRatio( StartRect, True ); fTransition.EndRect := AdjustRectToAspectRatio( EndRect, True ); end else begin fTransition.StartRect := StartRect; fTransition.EndRect := EndRect; end; PrepareTransitionBitmaps( OriginalBitmap, TargetBitmap, Effect, iWidth, iHeight ); end; {$IFDEF Delphi6orNewer} {$WARN SYMBOL_DEPRECATED ON} {$ENDIF} {$endif} {$ifdef IEIncludeDeprecatedInV4} // Deprecated prior to v4.3.1 // DEPRECATED: Use TImageEnProc.PrepareTransitionBitmaps/CreateTransitionBitmaps // TransitionProgress: The percentage that it is has progressed from the start image to the end image (ranging from 0.0 to 100.0) // ToBitmap: the bitmap to write it to procedure TImageEnView.CreateTransitionBitmap(TransitionProgress : Single; DestBitmap : TBitmap); begin SetupTransition; fTransition.CreateBitmap(TransitionProgress, DestBitmap); end; {$endif} {!! TImageEnView.AbortTransition Declaration procedure AbortTransition; Description This method aborts current transition started with . See Also - - - !!} procedure TImageEnView.AbortTransition; begin if assigned(fTransition) then fTransition.Stop; end; procedure TImageEnView.SetOnTransitionStop(value: TNotifyEvent); begin SetupTransition; fTransition.OnTransitionStop := value; end; {!! TImageEnView.OnTransitionStop Declaration property OnTransitionStop: TNotifyEvent; Description Occurs when the transition (that was started by using ) has finished its job (i.e. the transition effect has finished). !!} function TImageEnView.GetOnTransitionStop: TNotifyEvent; begin if assigned(fTransition) then result := fTransition.OnTransitionStop else result := nil; end; procedure TImageEnView.SetOnTransitionPaint(const Value: TIEOnTransitionPaint); begin SetupTransition; fTransition.OnTransitionPaint := Value; end; procedure TImageEnView.SetOnTransitionStep(value: TIETransitionStepEvent); begin SetupTransition; fTransition.OnTransitionStep := value; end; {!! TImageEnView.OnTransitionStep Declaration property OnTransitionStep: ; Description Occurs prior to the painting of each transition frame. Step is a value from 0 to 1024. !!} function TImageEnView.GetOnTransitionStep: TIETransitionStepEvent; begin if assigned(fTransition) then result := fTransition.OnTransitionStep else result := nil; end; {!! TImageEnView.OnTransitionPaint Declaration property OnTransitionPaint: ; Description Occurs immediately before a new transition frame is painted. Step is a value from 0 to 1024. !!} function TImageEnView.GetOnTransitionPaint: TIEOnTransitionPaint; begin if fTransition = nil then Result := nil else Result := fTransition.OnTransitionPaint; end; procedure TImageEnView.SetTransitionTiming(value: TIETransitionTiming); begin SetupTransition; fTransition.Timing := value; end; {!! TImageEnView.TransitionTiming Declaration property TransitionTiming: ; Description TransitionTiming provides alternative timing options for transition effect progress. Generally this will be iettLinear (normal progress). !!} function TImageEnView.GetTransitionTiming: TIETransitionTiming; begin SetupTransition; result := fTransition.Timing; end; {!! TImageEnView.Playing Declaration property Playing : boolean; Description Set Playing to True to animate GIF and AVI files. If is enabled then the animation will replay continuously Note: TImageEnView.Playing loads each frame on demand, which means that animations with short display times may appear jerky. It also cannot be used with LoadFromURL. You may find it more suitable to use TImageEnMView. instead which preloads all frames. !!} procedure TImageEnView.SetPlaying(const v : boolean); // Xequte: 13/11/12 begin if v = fPlaying then exit; fPlaying := v; if v = False then StopPlayTimer else StartPlayTimer; end; // Timer event for fPlayTimer procedure TImageEnView.WMTimer(var Message: TWMTimer); // Xequte: 13/11/12 begin StopPlayTimer; if IO.Params.ImageIndex >= IO.Params.ImageCount - 1 then begin IO.Seek(ieioSeekFirst); if fPlayLoop = False then begin // After we have looped back (in case they want to play again) Playing := False; exit; end; end else begin IO.Seek(ieioSeekNext); end; if IO.Aborting = False then StartPlayTimer; end; // Enable fPlayTimer if the current file is an animated GIF or AVI procedure TImageEnView.StartPlayTimer; // Xequte: 13/11/12 var iInterval: Integer; begin StopPlayTimer; if fPlaying = False then exit; iInterval := 0; if IO.Params.ImageCount > 1 then begin iInterval := IO.Params.ImageDelayTime; if iInterval < 1 then iInterval := Default_GIF_Animation_Delay_MS; end; if (iInterval > 0) and HasParentWindow then fPlayTimer := SetTimer(self.handle, 1, iInterval, nil); end; // Reset fPlayTimer procedure TImageEnView.StopPlayTimer; // Xequte: 13/11/12 begin // remove timer if fPlayTimer <> 0 then begin KillTimer(self.handle, 1); fPlayTimer := 0; end; end; // Returns an adjusted rect taking into account the aspect ratio of the image and display window // if TransitionActive it used whole client width, if false it excludes ruler area function TImageEnView.AdjustRectToAspectRatio(ARect: TRect; TransitionActive: Boolean): TRect; begin if IsEmpty then result := ARect else if TransitionActive then result := IEAdjustRectToAspectRatio( ARect, fIEBitmap_Width, fIEBitmap_Height, ClientWidth, ClientHeight ) else result := IEAdjustRectToAspectRatio( ARect, fIEBitmap_Width, fIEBitmap_Height, GetClientWidthExRulers, GetClientHeightExRulers ); end; {!! TImageEnView.AlphaChannel Declaration property AlphaChannel: ; Description Some formats like GIF, PNG, PSD, TIFF, ICO, CUR and TGA contain an alpha channel that specifies the image's transparency. The alpha channel is stored in the AlphaChannel property and in . property. !!} function TImageEnView.GetAlphaChannel: TIEBitmap; begin result := nil; if fIEBitmapValid then result := fIEBitmap.AlphaChannel; end; {!! TImageEnView.HasAlphaChannel Declaration property HasAlphaChannel: Boolean; (Read-only) Description Returns True if the current image has an alpha channel. !!} function TImageEnView.GetHasAlphaChannel: boolean; begin result := False; if fIEBitmapValid then result := fIEBitmap.HasAlphaChannel; end; {!! TImageEnView.InvertSelection Declaration procedure InvertSelection; Description InvertSelection changes the selection to everything except the current selection. Example ImageEnView1.Select(10, 10, 100, 100, iespReplace); // select box 10,10,100,100 ImageEnView1.InvertSelection; // select all excluding the box 10,10,100,100 !!} procedure TImageEnView.InvertSelection; begin fSelectionMask.SyncFull; if fSelectionMask.Full then Deselect else begin AnimPolygonClear(fHPolySel); ShowSelectionEx(true); fSelectionMask.Negative(fSelectionIntensity); fUpdateBackBuffer := true; Paint; end; end; {!! TImageEnView.EnableAlphaChannel Declaration property EnableAlphaChannel: Boolean; Description If EnableAlphaChannel is True, ImageEn uses the alpha channel to display the image. Some formats like Gif, Png, Tiff, Ico, Cur and Tga contain an alpha channel that specifies the image's transparency. The alpha channel is stored in the property (a object) and in TIEBitmap. property. !!} procedure TImageEnView.SetEnableAlphaChannel(v: boolean); begin if fEnableAlphaChannel <> v then begin fEnableAlphaChannel := v; Update; end; end; {!! TImageEnView.UpdateRect Declaration procedure UpdateRect(rclip: TRect); Description UpdateRect updates the rectangle, rclip. Use this function instead of Update when only a portion of the image has changed. Example // we assume that Zoom = 100 ImageEnView1.Bitmap.Canvas.Fill(0, 0, 10, 10); ImageEnView1.UpdateRect(rect(0, 0, 10, 10)); !!} procedure TImageEnView.UpdateRect(rclip: TRect); begin fUpdateBackBuffer := true; InvalidateRect(handle, @rclip, false); end; {!! TImageEnView.SetSelectedAreaAlpha Declaration procedure SetSelectedAreaAlpha(Alpha: Integer); Description Sets the Alpha value (transparency) for all pixels inside current selection. To activate the alpha channel (transparency), set to True. Example // set transparency to 180 inside 10,10,100,100 rectangle ImageEnView1.Select(10, 10, 100, 100); ImageEnVIew1.SetSelectedAreaAlpha(180); ImageEnView1.io.SaveToFile('C:\image.png'); // save with alpha channel !!} procedure TImageEnView.SetSelectedAreaAlpha(Alpha: integer); var y, x: integer; palpha: pbyte; psel: pbyte; begin if fIEBitmapValid = False then exit; if fSelectionMask.IsEmpty then // entire image GetAlphaChannel.Fill(Alpha) else begin // selected area for y := 0 to fSelectionMask.Height - 1 do begin palpha := fIEBitmap.AlphaChannel.ScanLine[y]; psel := fSelectionMask.ScanLine[y]; case fSelectionMask.BitsPerPixel of 1: for x := 0 to fSelectionMask.Width - 1 do begin if (pbytearray(psel)^[x shr 3] and iebitmask1[x and $7]) <> 0 then palpha^ := Alpha; inc(palpha); end; 8: for x := 0 to fSelectionMask.Width - 1 do begin if psel^ <> 0 then palpha^ := Alpha; inc(palpha); inc(psel); end; end; end; fIEBitmap.AlphaChannel.Full := false; end; Update; end; {!! TImageEnView.SetSelectionGripStyle Declaration procedure SetSelectionGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: Integer; ExtendedGrips: Boolean; boolean; Shape: ); Description SetSelectionGripStyle determines the appearance of selection grips. Parameter Description GripColor1 grip border color (default clBlack) GripColor2 grip brush color (default clWhite) GripBrushStyle brush style (default bsSolid) GripSize size in pixels of the grip (default 5) ExtendedGrips if true enables grips on border with 8 resizing grips (deault true) Shape specifies the grip shape
Use
to know current values. Example ImageEnView1.SetSelectionGripStyle(clWhite, clWhite, bsSolid, 5, true, iegsCircle); !!} procedure TImageEnView.SetSelectionGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: integer; ExtendedGrips: boolean; Shape: TIEGripShape); begin fGripColor1 := GripColor1; fGripColor2 := GripColor2; fGripBrushStyle := GripBrushStyle; fGripSize := GripSize; fGripShape := Shape; fExtendedGrips := ExtendedGrips; end; {!! TImageEnView.GetSelectionGripStyle Declaration procedure GetSelectionGripStyle(var GripColor1: TColor; var GripColor2: TColor; var GripBrushStyle: TBrushStyle; var GripSize: integer; var ExtendedGrips: boolean; var Shape: TIEGripShape); Description GetSelectionGripStyle returns properties which determines the appearance of selection grips. Parameter Description GripColor1 grip border color (default clBlack) GripColor2 grip brush color (default clWhite) GripBrushStyle brush style (default bsSolid) GripSize size in pixels of the grip (default 5) ExtendedGrips if true enables grips on border with 8 resizing grips (default: false) Shape specifies the grip shape
Use
to set current values. !!} procedure TImageEnView.GetSelectionGripStyle(var GripColor1: TColor; var GripColor2: TColor; var GripBrushStyle: TBrushStyle; var GripSize: integer; var ExtendedGrips: boolean; var Shape: TIEGripShape); begin GripColor1 := fGripColor1; GripColor2 := fGripColor2; GripBrushStyle := fGripBrushStyle; GripSize := fGripSize; Shape := fGripShape; ExtendedGrips := fExtendedGrips; end; {!! TImageEnView.SetLayersGripStyle Declaration procedure SetLayersGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: Integer; Shape: ); Description SetLayersGripStyle determines the appearance of layers grips. Parameter Description GripColor1 grip border color GripColor2 grip brush color GripBrushStyle brush style GripSize size in pixels of the grip Shape specifies the grip shape
Example ImageEnView1.SetLayersGripStyle(clWhite, clWhite, bsSolid, 5, iegsCircle); !!} procedure TImageEnView.SetLayersGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: integer; Shape: TIEGripShape); begin fLyrGripColor1 := GripColor1; fLyrGripColor2 := GripColor2; fLyrGripBrushStyle := GripBrushStyle; fLyrGripSize := GripSize; fLyrGripShape := Shape; end; {!! TImageEnView.SetChessboardStyle Declaration procedure SetChessboardStyle(Size: Integer; BrushStyle: TBrushStyle = bsSolid; Color1: TColor = clNone; Color2: TColor = clNone); Description Sets the size and brush of the chessboard background (when
is iebsChessboard). Parameter Description Size Specifies the box size (default 16) BrushStyle Specifies the brush style of the boxes (default bsSolid) Color1 Color 1 of chessboard. Specifying this as something other than clNone will set Color2 Color 2 of chessboard. If specified as clNone, then color 2 will be a reverse of Color 1
Example // Set small chessboard background of Yellow and Blue ImageEnView1.SetChessboardStyle( 5, bsSolid, clBlue, clYellow ); ImageEnView1.BackgroundStyle := iebsChessboard; !!} procedure TImageEnView.SetChessboardStyle(Size: integer = 16; BrushStyle: TBrushStyle = bsSolid; Color1: TColor = clNone_; Color2: TColor = clNone_); begin fChessboardSize := Size; fChessboardBrushStyle := BrushStyle; fChessboardColor2Customized := Color2 <> clNone_; if Color1 <> clNone_ then Background := Color1; if Color2 <> clNone_ then GradientEndColor := Color2; end; {!! TImageEnView.ApplyBitmapToSelection Declaration procedure ApplyBitmapToSelection(SrcBitmap: TBitmap; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); procedure ApplyBitmapToSelection(SrcBitmap: ; MergeAlpha: Boolean = True; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); Description Applies a bitmap to the selected region, stretching the image to the selection size. MergeAlpha will merge the alpha channel of the pasted bitmap with the background bitmap. If MaintainAspectRatio is False the inserted image will fill the entire selection. Set MaintainAspectRatio to true to maintain the aspect ratio of the original bitmap. CanStretch determines whether a source image smaller than the selection is enlarged or maintains its original size. Note: CanStretch has no effect if MaintainAspectRatio is False (image will always be stretched) Example // Flip just the selected portion of the image aIEBitmap := TIEBitmap.create; ImageEnView1.CopySelectionToBitmap( aIEBitmap ); aIEBitmap.Flip( fdVertical ); ImageEnView1.ApplyBitmapToSelection( aIEBitmap ); aIEBitmap.Free; // PARAMETER CHANGE EXAMPLES // Load Source Image aIEBitmap.Read( 'C:\Source.png' ); ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, False, False ); ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, True, False ); ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, True, True ); See Also - !!} procedure TImageEnView.ApplyBitmapToSelection(SrcBitmap: TBitmap; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); var TempBmp: TIEBitmap; begin TempBmp := TIEBitmap.Create; if SrcBitmap.PixelFormat <> pf1bit then SrcBitmap.PixelFormat := pf24bit; TempBmp.EncapsulateTBitmap( SrcBitmap, true ); ApplyBitmapToSelection( TempBmp, False, MaintainAspectRatio, CanStretch ); FreeAndNil( TempBmp ); end; procedure TImageEnView.ApplyBitmapToSelection(SrcBitmap: TIEBitmap; MergeAlpha: Boolean = True; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False); var iSX1, iSY1, iSX2, iSY2: Integer; aBitmap: TIEBitmap; Sz: TPoint; begin if (fIEBitmapValid = False) or (SrcBitmap.Width = 0) or (SrcBitmap.Height = 0) then exit; if assigned(fBitmap) then fIEBitmap.EncapsulateTBitmap(fBitmap, false); // synchronize fBitmap with fIEBitmap // Full image iSX1 := 0; iSY1 := 0; iSX2 := fIEBitmap.Width; iSY2 := fIEBitmap.Height; // Selection if Selected and not SelectionMask.IsEmpty then begin iSX1 := SelectionMask.X1; iSY1 := SelectionMask.Y1; iSX2 := SelectionMask.X2 + 1; iSY2 := SelectionMask.Y2 + 1; end; aBitmap := TIEBitmap.Create(); try if MaintainAspectRatio then begin Sz := GetImageSizeWithinArea( SrcBitmap.Width, SrcBitmap.Height, iSX2 - iSX1, iSY2 - iSY1, CanStretch ); iSX2 := iSX1 + Sz.X; iSY2 := iSY1 + Sz.Y; end; aBitmap.Allocate( iSX2 - iSX1, iSY2 - iSY1, SrcBitmap.PixelFormat ); _IEBmpStretchEx( SrcBitmap, aBitmap, nil, nil ); if SrcBitmap.HasAlphaChannel then begin _IEBmpStretchEx( SrcBitmap.AlphaChannel, aBitmap.AlphaChannel, nil, nil ); if MergeAlpha then SelectionMask.CombineWithAlpha( aBitmap.AlphaChannel, SelectionMask.x1, SelectionMask.y1, false ); end; aBitmap.CopyWithMask2( fIEBitmap, SelectionMask ); finally FreeAndNil(aBitmap); end; Update(); end; {!! TImageEnView.CopySelectionToBitmap Declaration procedure CopySelectionToBitmap(DestBitmap: TBitmap; FillBackground: Boolean = True); overload; procedure CopySelectionToBitmap(DestBitmap: ; FillBackground: Boolean = True); overload; Description Copies the current selection to the specified bitmap. If FillBackground is enabled, then non-selected areas of the copied rectangle of the image will be filled with the background color. Otherwise, it is transferred as alpha. Examples // Overload 1 ImageEnView1.CopySelectionToBitmap( ImageEnView2.Bitmap ); // Overload 2 ImageEnView1.CopySelectionToBitmap( ImageEnView2.IEBitmap ); // If an area of the image is selected, print the selection, otherwise print the whole image procedure TForm1.PrintImageClick(Sender: TObject); var bmp: TIEBitmap; IO: TImageEnIO; begin if ImageEnView1.Selected = False then ImageEnView1.IO.DoPrintPreviewDialog( iedtDialog, '' ) else begin bmp := TIEBitmap.Create; IO := TImageEnIO.CreateFromBitmap( bmp ); try ImageEnView1.CopySelectionToBitmap( bmp ); IO.DoPrintPreviewDialog( iedtDialog, '' ); finally IO.Free; bmp.Free; end; end; end; See Also - !!} // note: doesn't copy alpha channel procedure TImageEnView.CopySelectionToBitmap(DestBitmap: TBitmap; FillBackground: Boolean = True); var tempbmp: TIEBitmap; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); tempbmp := TIEBitmap.Create; if DestBitmap.PixelFormat<>pf1bit then DestBitmap.PixelFormat := pf24bit; tempbmp.EncapsulateTBitmap(DestBitmap, true); CopySelectionToBitmap(tempbmp, FillBackground); FreeAndNil(tempbmp); end; procedure TImageEnView.CopySelectionToBitmap(DestBitmap: TIEBitmap; FillBackground: Boolean = True); begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); if EnableAlphaChannel and not FillBackground then fIEBitmap.AlphaChannel; // Ensure we have an alpha channel so transparency is copied if (fRectResizing <> ieNone) or (fSelectMoving > -1) or fRectSelecting then begin fSelectionMask.Empty; EndSelect; end; if FillBackground then fIEBitmap.CopyWithMask1(DestBitmap, fSelectionMask, fBackground) else fIEBitmap.CopyWithMask1(DestBitmap, fSelectionMask); end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.0 procedure TImageEnView.CopySelectionToIEBitmap(DestBitmap: TIEBitmap; FillBackground: Boolean = True); begin CopySelectionToBitmap( DestBitmap, FillBackground ); end; {$endif} {!! TImageEnView.AssignSelTo Declaration procedure AssignSelTo(Dest: TPersistent); Description Assigns the selected area to the Dest object (can be a , TBitmap or TImage). Example // Create a triangular selection ImageEnView1.Deselect; ImageEnView1.AddSelPoint(100, 100); ImageEnView1.AddSelPoint(200, 100); ImageEnView1.AddSelPoint(150, 50); ImageEnView1.EndSelect; // assign selection to ImageEnView2 ImageEnView1.AssignSelTo( ImageEnView2 ); // assign selection to mybitmap (TBitmap) ImageEnView1.AssignSelTo( mybitmap ); !!} // Assign selection to Dest // Dest can be TImageEnView, TBitmap, TImage // Copy also background procedure TImageEnView.AssignSelTo(Dest: TPersistent); var di: TImageEnView; db: tbitmap; im: TImage; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); if Dest is TImageEnView then begin di := Dest as TImageEnView; if fSelectionMask.IsEmpty then di.IEBitmap.Assign(fIEBitmap) else CopySelectionToBitmap(di.IEBitmap, true); di.fBackground := Background; di.Update; di.ImageChange; end else if Dest is TBitmap then begin db := Dest as TBitmap; if fSelectionMask.IsEmpty then IECopyBitmap(fBitmap, db) else CopySelectionToBitmap(db); db.Modified := true; end else if Dest is TImage then begin im := Dest as TImage; if fSelectionMask.IsEmpty then IECopyBitmap(fBitmap, im.picture.bitmap) else CopySelectionToBitmap(im.picture.bitmap); im.picture.bitmap.Modified := true; end; end; {!! TImageEnView.CopyToBitmapWithAlpha Declaration procedure TImageEnView.CopyToBitmapWithAlpha(Dest: TBitmap; DestX, DestY: Integer); Description Copies the current image to the Dest bitmap, at DestX, DestY position. If the image has an alpha channel, CopyToBitmapWithAlpha copies only the visible area. Note: An exception will be raised if the image does not have an alpha channel. Example ImageEnView1.CopyToBitmapWithAlpha( ImageEnView2.Bitmap, 0, 0); ImageEnView2.Update; !!} // Dest must be pf24bit procedure TImageEnView.CopyToBitmapWithAlpha(Dest: TBitmap; DestX, DestY: integer); var dummy2, dummy3: PInteger; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); if Dest.PixelFormat <> pf24bit then Dest.PixelFormat := pf24bit; if fIEBitmap.HasAlphaChannel then begin dummy2 := nil; dummy3 := nil; fIEBitmap.RenderToTBitmap(Dest, dummy2, dummy3, nil, DestX, DestY, fIEBitmap.Width, fIEBitmap.Height, 0, 0, fIEBitmap.Width, fIEBitmap.Height, true, false, 255, rfNone, true, ielNormal); end else raise EIEException.create( 'Bitmap does not have an alpha channel' ); end; {!! TImageEnView.SetSelectedPixelsColor Declaration procedure SetSelectedPixelsColor(color: ); Description Sets selected pixels to the specified color. Example // select all pixels of a similar color to that 0, 0. Then fills all selected pixels with White. ImageEnView.SelectMagicWand(0, 0, iespReplace); ImageEnView.SetSelectedPixelsColor( CreateRGB(255, 255, 255) ); See Also - - - !!} procedure TImageEnView.SetSelectedPixelsColor(color: TRGB); var col, row: integer; px: PRGB; bitmapWidth, bitmapHeight: Integer; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); bitmapWidth := fIEBitmap.Width; bitmapHeight := fIEBitmap.Height; if fIEBitmap.PixelFormat = ie24RGB then begin for row := 0 to bitmapHeight - 1 do begin px := fIEBitmap.Scanline[row]; for col := 0 to bitmapWidth - 1 do begin if fSelectionMask.IsPointInside(col, row) then px^ := color; inc(px); end; end; Update; end; end; {!! TImageEnView.SetAlphaRangePixelsColor Declaration procedure SetAlphaRangePixelsColor(alphaMin, alphaMax: Integer; color: ); Description Sets all pixels that have an alpha channel value between alphaMin and alphaMax to the specified color. Example // this example loads an image with alpha channel, then paints all transparent pixels (0...254 alpha values) using White color, finally saves in a jpeg where we cannot save the alpha channel. ImageEnView.IO.LoadFromFile('C:\test.png'); ImageEnView.SetAlphaRangePixelsColor(0, 254, CreateRGB(255, 255, 255)); ImageEnView.IO.SaveToFile('C:\output.jpg'); See Also - - - !!} procedure TImageEnView.SetAlphaRangePixelsColor(alphaMin, alphaMax: integer; color: TRGB); var col, row: integer; px: PRGB; al: pbyte; bitmapWidth, bitmapHeight: Integer; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); if not HasAlphaChannel then exit; bitmapWidth := fIEBitmap.Width; bitmapHeight := fIEBitmap.Height; for row := 0 to bitmapHeight - 1 do begin px := fIEBitmap.Scanline[row]; al := fIEBitmap.AlphaChannel.ScanLine[row]; for col := 0 to bitmapWidth - 1 do begin if (al^ >= alphaMin) and (al^ <= alphaMax) then px^ := color; inc(px); inc(al); end; end; Update; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Layers {!! TImageEnView.LayersCount Declaration property LayersCount: Integer; Description LayersCount returns the number of layers. Examples // Clear the top-most layer ImageEnView1.LayersCurrent := ImageEnView1.LayersCount - 1; ImageEnView1.Clear; // Show each of the layers as a thumbnail in a TImageEnMView procedure Tfmain.RefreshLayerViewer; var i, idx: integer; begin 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; // Highlight current layer ImageEnMView1.SelectedImage := ImageEnView1.LayersCurrent; end; // Set rotation of all selected layers ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1Layers[ I ].Selected then ImageEnView1Layers[ I ].Rotate := 90; ImageEnView1.LayersFixRotations( LYR_SELECTED_LAYERS ); ImageEnView1.UnlockUpdate; !!} function TImageEnView.GetLayersCount: integer; begin result := fLayers.Count; end; function TImageEnView.GetLayer(idx: integer): TIELayer; begin result := TIELayer(fLayers[idx]); end; {!! TImageEnView.CurrentLayer Declaration property CurrentLayer: ; Description Provides access to the currently active layer. This is equivalent to: ImageEnView.Layers[ ImageEnView.LayersCurrent ] See the property for more info. Note: Use to get or set the current layer index. Use CurrentLayer to return the layer object. Example ImageEnView.LayersAdd; ImageEnView.CurrentLayer.Transparency := 200; // Remove the fill from the current layer ImageEnView1.CurrentLayer.FillColor := clNone; ImageEnView1.Update(); !!} function TImageEnView.GetCurrentLayer: TIELayer; begin result := TIELayer(fLayers[fLayersCurrent]); end; {!! TImageEnView.LayersCurrent Declaration property LayersCurrent: Integer; Description Use LayersCurrent to get/set the active layer. The first layer has the index of 0, the last is - 1. Making a layer current changes the and properties, so they point to the current layer (allowing specification of which layer is active for input/output and image processing operations). Notes: - Use to return the layer object. Use LayersCurrent to get or set the current layer index - Setting LayersCurrent does NOT deselect existing layers (if multiple layer selection is enabled) Example // load 'first.jpg' in layer 0 and 'second.jpg' in layer 1 ImageEnView1.LayersCurrent := 0; ImageEnView1.IO.LoadFromFile('C:\first.jpg'); ImageEnView1.LayersCurrent := 1; ImageEnView1.IO.LoadFromFile('C:\second.jpg'); // Clear the top-most layer ImageEnView1.LayersCurrent := ImageEnView1.LayersCount - 1; ImageEnView1.Clear; // Flip the 2nd layer ImageEnView1.LayersCurrent := 1; ImageEnView1.Proc.Flip( fdHorizontal ); !!} procedure TImageEnView.SetLayersCurrent(Value: integer); begin SetLayersCurrentEx( Value, False, False ); end; // Result is true if selection has changed function TImageEnView.SetLayersCurrentEx(Value: integer; bUserAction, bDeselectAll: Boolean; DoUpdate: Boolean = True): Boolean; var i: Integer; needUpdate: Boolean; begin needUpdate := False; if LayersAllowMultiSelect and bDeselectAll then for i := 0 to LayersCount - 1 do if ( i <> Value ) and TIELayer( fLayers[ I ]).fSelected then begin TIELayer( fLayers[ i ]).fSelected := False; if bUserAction then DoLayerNotify( i, ielDeselected ); needUpdate := True; end; if (Value >= 0) and (Value < fLayers.Count) and (Value <> fLayersCurrent) then begin // sync current layer (fLayersCurrent = -1 is a temporary state, where no layer is selected) if (fLayersCurrent > -1) and (fLayersCurrent < fLayers.Count) then begin SyncBitmapToCurrentLayer(); if fSel then SaveSelection; end; // set new layer while true do begin fLayersCurrent := Value; if (Layers[Value].Selectable = true) or (Value = 0) or (fLayersSelectConstrains = false) then break; dec(Value); end; // Non-image layers have no bitmap fIEBitmapValid := Layers[Value] is TIEImageLayer; if fIEBitmapValid then fIEBitmap := Layers[Value].Bitmap else fIEBitmap := Layers[0].Bitmap; if fIEBitmap.EncapsulatedFromTBitmap then fBitmap := fIEBitmap.VclBitmap else fBitmap := nil; if fSel then RestoreSelection(true, iersSyncLayers); CallBitmapChangeEvents; needUpdate := True; end; if LayersAllowMultiSelect and ( Value >= 0 ) and ( Value < fLayers.Count ) and ( Layers[Value].fSelected = False ) then begin Layers[ Value ].fSelected := True; SelectByGroupIndex( Layers[ Value ].GroupIndex, True, bUserAction ); SelectMaskOfLayer( Value, True, bUserAction ); needUpdate := True; end; if needUpdate and DoUpdate then begin if bUserAction and ( fLayersFastDrawing = iefDelayed ) then fStable := fDelayZoomTicks else Update; end; Result := needUpdate; end; // Sets all layers of a groupIndex to selected or unselected // DOES NOT CALL UPDATE procedure TImageEnView.SelectByGroupIndex(iGroupIndex: Integer; bSelect: Boolean; bUserAction: Boolean); var i: Integer; begin if iGroupIndex = 0 then exit; for i := 0 to LayersCount - 1 do if TIELayer( fLayers[ I ]).GroupIndex = iGroupIndex then begin TIELayer( fLayers[ i ]).fSelected := bSelect; SelectMaskOfLayer( i, bSelect, bUserAction ); if bUserAction then begin if bSelect then DoLayerNotify( i, ielSelected ) else DoLayerNotify( i, ielDeselected ); end; end; end; // If there is a layer mask associated with the specified layer then set it selected or unselected // DOES NOT CALL UPDATE procedure TImageEnView.SelectMaskOfLayer(iLayerIndex: Integer; bSelect: Boolean; bUserAction: Boolean); begin if not ( loAutoSelectMask in fLayerOptions ) then exit; if ( iLayerIndex + 1 < fLayers.Count ) and ( TIELayer( fLayers[ iLayerIndex + 1 ]).IsMask ) and ( TIELayer( fLayers[ iLayerIndex + 1 ]).fSelected <> bSelect ) then begin TIELayer( fLayers[ iLayerIndex + 1 ]).fSelected := bSelect; if bUserAction then begin if bSelect then DoLayerNotify( iLayerIndex + 1, ielSelected ) else DoLayerNotify( iLayerIndex + 1, ielDeselected ); end; end; end; {!! TImageEnView.LayersAdd Declaration // General overload function LayersAdd(Kind: = ielkImage): integer; overload; // Blank image overload (creates ) function LayersAdd(Width: Integer; Height: Integer; PixelFormat: = ie24RGB; PosX: Integer = -1; PosY: Integer = -1): Integer; // Assign bitmap overload (creates ) function LayersAdd(Bitmap: ): integer; // Loads image overload (creates ) function LayersAdd(FileName: String; PosX: Integer = -1; PosY: Integer = -1): integer; // Shape overload (creates ) function LayersAdd(Shape: ; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0): integer; // Text overload (creates ) function LayersAdd(Text: String; FontSize : Integer; FontColor : TColor; FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1): integer; Description Appends a new layer to the layers list. The new layer will become the current layer. First overload allows you to specify the layer type, all others create a . If the size and pixel format are not specified then the new layer assumes that of the current layer. You can specify PosX and PosY for the destination position of the layer. Pass as -1, -1 to use the next available position. Result is the index of the added layer. Examples ImageEnView1.IO.LoadFromFile( 'C:\first.jpg' ); // Load image into first layer (or current layer) ImageEnView1.LayersAdd(); // Append a new layer ImageEnView1.IO.LoadFromFile( 'C:\second.jpg' ); // Load image into the new layer (now the current layer) // Load an image from file and add it as a layer ImageEnView1.LayersAdd( 'C:\MyImage.jpg' ); // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 42, clRed, 'Arial Black', [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; // 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; // 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(); See Also - - - - - !!} function TImageEnView.LayersAddEx(Kind: TIELayerKind; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0; SrcBitmap: TIEBitmap = nil; DoCopyBitmap: Boolean = true; DoSaveUndo: Boolean = False; AssignDefaults: Boolean = False; SelLayer: Boolean = True ): Integer; begin Result := LayersInsertEx( fLayers.Count, Kind, PosX, PosY, Width, Height, SrcBitmap, DoCopyBitmap, DoSaveUndo, AssignDefaults, SelLayer ); end; function TImageEnView.LayersAdd(Kind: TIELayerKind = ielkImage): integer; begin result := fLayers.Count; LayersInsert( result, Kind ); end; function TImageEnView.LayersAdd(Width: Integer; Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB; PosX: Integer = -1; PosY: Integer = -1): Integer; begin result := fLayers.Count; LayersInsert( result, Width, Height, PixelFormat, PosX, PosY ); end; function TImageEnView.LayersAdd(FileName: WideString; PosX: Integer = -1; PosY: Integer = -1): Integer; begin result := fLayers.Count; LayersInsert( result, FileName, PosX, PosY ); end; function TImageEnView.LayersAdd(Bitmap: TIEBitmap; DoCopy: Boolean = True): integer; begin result := fLayers.Count; LayersInsert( Result, Bitmap, DoCopy ); end; function TImageEnView.LayersAdd(Shape: TIEShape; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0): Integer; begin result := fLayers.Count; LayersInsert( result, Shape, PosX, PosY, Width, Height ); end; function TImageEnView.LayersAdd(const Text: String; FontSize : Integer; FontColor : TColor; const FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1): integer; begin result := fLayers.Count; LayersInsert( result, Text, FontSize, FontColor, FontName, FontStyle, PosX, PosY ); end; {!! TImageEnView.LayersInsert Declaration // General overload procedure LayersInsert(Position: Integer; Kind: = ielkImage); overload; // Blank image overload (creates ) procedure LayersInsert(Position: Integer; Width: Integer; Height: Integer; PixelFormat: = ie24RGB; PosX: Integer = 0; PosY: Integer = 0); // Assign bitmap overload (creates ) procedure LayersInsert(Position: Integer; Bitmap: ); // Loads image overload (creates ) procedure LayersInsert(Position: Integer; FileName: String; PosX: Integer = -1; PosY: Integer = -1); // Shape overload (creates ) procedure LayersInsert(Position: Integer; Shape: ; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0); // Text overload (creates ) procedure LayersInsert(Position: Integer; Text: String; FontSize : Integer; FontColor : TColor; FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1); Description Inserts a new layer into the layers list at the specified position. The new layer will become the current layer. First overload allows you to specify the layer type, all others create a . If the size and pixel format are not specified then the new layer assumes that of the current layer. You can specify PosX and PosY for the destination position of the layer. Pass as -1, -1 to use the next available position. Note: Only a can be inserted at layer 0 (i.e. background). If you attempt to insert a non-image layer at position 0, it will be inserted at 1 Examples ImageEnView1.IO.LoadFromFile( 'C:\first.jpg' ); // Load image into first layer (will become background) ImageEnView1.LayersInsert( 1 ); // Insert a new layer above the background layer ImageEnView1.IO.LoadFromFile( 'C:\second.jpg' ); // Load image into the new layer (now the current layer) // Load an image from file and add it as a layer ImageEnView1.LayersInsert( 1, 'C:\MyImage.jpg' ); // Insert a text layer ImageEnView1.LayersInsert( 1, 'My text layer', 14, clBlack, 'Arial'); // Insert a yellow explosion shape layer at size 220 x 120 ImageEnView1.LayersInsert( 1, iesExplosion, 50, 50, 220, 120 ); ImageEnView1.CurrentLayer.FillColor := clYellow; ImageEnView1.CurrentLayer.BorderWidth := 0; ImageEnView1.Update(); // Insert an image layer and assign a pink border ImageEnView1.LayersAdd( 3, ielkImage ); // Insert an image layer after layer 2 (i.e. 3rd layer) ImageEnView1.IO.LoadFromFile('C:\New Zealand.jpg'); // Load image into the new/active layer ImageEnView1.CurrentLayer.BorderColor := $008000FF; ImageEnView1.CurrentLayer.BorderWidth := 3; // Insert a text layer ImageEnView1.LayersAdd( 1, 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(); See Also - - - - - !!} function TImageEnView.LayersInsertEx(Position: Integer; Kind: TIELayerKind; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0; SrcBitmap: TIEBitmap = nil; DoCopyBitmap: Boolean = true; DoSaveUndo: Boolean = False; AssignDefaults: Boolean = False; SelLayer: Boolean = True ): Integer; const Layer_Positioning_Left_Margin = 40; Layer_Positioning_Right_Margin = 50; Layer_Positioning_Increment = 40; var bmp: TIEBitmap; idx: Integer; begin SyncBitmapToCurrentLayer(); if DoSaveUndo then case Kind of ielkImage : Proc.SaveUndo( IEMsg( IEMsg_AddImageLayer ), ieuObjectsAndLayers, True, IEOP_ADDIMAGELAYER ); ielkShape : Proc.SaveUndo( IEMsg( IEMsg_AddShapeLayer ), ieuObjectsAndLayers, True, IEOP_ADDSHAPELAYER ); ielkLine : Proc.SaveUndo( IEMsg( IEMsg_AddLineLayer ), ieuObjectsAndLayers, True, IEOP_ADDLINELAYER ); ielkPolyline : Proc.SaveUndo( IEMsg( IEMsg_AddPolylineLayer ), ieuObjectsAndLayers, True, IEOP_ADDPOLYLINELAYER ); ielkText : Proc.SaveUndo( IEMsg( IEMsg_AddTextLayer ), ieuObjectsAndLayers, True, IEOP_ADDTEXTLAYER ); end; Result := Position; if ( Result < fLayers.Count ) and Layers[ Result ].IsMask then dec( Result ); if ( Result = 0 ) and ( Kind <> ielkImage ) then inc( Result ); // Base layer must be image case Kind of ielkImage : begin if SrcBitmap <> nil then begin // Create layer from passed bitmap if DoCopyBitmap then begin bmp := TIEBitmap.Create; bmp.Assign( SrcBitmap ); fLayers.Insert( Position, TIEImageLayer.Create(self, bmp, true)); end else fLayers.Insert( Position, TIEImageLayer.Create(self, SrcBitmap, true)); end else begin // Create blank bitmap layer if ( Width > 0 ) and ( Height > 0 ) then fLayers.Insert( Result, TIEImageLayer.Create( self, Width, Height )) else begin fLayers.Insert( Result, TIEImageLayer.Create( self, fIEBitmap, false )); if fIEBitmapValid = False then begin // inherit size of current object Layers[ Result ].Width := fIEBitmap_Width; Layers[ Result ].Height := fIEBitmap_Height; end; end; // Clear bitmap Layers[ Result ].Bitmap.Fill( fBackground ); Layers[ Result ].Bitmap.RemoveAlphaChannel( False, fBackground ); end; end; ielkShape : fLayers.Insert( Result, TIEShapeLayer.Create( self )); ielkLine : begin fLayers.Insert( Result, TIELineLayer.Create( self )); end; ielkPolyline : fLayers.Insert( Result, TIEPolylineLayer.Create( self )); ielkText : fLayers.Insert( Result, TIETextLayer.Create( self )); else raise Exception.create( 'Layer insertion error - Invalid Type: ' + IntToStr( ord( Kind ))); end; if Width > 0 then Layers[ Result ].Width := Width; if Height > 0 then Layers[ Result ].Height := Height; if ( PosX <> -1 ) and ( PosY <> -1 ) then begin Layers[ Result ].PosX := PosX; Layers[ Result ].PosY := PosY; end else if ( Layer_Positioning_Left_Margin + Layers[ Result ].Width + Layer_Positioning_Right_Margin < ClientWidth / fZoomD100X ) and ( Layer_Positioning_Left_Margin + Layers[ Result ].Height + Layer_Positioning_Right_Margin < ClientHeight / fZoomD100Y ) then begin inc( fNextLayerPosition, Layer_Positioning_Increment ); if ( fNextLayerPosition + Layers[ Result ].Width + Layer_Positioning_Right_Margin > ClientWidth / fZoomD100X ) or ( fNextLayerPosition + Layers[ Result ].Height + Layer_Positioning_Right_Margin > ClientHeight / fZoomD100Y ) then fNextLayerPosition := Layer_Positioning_Left_Margin; Layers[ Result ].PosX := fNextLayerPosition; Layers[ Result ].PosY := fNextLayerPosition; end; If AssignDefaults and ( fLayerDefaults <> nil ) then Layers[ Result ].SetProperties( fLayerDefaults ); idx := Result; if not SelLayer then idx := fLayersCurrent; fLayersCurrent := -1; SetLayersCurrentEx( idx, False, True ); // this calls update end; procedure TImageEnView.LayersInsert(Position: Integer; Kind: TIELayerKind = ielkImage); begin LayersInsertEx( Position, Kind, -1, -1, 0, 0, nil, False, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; procedure TImageEnView.LayersInsert(Position: Integer; Width: Integer; Height: Integer; PixelFormat: TIEPixelFormat = ie24RGB; PosX: Integer = -1; PosY: Integer = -1); begin LayersInsertEx( Position, ielkImage, PosX, PosY, -1, -1, TIEBitmap.Create( Max( 1, Width ), Max( 1, Height ), PixelFormat), False, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; procedure TImageEnView.LayersInsert(Position: Integer; FileName: WideString; PosX: Integer = -1; PosY: Integer = -1); begin LayersInsertEx( Position, ielkImage, PosX, PosY, 0, 0, nil, False, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); IO.LoadFromFile( FileName ); if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; procedure TImageEnView.LayersInsert(Position: Integer; Bitmap: TIEBitmap; DoCopy: Boolean = True); begin LayersInsertEx( Position, ielkImage, -1, -1, 0, 0, Bitmap, DoCopy, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; procedure TImageEnView.LayersInsert(Position: Integer; Shape: TIEShape; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0); begin LayersInsertEx( Position, ielkShape, PosX, PosY, Width, Height, nil, False, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); TIEShapeLayer( CurrentLayer ).Shape := Shape; if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; procedure TImageEnView.LayersInsert(Position: Integer; const Text: String; FontSize : Integer; FontColor : TColor; const FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1); begin LayersInsertEx( Position, ielkText, PosX, PosY, 0, 0, nil, False, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions ), True ); TIETextLayer( CurrentLayer ).Text := Text; if FontName <> '' then TIETextLayer( CurrentLayer ).Font.Name := FontName; if FontSize > 0 then TIETextLayer( CurrentLayer ).Font.Size := FontSize; if FontColor <> clNone_ then TIETextLayer( CurrentLayer ).Font.Color := FontColor; if FontStyle <> [] then TIETextLayer( CurrentLayer ).Font.Style := FontStyle; TIETextLayer( CurrentLayer ).SizeToText(); if assigned( fOnNewLayer ) then fOnNewLayer( Self, Position, CurrentLayer.Kind ); ImageChange(); end; {!! TImageEnView.LayersRemove Declaration procedure LayersRemove(LyrIndex: Integer = LYR_SELECTED_LAYERS); Description Removes a layer and frees the related bitmap. You can specify the index of a layer of LYR_SELECTED_LAYERS to remove all selected layers. Parameter Description idx Index of the layer to remove (0 = background/first layer). You can also specify LYR_SELECTED_LAYERS or LYR_ALL_LAYERS
Note: At least one layer must be present. Attempting to remove the final layer will empty its content. Example // Remove all selected layers ImageEnView1.LayersRemove(); // Remove the top-most layer ImageEnView1.LayersRemove( ImageEnView1.LayersCount - 1 ); See Also -
!!} // one layer musts remain procedure TImageEnView.LayersRemove(LyrIndex: Integer = LYR_SELECTED_LAYERS); begin LayersRemoveEx( LyrIndex, Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions )); end; procedure TImageEnView.LayersRemoveEx(LyrIndex: Integer = LYR_SELECTED_LAYERS; SaveUndo: Boolean = False); var idx: Integer; iWasLC: Integer; removeLayer: Boolean; begin if LyrIndex = LYR_ALL_LAYERS then begin LayersClear(); exit; end; if ( LyrIndex <> LYR_SELECTED_LAYERS ) and (( LyrIndex < 0 ) or ( LyrIndex >= fLayers.Count )) then exit; { Invalid selection } if SaveUndo then Proc.SaveUndo( IEMsg( IEMsg_RemoveLayer ), ieuObjectsAndLayers, True, IEOP_REMOVELAYER ); if ( LyrIndex = LYR_SELECTED_LAYERS ) and ( LayersAllowMultiSelect = False ) then LyrIndex := LayersCurrent; iWasLC := fLayersCurrent; SyncBitmapToCurrentLayer(); for idx := fLayers.Count - 1 downto 0 do begin if LyrIndex = LYR_SELECTED_LAYERS then removeLayer := TIELayer( fLayers[ idx ]).Selected else removeLayer := idx = LyrIndex; if removeLayer and ( idx = 0 ) and (( fLayers.Count = 1 ) or ( Layers[ idx + 1 ].Kind <> ielkImage )) then begin // Can't delete this layer (either last layer, or layer above is not an image), so just clear TIEImageLayer( Layers[ idx ]).Clear(); end else if removeLayer then begin // free idx + 1 layer if it is a layer mask if ( idx < fLayers.Count - 1 ) and Layers[ idx + 1 ].IsMask then begin Layers[ idx + 1 ].Free; fLayers.Delete( idx + 1 ); end; // free idx layer Layers[ idx ].Free; fLayers.Delete( idx ); if ( fLayersCurrent = idx ) or ( fLayersCurrent >= fLayers.Count )then fLayersCurrent := -1 else if idx < fLayersCurrent then dec( fLayersCurrent ); if LyrIndex <> LYR_SELECTED_LAYERS then Break; { No more to process } end; end; // set new current layer if fLayersCurrent = -1 then begin SetLayersCurrent( imin( iWasLC, fLayers.Count - 1 )); end else if fLayersCurrent > iWasLC then begin fLayersCurrent := -1; SetLayersCurrent( iWasLC - 1 ); end else if fLayersCurrent = 0 then Update(); ImageChange(); end; {!! TImageEnView.LayersClear Declaration procedure LayersClear; Description Removes all layers. Note: After completion only the background layer will remain (as an ImageEnView always requires at least one layer). Comparison of Methods Method Description Fills the current image with the background color and removes the alpha channel Calls and resets the image size to 1 x 1 Removes all of the layers Resets the image (calling ) and removes all layers (calling )
See Also - !!} // remove all layers procedure TImageEnView.LayersClear; var i: Integer; begin for i := fLayers.Count - 1 downto 1 do begin Layers[i].Free; fLayers.Delete(i); end; fLayersCurrent := -1; SetLayersCurrent( 0 ); Layers[0].SetDefaults; with Layers[0] do begin VisibleBox := false; Locked := true; end; Clear; end; {!! TImageEnView.LayersMove Declaration procedure LayersMove(CurIndex, NewIndex: Integer); Description Moves the layer at index, CurIndex, to the position, NewIndex. You can specify LYR_SELECTED_LAYERS (-2) for CurIndex to move all selected layers. NewIndex can be one of the following: >= 0 The new insertion index IEN_Send_To_Back The layer will become the new background layer (layer 0) IEN_Send_Backward The layer will move closer to the background IEN_Bring_Forward The layer will move closer to the foreground IEN_Bring_To_Front The layer will become the topmost one (in front of all others)
Notes: - If the layer has a mask it will be moved too - Only a
can be moved to layer 0 (i.e. background). If you attempt to move a non-image layer to position 0, it will be moved to 1 - Use LayersMove to arrange layer order. Use to change the position of layers Example // Move the current layer forward ImageEnView1.LayersMove( ImageEnView1.LayersCurrent, IEN_Bring_Forwards ); // Move selected layers backward ImageEnView1.LayersMove( LYR_SELECTED_LAYERS, IEN_Send_Backward ); // Move the selected layers to the back (but not replace the background layer ImageEnView1.LayersMove( LYR_SELECTED_LAYERS, 1 ); !!} procedure TImageEnView.LayersMove(CurIndex, NewIndex: integer); var curLayer: TIELayer; iLyrListLen: integer; LyrList: array of TIELayer; i: Integer; layerMask, movingLayer: TIELayer; a, b: Integer; allImageLayers: Boolean; bInclude: Boolean; begin // LYR_ALL_LAYERS is not relevant if ( CurIndex <> LYR_SELECTED_LAYERS ) and (( CurIndex < 0 ) or ( CurIndex >= fLayers.Count )) then exit; if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_ArrangeLayers ), ieuObjectsAndLayers, True, IEOP_ARRANGELAYERS ); if ( CurIndex = LYR_SELECTED_LAYERS ) and ( LayersAllowMultiSelect = False ) then CurIndex := fLayersCurrent; SyncBitmapToCurrentLayer(); // save current layer index and make no current layer if fLayersCurrent > -1 then curLayer := Layers[fLayersCurrent] else curLayer := nil; fLayersCurrent := -1; try if CurIndex <> LYR_SELECTED_LAYERS then begin // MOVE SPECIFIED LAYER case NewIndex of IEN_Send_To_Back : NewIndex := 0; IEN_Send_Backward : NewIndex := CurIndex - 1; IEN_Bring_Forward : NewIndex := CurIndex + 1; IEN_Bring_To_Front : NewIndex := fLayers.Count - 1; end; if ( NewIndex = 0 ) and ( curLayer.Kind <> ielkImage ) then NewIndex := 1; // only image layers at 0 if ( NewIndex < 0 ) or ( NewIndex >= fLayers.Count ) or ( CurIndex = NewIndex ) then exit; // check if it has a layer mask layerMask := nil; if ( CurIndex < fLayers.Count - 1 ) and Layers[ CurIndex + 1 ].IsMask then begin layerMask := Layers[ CurIndex + 1 ]; if NewIndex = CurIndex + 1 then inc( NewIndex ); end; // move layer movingLayer := Layers[ CurIndex ]; fLayers.Move( CurIndex, NewIndex ); // move layer mask if exists if layerMask <> nil then begin a := fLayers.IndexOf( layerMask ); b := fLayers.IndexOf( movingLayer ); if b < fLayers.Count - 1 then inc( b ); fLayers.Move( a, b ); end; end else begin // MOVE ALL SELECTED // Generate list of all selected layers SetLength( LyrList, fLayers.Count ); iLyrListLen := 0; allImageLayers := True; for i := 0 to fLayers.Count - 1 do begin bInclude := Layers[ i ].Selected; // check if its a layer mask of a selected layer if ( bInclude = False ) and Layers[ i ].IsMask and ( i > 0 ) and Layers[ i - 1 ].Selected then bInclude := True; if bInclude then begin LyrList[ iLyrListLen ] := Layers[ i ]; inc( iLyrListLen ); if Layers[ i ].Kind <> ielkImage then allImageLayers := False; end; end; if iLyrListLen = 0 then exit; case NewIndex of IEN_Send_To_Back : NewIndex := 0; IEN_Send_Backward : begin NewIndex := fLayers.IndexOf( LyrList[ 0 ] ) - 1; if NewIndex < 0 then NewIndex := 0; end; IEN_Bring_Forward : begin NewIndex := fLayers.IndexOf( LyrList[ iLyrListLen - 1 ] ) + 1; if NewIndex > fLayers.Count - 1 then NewIndex := fLayers.Count - 1; end; IEN_Bring_To_Front : NewIndex := fLayers.Count - 1; end; if ( NewIndex = 0 ) and ( allImageLayers = False ) then NewIndex := 1; // only image layers at 0 if ( NewIndex < 0 ) or ( NewIndex >= fLayers.Count ) or ( CurIndex = NewIndex ) then exit; // If we are moving things up the stack we need to iterate backwards through our list if NewIndex <= fLayers.IndexOf( LyrList[ 0 ] ) then begin for i := iLyrListLen - 1 downto 0 do begin CurIndex := fLayers.IndexOf( LyrList[ i ] ); fLayers.Move( CurIndex, NewIndex ); end end else begin for i := 0 to iLyrListLen - 1 do begin CurIndex := fLayers.IndexOf( LyrList[ i ] ); fLayers.Move( CurIndex, NewIndex ); end end; end; finally // set old current layer if curLayer <> nil then SetLayersCurrent( fLayers.IndexOf(curLayer) ); // Which calls update end; end; {!! TImageEnView.LayersSetProperties Declaration procedure LayersSetProperties(LayerIndex: integer; Props: TStrings); overload; procedure LayersSetProperties(LayerIndex: integer; const PropName, Value: Variant); overload; Description Sets properties of multiple layers in a batch (by calling ). Parameter Description LayerIndex Index of the layer to update. Generally this will be LYR_SELECTED_LAYERS or LYR_ALL_LAYERS Props A list of properties in Name=Value pairs PropName A property to update Value New value for the property
Names will be drawn from the
. Properties can be retrieved using . Example // Rotate all layers 45 degrees ImageEnView1.LayersSetProperties( LYR_ALL_LAYERS, IELP_Rotate, 45 ); // Set the text for all text layers (other layer types will be ignored) ImageEnView1.LayersSetProperties( LYR_ALL_LAYERS, IELP_Text, 'Double-click to edit text' ); // Set style properties for selected layers ss := TStringList.Create; ss.Add( 'IELP_BorderColor=clNone' ); ss.Add( 'IELP_BorderWidth=0' ); ss.Add( 'IELP_FillColor=clYellow' ); ss.Add( 'IELP_FillColor2=clRed' ); ss.Add( 'IELP_FillGradient=1' ); LayersSetProperties( LYR_SELECTED_LAYERS, ss ); ss.Free; See Also - - !!} procedure TImageEnView.LayersSetProperties(LayerIndex: integer; const PropName, Value: Variant); begin LayersSetPropertiesEx( LayerIndex, nil, PropName, Value, loAutoUndoChangesbyCode in fLayerOptions, '' ); end; procedure TImageEnView.LayersSetProperties(LayerIndex: integer; Props: TStrings); begin LayersSetPropertiesEx( LayerIndex, Props, '', '', loAutoUndoChangesbyCode in fLayerOptions, '' ); end; procedure TImageEnView.LayersSetPropertiesEx(LayerIndex: integer; Props: TStrings; { OR } const PropName, Value: string; SaveUndo: Boolean; UndoMsg: string); var idx: Integer; doLayer: Boolean; begin if ( LayerIndex <> LYR_SELECTED_LAYERS ) and ( LayerIndex <> LYR_ALL_LAYERS ) and (( LayerIndex < 0 ) or ( LayerIndex >= fLayers.Count )) then exit; { Invalid selection } if ( LayerIndex = LYR_SELECTED_LAYERS ) and ( LayersAllowMultiSelect = False ) then LayerIndex := LayersCurrent; if Proc.AutoUndo and SaveUndo then begin if UndoMsg = '' then UndoMsg := IEMsg( IEMsg_SetLayerProperties ); Proc.SaveUndo( UndoMsg, ieuLayer, True, IEOP_LAYERPROPS ); end; for idx := fLayers.Count - 1 downto 0 do begin case LayerIndex of LYR_ALL_LAYERS : doLayer := True; LYR_SELECTED_LAYERS : doLayer := TIELayer( fLayers[ idx ]).Selected else doLayer := idx = LayerIndex; end; if doLayer then begin if Assigned( Props ) then Layers[ idx ].SetProperties( Props ) else Layers[ idx ].SetProperties( PropName, Value ); if LayerIndex >= 0 then Break; { No more to process } end; end; Update(); end; {!! TImageEnView.Modified Declaration property Modified: Boolean; Description Returns true if the image has been changed since it was loaded. Modified will be set when there are changes to the using ( property), or to . Example btnSave.Enabled := ImageEnView1.Modified; // Reset modified after saving ImageEnView1.IO.SaveToFile( Filename ); ImageEnView1.Modified := False; See Also - - - !!} function TImageEnView.GetModified(): Boolean; begin Result := fModified; if assigned( fIEBitmap ) and fIEBitmap.Modified then Result := True; end; procedure TImageEnView.SetModified(value: Boolean); begin fModified := value; if ( Value = False ) and assigned( fIEBitmap ) then fIEBitmap.Modified := False; end; // if fIEBitmapValid returns fIEBitmap.Width, otherwise returns width of current layer object function TImageEnView.fIEBitmap_Width(): Integer; begin Result := 0; if fIEBitmapValid then Result := fIEBitmap.Width else if fLayersCurrent >= 0 then Result := CurrentLayer.Width; end; // if fIEBitmapValid returns fIEBitmap.Height, otherwise returns Height of current layer object function TImageEnView.fIEBitmap_Height(): Integer; begin Result := 0; if fIEBitmapValid then Result := fIEBitmap.Height else if fLayersCurrent >= 0 then Result := CurrentLayer.Height; end; // Write fIEBitmap back to CurrentLayer.Bitmap procedure TImageEnView.SyncBitmapToCurrentLayer(); begin if ( fLayersCurrent > -1 ) and ( Layers[ fLayersCurrent ] is TIEImageLayer ) then TIEImageLayer( Layers[ fLayersCurrent ]).fBitmap := fIEBitmap; end; function TImageEnView.MouseChangingLayers(): Boolean; begin result := (fMovingLayer >= 0) or (fRotatingLayer >= 0) or (fLayerResizing <> ieNone); end; // Synchronize current fBitmap and fAlphaChannel with layers list // Update layer coords // Result is true if the layers rect changed function TImageEnView.SyncLayers(): Boolean; var wasRect: TIERectangle; begin Result := False; if fBitmap <> nil then fIEBitmap.EncapsulateTBitmap(fBitmap, false); // only sync properties SyncBitmapToCurrentLayer(); if not (Center and MouseChangingLayers()) then begin wasRect := fLayersRect; if loDynamicCanvas in fLayerOptions then // Align view to all layers rect fLayersRect := LayersRect() else // Align view to layer 0 fLayersRect := IERectangle( Layers[0].PosX, Layers[0].PosY, Layers[0].Width, Layers[0].Height ); Result := ( wasRect.x <> fLayersRect.x ) or ( wasRect.y <> fLayersRect.y ) or ( wasRect.Width <> fLayersRect.Width ) or ( wasRect.Height <> fLayersRect.Height ); end; end; {!! TImageEnView.FindLayerAt Declaration function FindLayerAt(x, y: Integer; SelectablesOnly: Boolean = true): Integer; Description Returns the index of the layer at position x, y (in client area coordinates). If SelectablesOnly is true, it won't return any layer which isn't selectable. Returns -1 if no layer was found. !!} function TImageEnView.FindLayerAt(x, y: integer; SelectablesOnly: Boolean = True): integer; var rect: TRect; lyr: TIELayer; xx, yy: Integer; begin for result := fLayers.Count - 1 downto 0 do begin lyr := TIELayer(fLayers[result]); rect := lyr.ClientAreaBox; if (lyr.Selectable or not fLayersSelectConstrains or not SelectablesOnly) and lyr.Visible and IEPointInRect(x, y, Rect) then begin if (lyr.Kind <> ielkImage) or (not lyr.Bitmap.HasAlphaChannel) or (iesoSelectTranspLayers in fSelectionOptions) then break else begin xx := ilimit( lyr.ConvXScr2Bmp(x), 0, lyr.Bitmap.Width - 1 ); yy := ilimit( lyr.ConvYScr2Bmp(y), 0, lyr.Bitmap.Height - 1 ); if lyr.Bitmap.Alpha[ xx, yy ] > 0 then break; end; end; end; end; function TImageEnView.IsPointInsideLayer(x, y: Integer; layer: Integer): Boolean; var lyr: TIELayer; begin result := false; if layer>-1 then begin lyr := TIELayer(fLayers[layer]); if lyr.Rotate = 0 then with lyr.ClientAreaBox do result := lyr.Visible and IEPointInRect(x, y, Left, Top, Right, Bottom) else result := lyr.Visible and IEISPointInPoly(x, y, lyr.DrawingInfo.RotatedDest); end; end; {!! TImageEnView.LayersConvertToImageLayers Declaration procedure LayersConvertToImageLayers(LayerIdx: Integer = LYR_SELECTED_LAYERS; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False); Description Changes the type of the specified 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. ConvertImages affects only image layers. By default image layers are ignored, if ConvertImages is true, the rotated images are fixed using Note: - For text layers, a QualityFactor of 1 usually works best - To convert an individual layers, you can also use Examples // Convert all selected layers to image layers ImageEnView1.LayersConvertToImageLayers(); // Convert the current layer to an image ImageEnView1.LayersConvertToImageLayers( ImageEnView1.LayersCurrent ); // Which is the same as... ImageEnView1.CurrentLayer.ConvertToImageLayer(); !!} // OK to use: LYR_ALL_LAYERS and LYR_SELECTED_LAYERS procedure TImageEnView.LayersConvertToImageLayers(LayerIdx: integer = LYR_SELECTED_LAYERS; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False); begin LayersConvertToImageLayersEx( LayerIdx, QualityFactor, CropAlpha, ConvertImages, Proc.AutoUndo and ( loAutoUndoChangesByCode in fLayerOptions )); Update(); end; procedure TImageEnView.LayersConvertToImageLayersEx(LayerIdx: integer = -2; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False; DoSaveUndo: Boolean = False); var aLayer : TIELayer; doLayer: Boolean; i, l: Integer; begin if ( LayerIdx <> LYR_ALL_LAYERS ) and ( LayerIdx <> LYR_SELECTED_LAYERS ) and (( LayerIdx < 1 {Ignore BG} ) or ( LayerIdx >= LayersCount )) then exit; if DoSaveUndo then Proc.SaveUndo( IEMsg( IEMsg_ConvertToImageLayer ), ieuObjectsAndLayers, True, IEOP_OTHER ); l := fLayersCurrent; SyncBitmapToCurrentLayer(); for i := 0 to fLayers.Count - 1 do begin case LayerIdx of LYR_ALL_LAYERS : doLayer := True; LYR_SELECTED_LAYERS : doLayer := Layers[i].Selected; else doLayer := i = LayerIdx; end; if doLayer and ( Layers[i].Kind <> ielkImage ) then begin l := i; aLayer := TIEImageLayer.Create( self, Layers[ i ], QualityFactor, CropAlpha ); Layers[ i ].Free; fLayers[ i ] := aLayer; end else if doLayer and ( Layers[i].Kind = ielkImage ) and ConvertImages then begin LayersFixRotations( i ); end end; fLayersCurrent := -1; SetLayersCurrentEx( l, False, True, False { Do NOT call update } ); end; {!! TImageEnView.LayersMergeTo Declaration procedure LayersMergeTo(Layer1, Layer2: integer; Destination: ); Description Merges Layer1 and Layer2 into a TIEBitmap object. The new bitmap will inherit the []. and alpha channels. The resulting bitmap will always be 24 bit (ie24RGB). Notes: - If either layer is not a , it will be converted to a TIEImageLayer - LayersMergeTo can merge a layer with its own layer mask (to create a layer with the transparency of the mask). - will specify the quality of image layers, if they do not have a custom Example // we want to get a background image and then merge over it another image in semitransparency. ImageEnView.IO.LoadFromFile('C:\background.jpg'); ImageEnView.LayersAdd; ImageEnView.IO.LoadFromFile('C:\foreground.jpg'); ImageEnView.Layers[1].Transparency := 128; // the second layer has 50% transparency ImageEnView.LayersMergeTo(0, 1, ImageEnView2.IEBitmap); ImageEnView2.IO.SaveToFile('C:\output.jpg'); !!} procedure TImageEnView.LayersMergeTo(Layer1, Layer2: integer; Destination: TIEBitmap); var UpLayer, DownLayer: Integer; LayerMask: TIELayer; baseLayer: TIELayer; begin {$IFDEF UNITTESTING} fDebugUpdatedCount := 0; {$ENDIF} if Layers[ Layer1 ].Kind <> ielkImage then LayersConvertToImageLayersEx( Layer1 ); if Layers[ Layer2 ].Kind <> ielkImage then LayersConvertToImageLayersEx( Layer2 ); DownLayer := imin(Layer1, Layer2); UpLayer := imax(Layer1, Layer2); if Layers[UpLayer].IsMask then begin // upper layer is a layermask (this case can happen only when application tries to merge a layer with its mask) baseLayer := TIEImageLayer.Create(nil, Layers[DownLayer].Bitmap, false); try baseLayer.Bitmap.Fill(0); baseLayer.Bitmap.AlphaChannel.Fill(0); IELayersMerge( baseLayer, Layers[DownLayer], Layers[UpLayer], Destination, fLayersMergeFilter, fBackground, DownLayer > 0 ); finally baseLayer.Free(); end; end else begin if (UpLayer < fLayers.Count - 1) and Layers[UpLayer + 1].IsMask then LayerMask := Layers[UpLayer + 1] else LayerMask := nil; IELayersMerge( Layers[DownLayer], Layers[UpLayer], LayerMask, Destination, fLayersMergeFilter, fBackground, DownLayer > 0 ); end; {$IFDEF UNITTESTING} if fDebugUpdatedCount > 0 then raise Exception.create( 'Unexpected Update called' ); {$ENDIF} end; {!! TImageEnView.LayersMerge Declaration procedure LayersMerge(); overload; procedure LayersMerge(Layer1, Layer2: integer; RemoveUpperLayer: Boolean = true); overload; procedure LayersMerge(LayerList: array of integer); overload; procedure LayersMerge(LayerList: ); overload; Description Merges two or more layers into one layer. The new layer has the lesser index. The new layer will inherit the . and the bitmap's alpha channels. The LayersMerge() overload will merge selected layers. Notes: - To merge a layer with its own mask (to create a layer with the transparency of the mask) pass only two indexes (i.e. the indexes of the layer and the mask). - If any of the layers are not a , they will be converted to a TIEImageLayer - will specify the quality of image layers, if they do not have a custom Parameter Description Layer1 Index of the first layer to merge. Layer2 Index of the second layer to merge. RemoveUpperLayer If RemoveUpperLayer is false, the upper layer will not be removed. LayerList An array of layer indexes to remove. The array must be ordered and all layers will be merged into the layer specified by the first index. Empty list means "all layers".
Example // merge layer 1 with background (layer 0) ImageEnView1.LayersMerge([ 1, 0 ]); // merge layers 0, 1 and 2 ImageEnView1.LayersMerge([ 0, 1, 2 ]); // merge all layers ImageEnView1.LayersMerge([]); // merge all selected layers ImageEnView1.LayersMerge(); // merge layer 1 with its mask ImageEnView1.LayersMerge( 1, 2 ); // we want to get a background image and then merge over it another image in semi-transparency. ImageEnView.IO.LoadFromFile('C:\background.jpg'); ImageEnView.LayersAdd; ImageEnView.IO.LoadFromFile('C:\foreground.jpg'); ImageEnView.Layers[1].Transparency := 128; // the second layer has 50% transparency ImageEnView.LayersMerge(0, 1); // from now we have only one layer ImageEnView.IO.SaveToFile('C:\output.jpg'); !!} procedure TImageEnView.LayersMerge(Layer1, Layer2: integer; RemoveUpperLayer: Boolean = True); var outlayer: TIELayer; lamin, lamax: integer; layerCropped: boolean; oldnav: TImageEnView; begin {$IFDEF UNITTESTING} fDebugUpdatedCount := 0; {$ENDIF} if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_MergeLayers ), ieuObjectsAndLayers, True, IEOP_MERGELAYERS ); oldnav := fNavigator; SetNavigator(nil); lamin := imin(Layer1, Layer2); lamax := imax(Layer1, Layer2); outlayer := TIEImageLayer.Create(self, Layers[ lamin ].Bitmap, false); // Ensure layer 2 is cropped if needed if fLayersCropped then Layers[ lamax ].Cropped := True; LayersMergeTo( lamin, lamax, outlayer.Bitmap); if lamin > 0 then begin // Not merging to background layer outlayer.PosX := imin( Layers[ lamin ].PosX, Layers[ lamax ].PosX ); outlayer.PosY := imin( Layers[ lamin ].PosY, Layers[ lamax ].PosY ); end else begin // Merging background layer. If layers are not cropped shift new layer to position of outside layer layerCropped := fLayersCropped or Layers[lamax].Cropped; outlayer.PosX := Layers[lamin].PosX; if ( layerCropped = False ) and ( Layers[lamax].PosX < Layers[lamin].PosX ) then outlayer.PosX := Layers[lamax].PosX; outlayer.PosY := Layers[lamin].PosY; if ( layerCropped = False ) and ( Layers[lamax].PosY < Layers[lamin].PosY ) then outlayer.PosY := Layers[lamax].PosY; end; outlayer.Locked := TIELayer(Layers[lamin]).Locked; outlayer.VisibleBox := TIELayer(Layers[lamin]).VisibleBox; outlayer.Selectable := TIELayer(Layers[lamin]).Selectable; // remove old layers if RemoveUpperLayer then begin if (lamax 0 then raise Exception.create( 'Unexpected Update called' ); {$ENDIF} LayersCurrent := lamin; // this calls update SetNavigator(oldnav); end; // Merge selected procedure TImageEnView.LayersMerge(); begin if MultiSelectedLayersCount() > 0 then LayersMerge( MultiSelectedLayersList() ); end; procedure TImageEnView.LayersMerge(LayerList: array of integer); var llist: TIEArrayOfInteger; i: integer; begin SetLength(llist, length(LayerList)); for i := 0 to length(LayerList) - 1 do llist[i] := LayerList[i]; LayersMerge(llist); end; // indexes in LayerList must be sorted (lower indexes first) procedure TImageEnView.LayersMerge(LayerList: TIEArrayOfInteger); var i, idx: integer; llistLen: integer; llist: array of TIELayer; oldnav: TImageEnView; outLayer, lyrMask: TIELayer; firstLastIndex: integer; layerCropped: boolean; begin if length(LayerList) = 1 then // unique invalid case (0 = all layers) exit; if length(LayerList) = 2 then begin // Allow merging of layer with its mask LayersMerge( LayerList[0], LayerList[1] ); exit; end else if ( length(LayerList) = 0 ) and ( fLayers.Count = 2 ) then begin // Allow merging of background layer with its mask LayersMerge( 0, 1 ); exit; end; {$IFDEF UNITTESTING} fDebugUpdatedCount := 0; {$ENDIF} if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_MergeLayers ), ieuObjectsAndLayers, True, IEOP_MERGELAYERS ); oldnav := fNavigator; SetNavigator(nil); fLayersCurrent := -1; LockUpdate(); // creates a list of pointers to layers (excluding masks) if length(LayerList) = 0 then begin // empty array means All layers SetLength(llist, fLayers.Count); llistLen := 0; for i := 0 to fLayers.Count - 1 do if not Layers[i].IsMask then begin llist[llistLen] := Layers[i]; inc(llistLen); end; firstLastIndex := 0; end else begin // get list from LayerList SetLength(llist, length(LayerList)); llistLen := 0; for i := 0 to length(LayerList) - 1 do begin if not Layers[LayerList[i]].IsMask then begin llist[llistLen] := Layers[LayerList[i]]; inc(llistLen); end; end; firstLastIndex := LayerList[0]; end; if llistLen > 1 then begin for i := 1 to llistLen - 1 do begin if llist[i].Kind <> ielkImage then begin idx := llist[i].GetIndex; LayersConvertToImageLayersEx( idx, 1 ); llist[i] := Layers[idx]; end; outLayer := TIEImageLayer.Create(self, llist[0].Bitmap, false); IELayersMerge( llist[0], llist[i], llist[i].GetLayerMask(), outLayer.Bitmap, fLayersMergeFilter, fBackground, firstLastIndex > 0, fLayersCropped ); if firstLastIndex > 0 then begin // Not merging to background layer outlayer.PosX := imin( llist[0].PosX, llist[i].PosX ); outlayer.PosY := imin( llist[0].PosY, llist[i].PosY ); end else begin // Merging background layer. If layers are not cropped shift new layer to position of outside layer layerCropped := fLayersCropped or llist[i].Cropped; outlayer.PosX := llist[0].PosX; if ( layerCropped = False ) and ( llist[i].PosX < llist[0].PosX ) then outlayer.PosX := llist[i].PosX; outlayer.PosY := llist[0].PosY; if ( layerCropped = False ) and ( llist[i].PosY < llist[0].PosY ) then outlayer.PosY := llist[i].PosY; end; outlayer.Locked := llist[0].Locked; outlayer.VisibleBox := llist[0].VisibleBox; outlayer.Selectable := llist[0].Selectable; fLayers.Insert(firstLastIndex, outlayer); lyrMask := llist[i].GetLayerMask(); // Get mask before we remove layer from list fLayers.Remove( llist[ 0 ]); fLayers.Remove( lyrMask ); fLayers.Remove( llist[ i ]); FreeAndNil( llist[ 0 ]); FreeAndNil( lyrMask ); FreeAndNil( llist[ i ]); llist[0] := outlayer; end; end; {$IFDEF UNITTESTING} if fDebugUpdatedCount > 0 then raise Exception.create( 'Unexpected Update called' ); {$ENDIF} LayersCurrent := firstLastIndex; // this call update SetNavigator(oldnav); UnlockUpdate(); end; // Layers ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {!! TImageEnView.Bitmap Declaration property Bitmap: TBitmap; Description Bitmap contains the image (current layer) to display. If
is True, is just a wrapper for TBitmap that may be accessed using the Bitmap property. !!} // after changing sizes using Bitmap, we should call Update to sync fIEBitmap function TImageEnView.GetFBitmap: TBitmap; begin result := fBitmap; end; {!! TImageEnView.IEBitmap Declaration property IEBitmap: ; Description Contains the image (current layer) to display. The object TIEBitmap also contains the alpha channel of the image. If your image contains multiple layers then IEBitmap is the bitmap of the selected image layer. If a non-image layer is selected then IEBitmap will be the background layer (Layer 0). Notes: - You must call if you modify IEBitmap directly - If is True, IEBitmap is just a wrapper for TBitmap that may be accessed using the Bitmap property !!} function TImageEnView.GetIEBitmap: TIEBitmap; begin result := fIEBitmap; end; {!! TImageEnView.LegacyBitmap Declaration property LegacyBitmap: Boolean; Description If LegacyBitmap is True, ImageEn uses TBitmap to store the image, otherwise ImageEn uses . TIEBitmap handles images using memory mapped file (for large images) or main memory. This allows handling of large images and to include input/output and image processing in a multi-threaded environment. Also TIEBitmap supports a larger number of pixel formats (). Note: LegacyBitmap should be set to FALSE for new applications. !!} procedure TImageEnView.SetLegacyBitmap(Value: boolean); begin if Value <> fLegacyBitmap then begin // Select base layer SetLayersCurrent( 0 ); if fLegacyBitmap = true then begin // from fBitmap to fIEBitmap fIEBitmap.EncapsulatedFromTBitmap := false; // this allows fIEBitmap to fully own fBitmap fIEBitmap.Location := ieFile; fBitmap := nil; // fBitmap freedom by fIEBitmap end else begin // from fIEBitmap to fBitmap fIEBitmap.Location := ieTBitmap; fIEBitmap.EncapsulatedFromTBitmap := true; // this deny fIEBitmap to own fBitmap fBitmap := fIEBitmap.VclBitmap; end; fLegacyBitmap := Value; CallBitmapChangeEvents; Update; end; end; // fOffX, fOffY, frx, fry, fo1x, fo1y, fo2x, fo2y must be valid procedure TImageEnView.PaintSelection(OutBitmap: TBitmap); begin if fVisibleSelection then begin if (iesoFilled in fSelectionOptions) and PIEAnimPoly(fHPolySel)^.Enabled then with CurrentLayer.DrawingInfo do fSelectionMask.InvertCanvas(OutBitmap.Canvas, XDst, YDst, WidthDst, HeightDst, XSrc, YSrc, WidthSrc, HeightSrc); if (iesoMarkOuter in fSelectionOptions) and PIEAnimPoly(fHPolySel)^.Enabled then with CurrentLayer.DrawingInfo do fSelectionMask.DrawOuter(OutBitmap, XDst, YDst, WidthDst, HeightDst, XSrc, YSrc, WidthSrc, HeightSrc, fMarkOuterAlpha, fMarkOuterColor); end; end; // fOffX, fOffY, frx, fry, fo1x, fo1y, fo2x, fo2y must be valid procedure TImageEnView.PaintPixelGrid(OutBitmap: TBitmap); var x1, y1, x2, y2, y, x: integer; dx, dy: double; lyr: TIELayer; MajorStepMode : TPenMode; begin if fDisplayGridLyr = -1 then lyr := CurrentLayer else lyr := Layers[imin(fDisplayGridLyr, LayersCount-1)]; // DRAW GRID LINES (SEE ALSO: DRAW GUIDE LINES) if ( fDisplayGridKind = iedgPixelGrid ) and lyr.Visible and (( fZoomX >= IEGlobalSettings().MinZoomDisplayGrid ) or ( fZoomY >= IEGlobalSettings().MinZoomDisplayGrid )) and (( fLayersRect.width > 1 ) or ( fLayersRect.height > 1 )) then begin OutBitmap.Canvas.Pen.Assign( IEGlobalSettings().GridPen ); if IEGlobalSettings().GridPen.Mode = pmCopy then MajorStepMode := pmNotCopy else MajorStepMode := pmCopy; // VERT GRID LINES y1 := lyr.DrawingInfo.YDst; y2 := lyr.DrawingInfo.YDst + lyr.DrawingInfo.HeightDst; dx := lyr.DrawingInfo.WidthDst / lyr.DrawingInfo.WidthSrc; x := 0; while x <= lyr.DrawingInfo.WidthSrc do begin if IEGlobalSettings().GridMajorStep > 1 then begin // Draw inverted grid? if x mod IEGlobalSettings().GridMajorStep = 0 then OutBitmap.Canvas.Pen.Mode := MajorStepMode else OutBitmap.Canvas.Pen.Mode := IEGlobalSettings().GridPen.Mode; end; x1 := round( lyr.DrawingInfo.XDst + x * dx ); OutBitmap.Canvas.MoveTo(x1, y1); OutBitmap.Canvas.LineTo(x1, y2); inc(x); end; // HORZ GRID LINES x1 := lyr.DrawingInfo.XDst; x2 := lyr.DrawingInfo.XDst + lyr.DrawingInfo.WidthDst; dy := lyr.DrawingInfo.HeightDst / lyr.DrawingInfo.HeightSrc; y := 0; while y <= lyr.DrawingInfo.HeightSrc do begin if IEGlobalSettings().GridMajorStep > 1 then begin // Draw inverted grid? if y mod IEGlobalSettings().GridMajorStep = 0 then OutBitmap.Canvas.Pen.Mode := MajorStepMode else OutBitmap.Canvas.Pen.Mode := IEGlobalSettings().GridPen.Mode; end; y1 := round(lyr.DrawingInfo.YDst + y * dy); OutBitmap.Canvas.MoveTo(x1, y1); OutBitmap.Canvas.LineTo(x2, y1); inc(y); end; if (fHighlightedPixel.X >= 0) and (fHighlightedPixel.Y >= 0) then begin x1 := lyr.ConvXBmp2Scr(fHighlightedPixel.X); y1 := lyr.ConvYBmp2Scr(fHighlightedPixel.Y); x2 := lyr.ConvXBmp2Scr(fHighlightedPixel.X + 1); y2 := lyr.ConvYBmp2Scr(fHighlightedPixel.Y + 1); with TIECanvas.Create(OutBitmap.Canvas, true, true) do begin Pen.Color := fHighlightedPixelColor; Pen.Width := 2; Brush.Style := bsClear; RoundRect(x1, y1, x2, y2, 5, 5); Free; end; end; end; end; procedure TImageEnView.PaintGuideLines(Canvas: TCanvas); const Square_Grid = True; // Adjust number of grid lines to make grid as square as possible var MajorStepMode : TPenMode; iGLCount: Integer; x1, y1, x2, y2, y, x: integer; dx, dy: double; iHLines, iVLines: Integer; begin if ( fDisplayGridKind <> iedgGuideLines ) or ( IEGlobalSettings().GuidelineCount < 1 ) then exit; // DRAW GUIDE LINES (SEE ALSO: DRAW GRID LINES) Canvas.Pen.Assign( IEGlobalSettings().GridPen ); if IEGlobalSettings().GridPen.Mode = pmCopy then MajorStepMode := pmNotCopy else MajorStepMode := pmCopy; // Scale down guide lines if image is small in window iGLCount := max( Round( IEGlobalSettings().GuidelineCount * fExtX / ClientWidth ), Round( IEGlobalSettings().GuidelineCount * fExtY / ClientHeight )); if iGLCount < 1 then iGLCount := 1; // VERT GUIDE LINES y1 := fOffY; y2 := fOffY + fExtY; if Square_Grid = False then iVLines := max( 1, Round( IEGlobalSettings().GuidelineCount * fExtX / ClientWidth )) else if ClientHeight > ClientWidth then iVLines := iGLCount else iVLines := Round( iGLCount * fExtX / fExtY ); dx := fExtX / ( iVLines + 1 ); for x := 1 to iVLines do begin if IEGlobalSettings().GridMajorStep > 1 then begin // Draw inverted grid? if x mod IEGlobalSettings().GridMajorStep = 0 then Canvas.Pen.Mode := MajorStepMode else Canvas.Pen.Mode := IEGlobalSettings().GridPen.Mode; end; x1 := fOffX + round( x * dx ); Canvas.MoveTo(x1, y1); Canvas.LineTo(x1, y2); end; // HORZ GUIDE LINES x1 := fOffX; x2 := fOffX + fExtX; if Square_Grid = False then iHLines := Round( iVlines * fExtY / fExtX ) else iHLines := max( 1, Round( IEGlobalSettings().GuidelineCount * fExtY / ClientHeight )); dy := fExtY / ( iHLines + 1 ); for y := 1 to iHLines do begin if IEGlobalSettings().GridMajorStep > 1 then begin // Draw inverted grid? if y mod IEGlobalSettings().GridMajorStep = 0 then Canvas.Pen.Mode := MajorStepMode else Canvas.Pen.Mode := IEGlobalSettings().GridPen.Mode; end; y1 := fOffY + round( y * dy ); Canvas.MoveTo(x1, y1); Canvas.LineTo(x2, y1); end; end; {!! TImageEnView.GetRenderRectangles Declaration procedure GetRenderRectangles(var xDst, yDst, dxDst, dyDst: integer; var xSrc, ySrc, dxSrc, dySrc: integer); Description Returns the rendered rectangle related to the client area and the source rectangle related to the bitmap of current layer. xDst, yDst, dxDst, dyDst : the destination x, y and width, height where the image has been rendered xSrc, ySrc, dxSrc, dySrc : the source x, y and width, height of the source image. !!} procedure TImageEnView.GetRenderRectangles(var xDst, yDst, dxDst, dyDst: integer; var xSrc, ySrc, dxSrc, dySrc: integer); begin SyncLayers(); CalcPaintCoords; CreateCoordConvLUT; // recalculates coordinate conversion LUT xDst := fOffX; yDst := fOffY; dxDst := frx; dyDst := fry; xSrc := fo1x; ySrc := fo1y; dxSrc := fo2x; dySrc := fo2y; end; procedure TImageEnView.UserInteractions_Paint(const UpdateRect: TRect); var i: integer; begin for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled then (fUserInteractions[i] as TIEUserInteraction).Paint(UpdateRect); end; // ABitmap must be pf24bit, width=clientwidth height=clientheight // If UpdRect=nil updates entire ABitmap width*height procedure TImageEnView.PaintToEx(ABitmap: TIEBitmap; UpdRect: PRect; drawBackground: boolean; drawGadgets: boolean); var i: integer; IsFirst: boolean; zf: TResampleFilter; // effective zoom filter layer: TIELayer; w, h: integer; x1, y1, x2, y2: integer; x, y: integer; layerMask: TIELayer; oldAlpha: TIEBitmap; newAlpha: TIEBitmap; FreeLayerMask: boolean; px: PRGB; rotateFilter: TIEAntialiasMode; procedure SubDrawBackground(force: boolean; layerHasAlpha: Boolean = False); var bHandledBG: boolean; begin if force or (layer.PosX <> 0) or (layer.PosY <> 0) or (layer.Rotate <> 0) or (fOffX > 0) or (fOffY > 0) or (frx < ABitmap.Width) or (fry < ABitmap.Height) or (fEnableAlphaChannel and layerHasAlpha) or (IsFirst and (layer.Operation <> ielNormal)) or (layer.Transparency < 255) or (layer.Opacity < 1.0) or (fLayersRect.width <> Layers[0].OriginalWidth) or (fLayersRect.height <> Layers[0].OriginalHeight) then begin if UpdRect <> nil then begin with UpdRect^ do IntersectClipRect(ABitmap.Canvas.Handle, left, top, right + 1, bottom + 1); end; bHandledBG := false; if assigned(fOnDrawBackground) then fOnDrawBackground(self, ABitmap.Canvas, Rect(0, 0, ABitmap.Width, ABitmap.Height), bHandledBG); if ( bHandledBG = false ) and fNeedUpdateLiveBackground and ( BackgroundStyle = iebsBlurredImage ) then UpdateLiveBackground( Layers[0].Bitmap ); if bHandledBG = false then IEDrawBackground(ComponentState, ABitmap.Canvas, ABitmap.VclBitmap, fBackgroundStyle, GetThemeColor( ietpControlBackground, fBackground ), 0, 0, ABitmap.Width, ABitmap.Height, fOffX, fOffY, fOffX + frx, fOffY + fry, fChessboardSize, fChessboardBrushStyle, fChessboardColor2Customized, GetThemeColor( ietpControlBackgroundGradientEnd, fGradientEndColor ), fWallpaper, fWallpaperStyle, fLiveBackground); SelectClipRgn(ABitmap.canvas.handle, 0); end; end; procedure SetLayerMask(lBitmap: TIEBitmap); var pold, pnew: pbyte; i, j: integer; aw, ah: integer; // alpha width and height mw, mh: integer; // mask width and height v: integer; rx, ry: double; zx, zy: double; mx, my: integer; mxarr: pintegerarray; msk_p: pbytearray; l0width, l0height: integer; rmy: integer; armx: pintegerarray; doloop: boolean; begin if layer.fCachedLayerMask <> nil then begin // cached oldAlpha := lBitmap.DetachAlphaChannel(true); lBitmap.ReplaceAlphaChannel(layer.fCachedLayerMask); newAlpha := layer.fCachedLayerMask; end else begin // check pixelformat of layer mask if layerMask.Bitmap.PixelFormat <> ie8g then begin layerMask.Bitmap.PixelFormat := ie8g; if layerMask.Bitmap.HasAlphaChannel then layerMask.Bitmap.RemoveAlphaChannel; // a layer mask cannot have alpha channel end; l0width := Layers[0].Bitmap.Width; l0height := Layers[0].Bitmap.Height; oldAlpha := lBitmap.DetachAlphaChannel(true); newAlpha := TIEBitmap.Create; newAlpha.Allocate(oldAlpha.Width, oldAlpha.Height, ie8g); lBitmap.ReplaceAlphaChannel(newAlpha); aw := newAlpha.Width; ah := newAlpha.Height; mw := layerMask.Bitmap.Width; mh := layerMask.Bitmap.Height; zx := (layer.Width / layer.Bitmap.Width); zy := (layer.Height / layer.Bitmap.Height); rx := (layerMask.Width / layerMask.Bitmap.Width); ry := (layerMask.Height / layerMask.Bitmap.Height); armx := nil; getmem(mxarr, sizeof(integer) * aw); for j := 0 to aw - 1 do mxarr[j] := round((j * zx / rx - layerMask.PosX / rx) + layer.PosX / rx); if fSoftCrop = iesfAlphaBlend then begin getmem(armx, sizeof(integer) * aw); for j := 0 to aw - 1 do begin i := round(mxarr[j] * rx) + layer.PosX; if (i < 0) or (i > l0width) then armx[j] := 0 else armx[j] := - 1; end; end; for i := 0 to ah - 1 do begin pold := oldAlpha.Scanline[i]; pnew := newAlpha.Scanline[i]; my := round((i * zy / ry - layerMask.PosY / ry) + layer.PosY / ry); msk_p := layerMask.Bitmap.Scanline[imin(imax(0, my), layerMask.Bitmap.Height - 1)]; doloop := true; if fSoftCrop = iesfAlphaBlend then begin rmy := round(my * ry) + layer.PosY; if (rmy < 0) or (rmy > l0height) then begin FillChar(pnew^, aw, fSoftCropValue); doloop := false; end; end; if doloop then begin for j := 0 to aw - 1 do begin if (fSoftCrop = iesfAlphaBlend) and (armx[j] = 0) then v := fSoftCropValue else begin mx := mxarr[j]; if (my < mh) and (my >= 0) and (mx < mw) and (mx >= 0) then v := msk_p[mx] else v := 0; end; if pold^ < v then pnew^ := pold^ else pnew^ := v; inc(pold); inc(pnew); end; end; end; freemem(mxarr); if fSoftCrop = iesfAlphaBlend then freemem(armx); end; end; procedure UnSetLayerMask; begin if layerMask <> nil then begin layer.Bitmap.DetachAlphaChannel(); // detach "newAlpha" so it can be reused. Otherwise ReplaceAlphaChannel will free its alpha (newAlpha) layer.Bitmap.ReplaceAlphaChannel(oldAlpha); if layer.fCachedLayerMask = nil then layer.fCachedLayerMask := newAlpha else if layer.fCachedLayerMask <> newAlpha then begin // this should never happen FreeAndNil(layer.fCachedLayerMask); layer.fCachedLayerMask := newAlpha; end; end; end; begin SyncLayers(); CalcPaintCoords(); CreateCoordConvLUT(); // recalculates coordinate conversion LUT // check for errors in current layer if (csDesigning in ComponentState) or (fIEBitmap_Height = 0) or (fIEBitmap_Width = 0) then exit; // EXIT! if ( fIEBitmapValid ) and fIEBitmap.HasAlphaChannel and ((fIEBitmap.AlphaChannel.Width <> fIEBitmap.Width) or (fIEBitmap.AlphaChannel.Height <> fIEBitmap.Height)) then exit; // EXIT! // draw layers IsFirst := true; for i := 0 to fLayers.Count - 1 do begin layer := TIELayer(fLayers[i]); if layer.Visible and ( i <> fEditingLayer { text editor is active } ) and ((layer.Kind <> ielkImage ) or (layer.Bitmap.Width >= fMinBitmapSize) or (layer.Bitmap.Height >= fMinBitmapSize)) then begin // layer mask and softcropping layerMask := nil; FreeLayerMask := false; if (i < fLayers.Count - 1) and Layers[i + 1].IsMask and (not layer.IsMask) and (layer.Rotate = 0) and (layer.Kind = ielkImage) then layerMask := Layers[i + 1]; if (i > 0) and (layerMask = nil) and (fSoftCrop = iesfAlphaBlend) then begin FreeLayerMask := true; layerMask := TIEImageLayer.Create(self, nil, false); layerMask.Bitmap.Allocate(layer.Bitmap.Width, layer.Bitmap.Height, ie8g); layerMask.Bitmap.Fill(255); layerMask.PosX := layer.PosX; layerMask.PosY := layer.PosY; layerMask.WidthD := layer.WidthD; layerMask.HeightD := layer.HeightD; end; if layerMask <> nil then SetLayerMask( layer.Bitmap ); if IsFirst and drawBackground then SubDrawBackground(false, layer.Bitmap.HasAlphaChannel and (not layer.Bitmap.AlphaChannel.Full)); zf := fActualZoomFilter; if (fStable > 0) or ((layer.WidthD = 0) and (layer.HeightD = 0) and (fZoomX = 100) and (fZoomY = 100)) then zf := rfNone else if ( layer is TIEImageLayer ) and TIEImageLayer( layer ).UseResampleFilter then zf := TIEImageLayer( layer ).ResampleFilter; rotateFilter := ierNone; if fLayersRotationUseFilterOnPreview and fLayersRotationAntialias then rotateFilter := fLayersRotationFilter; layer.PaintTo( ABitmap, i, pinteger(fXScr2Bmp), pinteger(fYScr2Bmp), UpdRect, fOffX, fOffY, frx, fry, fo1x, fo1y, fo2x, fo2y, fEnableAlphaChannel, (fBackgroundStyle = iebsSolid) and IsFirst, zf, rotateFilter, fLayerResizing <> ieNone ); AfterDrawLayer(i, ABitmap, updRect^); if drawGadgets then begin if layer.DrawOuter and (i = fLayersCurrent) then DrawLayerOuter(ABitmap.VclBitmap, i); end; if assigned(fOnDrawLayer) then fOnDrawLayer(self, ABitmap, i); UnSetLayerMask; if FreeLayerMask then begin layerMask.Free; end; IsFirst := False; end; // end of Visible and (frx<>0) and (fry<>0) end; if (fSoftCrop = iesfGrid) or (fSoftCrop = iesfAdd) then begin w := ABitmap.Width; h := ABitmap.Height; x1 := Layers[0].DrawingInfo.XDst; y1 := Layers[0].DrawingInfo.YDst; x2 := x1 + Layers[0].DrawingInfo.WidthDst; y2 := y1 + Layers[0].DrawingInfo.HeightDst; for y := 0 to h - 1 do begin px := ABitmap.Scanline[y]; case fSoftCrop of iesfGrid: for x := 0 to w - 1 do begin if (y < y1) or (y > y2) or (x < x1) or (x > x2) then if ((x + y) and 1) = 0 then with px^ do begin r := 128; g := 128; b := 128; end; inc(px); end; iesfAdd: for x := 0 to w - 1 do begin if (y < y1) or (y >= y2) or (x < x1) or (x >= x2) then with px^ do begin r := blimit(r + fSoftCropValue); g := blimit(g + fSoftCropValue); b := blimit(b + fSoftCropValue); end; inc(px); end; end; end; end; // check if no layer is displayed if IsFirst and drawBackground then SubDrawBackground(true); if drawGadgets then begin for i := 0 to fLayers.Count - 1 do if Layers[i].VisibleBox then begin if Layers[i].Selected then begin if (miMoveLayers in fMouseInteract) or (miResizeLayers in fMouseInteract) or (miRotateLayers in fMouseInteract) then DrawLayerBox(ABitmap.VclBitmap, i); if (miResizeLayers in fMouseInteract) and (not Layers[i].Locked) then DrawLayerGrips(ABitmap.VclBitmap, i); if (miRotateLayers in fMouseInteract) and CurrentLayer.SupportsFeature(ielfMoveRotationCenter) then DrawLayerRotationCenter(ABitmap.VclBitmap, i); end else if fLayersDrawBox then DrawLayerBox(ABitmap.VclBitmap, i); end; // draw selection PaintSelection(ABitmap.VclBitmap); // draw grid PaintPixelGrid(ABitmap.VclBitmap); end; end; procedure TImageEnView.AfterDrawLayer(layerIndex: Integer; DestBitmap: TIEBitmap; const DestRect: TRect); begin // nothing to do end; {!! TImageEnView.LayersMergeAll Declaration procedure LayersMergeAll(AlphaCompositing: Boolean = False); Description Call LayersMergeAll to merge all layers in one step. When AlphaCompositing is False then this method performs the same task as , but replaces all layers with the merged result. This method is fast and works with all layer options, so should be used to merge layers before printing or saving. It does not support transparency. When AlphaCompositing is True the result is equivalent to calling ([]). will specify the quality of image layers, if they do not have a custom Example // Apply a "Paid" stamp to image with ImageEnView1 do begin LayersAdd( 'PAID', 42, clRed, 'Arial Black', [fsBold] ); CurrentLayer.Rotate := 30; TIETextLayer( CurrentLayer ).SizeToText(); CurrentLayer.PosX := IELayer_Pos_HCenter; CurrentLayer.PosY := IELayer_Pos_VCenter; LayersMergeAll(); end; See Also - !!} procedure TImageEnView.LayersMergeAll(AlphaCompositing: Boolean = False); var bmp: TIEBitmap; posX, posY: Integer; begin if fLayers.Count < 2 then exit; if AlphaCompositing then LayersMerge([]) else begin if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_MergeLayers ), ieuObjectsAndLayers, True, IEOP_MERGELAYERS ); // Select base layer SetLayersCurrent( 0 ); posX := LayersRect().X; posY := LayersRect().Y; bmp := TIEBitmap.Create(fIEBitmap.Width, fIEBitmap.Height); try bmp.Fill(Background); LayersDrawTo(bmp); LayersClear(); fIEBitmap.Assign(bmp); Layers[0].PosX := posX; Layers[0].PosY := posY; finally bmp.free; end; Update; end; end; {!! TImageEnView.LayersDrawTo Declaration procedure LayersDrawTo(Destination: ; AdjustBitmap: Boolean = True); Description Merges all layers and draws the result to Destination bitmap. This function should replace a sequence of calls. The destination bitmap will not have a transparency channel. If AdjustBitmap is true the Destination bitmap will be sized to display all layers. Example // draws all layers of ImageEnView1 to ImageEnView2 ImageEnView1.LayersDrawTo( ImageEnView2.IEBitmap ); ImageEnView2.Update; See Also - !!} procedure TImageEnView.LayersDrawTo(Destination: TIEBitmap; AdjustBitmap: Boolean = True); var lzoomx, lzoomy: Double; lviewx, lviewy: Integer; lMaxLayerWidth, lMaxLayerHeight: Integer; allLayersRect: TIERectangle; begin SetDisplayStable( True ); // Ensure normal quality allLayersRect := LayersRect(); if AdjustBitmap then Destination.Resize( allLayersRect.Width, allLayersRect.Height, Background, 255, iehLeft, ievTop); // paint layers lzoomx := fZoomX; lzoomy := fZoomY; fZoomX := 100; fZoomY := 100; fZoomD100X := 1; fZoomD100Y := 1; f100DZoomX := 1; f100DZoomY := 1; lviewx := fViewX; lviewy := fViewY; fViewX := 0; fViewY := 0; fOffX := -1 * allLayersRect.x; fOffY := -1 * allLayersRect.y; fExtX := Layers[0].Bitmap.Width; fExtY := Layers[0].Bitmap.Height; fZZWW := Layers[0].Bitmap.Width; fZZHH := Layers[0].Bitmap.Height; lMaxLayerWidth := fLayersRect.width; lMaxLayerHeight := fLayersRect.height; fLayersRect.width := Layers[0].Bitmap.Width; fLayersRect.height := Layers[0].Bitmap.Height; PaintToEx(Destination, nil, false, false); fLayersRect.width := lMaxLayerWidth; fLayersRect.height := lMaxLayerHeight; fViewX := lviewx; fViewY := lviewy; fZoomX := lzoomx; fZoomY := lzoomy; fZoomD100X := fZoomX / 100; f100DZoomX := 100 / fZoomX; fZoomD100Y := fZoomY / 100; f100DZoomY := 100 / fZoomY; fUpdateInvalidate := false; Update(); // restores other old values fUpdateInvalidate := true; CalcPaintCoords(); CreateCoordConvLUT(); end; {!! TImageEnView.LayersSaveMergedTo Declaration procedure LayersSaveMergedTo(Destination: ; FastOutput: Boolean = False); overload; procedure LayersSaveMergedTo(const Filename: string; FastOutput: Boolean = False); overload; procedure LayersSaveMergedTo(const Stream: TStream; FileType: ; FastOutput: Boolean = False); overload; Description Output a merged version of all layers to a , file or stream. This method will preserve any alpha channel in the image. Pass FastOutput as True, if you only require a low quality output (without quality filtering or anti-aliasing). This is useful if you will downsize to a thumbnail for example. Notes: - will specify the quality of image layers, if they do not have a custom - The existing image is not changed. Example // Save a merged version of the layers in ImageEnView1 (preserving the alpha channel aBitmap := TIEBitmap.Create; ImageEnView1.LayersSaveMergedTo( aBitmap ); aBitmap.Write( 'd:\Merged.png' ); aBitmap.Free; // Or alternatively ImageEnView1.LayersSaveMergedTo( 'd:\Merged.png' ); // Create a thumbnail of this image aBitmap := TIEBitmap.Create; ImageEnView1.LayersSaveMergedTo( aBitmap, True ); aBitmap.Resample( 100, 100, rfFastLinear, True ); aBitmap.Write( 'd:\Thumb.jpeg' ); aBitmap.Free; See Also - - - !!} procedure TImageEnView.LayersSaveMergedTo(Destination: TIEBitmap; FastOutput: Boolean = False); var aIEView: TImageEnView; begin aIEView := TImageEnView.Create( nil ); try aIEView.LayersFastOutput := FastOutput; aIEView.Assign( Self ); aIEView.LayersMergeAll( True ); Destination.Assign( aIEView.IEBitmap ); finally FreeAndNil( aIEView ); end; end; procedure TImageEnView.LayersSaveMergedTo(const Filename: string; FastOutput: Boolean = False); var aIEView: TImageEnView; begin aIEView := TImageEnView.Create( nil ); try aIEView.LayersFastOutput := FastOutput; aIEView.Assign( Self ); aIEView.LayersMergeAll( True ); aIEView.IO.SaveToFile( Filename ); finally FreeAndNil( aIEView ); end; end; procedure TImageEnView.LayersSaveMergedTo(const Stream: TStream; FileType: TIOFileType; FastOutput: Boolean = False); var aIEView: TImageEnView; begin aIEView := TImageEnView.Create( nil ); try aIEView.LayersFastOutput := FastOutput; aIEView.Assign( Self ); aIEView.LayersMergeAll( True ); aIEView.IO.SaveToStream( Stream, FileType ); finally FreeAndNil( aIEView ); end; end; {!! TImageEnView.LayerOptions Declaration property LayerOptions: ; Description Options to control layer behavior: Value Description loAllowMultiSelect If enabled, users can select multiple layers by holding down the Shift key. Moving, resizing, rotation, and other methods will apply to all selected layers loAutoSelectMask If you have enabled a mask for a layer, then when selecting the layer the mask will also be selected (so that any resizing actions apply to the mask layer too) loAutoUndoChangesByUser If you have enabled , then changes to layers made by users (using layer interactions or layer TActions) will be saved to the undo stack loAutoUndoChangesByCode If you have enabled , then programmatic changes to layers will be saved to the undo stack. This applies to the methods: , , , , , , , , , , , , , , loAutoPromptForImage When setting to miCreateImageLayers, the user can drag select to create an If loAutoPromptForImage is enabled, then the user will be prompted to browse for an image file when after completing the selection. If the user cancels, the image layer is not added. loAutoFixBorders If enabled, will be called prior to rotation to removes any transparency around the edges of the image. loAutoFixRotation If enabled, will be called after rotation to lock in the rotation angle of image layers. loDynamicCanvas If enabled, ImageEn will align the view to the bounds of all layers (i.e. by ). You will be able to scroll to access layers that have been pushed beyond the bounds of Layer 0. However this may cause the view to scroll when moving layers around (so is best paired with =False). When not enabled, the view is aligned with Layer 0, and any layers pushed outside of the bounds of layer 0 may be inaccessible if they are off-screen.
Default: [loAllowMultiSelect, loAutoUndoChangesByUser, loAutoPromptForImage, loAutoFixBorders] Note: To disable movement of layers by the keyboard, see iesoAllowMoveByKeyboard of Examples // Enable automatic mask selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoSelectMask ]; // Enable automatic undo for all image changes including layer changes ImageEnView1.Proc.AutoUndo := True; ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoUndoChangesByUser ]; // Disable multiple selection of layers ImageEnView1.LayerOptions := ImageEnView1.LayerOptions - [ loAutoSelectMask ]; // Allow users to create image layers. Prompt for an image file after selection ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loAutoPromptForImage ]; ImageEnView1.MouseInteract := [ miCreateImageLayers ]; // Display the entire image (including outlying layers) within the view ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loFitToLayersWhenZooming ]; ImageEnView1.Fit( False ); See Also - - - - - !!} procedure TImageEnView.SetLayerOptions(const Value: TIELayerOptions); var multiSelChanged, dynamicCanvasChanged: Boolean; begin multiSelChanged := ( loAllowMultiSelect in Value ) <> ( loAllowMultiSelect in fLayerOptions ); dynamicCanvasChanged := ( loDynamicCanvas in Value ) <> ( loDynamicCanvas in fLayerOptions ); fLayerOptions := Value; if multiSelChanged and not LayersAllowMultiSelect then LayersDeselectAll else if dynamicCanvasChanged then Update(); end; {!! TImageEnView.LayerDefaults Declaration property LayerDefaults: TStringList; Description Specifies a list of properties that are assigned to all new layers. The properties are a list of Name=Value pairs, with names from the . Notes: - These properties apply to layers created programmatically (e.g. using ) and by the user (e.g. using miCreateShapeLayers). - The event can also be used to apply default properties Sample Output IELP_BorderColor=clNone IELP_BorderWidth=0 IELP_FillColor=clYellow IELP_FillColor2=clRed IELP_FillGradient=1 IELP_Rotate=0 Example ImageEnView1.LayerDefaults.Clear(); ImageEnView1.LayerDefaults.Add( IELP_BorderColor +'=$008000FF' ); ImageEnView1.LayerDefaults.Add( IELP_BorderWidth +'=3' ); ImageEnView1.LayersAdd( 'C:\New Zealand.jpg' ); // Added image will have a pink border // Allow the user to create, size and select red arrows ImageEnView1.LayerDefaults.Clear(); ImageEnView1.LayerDefaults.Add( IELP_LineColor +'=clRed' ); ImageEnView1.LayerDefaults.Add( IELP_LineWidth +'=6' ); ImageEnView1.LayerDefaults.Add( IELP_LineShapeSize +'=20' ); ImageEnView1.LayerDefaults.Add( IELP_LineStartShape +'=1' ); ImageEnView1.LayerDefaults.Add( IELP_Rotate +'=235' ); ImageEnView1.MouseInteract := [ miCreateLineLayers, miMoveLayers, miResizeLayers ]; See Also - - - - !!} function TImageEnView.GetLayerDefaults() : TStringList; begin if not assigned( fLayerDefaults ) then fLayerDefaults := TStringList.Create(); Result := fLayerDefaults; end; // Return true if the LayersFastDrawing property means we are currently using fast drawing function TImageEnView.LayersFastDrawingActive: Boolean; begin if fLayersFastDrawing = iefDelayed then Result := fStable <> 0 else Result := fLayersFastDrawing = iefFast end; {!! TImageEnView.LayersCropped Declaration property LayersCropped: Boolean; Description When enabled, any part of layers that are outside the background image (layer 0) area will not be displayed. If true, it overrides the property of individual layers. Default: False Example // Crop the display of only the current layer ImageEnView1.LayersCropped := False; ImageEnView1.CurrentLayer.Cropped := True; // Crop the display of all layers ImageEnView1.LayersCropped := True; // Don't crop the display of any layers ImageEnView1.LayersCropped := False; for i := 0 to ImageEnView1.LayersCount - 1 do ImageEnView1.Layers[ I ].Cropped := False; !!} procedure TImageEnView.SetLayersCropped(const Value: Boolean); begin if fLayersCropped <> Value then begin fLayersCropped := Value; Update(); end; end; // Count of selected layers function TImageEnView.MultiSelectedLayersCount: Integer; var i: Integer; begin Result := 0; for i := 0 to fLayers.Count - 1 do if TIELayer( fLayers[ I ]).Selected then Inc( Result ); end; // List of indexes of selected layers function TImageEnView.MultiSelectedLayersList(): TIEArrayOfInteger; var i: integer; idx: Integer; begin idx := 0; SetLength( result, MultiSelectedLayersCount() ); for i := 0 to fLayers.Count - 1 do if TIELayer( fLayers[ I ]).Selected then begin result[ idx ] := i; Inc( idx ); end; end; {!! TImageEnView.SetLayersBoxStyle Declaration procedure SetLayersBoxStyle(PenStyle: TPenStyle = psDot; PenMode: TPenMode = pmNot; PenWidth: Integer = 1; PenColor: TColor = clBlack); Description Specifies the style of layer box border, if is enabled. For more control, use !!} procedure TImageEnView.SetLayersBoxStyle(PenStyle: TPenStyle; PenMode: TPenMode; PenWidth: Integer; PenColor: TColor); begin fLayerBoxPen.Style := PenStyle; fLayerBoxPen.Mode := PenMode; fLayerBoxPen.Width := PenWidth; fLayerBoxPen.Color := PenColor; end; procedure TImageEnView.DrawLayerBox(ABitmap: TBitmap; idx: integer); var lyr: TIELayer; begin if assigned(fOnDrawLayerBox) then fOnDrawLayerBox(self, ABitmap, idx) else with ABitmap.Canvas do begin Pen.Assign( fLayerBoxPen ); Brush.Style := bsClear; lyr := TIELayer(fLayers[idx]); if lyr.Rotate = 0 then begin with lyr.ClientAreaBox do Rectangle(Left, Top, Right, Bottom); end else begin Polygon(lyr.DrawingInfo.RotatedDest); end; end; end; procedure TImageEnView.DrawLayerOuter(ABitmap: TBitmap; idx: integer); var i, j: integer; rgb: PRGB; bwidth, bheight: integer; begin with ABitmap.Canvas do begin with TIELayer(fLayers[idx]).ClientAreaBox do begin bwidth := ABitmap.Width; bheight := ABitmap.Height; for i := 0 to bheight - 1 do begin rgb := ABitmap.Scanline[i]; for j := 0 to bwidth - 1 do begin if ((j < Left) or (j > Right) or (i < Top) or (i > Bottom)) and ((((i and 1) = 0) and ((j and 1) = 0)) or (((i and 1) = 1) and ((j and 1) = 1))) then with rgb^ do begin r := 97; g := 97; b := 97; end; inc(rgb); end; end; end; end; end; // a layer must be selected (fLayersCurrent must be >-1) function TImageEnView.FindLayerGrip(x, y: integer): TIEGrip; var coords: array[0..8] of TRect; i: integer; begin result := ieNone; if fLayersCurrent > -1 then begin CalcLayerGripCoords(fLayersCurrent, coords); for i := 0 to 8 do if IEPointInRect(x, y, coords[ i ].left, coords[ i ].top, coords[ i ].right, coords[ i ].bottom) then begin result := TIEGrip(i + 1); if not (miRotatelayers in fMouseInteract) and (result = ieRotationCenter) then result := ieNone; break; end; end; end; // Returns the grip for any selected layer // bSetCurrent = True: Makes the layer the active one function TImageEnView.FindLayerGripAnySel(x, y: integer; bSetCurrent: Boolean = False): TIEGrip; var coords: array[0..8] of TRect; i, iL: integer; ALayer: TIELayer; begin result := ieNone; if fLayersCurrent > -1 then Result := FindLayerGrip( x, y ); if ( result <> ieNone ) or ( LayersAllowMultiSelect = False ) then exit; for iL := 1 to LayersCount - 1 do begin ALayer := TIELayer( fLayers[ iL ]); if ( ALayer.Locked = False ) and ALayer.Selected then begin CalcLayerGripCoords(iL, coords); for i := 0 to 8 do if IEPointInRect(x, y, coords[ i ].left, coords[ i ].top, coords[ i ].right, coords[ i ].bottom) then begin result := TIEGrip(i + 1); if not (miRotatelayers in fMouseInteract) and (result = ieRotationCenter) then result := ieNone; if ( Result <> ieNone ) and bSetCurrent then begin if SetLayersCurrentEx( iL, True, False ) then DoLayerNotify(fLayersCurrent, ielSelected); end; exit; end; end; end; end; function TImageEnView.FindLayerGripDist(x, y: integer; var Distance: Double): TIEGrip; var coords: array[0..8] of TRect; i: integer; d: Double; begin result := ieNone; Distance := 10000000; if fLayersCurrent > -1 then begin CalcLayerGripCoords(fLayersCurrent, coords); for i := 0 to 8 do with coords[i] do begin d := sqrt(sqr(x-((Left+Right)/2))+sqr(y-((Top+Bottom)/2))); if d < Distance then begin Distance := d; result := TIEGrip(i + 1); end; end; end; end; // 0=left-top 1=right-top 2=right-bottom 3=left-bottom // 4=left side // 5=right side // 6=top side // 7=bottom side // 8=rotation center grip procedure TImageEnView.CalcLayerGripCoords(layeridx: integer; var coords: array of TRect); var lyr: TIELayer; begin lyr := TIELayer(fLayers[layeridx]); if ( lyr.Kind <> ielkImage ) or ( lyr.Rotate = 0 ) then begin with lyr.ClientAreaBox do begin // left | top coords[0].Left := left - fLyrGripSize; coords[0].Top := top - fLyrGripSize; coords[0].Right := left + fLyrGripSize; coords[0].Bottom := top + fLyrGripSize; // right | top coords[1].Left := right - fLyrGripSize; coords[1].Top := top - fLyrGripSize; coords[1].Right := right + fLyrGripSize; coords[1].Bottom := top + fLyrGripSize; // right | bottom coords[2].Left := right - fLyrGripSize; coords[2].Top := bottom - fLyrGripSize; coords[2].Right := right + fLyrGripSize; coords[2].Bottom := bottom + fLyrGripSize; // left | bottom coords[3].Left := left - fLyrGripSize; coords[3].Top := bottom - fLyrGripSize; coords[3].Right := left + fLyrGripSize; coords[3].Bottom := bottom + fLyrGripSize; // left | center coords[4].Left := left - fLyrGripSize; coords[4].Top := ((top + bottom) div 2) - fLyrGripSize; coords[4].Right := left + fLyrGripSize; coords[4].Bottom := ((top + bottom) div 2) + fLyrGripSize; // right | center coords[5].Left := right - fLyrGripSize; coords[5].Top := ((top + bottom) div 2) - fLyrGripSize; coords[5].Right := right + fLyrGripSize; coords[5].Bottom := ((top + bottom) div 2) + fLyrGripSize; // top | center coords[6].Left := ((left + right) div 2) - fLyrGripSize; coords[6].Top := top - fLyrGripSize; coords[6].Right := ((left + right) div 2) + fLyrGripSize; coords[6].Bottom := top + fLyrGripSize; // bottom | center coords[7].Left := ((left + right) div 2) - fLyrGripSize; coords[7].Top := bottom - fLyrGripSize; coords[7].Right := ((left + right) div 2) + fLyrGripSize; coords[7].Bottom := bottom + fLyrGripSize; end; end else begin with lyr.DrawingInfo do begin // left | top coords[0].Left := RotatedDest[0].X - fLyrGripSize; coords[0].Top := RotatedDest[0].Y - fLyrGripSize; coords[0].Right := RotatedDest[0].X + fLyrGripSize; coords[0].Bottom := RotatedDest[0].Y + fLyrGripSize; // right | top coords[1].Left := RotatedDest[1].X - fLyrGripSize; coords[1].Top := RotatedDest[1].Y - fLyrGripSize; coords[1].Right := RotatedDest[1].X + fLyrGripSize; coords[1].Bottom := RotatedDest[1].Y + fLyrGripSize; // right | bottom coords[2].Left := RotatedDest[2].X - fLyrGripSize; coords[2].Top := RotatedDest[2].Y - fLyrGripSize; coords[2].Right := RotatedDest[2].X + fLyrGripSize; coords[2].Bottom := RotatedDest[2].Y + fLyrGripSize; // left | bottom coords[3].Left := RotatedDest[3].X - fLyrGripSize; coords[3].Top := RotatedDest[3].Y - fLyrGripSize; coords[3].Right := RotatedDest[3].X + fLyrGripSize; coords[3].Bottom := RotatedDest[3].Y + fLyrGripSize; // left | center coords[4].Left := ((RotatedDest[0].X+RotatedDest[3].X) div 2) - fLyrGripSize; coords[4].Top := ((RotatedDest[0].Y+RotatedDest[3].Y) div 2) - fLyrGripSize; coords[4].Right := coords[4].Left + fLyrGripSize*2; coords[4].Bottom := coords[4].Top + fLyrGripSize*2; // right | center coords[5].Left := ((RotatedDest[1].X+RotatedDest[2].X) div 2) - fLyrGripSize; coords[5].Top := ((RotatedDest[1].Y+RotatedDest[2].Y) div 2) - fLyrGripSize; coords[5].Right := coords[5].Left + fLyrGripSize*2; coords[5].Bottom := coords[5].Top + fLyrGripSize*2; // top | center coords[6].Left := ((RotatedDest[0].X+RotatedDest[1].X) div 2) - fLyrGripSize; coords[6].Top := ((RotatedDest[0].Y+RotatedDest[1].Y) div 2) - fLyrGripSize; coords[6].Right := coords[6].Left + fLyrGripSize*2; coords[6].Bottom := coords[6].Top + fLyrGripSize*2; // bottom | center coords[7].Left := ((RotatedDest[2].X+RotatedDest[3].X) div 2) - fLyrGripSize; coords[7].Top := ((RotatedDest[2].Y+RotatedDest[3].Y) div 2) - fLyrGripSize; coords[7].Right := coords[7].Left + fLyrGripSize*2; coords[7].Bottom := coords[7].Top + fLyrGripSize*2; end; end; // rotation center coords[8].Left := lyr.ConvXBmp2Scr( round(lyr.OriginalWidth * lyr.RotateCenterX ) ) - fLyrGripSize; coords[8].Top := lyr.ConvYBmp2Scr( round(lyr.OriginalHeight * lyr.RotateCenterY ) ) - fLyrGripSize; coords[8].Right := coords[8].Left + fLyrGripSize*2; coords[8].Bottom := coords[8].Top + fLyrGripSize*2; end; procedure TImageEnView.DrawLayerGrips(ABitmap: TBitmap; idx: integer); var i: integer; coords: array[0..8] of TRect; iec: TIECanvas; begin CalcLayerGripCoords(idx, coords); if assigned(fOnDrawLayerGrip) then begin for i := 0 to 8 do fOnDrawLayerGrip(self, ABitmap, idx, i, coords[i]); end else begin iec := TIECanvas.Create(ABitmap.Canvas, true, true); with iec do begin Pen.Style := psSolid; Pen.Mode := pmCopy; Pen.Color := fLyrGripColor1; Pen.Width := 1; Brush.Style := fLyrGripBrushStyle; Brush.Color := fLyrGripColor2; for i := 0 to 7 do with coords[i] do case fLyrGripShape of iegsBox: Rectangle(Left, Top, Right, Bottom); iegsCircle: Ellipse(Left, Top, Right, Bottom); end; end; iec.Free; end; end; procedure TImageEnView.DrawLayerRotationCenter(ABitmap: TBitmap; idx: integer); var coords: array[0..8] of TRect; iec: TIECanvas; begin CalcLayerGripCoords(idx, coords); iec := TIECanvas.Create(ABitmap.Canvas, true, true); with iec do begin Pen.Style := psSolid; Pen.Mode := pmCopy; Pen.Color := fLyrGripColor1; Brush.Style := fLyrGripBrushStyle; Brush.Color := fLyrGripColor2; Ellipse(coords[8]); end; iec.Free; end; {!! TImageEnView.SaveSelectionToStream Declaration procedure SaveSelectionToStream(Stream: TStream); Description Saves the current selection to the specified stream (just the user selection, not the image content) Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToStream(sel1); .. sel1.Position := 0; ImageEnView1.LoadSelectionFromStream(sel1); // this equates to Select(10, 10, 100, 100) !!} procedure TImageEnView.SaveSelectionToStream(Stream: TStream); var val: Integer; begin // main sizes Stream.Write(fSelectionMask.Width, sizeof(fSelectionMask.Width)); Stream.Write(fSelectionMask.Height, sizeof(fSelectionMask.Height)); // TImageEnView Stream.Write(PIEAnimPoly(fHPolySel)^.PolyCount, sizeof(PIEAnimPoly(fHPolySel)^.PolyCount)); if PIEAnimPoly(fHPolySel)^.Poly <> nil then Stream.Write(PIEAnimPoly(fHPolySel)^.Poly^, sizeof(TPoint) * PIEAnimPoly(fHPolySel)^.PolyCount); Stream.Write(PIEAnimPoly(fHPolySel)^.RX1, sizeof(PIEAnimPoly(fHPolySel)^.RX1)); Stream.Write(PIEAnimPoly(fHPolySel)^.RY1, sizeof(PIEAnimPoly(fHPolySel)^.RY1)); Stream.Write(PIEAnimPoly(fHPolySel)^.RX2, sizeof(PIEAnimPoly(fHPolySel)^.RX2)); Stream.Write(PIEAnimPoly(fHPolySel)^.RY2, sizeof(PIEAnimPoly(fHPolySel)^.RY2)); Stream.Write(fSel, sizeof(fSel)); val := CurrentLayer.PosX; Stream.Write( val, sizeof( integer )); val := CurrentLayer.PosY; Stream.Write( val, sizeof( integer )); // TIEMask Stream.Write(fSelectionMask.BitsPerPixel, sizeof(fSelectionMask.BitsPerPixel)); Stream.Write(fSelectionMask.X1, sizeof(fSelectionMask.X1)); Stream.Write(fSelectionMask.Y1, sizeof(fSelectionMask.Y1)); Stream.Write(fSelectionMask.X2, sizeof(fSelectionMask.X2)); Stream.Write(fSelectionMask.Y2, sizeof(fSelectionMask.Y2)); Stream.Write(fSelectionMask.Full, sizeof(fSelectionMask.Full)); Stream.Write(fSelectionMask.Bits^, fSelectionMask.Height * fSelectionMask.RowLen); end; {!! TImageEnView.LoadSelectionFromStream Declaration function LoadSelectionFromStream(Stream: TStream; Options: = iersMoveToAdapt): boolean;; Description Loads a selection from a stream (saved using or ). Returns False if it fails. Options specifies how the selection is adapted when it is applied to an image of a different size or position. Note: To share the same selection among layers you must use iersSyncLayers. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToStream(sel1); .. sel1.Position := 0; ImageEnView1.LoadSelectionFromStream(sel1); // this equates to Select(10, 10, 100, 100) !!} // return false if cannot load the selection (the background bitmap has wrong sizes) function TImageEnView.LoadSelectionFromStream(Stream: TStream; Options: TIERSOptions): boolean; var w, h, b, x1, y1, x2, y2: integer; f: boolean; psx, psy: Integer; ix, iy: Integer; begin // main sizes result := true; Stream.Read(w, sizeof(fSelectionMask.Width)); Stream.Read(h, sizeof(fSelectionMask.Height)); // TImageEnView if PIEAnimPoly(fHPolySel)^.Poly <> nil then freemem(PIEAnimPoly(fHPolySel)^.Poly); PIEAnimPoly(fHPolySel)^.Poly := nil; Stream.Read(PIEAnimPoly(fHPolySel)^.PolyCount, sizeof(PIEAnimPoly(fHPolySel)^.PolyCount)); getmem(PIEAnimPoly(fHPolySel)^.Poly, sizeof(TPoint) * (PIEAnimPoly(fHPolySel)^.PolyCount)); PIEAnimPoly(fHPolySel)^.PolyCapacity := PIEAnimPoly(fHPolySel)^.PolyCount; if PIEAnimPoly(fHPolySel)^.Poly <> nil then Stream.Read(PIEAnimPoly(fHPolySel)^.Poly^, sizeof(TPoint) * PIEAnimPoly(fHPolySel)^.PolyCount); Stream.Read(PIEAnimPoly(fHPolySel)^.RX1, sizeof(PIEAnimPoly(fHPolySel)^.RX1)); Stream.Read(PIEAnimPoly(fHPolySel)^.RY1, sizeof(PIEAnimPoly(fHPolySel)^.RY1)); Stream.Read(PIEAnimPoly(fHPolySel)^.RX2, sizeof(PIEAnimPoly(fHPolySel)^.RX2)); Stream.Read(PIEAnimPoly(fHPolySel)^.RY2, sizeof(PIEAnimPoly(fHPolySel)^.RY2)); Stream.Read(fSel, sizeof(fSel)); Stream.Read(psx, sizeof(integer)); Stream.Read(psy, sizeof(integer)); // TIEMask Stream.Read(b, sizeof(fSelectionMask.BitsPerPixel)); fSelectionMask.AllocateBits(w, h, b); Stream.Read(x1, sizeof(fSelectionMask.X1)); Stream.Read(y1, sizeof(fSelectionMask.Y1)); Stream.Read(x2, sizeof(fSelectionMask.X2)); Stream.Read(y2, sizeof(fSelectionMask.Y2)); fSelectionMask.X1 := x1; fSelectionMask.Y1 := y1; fSelectionMask.X2 := x2; fSelectionMask.Y2 := y2; Stream.Read(f, sizeof(fSelectionMask.Full)); fSelectionMask.Full := f; Stream.Read(fSelectionMask.Bits^, fSelectionMask.Height * fSelectionMask.RowLen); LockUpdate; // sync layers if (Options = iersSyncLayers) then begin AnimPolygonClear(fHPolySel); fSelectionMask.Resize(fIEBitmap_Width + imax(0, psx) + w, fIEBitmap_Height + imax(0, psy) + h); fSelectionMask.TranslateBitmap(psx, psy, true); ix := -CurrentLayer.PosX; iy := -CurrentLayer.PosY; fSelectionMask.TranslateBitmap(ix, iy, true ); fSelectionMask.Resize(fIEBitmap_Width, fIEBitmap_Height); fSelectionMask.SyncFull; fSelectionMask.SyncRect; end else begin if ((w <> fIEBitmap_Width) or (h <> fIEBitmap_Height)) then begin if (not fSelectionMask.IsEmpty) then begin // try to move the selection if (Options = iersMoveToAdapt) and (x2 > fIEBitmap_Width) then begin x1 := fIEBitmap_Width - (fSelectionMask.X2-fSelectionMask.X1+1); MoveSelection( -(fSelectionMask.X1-x1), 0 ); end; if (Options = iersMoveToAdapt) and (y2 > fIEBitmap_Height) then begin y1 := fIEBitmap_Height - (fSelectionMask.Y2-fSelectionMask.Y1+1); MoveSelection( 0, -(fSelectionMask.Y1-y1) ); end; fSelectionMask.Resize(fIEBitmap_Width, fIEBitmap_Height); fSelectionMask.SyncFull; fSelectionMask.SyncRect; end else fSelectionMask.Resize(fIEBitmap_Width, fIEBitmap_Height); end; end; if fSelectionMask.IsEmpty then Deselect else fSel := true; ShowSelectionEx(true); UnLockUpdate; Update; end; {!! TImageEnView.SaveSelectionToFile Declaration procedure SaveSelectionToFile(const FileName: String); Description Saves the current selection to the specified file (just the user selection, not the image content). Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToFile('selection1'); .. sel1.Position := 0; ImageEnView1.LoadSelectionFromFile('selection1'); // this equates to Select(10, 10, 100, 100) !!} procedure TImageEnView.SaveSelectionToFile(const FileName: String); var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmCreate); try SaveSelectionToStream(fs); finally FreeAndNil(fs); end; end; {!! TImageEnView.LoadSelectionFromFile Declaration function LoadSelectionFromFile(const FileName: String; Options: = iersMoveToAdapt): boolean; Description Loads a selection from a file (saved using or ). Returns False if it fails. Options specifies how the selection is adapted when it comes from an image with different size or position. Note: To share the same selection among layers you must use iersSyncLayers. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToFile('C:\selection1'); .. sel1.Position := 0; ImageEnView1.LoadSelectionFromFile('C:\selection1'); // this equates to Select(10, 10, 100, 100) !!} function TImageEnView.LoadSelectionFromFile(const FileName: String; Options: TIERSOptions = iersMoveToAdapt): boolean; var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := LoadSelectionFromStream(fs, Options); finally FreeAndNil(fs); end; end; {!! TImageEnView.MergeSelectionFromFile Declaration function MergeSelectionFromFile(const FileName: String): Boolean; Description Loads a selection from a file (saved using or ) merging it with the currently one. Returns False if it fails. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToFile('C:\selection1'); .. sel1.Position := 0; ImageEnView1.MergeSelectionFromFile('C:\selection1'); // this equates to Select(10, 10, 100, 100, iespAdd) !!} function TImageEnView.MergeSelectionFromFile(const FileName: String): Boolean; var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := MergeSelectionFromStream(fs); finally FreeAndNil(fs); end; end; {!! TImageEnView.MergeSelectionFromStream Declaration function MergeSelectionFromStream(Stream: TStream): Boolean; Description Loads a selection from a stream (saved using or ) merging it with the currently one. Returns False if it fails. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelectionToStream(sel1); .. sel1.Position := 0; ImageEnView1.MergeSelectionFromStream(sel1); // this equates to Select(10, 10, 100, 100, iespAdd) !!} function TImageEnView.MergeSelectionFromStream(Stream: TStream): boolean; var w, h, b, x1, y1, x2, y2: integer; f: boolean; msk2: TIEMask; src, dst, x, y: Integer; psx, psy: Integer; begin // main sizes result := true; Stream.Read(w, sizeof(fSelectionMask.Width)); Stream.Read(h, sizeof(fSelectionMask.Height)); // TImageEnView if PIEAnimPoly(fHPolySel)^.Poly <> nil then freemem(PIEAnimPoly(fHPolySel)^.Poly); PIEAnimPoly(fHPolySel)^.Poly := nil; Stream.Read(PIEAnimPoly(fHPolySel)^.PolyCount, sizeof(PIEAnimPoly(fHPolySel)^.PolyCount)); getmem(PIEAnimPoly(fHPolySel)^.Poly, sizeof(TPoint) * (PIEAnimPoly(fHPolySel)^.PolyCount)); PIEAnimPoly(fHPolySel)^.PolyCapacity := PIEAnimPoly(fHPolySel)^.PolyCount; if PIEAnimPoly(fHPolySel)^.Poly <> nil then Stream.Read(PIEAnimPoly(fHPolySel)^.Poly^, sizeof(TPoint) * PIEAnimPoly(fHPolySel)^.PolyCount); Stream.Read(PIEAnimPoly(fHPolySel)^.RX1, sizeof(PIEAnimPoly(fHPolySel)^.RX1)); Stream.Read(PIEAnimPoly(fHPolySel)^.RY1, sizeof(PIEAnimPoly(fHPolySel)^.RY1)); Stream.Read(PIEAnimPoly(fHPolySel)^.RX2, sizeof(PIEAnimPoly(fHPolySel)^.RX2)); Stream.Read(PIEAnimPoly(fHPolySel)^.RY2, sizeof(PIEAnimPoly(fHPolySel)^.RY2)); Stream.Read(fSel, sizeof(fSel)); Stream.Read(psx, sizeof(integer)); Stream.Read(psy, sizeof(integer)); AnimPolygonClear(fHPolySel); // TIEMask Stream.Read(b, sizeof(fSelectionMask.BitsPerPixel)); msk2 := TIEMask.Create; msk2.AllocateBits(w, h, b); Stream.Read(x1, sizeof(fSelectionMask.X1)); Stream.Read(y1, sizeof(fSelectionMask.Y1)); Stream.Read(x2, sizeof(fSelectionMask.X2)); Stream.Read(y2, sizeof(fSelectionMask.Y2)); msk2.X1 := x1; msk2.Y1 := y1; msk2.X2 := x2; msk2.Y2 := y2; Stream.Read(f, sizeof(fSelectionMask.Full)); msk2.Full := f; Stream.Read(msk2.Bits^, msk2.Height * msk2.RowLen); for y := y1 to y2 do for x := x1 to x2 do begin src := msk2.GetPixel(x, y); dst := fSelectionMask.GetPixel(x, y); fSelectionMask.SetPixel(x, y, imax(src, dst) ); end; fSelectionMask.Full := msk2.Full and fSelectionMask.Full; SelectCustom; FreeAndNil(msk2); end; {!! TImageEnView.SavedSelectionsCount Declaration property SavedSelectionsCount: Integer Description Returns the number of saved selections. !!} function TImageEnView.GetSavedSelectionsCount: Integer; begin result := fSavedSelection.Count; end; // push current selection in fSavedSelection list {!! TImageEnView.SaveSelection Declaration procedure SaveSelection; Description Adds the current selection to the stack (selections list). Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelection; ImageEnView1.Select(200, 200, 150, 150); ImageEnView1.SaveSelection; ImageEnView1.Deselect; ImageEnView1.RestoreSelection; // reload 200,200,150,150 .. ImageEnView1.RestoreSelection; // reload 10,10,100,100 !!} procedure TImageEnView.SaveSelection; var ms: TMemoryStream; begin ms := TMemoryStream.Create; SaveSelectionToStream(ms); fSavedSelection.Add(ms); end; // pop a selection from fSavedSelection list {!! TImageEnView.RestoreSelection Declaration function RestoreSelection(Remove: Boolean=true; Options: = iersMoveToAdapt): boolean; Description Restore a saved selection from the selections stack. RestoreSelection returns false when there aren't any selections saved in the stack. Options specifies how the selection is adapted when it comes from an image with different size or position. Note: To share the same selection among layers you must use iersSyncLayers. Remove allows you to remove restored selection from selections stack. Example ImageEnView1.Select(10, 10, 100, 100); ImageEnView1.SaveSelection; ImageEnView1.Select(200, 200, 150, 150); ImageEnView1.SaveSelection; ImageEnView1.Deselect; ImageEnView1.RestoreSelection; // reload 200,200,150,150 .. ImageEnVIew1.RestoreSelection; // reload 10,10,100,100 !!} function TImageEnView.RestoreSelection(Remove: Boolean; Options: TIERSOptions): boolean; var ms: TMemoryStream; begin result := false; if fSavedSelection.Count > 0 then begin ms := fSavedSelection[fSavedSelection.Count - 1]; ms.Position := 0; result := LoadSelectionFromStream(ms, Options); if Remove then begin fSavedSelection.Delete(fSavedSelection.Count - 1); FreeAndNil(ms); end; end; end; {!! TImageEnView.DiscardSavedSelection Declaration function DiscardSavedSelection: boolean; Description Removes the last saved selection from the stack (saved using ). You can use this method if you don't want to restore the saved selection. !!} function TImageEnView.DiscardSavedSelection: boolean; var ms: TMemoryStream; begin result := false; if fSavedSelection.Count > 0 then begin ms := fSavedSelection[fSavedSelection.Count - 1]; FreeAndNil(ms); fSavedSelection.Delete(fSavedSelection.Count - 1); result := true; end; end; {!! TImageEnView.RemoveAlphaChannel Declaration procedure RemoveAlphaChannel(Merge: Boolean=false); Description Removes the alpha channel and its allocated memory. will be set to false. If Merge is true the image will be merged with the background color using its alpha channel. Example // remove alpha channel from a gif ImageEnView.io.LoadFromFile('C:\test.gif'); ImageEnView.RemoveAlphaChannel; // this add a shadow (that uses the alpha channel) then save it to a jpeg (that cannot support alpha channel) ImageEnView.Proc.AddSoftShadow(4, 3, 3); ImageEnView.RemoveAlphaChannel( True ); // merge the alpha channel ImageEnView.IO.SaveToFile('C:\output.jpg'); !!} // if merge is true merges the alpha channel with the background color procedure TImageEnView.RemoveAlphaChannel(Merge: boolean); begin if fIEBitmapValid = False then exit; fIEBitmap.RemoveAlphaChannel(Merge, fBackground); Update(); end; function TImageEnView.QuantizeViewX(vx: integer): integer; begin result := vx; if result < 0 then result := 0; if (result < fZZWW) and (fGXBmp2Scr <> nil) and (fXScr2BmpSize > 0) and (result < fGXScr2BmpSize) then result := fGXBmp2Scr[fGXScr2Bmp[result]]; end; function TImageEnView.QuantizeViewY(vy: integer): integer; begin result := vy; if result < 0 then result := 0; if (result < fZZHH) and (fGYBmp2Scr <> nil) and (fYScr2BmpSize > 0) and (result < fGYScr2BmpSize) then result := fGYBmp2Scr[fGYScr2Bmp[result]]; end; // recalculate coordinate conversion LUT procedure TImageEnView.CreateCoordConvLUT; var i, v: integer; scrx, scry, bmpx, bmpy: integer; qviewx, qviewy: integer; begin if (fLutLastZoomX <> fZoomX) or (fLutLastZoomY<>fZoomY) or (fLutLastFRX <> frx) or (fLutLastFRY <> fry) or (fLutLastMaxLayerWidth <> fLayersRect.width) or (fLutLastMaxLayerHeight <> fLayersRect.height) then begin // free olds if fGXScr2Bmp <> nil then freemem(fGXScr2Bmp); if fGYScr2Bmp <> nil then freemem(fGYScr2Bmp); if fGXBmp2Scr <> nil then freemem(fGXBmp2Scr); if fGYBmp2Scr <> nil then freemem(fGYBmp2Scr); fGXScr2Bmp := nil; fGYScr2Bmp := nil; fGXScr2BmpSize := 0; fGYScr2BmpSize := 0; fGXBmp2Scr := nil; fGYBmp2Scr := nil; fXScr2Bmp := nil; fYScr2Bmp := nil; fXBmp2Scr := nil; fYBmp2Scr := nil; fXScr2BmpSize := 0; fYScr2BmpSize := 0; fXBmp2ScrSize := 0; fYBmp2ScrSize := 0; // check validity if (fry = 0) or (frx = 0) then exit; if (fIEBitmap_Width = 0) or (fIEBitmap_Height = 0) then exit; // sizes fXScr2BmpSize := frx; fYScr2BmpSize := fry; fXBmp2ScrSize := trunc(frx * f100DZoomX); fYBmp2ScrSize := trunc(fry * f100DZoomY); scrx := fZZWW + fXScr2BmpSize + 1; scry := fZZHH + fYScr2BmpSize + 1; bmpx := trunc(scrx * f100DZoomX) + 1; bmpy := trunc(scry * f100DZoomY) + 1; fGXScr2BmpSize := (scrx + 1); fGYScr2BmpSize := (scry + 1); fGXScr2Bmp := allocmem(fGXScr2BmpSize * sizeof(integer)); fGYScr2Bmp := allocmem(fGYScr2BmpSize * sizeof(integer)); fGXBmp2Scr := allocmem((bmpx + 1) * sizeof(integer)); fGYBmp2Scr := allocmem((bmpy + 1) * sizeof(integer)); if fZoomX > 100 then begin for i := scrx - 1 downto 0 do begin v := trunc(i * f100DZoomX); fGXBmp2Scr[v] := i; fGXScr2Bmp[i] := imin(v, imax(fLayersRect.width - 1, 0)); end; end else begin for i := bmpx - 1 downto 0 do begin v := trunc(i * fZoomD100X); fGXBmp2Scr[i] := v; fGXScr2Bmp[v] := imin(i, imax(fLayersRect.width - 1, 0)); end; end; if fZoomY > 100 then begin for i := scry - 1 downto 0 do begin v := trunc(i * f100DZoomY); fGYBmp2Scr[v] := i; fGYScr2Bmp[i] := imin(v, imax(fLayersRect.height - 1, 0)); end; end else begin for i := bmpy - 1 downto 0 do begin v := trunc(i * fZoomD100Y); fGYBmp2Scr[i] := v; fGYScr2Bmp[v] := imin(i, imax(fLayersRect.height - 1, 0)); end; end; fLutLastZoomX := fZoomX; fLutLastZoomY := fZoomY; fLutLastFRX := frx; fLutLastFRY := fry; fLutLastMaxLayerWidth := fLayersRect.width; fLutLastMaxLayerHeight := fLayersRect.height; end; if fXScr2BmpSize > 0 then begin // check one for all (don't care YScr2BmpSize...) qviewx := QuantizeViewX(fViewX); qviewy := QuantizeViewY(fViewY); fXBmp2Scr := @fGXBmp2Scr[imax(0, fGXScr2Bmp[qViewX] - fo1x)]; fYBmp2Scr := @fGYBmp2Scr[imax(0, fGYScr2Bmp[qViewY] - fo1y)]; fXScr2Bmp := @fGXScr2Bmp[qViewX]; fYScr2Bmp := @fGYScr2Bmp[qViewY]; end; end; {!! TImageEnView.Cursor Declaration property Cursor: TCursor; Description Specifies the image used for the mouse pointer when it passes over the control. Note: If you have enabled then ImageEn will automatically change the cursor when relevant. ImageEn Cursors Constant Value Cursor crIEZoomOut 1778 crIEZoomIn 1779 crIEThickCross2 1780 crIEEraser 1781 crIEHandDrag 1782 crIEPencil 1783 crIECross 1784 crIECrossSight 1785 crIESizeNWSE 1786 crIESizeNS 1787 crIESizeNESW 1788 crIESizeWE 1789 crIESizeAll 1790 crIECrossSightPlus 1791 crIECrossSightMinus 1792 crIEThickCross 1793 crIEThickCrossPlus 1794 crIECrossSightMinus2 1795 crIECrossSightMinus3 1796 crIEBrush 1797 crIEEyeDropper3 1798 crIEPaintFill 1799 crIEStamp 1800 crIECrop 1801 crIECrossSmallPlus 1802 crIESmallArrow 1803 crIEMultipleArrow 1804 crIEEyeDropper2 1805 crIEEyeDropper 1806 crIECut 1807 crIESelectArrow 1808 crIEPen 1809 crIEPlusMinus 1810 crIERotateNE 1811 crIERotateSW 1812 crIERotateNW 1813 crIERotateSE 1814
System Cursors Constant Value Cursor crNone -1 crArrow -2 crCross -3 crIBeam -4 crSizeNESW -6 crSizeNS -7 crSizeNWSE -8 crSizeWE -9 crUpArrow -10 crHourGlass -11 crDrag -12 crNoDrop -13 crHSplit -14 crVSplit -15 crMultiDrag -16 crSQLWait -17 crNo -18 crAppStart -19 crHelp -20 crHandPoint -21 crSizeAll -22
!!} procedure TImageEnView.SetCursor(Value: TCursor); begin if assigned(fOnSetCursor) then fOnSetCursor(self, Value); fLCursor := Value; inherited Cursor := Value; fCursor := Value; //Windows.SetCursor(Screen.Cursors[Value]); end; procedure TImageEnView.SetTempCursor(Value: TCursor; bOnMouseDown : Boolean = False); begin if assigned(fOnSetCursor) then fOnSetCursor(self, Value); if fAutoCursors then begin inherited Cursor := Value; fCursor := Value; if bOnMouseDown then begin // Note: Need special handling for OnMouseDown because a control's cursor cannot be changed on mouse down because it has been captured (until mouse up). So need to change screen's cursor fWasScreenCursor := Screen.Cursor; Screen.Cursor := Value; end; end; end; // restore the cursor for fLCursor (default cursor) procedure TImageEnView.RestoreCursor; begin SetTempCursor(fLCursor); if fWasScreenCursor <> crNone then begin Screen.Cursor := fWasScreenCursor; fWasScreenCursor := crNone; end; end; procedure TImageEnView.SetDelayTimer(Value: integer); begin fDelayTimer := Value; if fDelayTimer > 0 then begin SetupAniPolyTimer; fAnimPolyTimer.Interval := Value; end; end; {!! TImageEnView.DelayTimer Declaration property DelayTimer: Integer; Description ImageEn has a timer that decrements a counter at each tick (you can set the tick delay using DelayTimer property). This timer controls the selection animation and the application of filters on scrolling (when
is True). If you set negative values DelayTimer changes its behavior. Negative values represent the maximum CPU time that ImageEn can use to show selections. For example setting: ImageEnView.DelayTimer := -10; ImageEn will not use much more than 10% of the CPU time. The default DelayTimer's value is -20 (maximum 20% of the CPU time). !!} function TImageEnView.GetDelayTimer: integer; begin result := fDelayTimer; end; {!! TImageEnView.GradientEndColor Declaration property GradientEndColor: TColor Description Specifies the ending color of the gradient when is iebsGradient. The gradient start color is set using . Note: This value may be overridden if is enabled. Default: clBtnShadow !!} procedure TImageEnView.SetGradientEndColor(Value: TColor); begin fGradientEndColor := Value; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.CenterImage Declaration procedure CenterImage; Description If the image is larger than the component client area, CenterImage will scroll the image so that it is centered. !!} procedure TImageEnView.CenterImage; begin SetViewXY(trunc((fIEBitmap_Width*fZoomD100X - GetClientWidthExRulers)/2), trunc((fIEBitmap_Height*fZoomD100Y - ClientHeight)/2)); end; {!! TImageEnView.LockUpdate Declaration procedure LockUpdate; Description Disables all calls to the method (increasing . LockUpdate and are useful, for example, when resampling multiple layers. Example ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount-1 do begin ImageEnView1.LayersCurrent := i; ImageEnView1.Proc.Resample(300, -1, rfNone); // withtout LockUpdate this call resizes all other layers end; ImageEnView1.UnlockUpdate; !!} procedure TImageEnView.LockUpdate; begin inc(fUpdateLocked); end; {!! TImageEnView.UnlockUpdate Declaration procedure UnlockUpdate; Description Re-enables all calls to the method, after a call to . LockUpdate and UnLockUpdate are useful, for example, when you need to resample multiple layers. UnLockUpdate descreases and calls when the count reverts to zero. Example ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount-1 do begin ImageEnView1.LayersCurrent := i; ImageEnView1.Proc.Resample(300, -1, rfNone); // without LockUpdate this call resizes all other layers end; ImageEnView1.UnlockUpdate; !!} procedure TImageEnView.UnLockUpdate; begin UnLockUpdateEx; if fUpdateLocked = 0 then Update; end; {!! TImageEnView.UnLockUpdateEx Declaration procedure UnLockUpdateEx; Description UnLockUpdateEx re-enables all calls to the method, after a call to . LockUpdate and UnLockUpdateEx are useful, for example, when you need to resample multiple layers. UnLockUpdateEx doesn't call when the update can be unlocked. !!} procedure TImageEnView.UnLockUpdateEx; begin if fUpdateLocked>0 then dec(fUpdateLocked); end; {!! TImageEnView.DrawVersion Declaration property DrawVersion: Boolean; Description When DrawVersion is True, the ImageEn version and release date are displayed on bottom-left side of the ImageEnView window. !!} procedure TImageEnView.SetDrawVersion(v: boolean); begin fDrawVersion := v; Paint; end; {!! TImageEnView.SelectionMaskDepth Declaration property SelectionMaskDepth: Integer; Description The SelectionMaskDepth property allows the specification of the selection depth in bits. The default is 1 bit which means a pixel has two states "unselected" (0) or "selected" (1). If the setting is 8 (8 bit), a pixel can be "unselected" (0), "semi-selected" (1 to 254), or "fully selected" (255). This allows creating soft or feathered selections. Note: =iesoFilled is not supported when the SelectionMaskDepth = 8 Example ImageEnView.SelectionMaskDepth := 8; ImageEnView.SelectionIntensity := 128; ImageEnView.Select( 10, 10, 100, 100 ); ImageEnView.Proc.Negative; // the negative is applied at 50 % (128=semi selected) !!} procedure TImageEnView.SetSelectionMaskDepth(value: integer); var owidth, oheight: Integer; begin if (value <> fSelectionMaskDepth) and ((value = 1) or (value = 8)) then begin if fSel then Deselect; fSelectionMaskDepth := value; owidth := fSelectionMask.Width; oheight := fSelectionMask.Height; fSelectionMask.AllocateBits(owidth, oheight, fSelectionMaskDepth); case value of 1: fSelectionIntensity := 1; 8: fSelectionIntensity := 255; end; end; end; {!! TImageEnView.SelectionIntensity Declaration property SelectionIntensity: Integer; Description Specifies the selection intensity and is valid only when the is 8 (8 bit), otherwise it must be 1. You can assign a value from 0 to 255 which will be applied to the next or current selection. See also: . Demo Demos\ImageEditing\SoftSelections\SoftSel.dpr Example ImageEnView.SelectionMaskDepth := 8; ImageEnView.SelectionIntensity := 128; ImageEnView.Select( 10, 10, 100, 100 ); ImageEnView.Proc.Negative; // the negative is applied at 50 % (128=semi selected) !!} procedure TImageEnView.SetSelectionIntensity(value: integer); var px: pbyte; i, j: integer; begin fSelectionIntensity := value; if fSel and (fSelectionMask.BitsPerPixel = 8) then begin // changes current selection with fSelectionMask do begin for i := y1 to y2 do begin px := Scanline[i]; inc(px, x1); for j := x1 to x2 do begin if px^ > 0 then px^ := value; inc(px); end; end; end; end; end; {!! TImageEnView.MakeSelectionFeather Declaration procedure MakeSelectionFeather(radius: Double); Description Modifies the current selection by applying a blur effect to make soften the borders. This property works only if is 8. Radius specifies the feathering intensity (amount of blur). Demo Demos\ImageEditing\SoftSelections\SoftSel.dpr Example ImageEnView.SelectionMaskDepth := 8; ImageEnView.Select( 10, 10, 100, 100 ); ImageEnView.MakeSelectionFeather( 4 ); !!} procedure TImageEnView.MakeSelectionFeather(radius: double); var bmp: TIEBitmap; ww, x1, y1, x2, y2: integer; begin if fSel and (fSelectionMask.BitsPerPixel = 8) then begin AnimPolygonClear(fHPolySel); bmp := TIEBitmap.Create; bmp.EncapsulateMemory(fSelectionMask.Bits, fSelectionMask.Width, fSelectionmask.Height, ie8g, false); ww := imax(trunc(radius * 5), 1); x1 := imax(fSelectionMask.X1 - ww, 0); y1 := imax(fSelectionMask.Y1 - ww, 0); x2 := imin(fSelectionMask.X2 + ww, fSelectionMask.Width - 1); y2 := imin(fSelectionMask.Y2 + ww, fSelectionMask.Height - 1); _IEGBlurRect8(bmp, x1, y1, x2, y2, radius); FreeAndNil(bmp); fSelectionMask.SyncRect; ShowSelectionEx(true); fUpdateBackBuffer := true; Paint; end; end; {!! TImageEnView.LayersRect Declaration function LayersRect(SelOnly: Boolean = False; ExcludeLayer0: Boolean = False): ; Description Returns the coverage area of all or selected layers. The result will include any layers outside the background layer (if and are not set). If ExcludeLayer0 is False, then the background layer is not included in the result. Notes: - If layers extend to the left or above the background layer, then Result.X/Y will be less than PosX/Y of Layer 0 - If layers extend to the right or below the background layer, then Result.Width/Height may be greater than the dimensions of See Also - - !!} // Returns the coverage area of all layers // x,y will be less than zero if layers are left of layer 0 (and layer is not cropped) // width, height will be greater than layer 0 size if they extend outside it (and layer is not cropped) function TImageEnView.LayersRect(SelOnly: Boolean = False; ExcludeLayer0: Boolean = False): TIERectangle; var i: Integer; minX, minY, maxX, maxY: Integer; currX, currY, currX2, currY2: Integer; begin // calculates maximum extension and minimum left/top coordinates Result.x := 0; Result.y := 0; Result.Width := 0; Result.Height := 0; maxX := 0; maxY := 0; minX := MAXINT; minY := MAXINT; if ( ExcludeLayer0 = False ) and (( SelOnly = False ) or Layers[0].Selected ) then begin minX := Layers[0].PosX; minY := Layers[0].PosY; maxX := Layers[0].PosX + Layers[0].Width; maxY := Layers[0].PosY + Layers[0].Height; end; for i := 1 to LayersCount - 1 do if ( SelOnly = False ) or Layers[i].Selected then begin currX := Layers[i].PosX; currY := Layers[i].PosY; currX2 := Layers[i].PosX + Layers[i].Width; currY2 := Layers[i].PosY + Layers[i].Height; if fLayersCropped or Layers[i].Cropped then begin currX := imax( currX, Layers[0].PosX ); currY := imax( currY, Layers[0].PosY ); currX2 := imin( currX2, Layers[0].PosX + Layers[0].Width ); currY2 := imin( currY2, Layers[0].PosY + Layers[0].Height ); end; minX := imin( minX, currX ); minY := imin( minY, currY ); maxX := imax( maxX, currX2 ); maxY := imax( maxY, currY2 ); end; if minX < MAXINT then begin Result.x := minX; if maxX > 0 then Result.Width := maxX - minX; end; if minY < MAXINT then begin Result.y := minY; if maxY > 0 then Result.Height := maxY - minY; end; end; {!! TImageEnView.MaxLayerWidth Declaration function MaxLayerWidth() : integer; Description Returns the maximum width of all layers. The result will include any layers outside the background layer (if and are not set). See Also - - !!} function TImageEnView.MaxLayerWidth() : integer; begin result := LayersRect().width; end; {!! TImageEnView.MaxLayerHeight Declaration function MaxLayerHeight() : integer; Description Returns the maximum height of all layers. The result will include any layers outside the background layer (if and are not set). See Also - - !!} function TImageEnView.MaxLayerHeight() : integer; begin result := LayersRect().height end; {!! TImageEnView.LayersDrawBox Declaration property LayersDrawBox: Boolean; Description Specify whether a box is displayed around layers. This option has no effect if []. is set to false. If Layers[].VisibleBox is true and LayersDrawBox is false, a box is drawn only on the selected layer. If Layers[].VisibleBox is true and LayersDrawBox is true, a box is drawn on all layers. Default: False Note: You can customize the style of layer box using , or for more control, !!} procedure TImageEnView.SetLayersDrawBox(value: boolean); begin if value <> fLayersDrawBox then begin fLayersDrawBox := value; UpdateReason := ieurComponentStuffChanged; Update; end; end; {!! TImageEnView.LayersCaching Declaration property LayersCaching: Integer; Description Whether a cached view of every layer is stored in memory. Supported values: Value Description -1 A cached view is stored for each layers. This provides the best performance, but can use a lot of memory if there are many layers 0 No cached views of layers are stored. This uses the least memory >0 Specifies a maximum number of cached views to store
Default: 0 Example // Cache all layers ImageEnView1.LayersCaching := -1; // Cache a maximum of 30 layers ImageEnView1.LayersCaching := 30; // Disable all layer caching ImageEnView1.LayersCaching := 0; See Also -
!!} procedure TImageEnView.SetLayersCaching(v: Integer); begin if v <> fLayersCaching then begin fLayersCaching := v; if fLayersCaching <> -1 then LayersSetProperties( LYR_ALL_LAYERS, IELP_LAYER_CACHE_CLEAR, True ); end; end; procedure TImageEnView.DoLayerNotify(layer: integer; event: TIELayerEvent); begin if assigned(fOnLayerNotify) then begin SwapSelectionBase; fOnLayerNotify(self, layer, event); SwapSelectionBase; end; if ( event in [ ielSelected, ielDeselected ]) and assigned( OnLayerSelectionChange ) then OnLayerSelectionChange( Self ); if event in [ ielMoved, ielResized, ielRotated, ielEdited, ielCreated ] then ImageChange(); end; {$IFDEF IEINCLUDEDIRECTSHOW} procedure TImageEnView.DShowNewFrame(var Message: TMessage); var dshow: TIEDirectShow; begin dshow := TIEDirectShow(pointer(Message.LParam)); dshow.AcceptNextFrame := false; if assigned(dshow) and dshow.Connected and assigned(fOnDShowNewFrame) then fOnDShowNewFrame(self); dshow.AcceptNextFrame := true; end; procedure TImageEnView.DShowEvent(var Message: TMessage); var dshow: TIEDirectShow; event: integer; begin dshow := TIEDirectShow(pointer(Message.LParam)); if assigned(dshow) and dshow.Connected then begin if assigned(fOnDShowEvent) then fOnDShowEvent(self) else begin dshow.GetEventCode(event); case event of IEEC_COMPLETE: dshow.EndOfStream := true; end; end; end; end; {$ENDIF} {$IFDEF IEINCLUDEMEDIAFOUNDATION} procedure TImageEnView.MediaFoundationNotify(var Message: TMessage); var notify: TIEMediaFountationNotifyType; mediaFoundation: TObject; begin notify := TIEMediaFountationNotifyType(Message.WParam); mediaFoundation := TObject(pointer(Message.LParam)); if assigned(mediaFoundation) then begin if assigned(fOnMediaFoundationNotify) then fOnMediaFoundationNotify(self, mediaFoundation, notify); end; end; {$ENDIF} {!! TImageEnView.SelectionAspectRatio Declaration property SelectionAspectRatio: Double; Description Specifies whether the selection is locked to a specific size or aspect ratio. If SelectionAspectRatio is -1, the aspect ratio is locked only when user press the ALT key, and is automatically calculated. If SelectionAspectRatio is 0, the size of the selection is fixed by the and properties. If SelectionAspectRatio is >0, ImageEn locks the selection to the specified aspect ratio. Example // we want standard behavior ImageEnView1.SelectionAspectRatio := -1; // we want a fixed selection of 100 x 100 pixels ImageEnView1.SelectionAbsWidth := 100; ImageEnView1.SelectionAbsHeight := 100; ImageEnView1.SelectionAspectRatio := 0; // we want a fixed aspect ratio of 4:3 (standard landscape, i.e. height is 75% of height) ImageEnView1.SelectionAspectRatio := 4 / 3; See Also - !!} procedure TImageEnView.SetSelectionAspectRatio(value: Double); begin if value<>fSelectionAspectRatio then begin fSelectionAspectRatio := value; if fSelectionAspectRatio = 0 then SelectionOptions := SelectionOptions - [iesoSizeable] else SelectionOptions := SelectionOptions + [iesoSizeable]; end; end; {$ifdef IEINCLUDEFLATSB} {!! TImageEnView.FlatScrollBars Declaration property FlatScrollBars: Boolean; Description Specifies whether the component's scroll bars are flat. ImageEn only supports flat scroll bars if the system comctl32.dll is version 472 or later. This property must be set at Design Time (has not effect at run-time) !!} procedure TImageEnView.SetFlatScrollBars(Value: Boolean); begin if Value<>fFlatScrollBars then begin fFlatScrollBars := Value; if fFlatScrollBars then begin IESetScrollRange(Handle, SB_HORZ, 0, 65535, false, false); // Why this? Please ask to Microsoft programmers! IESetScrollRange(Handle, SB_VERT, 0, 65535, false, false); // Why this? Please ask to Microsoft programmers! InitializeFlatSB(Handle); IEShowScrollBar(handle, SB_HORZ, false, true); // Why this? Please ask to Microsoft programmers! IEShowScrollBar(handle, SB_VERT, false, true); // Why this? Please ask to Microsoft programmers! end else UninitializeFlatSB(Handle); end; end; {$endif} procedure TImageEnView.SwapSelectionBase; var x: TIESelectionBase; begin x := fSavedSelectionBase; fSavedSelectionBase := fSelectionBase; fSelectionBase := x; end; procedure TImageEnView.DoZoomIn(var NewZoom: double); begin SwapSelectionBase; if assigned(fOnZoomIn) then fOnZoomIn(self, NewZoom); SwapSelectionBase; end; procedure TImageEnView.DoZoomOut(var NewZoom: double); begin SwapSelectionBase; if assigned(fOnZoomOut) then fOnZoomOut(self, NewZoom); SwapSelectionBase; end; procedure TImageEnView.DoMouseInResizingGrip(Grip: TIEGrip); begin SwapSelectionBase; if assigned(fOnMouseInResizingGrip) then fOnMouseInResizingGrip(self, Grip); SwapSelectionBase; end; procedure TImageEnView.DoMouseInSel; begin SwapSelectionBase; if assigned(fOnMouseInSel) then fOnMouseInSel(self); SwapSelectionBase; end; procedure TImageEnView.NavigatorSelectionChanging(Sender: TObject); var x, y: Integer; z: double; begin if (ienoDontRefreshSrcIfNavNotFocused in fNavigator.fNavigatorOptions) and not fNavigator.Focused then exit; if fNavigatorInside then exit; fNavigatorInside := true; z := fIEBitmap_Width / fNavigator.IEBitmap.Width; x := round( z * Zoom / 100 * fNavigator.SelX1 ); y := round( z * Zoom / 100 * fNavigator.SelY1 ); SetViewXY(x, y); fNavigatorInside := false; end; procedure TImageEnView.NavigatorMouseWheel(Sender: TObject; Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); var dPos: double; dir: integer; begin if WheelDelta > 0 then dir := -1 else dir := 1; if fNavigator.fMouseWheelParams.InvertDirection then dir := -1 * dir; dPos := fZoomX; case fNavigator.fMouseWheelParams.Variation of iemwAbsolute: dPos := fZoomX + dir * fNavigator.fMouseWheelParams.Value; iemwPercentage: dPos := fZoomX + imax(round(fZoomX * fNavigator.fMouseWheelParams.Value / 100), 1) * dir; end; if (dPos > fZoomX) then DoZoomIn(dPos); if (dPos < fZoomX) then DoZoomOut(dPos); if fNavigator.fMouseWheelParams.ZoomPosition = iemwCenter then SetZoom(dPos) else ZoomAt(MousePos.X, MousePos.Y, dPos, false); Handled := true; end; procedure TImageEnView.SetNavigatorRect; var x1, y1, x2, y2: Integer; z: Double; begin if fNavigatorInside or (fLockPaint > 0) then exit; fNavigatorInside := true; if not (ienoDontPaintSrcBitmap in fNavigator.fNavigatorOptions) then Paint(); // this updates offsets z := fNavigator.IEBitmap.Width / fIEBitmap_Width; x1 := round(z * XScr2Bmp( OffsetX, False )); y1 := round(z * YScr2Bmp( OffsetY, False )); x2 := round(z * XScr2Bmp( OffsetX + ExtentX, False )); y2 := round(z * YScr2Bmp( OffsetY + ExtentY, False )); fNavigator.SelectionAbsWidth := x2-x1; fNavigator.SelectionAbsHeight := y2-y1; fNavigator.SelectionAspectRatio := 0; fNavigator.Select(x1, y1, x2, y2, iespReplace); fNavigatorInside := false; end; {!! TImageEnView.SetNavigator Declaration procedure SetNavigator(nav: ; options: ); Description SetNavigator specifies a TImageEnView component which works as navigator of current image. A navigator shows a selection that controls the zoom and scroll of the main control. Use options to fine-tune navigator behavior. Demos Demos\Display\Navigator\Navigator.dpr Demos\Display\Navigator2\Navigator.dpr Example ImageEnView1.SetNavigator(ImageEnView2, [ienoMouseWheelZoom, ienoMarkOuter]); ImageEnView1.IO.LoadFromFile('input.jpg'); !!} procedure TImageEnView.SetNavigator(nav: TImageEnView; options: TIENavigatorOptions); begin if ( nav <> nil ) and ( fIEBitmapValid = False ) then raise EIEException.create( 'Method only supported for image layers' ); if fNavigator <> nil then begin fNavigator.OnSelectionChanging := nil; if not IEBitmap.IsVirtual then fNavigator.SetExternalBitmap(nil); fNavigator.fIsNavigator := false; end; fNavigator := nav; if fNavigator<>nil then begin fNavigator.fIsNavigator := true; fNavigator.EnableAlphaChannel := EnableAlphaChannel; fNavigator.AutoFit := True; fNavigator.MouseInteract := [miSelect]; fNavigator.SelectionBase := iesbBitmap; fNavigator.SelectionOptions := [iesoMoveable, iesoCanScroll]; if ( not ( ienoDontAssignNavBitmap in Options )) and ( IEBitmap.IsVirtual = False ) then fNavigator.SetExternalBitmap( IEBitmap ); fNavigator.fOnSelectionChanging := NavigatorSelectionChanging; fNavigator.fNavigatorOptions := options; if ienoMOUSEWHEELZOOM in options then fNavigator.OnMouseWheel := NavigatorMouseWheel; fNavigator.FreeNotification(self); SetNavigatorRect; end; end; procedure TImageEnView.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (AComponent = fNavigator) and (Operation = opRemove) then begin fNavigator := nil; end; end; {!! TImageEnView.SetExternalBitmap Declaration procedure SetExternalBitmap(bmp: ); Description Allows you to connect the TImageEnView component to another , including sharing the bitmap of another TImageEnView. This is useful to view the same image with multiple TImageEnView components, but loading the image only once. Demo Demos\Display\ExternalBitmap\ExternalBMP.dpr Example ImageEnView1.IO.LoadFromFile('C:\input.jpg'); ImageEnView2.SetExternalBitmap( ImageEnView1.IEBitmap ); ..Both ImageEnView1 and ImageEnView2 now show input.jpg. !!} procedure TImageEnView.SetExternalBitmap(bmp: TIEBitmap); begin if fLayersCurrent > -1 then begin // Ensure an image layer is active if Layers[ fLayersCurrent ].Kind <> ielkImage then SetLayersCurrent( 0 ); // Base layer always image fIEBitmap.fOwner := nil; if bmp <> nil then begin if TIEImageLayer( CurrentLayer ).fFreeBitmapOnDestroy then begin if fIEBitmap.EncapsulatedFromTBitmap then FreeAndNil(fBitmap); FreeAndNil(fIEBitmap); end; bmp.fOwner := Self; TIEImageLayer( CurrentLayer ).fBitmap := bmp; TIEImageLayer( CurrentLayer ).fFreeBitmapOnDestroy := false; fIEBitmap := TIEImageLayer( CurrentLayer ).Bitmap; if fIEBitmap.EncapsulatedFromTBitmap then fBitmap := fIEBitmap.VclBitmap else fBitmap := nil; CallBitmapChangeEvents; Update; end else begin TIEImageLayer( CurrentLayer ).fFreeBitmapOnDestroy := true; fIEBitmap := TIEBitmap.Create; fIEBitmap.fOwner := Self; fBitmap := nil; // Assign new fIEBitmap to current layer SyncBitmapToCurrentLayer(); end; end; end; {!! TImageEnView.ImageEnVersion Declaration property ImageEnVersion: String; Description Returns the ImageEn version as a string. !!} function TImageEnView.GetImageEnVersion: String; begin result := IEMAINVERSION; end; procedure TImageEnView.SetImageEnVersion(Value: String); begin // this is a read-only property, but it must be displayed in object inspector end; {$ifdef IEDOTNETVERSION} procedure TImageEnView.WMContextMenu(var Message: TWMContextMenu); begin // just to remove Delphi default behavior end; {$endif} {!! TImageEnView.ChangeResolution Declaration procedure ChangeResolution(NewDPI: Integer; ResampleFilter: ); Description Modifies the DPI of the image (IO.Params.DpiX and IO.Params.DpiY), resampling it and setting the new DPI values. Note: You should ensure the source DPI contains valid values before calling ChangeResolution. This method has no effect if DPI is 0. Example // load input.jpg which has 100 dpi ImageEnView1.IO.LoadFromFile('C:\input.jpg'); // we want 75 dpi ImageEnView1.ChangeResolution(75, rfTriangle); // save back as 75 dpi ImageEnView1.IO.SaveToFile('C:\output.jpg'); !!} procedure TImageEnView.ChangeResolution(NewDPI: Integer; ResampleFilter: TResampleFilter); var iOldDpi: Integer; iLayersCurrent: Integer; I: Integer; procedure _UpdateCurrentLayer(bSetDPI: Boolean); var iNewHeight: Integer; Proc: TImageEnProc; begin iNewHeight := round( fIEBitmap.Height / iOldDpi * NewDPI ); Proc := TImageEnProc.CreateFromBitmap( fIEBitmap ); try Proc.OnProgress := fOnProgress; Proc.OnFinishWork := fOnFinishWork; Proc.Resample( -1, iNewHeight, ResampleFilter ); finally FreeAndNil( Proc ); end; if bSetDPI then begin GetImageEnIO.Params.DpiY := NewDPI; GetImageEnIO.Params.DpiX := round( GetImageEnIO.Params.DpiX / iOldDpi * NewDPI ); end; end; begin if ( GetImageEnIO.Params.DpiX = 0 ) or ( GetImageEnIO.Params.DpiY = 0 ) then exit; iOldDpi := GetImageEnIO.Params.DpiY; if LayersCount = 0 then _UpdateCurrentLayer( True ) else begin // Iterate through all layers LockUpdate(); iLayersCurrent := LayersCurrent; try for I := 0 to LayersCount - 1 do begin LayersCurrent := I; if Layers[ fLayersCurrent ] is TIEImageLayer then _UpdateCurrentLayer( I = 0 ) else begin CurrentLayer.Width := round( CurrentLayer.Width / iOldDpi * NewDPI ); CurrentLayer.Height := round( CurrentLayer.Height / iOldDpi * NewDPI ); end; if I > 0 then begin CurrentLayer.PosX := round( CurrentLayer.PosX / iOldDpi * NewDPI ); CurrentLayer.PosY := round( CurrentLayer.PosY / iOldDpi * NewDPI ); end; end; finally LayersCurrent := iLayersCurrent; UnlockUpdate(); end; end; CallBitmapChangeEvents; Update; end; // warning: ioTIFF not supported // if compressionFormat = -1 then use internal compressed format (preserves pixelformat and transparency) // if compressionFormat = -2 then use internal noncompressed format (preserves pixelformat and transparency) procedure TImageEnView.LayersSaveToFile(const FileName: String; CompressionFormat: TIOFileType = -1); var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmCreate); try LayersSaveToStream(fs, CompressionFormat); finally FreeAndNil(fs); end; end; function TImageEnView.LayersLoadFromFile(const FileName: String; Append: Boolean = False): Boolean; var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try result := LayersLoadFromStream( fs, Append ); // this calls Update finally FreeAndNil(fs); end; end; {!! TImageEnView.LayersImport Declaration function LayersImport(const FileName: String; Stream: TStream = nil; FileFormat: = ioUnknown; Append: Boolean = False): Integer; Description Imports layers from a file or stream in IEV, ALL or DXF format. Parameter Description FileName The full path to a file to import (or '' if importing from a stream) Stream A stream to import from (or nil if importing from file) FileFormat The type of file, if known. It should be one ioIEV, ioALL or ioDXF. You can also specify ioUnknown, whereby ImageEn will infer the format from the content (with DXF only the file extension is considered) Append When false the existing content is cleared before importing
Result is -1 in the case of an error, otherwise returns the number of layers added. IEV and ALL are object formats of
. Conversion is as follows: Object Kind Converted To Notes iekLINE - iekBOX - iekELLIPSE - iekARC Skipped - iekBITMAP - iekTEXT - iekRULER Skipped - iekPOLYLINE - iekANGLE Skipped - iekMEMO Text formatting is lost iekLINELABEL Inward arrows are converted to outward arrows
DXF is an Autocad vector format. DXF file can only be imported from file and only lines and ellipses objects are supported. Example // Import from an IEV file (replacing the existing layers) ImageEnView1.LayersImport( 'C:\Vect.iev' ); // Import from an IEV file (adding to the existing layers) ImageEnView1.LayersImport( 'C:\Vect.iev', nil, ioIEV, True ); // Import from an IEV stream (replacing the existing layers) ImageEnView1.LayersImport( '', myStream ); // Import from an IEV stream (adding to the existing layers) ImageEnView1.LayersImport( '', myStream, ioIEV, True ); // Import from an Autocad file ImageEnView1.LayersImport( 'C:\cad.dxf', nil, ioDXF ); See Also - - - - - - - - !!} function TImageEnView.LayersImport(const FileName: String; Stream: TStream = nil; FileFormat: TIOFileType = ioUnknown; Append: Boolean = False): Integer; var IEVect : TImageEnVect; loadOK: Boolean; oldLayersCount: Integer; lp: int64; begin Result := -1; IEVect := TImageEnVect.create( nil ); try if FileFormat = ioUnknown then begin if ( FileName <> '' ) and ( string(IEExtractFileExtW(FileName)) = '.dxf' ) then FileFormat := ioDXF else if Stream <> nil then begin lp := Stream.Position; FileFormat := FindStreamFormat( Stream ); Stream.Position := lp; end else FileFormat := FindFileFormat( FileName ); if FileFormat = ioUnknown then exit; end; loadOK := False; if Stream <> nil then case FileFormat of ioIEV : loadOK := IEVect.LoadFromStreamIEV( Stream, False ); ioALL : loadOK := IEVect.LoadFromStreamALL( Stream ); else loadOK := IEVect.IO.LoadFromStream( Stream, FileFormat ); end else if FileName <> '' then case FileFormat of ioIEV : loadOK := IEVect.LoadFromFileIEV( FileName, False ); ioALL : loadOK := IEVect.LoadFromFileALL( FileName ); ioDXF : loadOK := IEVect.ImportDXF( FileName ); else loadOK := IEVect.IO.LoadFromFile( FileName, FileFormat ); end; if not loadOK then exit; LockUpdate(); if not Append then begin ClearAll(); Assign( IEVect ); // get background image end; oldLayersCount := fLayers.Count; IEVect.CopyAllObjectsTo( Self ); UnlockUpdate(); Result := fLayers.Count - oldLayersCount; finally IEVect.free; end; end; {!! TImageEnView.LayersAlign Declaration procedure LayersAlign(Alignment: ; Index: Integer = LYR_SELECTED_LAYERS); Description Aligns all selected layers relative to the image or other layers. The index of a specific layer can be specified, or LYR_ALL_LAYERS (-1) to process all layers, or LYR_SELECTED_LAYERS (-2) Example // Align selected layers on the left edge ImageEnView1.LayersAlign( ilaAlignLeftEdges ); // Position all layers in the center of the document ImageEnView1.LayersAlign( ilaAlignHorizontalCenters ); // Move layer #3 to the center of the image ImageEnView1.LayersAlign( ilaAlignToVerticalCenter, 2 ); See Also - !!} procedure TImageEnView.LayersAlign(Alignment: TIEAlignLayers; Index: Integer = LYR_SELECTED_LAYERS); var bSet: Boolean; I: Integer; iCurr: integer; iPos: integer; lyrCount: integer; {} function _DoProcessLayer(LayerId: Integer) : boolean; begin case Index of LYR_ALL_LAYERS : Result := True; LYR_SELECTED_LAYERS : Result := TIELayer( fLayers[ LayerId ]).Selected; else Result := LayerId = Index; end; end; {} begin if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then begin if Alignment in [ ilaMatchWidth, ilaMatchHeight ] then Proc.SaveUndo( IEMsg( IEMsg_ResizeLayers ), ieuLayer, True, IEOP_RESIZELAYER ) else Proc.SaveUndo( IEMsg( IEMsg_MoveLayers ), ieuLayer, True, IEOP_MOVELAYER ); end; // If there is no background layer then can't align relative to "image" if ( Layers[ 0 ].Width < 2 ) and ( Layers[ 0 ].Height < 2 ) then case Alignment of ilaAlignToLeft : Alignment := ilaAlignLeftEdges ; ilaAlignToRight : Alignment := ilaAlignRightEdges ; ilaAlignToTop : Alignment := ilaAlignTopEdges ; ilaAlignToBottom : Alignment := ilaAlignBottomEdges ; ilaAlignToHorizontalCenter : Alignment := ilaAlignHorizontalCenters; ilaAlignToVerticalCenter : Alignment := ilaAlignVerticalCenters ; end; // Check selection case Index of LYR_ALL_LAYERS : lyrCount := LayersCount - 1; LYR_SELECTED_LAYERS : lyrCount := LayersSelCount(); else if ( Index > 0 ) and ( Index < LayersCount ) then lyrCount := 1 else lyrCount := 0; end; if ( not ( Alignment in [ ilaAlignToLeft, ilaAlignToRight, ilaAlignToTop, ilaAlignToBottom, ilaAlignToHorizontalCenter, ilaAlignToVerticalCenter, ilaMatchWidth, ilaMatchHeight ])) and ( lyrCount < 2 ) then exit else if ( lyrCount < 1 ) then exit; // Get new position case Alignment of ilaAlignToLeft : iPos := Layers[ 0 ].PosX; ilaAlignToRight : iPos := Layers[ 0 ].PosX + Layers[ 0 ].Width; ilaAlignToTop : iPos := Layers[ 0 ].PosY; ilaAlignToBottom : iPos := Layers[ 0 ].PosY + Layers[ 0 ].Height; ilaAlignToHorizontalCenter : iPos := Layers[ 0 ].PosY + ( Layers[ 0 ].Height div 2 ); ilaAlignToVerticalCenter : iPos := Layers[ 0 ].PosX + ( Layers[ 0 ].Width div 2 ); ilaAlignLeftEdges , ilaAlignTopEdges , ilaAlignRightEdges , ilaAlignBottomEdges , ilaAlignHorizontalCenters , ilaAlignVerticalCenters , ilaMatchWidth , ilaMatchHeight : begin bSet := False; iPos := 0; iCurr := 0; for I := 1 to LayersCount - 1 do if _DoProcessLayer( I ) then begin case Alignment of ilaAlignLeftEdges : iCurr := Layers[ i ].PosX; ilaAlignRightEdges : iCurr := Layers[ i ].PosX + Layers[ i ].Width; ilaAlignTopEdges : iCurr := Layers[ i ].PosY; ilaAlignBottomEdges : iCurr := Layers[ i ].PosY + Layers[ i ].Height; ilaAlignHorizontalCenters : iCurr := Layers[ i ].PosY + ( Layers[ i ].Height div 2 ); ilaAlignVerticalCenters : iCurr := Layers[ i ].PosX + ( Layers[ i ].Width div 2 ); ilaMatchWidth : iCurr := Layers[ i ].Width; ilaMatchHeight : iCurr := Layers[ i ].Height; end; if bSet = False then iPos := iCurr else if Alignment in [ ilaAlignLeftEdges, ilaAlignTopEdges ] then begin if iCurr < iPos then iPos := iCurr; end else begin if iCurr > iPos then iPos := iCurr; end; bSet := True; // Use first selection for centering if Alignment in [ ilaAlignHorizontalCenters, ilaAlignVerticalCenters ] then break; end; if not bSet then exit; end; else exit; end; // Now set positions for I := 1 to LayersCount - 1 do if _DoProcessLayer( I ) then case Alignment of ilaAlignToLeft, ilaAlignLeftEdges : Layers[ i ].PosX := iPos; ilaAlignToRight, ilaAlignRightEdges : Layers[ i ].PosX := iPos - Layers[ i ].Width; ilaAlignToTop, ilaAlignTopEdges : Layers[ i ].PosY := iPos; ilaAlignToBottom, ilaAlignBottomEdges : Layers[ i ].PosY := iPos - Layers[ i ].Height; ilaAlignToHorizontalCenter, ilaAlignHorizontalCenters : Layers[ i ].PosY := iPos - ( Layers[ i ].Height div 2 ); ilaAlignToVerticalCenter, ilaAlignVerticalCenters : Layers[ i ].PosX := iPos - ( Layers[ i ].Width div 2 ); ilaMatchWidth : Layers[ i ].Width := iPos; ilaMatchHeight : Layers[ i ].Height := iPos; end; Update; end; // Shortcut method to determine whether loAllowMultiSelect is defined in LayerOptions function TImageEnView.LayersAllowMultiSelect: boolean; begin Result := loAllowMultiSelect in fLayerOptions; end; {!! TImageEnView.LayersSelectAll Declaration procedure LayersSelectAll(bIncludeLocked: Boolean = True); Description Enables the property of all layers. If bIncludeLocked = False then layers are not selected. Notes: - Does not select the background layer (layer 0) - Has no effect if multiple layer selection is not enabled. Example ImageEnView1.LayersSelectAll(); !!} procedure TImageEnView.LayersSelectAll(bIncludeLocked: Boolean = True); var i: Integer; ALayer: TIELayer; begin if not LayersAllowMultiSelect then exit; TIELayer( fLayers[ 0 ]).fSelected := False; for i := 1 { Skip BG } to LayersCount - 1 do begin ALayer := TIELayer( fLayers[ I ]); if bIncludeLocked or ( ALayer.Locked = False ) then ALayer.fSelected := True; end; Update; end; {!! TImageEnView.LayersDeselectAll Declaration procedure LayersDeselectAll(); Description Sets the property of all layers to false. Example ImageEnView1.LayersDeselectAll(); !!} procedure TImageEnView.LayersDeselectAll(); var i: Integer; begin for i := 0 to LayersCount - 1 do TIELayer( fLayers[ I ]).fSelected := False; Update; end; {!! TImageEnView.LayersSelCount Declaration function LayersSelCount(bCountBackgroundLayer: Boolean = True): Integer; Description Return number of layers that are selected. If bCountBackgroundLayer is false, then the background layer (layer 0) is not included in the count. If multiple layer selection is enabled then it counts any layer that has set to true. Otherwise it just checks whether is not -1. A selected text layer: Example // Enable the "Remove Layers" button if a layer is selected (but not the background layer) btnRemoveLayers.Enabled := ImageEnView1.LayersHaveSelection( False ) > 0; !!} function TImageEnView.LayersSelCount(bCountBackgroundLayer: Boolean = True): Integer; var I: Integer; begin Result := 0; if LayersAllowMultiSelect = False then begin if bCountBackgroundLayer and ( fLayersCurrent >= 0 ) then Result := 1 else if fLayersCurrent >= 1 then Result := 1; end else begin for I := 0 to LayersCount - 1 do begin if ( I = 0 ) and ( bCountBackgroundLayer = False ) then begin { SKIP } end else if TIELayer( fLayers[ i ]).fSelected then inc( Result ); end; end; end; {!! TImageEnView.LayersGroup Declaration procedure LayersGroup(bSelectedOnly: Boolean = True); Description Sets the group index of layers so they selected as a group (selecting one layer of the group will select all of them). If bSelectedOnly is true, grouping only affects layers that are selected. If false, it applies to all layers. Note: LayersGroup has no effect if multiple layer selection is not enabled Example // Add all selected layers to a group ImageEnView1.LayersGroup(); See Also - - !!} procedure TImageEnView.LayersGroup(bSelectedOnly: Boolean = True); var ALayer: TIELayer; iNextID: Integer; i: Integer; begin if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_GroupLayers ), ieuLayer, True, IEOP_LAYERPROPS ); // Get a unique ID iNextID := 1000; for i := 0 to LayersCount - 1 do begin ALayer := TIELayer( fLayers[ I ]); if ALayer.GroupIndex >= iNextID then iNextID := ALayer.GroupIndex + 1; end; for i := 0 to LayersCount - 1 do begin ALayer := TIELayer( fLayers[ I ]); if ( bSelectedOnly = false ) or ALayer.Selected then ALayer.fGroupIndex := iNextID; end; end; {!! TImageEnView.LayersUngroup Declaration procedure LayersUngroup(bSelectedOnly: Boolean = True); Description Resets the group index of layers so they are not selected as a group. If bSelectedOnly is true, ungrouping only affects layers that are selected. If false, it applies to all layers. Note: LayersGroup has no effect if multiple layer selection is not enabled Example // Remove grouping from selected layers ImageEnView1.LayersUngroup(); // Unselect the layers ImageEnView1.LayersDeselectAll(); See Also - - !!} procedure TImageEnView.LayersUngroup(bSelectedOnly: Boolean = True); var ALayer: TIELayer; i: Integer; begin if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_UngroupLayers ), ieuLayer, True, IEOP_LAYERPROPS ); for i := 0 to LayersCount - 1 do begin ALayer := TIELayer( fLayers[ I ]); if ( bSelectedOnly = false ) or ALayer.Selected then ALayer.fGroupIndex := 0; end; 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 TImageEnView.LayersSaveToStream(Stream: TStream; CompressionFormat: TIOFileType = -1; SelectedOnly: Boolean = False; ExcludeImageLayers: Boolean = False; SaveThumbnail: Boolean = False; ProgressEvent: TIEProgressEvent = nil); var headDesc: WideString; headWidth, headHeight: integer; recHead: TLayerHeader; lcurrent: Integer; lconstrains: Boolean; Thumbnail: TIEBitmap; l, sz: Integer; // function _WriteLayers(CountOnly: Boolean): Integer; var i: Integer; writeLayer: Boolean; begin Result := 0; for i := 0 to fLayers.Count - 1 do begin writeLayer := True; if SelectedOnly then writeLayer := TIELayer( fLayers[ i ]).Selected; if writeLayer and ExcludeImageLayers and ( TIELayer( fLayers[ i ]) is TIEImageLayer ) then writeLayer := False; if writeLayer then begin inc( Result ); if not CountOnly then begin if assigned( ProgressEvent ) then ProgressEvent( Self.IO, MulDiv( i + 1, 100, recHead.LayersCount + 1 )); // Include loading of header Layers[i].SaveToStream( Stream, False, CompressionFormat ); end; end; end; end; // begin if assigned( ProgressEvent ) then ProgressEvent( Self.IO, 0 ); lcurrent := LayersCurrent; lconstrains := LayersSelectConstrains; LayersSelectConstrains := false; Thumbnail := nil; try // prepare header recHead.Version := IELayers_File_Version; recHead.LayersCount := _WriteLayers( True ); recHead.FileFormat := CompressionFormat; move(IELayers_File_Magic[1], recHead.Magic[0], length(IELayers_File_Magic)); // write header Stream.Write(recHead, sizeof(TLayerHeader)); headWidth := MaxLayerWidth(); headHeight := MaxLayerHeight(); headDesc := ''; if assigned(fImageEnIO) then headDesc := IO.Params.IEN_Description; Stream.Write( headWidth, SizeOf( integer )); Stream.Write( headHeight, SizeOf( integer )); IESaveStringToStreamW( Stream, headDesc ); if IEGlobalSettings().ThumbnailSize < 1 then SaveThumbnail := False; if SaveThumbnail then begin Thumbnail := TIEBitmap.create(); LayersSaveMergedTo( Thumbnail, IEGlobalSettings().ThumbnailSize < 1000 ); if ( Thumbnail.Width < 5 ) or ( Thumbnail.Height < 5 ) then SaveThumbnail := False else if ( Thumbnail.Width < Thumbnail.Height ) and ( Thumbnail.Width > IEGlobalSettings().ThumbnailSize ) then Thumbnail.Resample( IEGlobalSettings().ThumbnailSize, -1, rfFastLinear ) // Maintain height else if Thumbnail.Height > IEGlobalSettings().ThumbnailSize then Thumbnail.Resample( -1, IEGlobalSettings().ThumbnailSize, rfFastLinear ); // Maintain width end; Stream.Write( SaveThumbnail, SizeOf( Boolean )); if SaveThumbnail then begin l := Stream.Position; Stream.Write(l, sizeof(integer)); // Place holder for size Thumbnail.Write( Stream, Layers_Thumbnail_Format ); // Write size sz := Stream.Position - l; Stream.Position := l; Stream.Write(sz, sizeof(integer)); // Write size Stream.Position := l + sz; // Position at end of thumbnail end; // write layers data _WriteLayers( False ); finally {$IFDEF UNITTESTING} if LayersCurrent <> lcurrent then raise Exception.create( 'Unexpected LayersCurrent change' ); {$ENDIF} if LayersCurrent <> lcurrent then LayersCurrent := lcurrent; LayersSelectConstrains := lconstrains; FreeAndNil( Thumbnail ); end; end; // LoadThumb must be true at all times, except when we ONLY need to get the IO Params function IELayersLoadHeaderFromStream(Stream: TStream; out Header: TLayerHeader; out Width: Integer; out Height: Integer; out Description: Widestring; var Thumbnail: TIEBitmap; LoadThumb: Boolean = True ): Boolean; var doFreeThumb: Boolean; ThumbSaved: Boolean; l, sz: Integer; begin result := false; doFreeThumb := not assigned( Thumbnail ); try // read header Stream.Read( Header, sizeof(TLayerHeader)); if {$IfDef DelphiXE4orNewer}AnsiStrings.{$EndIf}StrLComp( Header.Magic, PAnsiChar(IELayers_File_Magic), length(IELayers_File_Magic)) <> 0 then exit; if Header.Version >= 7000 then begin Stream.Read( Width, SizeOf( integer )); Stream.Read( Height, SizeOf( integer )); IELoadStringFromStreamW(Stream, Description); if LoadThumb then Stream.Read( ThumbSaved, SizeOf( Boolean )) else ThumbSaved := False; if ThumbSaved and ( Header.Version >= 7003 ) then begin l := Stream.Position; Stream.Read(sz, sizeof(integer)); if assigned( Thumbnail ) then Thumbnail.Read( Stream, Layers_Thumbnail_Format ); // Position at end of thumbnail Stream.Position := l + sz; end else if ThumbSaved and ( Header.Version < 7003 ) then begin if not assigned( Thumbnail ) then Thumbnail := TIEBitmap.Create(); Thumbnail.Read( Stream, ioPNG ); end else if assigned( Thumbnail ) then Thumbnail.Clear(); end; Result := Header.Version > 0; finally if doFreeThumb then FreeAndNil( Thumbnail ); end; end; function TImageEnView.LayersLoadFromStream(Stream: TStream; Append: Boolean = False; ProgressEvent: TIEProgressEvent = nil): Boolean; var recHead: TLayerHeader; i: Integer; lyrKind: TIELayerKind; sz: Integer; Guid: TGuid; Thumbnail: TIEBitmap; headWidth, headHeight: Integer; headDesc: Widestring; begin LockUpdate(); try if assigned( ProgressEvent ) then ProgressEvent( Self.IO, 0 ); Thumbnail := nil; result := IELayersLoadHeaderFromStream( Stream, recHead, headWidth, headHeight, headDesc, Thumbnail ); if Result = False then exit; if assigned(fImageEnIO) then begin IO.Params.IEN_Compression := recHead.FileFormat; IO.Params.fIEN_LayerCount := recHead.LayersCount; IO.Params.fIEN_Version := recHead.Version; IO.Params.IEN_Description := ''; if recHead.Version >= 7000 then begin IO.Params.IEN_Description := headDesc; IO.Params.Width := headWidth; IO.Params.Height := headHeight; IO.Params.OriginalWidth := headWidth; IO.Params.OriginalHeight := headHeight; end; end; if recHead.Version > 0 then begin if not Append then for i := fLayers.Count - 1 downto 1 do LayersRemoveEx( i ); // read layers data and images for i := 0 to recHead.LayersCount - 1 do begin if assigned( ProgressEvent ) then ProgressEvent( Self.IO, MulDiv( i + 1, 100, recHead.LayersCount + 1 )); // Include loading of header if recHead.Version < 6400 then lyrKind := ielkImage else ReadLayerPropsFromStream( Stream, True, sz, lyrKind, Guid ); if Append or ( i > 0 ) then LayersAddEx( lyrKind, 0, 0 ); if recHead.Version < 6400 then CurrentLayer.LoadFromLegacyStream( Stream, recHead.Version, recHead.FileFormat ) else CurrentLayer.LoadFromStream( Stream ); end; result := true; end; if ( recHead.Version < 7000 ) and assigned(fImageEnIO) then begin IO.Params.Width := Layers[0].Bitmap.Width; IO.Params.Height := Layers[0].Bitmap.Height; IO.Params.OriginalWidth := Layers[0].Bitmap.Width; IO.Params.OriginalHeight := Layers[0].Bitmap.Height; end; // Default to first idx (if not appending) if Append = False then SetLayersCurrentEx( 0, False, False ); finally UnlockUpdate(); end; end; {!! TImageEnView.Wallpaper Declaration property Wallpaper: TPicture; Description The Wallpaper property allows you to use an image for your background (behind the main image and layers). Use to specify how to paint the wallpaper. Example // Tile a bitmap over the background ImageEnView1.WallpaperStyle := iewoTile ImageEnView1.Wallpaper.LoadFromFile('D:\MyWallpaper.bmp'); // Clear the wallpaper ImageEnView1.Wallpaper := nil; !!} procedure TImageEnView.SetWallpaper(Value: TPicture); begin if assigned(Value) then begin if not assigned(fWallpaper) then fWallpaper := TPicture.Create; fWallpaper.Assign(Value); end else begin // Reset TPicture if assigned(fWallpaper) then FreeAndNil(fWallpaper); fWallpaper := TPicture.Create; end; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.WallpaperStyle Declaration property WallpaperStyle: ; Description If you are using an image for your background (specified by ), then WallpaperStyle defines how it will be painted. Example // Tile a bitmap over the background ImageEnView1.WallpaperStyle := iewoTile ImageEnView1.Wallpaper.LoadFromFile('D:\MyWallpaper.bmp'); !!} procedure TImageEnView.SetWallpaperStyle(Value: TIEWallpaperStyle); begin if Value <> fWallpaperStyle then begin fWallpaperStyle := Value; UpdateReason := ieurComponentStuffChanged; Update; end; end; procedure TImageEnView.DrawBackgroundToCanvas(ACanvas: TCanvas; iWidth: Integer = -1; iHeight: Integer = -1); begin if (iWidth = -1) and (iHeight = -1) then begin iWidth := Width; iHeight := Height; end; // draws only the background IEDrawBackground(ComponentState, ACanvas, nil, fBackgroundStyle, GetThemeColor( ietpControlBackground, fBackground ), 0, 0, iWidth, iHeight, 0, 0, 0, 0, fChessboardSize, fChessboardBrushStyle, fChessboardColor2Customized, GetThemeColor( ietpControlBackgroundGradientEnd, fGradientEndColor ), fWallpaper, fWallpaperStyle, fLiveBackground); end; {!! TImageEnView.VisibleBitmapRect Declaration property VisibleBitmapRect : TRect; (read/write) Description Show a specific area of the current image, or return the area of the image that is shown. Note: The rectangle passed will be automatically adjusted to ensure the correct aspect ratio. Examples // Show the central portion of an image ImageEnView1.VisibleBitmapRect := Rect( 100, 100, 200, 200 ); // Output the visible bitmap in ImageEnView1 to ImageEnView2 ImageEnView2.IEBitmap.Width := IERectangle( ImageEnView1.VisibleBitmapRect ).Width; ImageEnView2.IEBitmap.Height := IERectangle( ImageEnView1.VisibleBitmapRect ).Height; ImageEnView1.IEBitmap.DrawToTIEBitmap( ImageEnView2.IEBitmap, 0, 0, IERectangle( ImageEnView1.VisibleBitmapRect ) ); ImageEnView2.Update; See Also - - - - !!} function TImageEnView.GetVisibleBitmapRect : TRect; begin Result.Left := XScr2Bmp( OffsetX, False ); Result.Top := YScr2Bmp( OffsetY, False ); Result.Right := XScr2Bmp( GetClientWidthExRulers - OffsetX, False ) - 1; Result.Bottom := YScr2Bmp( GetClientHeightExRulers - OffsetY, False ) - 1; end; procedure TImageEnView.SetVisibleBitmapRect(ARect: TRect); var dZoom: Double; begin LockPaint; try ARect := AdjustRectToAspectRatio( ARect, False ); if (ARect.Bottom-ARect.Top) = 0 then exit; dZoom := ClientHeight / (ARect.Bottom - ARect.Top); Zoom := dZoom * 100; ViewX := round(ARect.left * dZoom); ViewY := round(ARect.top * dZoom ); finally UnlockPaint; end; end; {!! TImageEnView.LayersCreateFromSelection Declaration function LayersCreateFromSelection(): Integer; Description Creates a new image layer from the current selection. This might be used to copy & paste selections, for example. Returns the index of the new layer. Example // select an ellipse ImageEnView1.SelectEllipse(150, 150, 50, 50); // copy selected area and create a new layer ImageEnView1.LayersCreateFromSelection; // move the new layer ImageEnView1.CurrentLayer.PosX := 100; ImageEnView1.CurrentLayer.PosY := 100; // paste to the background ImageEnView1.LayersMerge(0, 1); !!} function TImageEnView.LayersCreateFromSelection: Integer; var baseLayer: Integer; begin baseLayer := LayersCurrent; result := LayersAdd( ielkImage ); // Use LayersAdd so it saves Undo if needed LayersCurrent := baseLayer; if Selected then begin CopySelectionToBitmap( Layers[result].Bitmap, not EnableAlphaChannel ); Layers[result].PosX := SelX1 + CurrentLayer.PosX; Layers[result].PosY := SelY1 + CurrentLayer.PosY; end else begin Layers[Result].Bitmap.Assign( CurrentLayer.Bitmap ); Layers[result].PosX := CurrentLayer.PosX; Layers[result].PosY := CurrentLayer.PosY; end; SetLayersCurrentEx( result, False, True ); // this disables selection end; {!! TImageEnView.LayersCreateFromClipboard Declaration function LayersCreateFromClipboard: Integer; Description Creates a new layer with the content of the clipboard. The clipboard can either contain an image or a layer copied from a TImageEnView. This is the same as calling TImageEnView.Proc.( iecpLayer ); However it returns an index of the new layer. !!} function TImageEnView.LayersCreateFromClipboard: Integer; begin Result := Proc.PasteFromClipboard_Layer(); end; {!! TImageEnView.LayersCreateFromFile Declaration function LayersCreateFromFile(Filename : string = '') : Integer; Description Loads an image from a file and adds it as a new image layer. If Filename is '' then an open dialog is displayed (using ) to allow the user to browse for an image to load for the layer. Returns the index of the new layer, or -1 in case of error. Examples // Prompt the user to select an image to load as a layer ImageEnView1.LayersCreateFromFile(); // Load an image as a new layer ImageEnView1.LayersCreateFromFile( 'C:\MyImage.jpg' ); // Which is the same as... ImageEnView1.LayersAdd( 'C:\MyImage.jpg' ); !!} function TImageEnView.LayersCreateFromFile(Filename : string = '') : integer; begin if Filename = '' then Filename := IO.ExecuteOpenDialog('', '', false); if Filename = '' then begin Result := -1; exit; end; Result := LayersAdd( ielkImage ); // Use LayersAdd so it saves Undo if needed try IO.LoadFromFile(Filename); if IO.Aborting then raise EIEException.create('Load Error'); except LayersRemoveEx( Result ); Result := -1; end; end; {!! TImageEnView.LayersCreateFromEdge Declaration function LayersCreateFromEdge(ScreenX, ScreenY: integer; Tolerance: integer; MaxFilter: boolean = False): Integer; Description Creates a new Polyline layer with a closed polyline (polygon) along the edge of the background layer. The edge is determined by simulating a flood fill starting at the point specified by ScreenX and ScreenY (these are points within the control, not points of the bitmap). Tolerance specifies the color difference between the starting pixel and the pixel being tested. Set MaxFilter to True to apply a maximum filter that removes noise. Result is the index of the created layer, or -1 if the method fails Examples // Create a new polygon layer when the user clicks on the image procedure TForm1.ImageEnView1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ImageEnView1.LayersCreateFromEdge( X, Y, 25, true ); end; // Create a new polygon using a floodfill from the top left of the background image ImageEnView1.LayersCreateFromEdge( ImageEnView1.XBmp2Scr( 0 ), ImageEnView1.YBmp2Scr( 0 ), 25, true); !!} function TImageEnView.LayersCreateFromEdge(ScreenX, ScreenY: integer; Tolerance: integer; MaxFilter: boolean = False): Integer; var points: TIEArrayOfTPoint; x, y: Integer; minX, maxX, minY, maxY : Integer; layerX, layerY: Integer; begin result := -1; x := XScr2Bmp( ScreenX, True ); y := YScr2Bmp( ScreenY, True ); points := IEMakeMagicWandPoints(fIEBitmap, x, y, MaxFilter, Tolerance); if length(points) > 0 then begin IEGetPointsRange( points, length(points), minX, minY, maxX, maxY ); if ( maxX < 1 ) or ( maxY < 1 ) then exit; layerX := CurrentLayer.PosX; layerY := CurrentLayer.PosY; result := LayersAdd( ielkPolyLine ); // Use LayersAdd so it saves Undo if needed Layers[ result ].PosX := layerX + minX; Layers[ result ].PosY := layerY + minY; Layers[ result ].Width := maxX - minX; Layers[ result ].Height := maxY - minY; // Scale points to 0-1000 range of TIEPolyLineLayer IEScalePoints( points, length(points), 0, 0, 1000, 1000, False); TIEPolyLineLayer( Layers[ result ]).SetPoints( points, True ); Update(); end; end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (23/11/16) function TImageEnView.LayersCreateFromText(const Text : string; const sFontName : string; iFontSize : Integer; cFontColor : TColor; Style : TFontStyles; bAddShadow: boolean = False; iBlurRadius : Integer = 3; iShadowOffset : Integer = 2; Angle : Integer = 0; bAntiAlias : Boolean = true) : integer; var WasBackground: TColor; begin LockPaint(); try // Add a new layer Result := LayersAdd( ielkImage ); // Use LayersAdd so it saves Undo if needed // TextOut will resize and fill the layer fIEBitmap.Allocate(1, 1); // Output our text if Angle = 0 then begin fIEBitmap.AlphaChannel.Fill(0); Proc.TextOut(0, 0, Text, sFontName, iFontSize, cFontColor, Style, Angle, True, True); end else begin WasBackground := fBackground; fBackground := clWhite; fIEBitmap.Pixels[ 0, 0 ] := CreateRGB( 255, 255, 255 ); Proc.TextOut(0, 0, Text, sFontName, iFontSize, cFontColor, Style, Angle, False, True); // Make the white background transparent Proc.SetTransparentColors( CreateRGB( 255, 255, 255 ), CreateRGB( 255, 255, 255 ), 0 ); fBackground := WasBackground; end; // Add our shadow if bAddShadow then Proc.AddSoftShadow(iBlurRadius, iShadowOffset, iShadowOffset); // Remove the excess transparency Proc.CropTransparentBorder; finally UnlockPaint(); end; end; {$ENDIF} {!! TImageEnView.BackBuffer Declaration property BackBuffer: TBitmap; Description Provides access to the back buffer where ImageEn will draw the image (and layers) prior to the paint event. You can draw on BackBuffer by handling the event to paint onto the Backbuffer canvas. BackBuffer is updated whenever is called. Example Procedure Form1OnDrawBackBuffer(Sender: TObject); Begin With ImageEnView1.BackBuffer.Canvas do begin Pen.Color := clRed; MoveTo( 0, 0 ); LineTo( 100, 100 ); End; End; !!} function TImageEnView.GetBackBuffer: TBitmap; begin result := fBackBuffer.VclBitmap; end; procedure TImageEnView.SetOnSaveUndo(value: TIESaveUndoEvent); begin fOnSaveUndo := value; if assigned(fImageEnProc) then fImageEnProc.OnSaveUndo := value; end; {!! TImageEnView.OnSaveUndo Declaration property OnSaveUndo: ; Description OnSaveUndo occurs after is called by user action or your code. source is the same parameter used when calling . !!} function TImageEnView.GetOnSaveUndo: TIESaveUndoEvent; begin result := fOnSaveUndo; end; {!! TImageEnView.LayersFixSizes Declaration procedure LayersFixSizes(layer: Integer = LYR_ALL_LAYERS); Description Resamples the bitmap of layers to match their actual size. This will improve the quality of the layer. The index of a specific layer can be specified, or LYR_ALL_LAYERS (-1) to process all layers, or LYR_SELECTED_LAYERS (-2) to process selected layers. Note: will specify the quality of image layers, if they do not have a custom Example // Resample top-most layer ImageEnView1.LayersFixSizes( ImageEnView1.LayersCount - 1 ); // Resample all layers ImageEnView1.LayersFixSizes( LYR_ALL_LAYERS ); // Resample selected layers ImageEnView1.LayersFixSizes( LYR_SELECTED_LAYERS ); // Make all selected layers 1/3 size ImageEnView1.LockUpdate; for i := 0 to ImageEnView1.LayersCount - 1 do if ImageEnView1Layers[ I ].Selected then begin ImageEnView1Layers[ I ].Width := ImageEnView1Layers[ I ].Width div 3; ImageEnView1Layers[ I ].Height := ImageEnView1Layers[ I ].Height div 3; end; ImageEnView1.LayersFixSizes( LYR_SELECTED_LAYERS ); ImageEnView1.UnlockUpdate; !!} // layer = -1 : all layers procedure TImageEnView.LayersFixSizes(layer: Integer = LYR_ALL_LAYERS); var lyr: TIELayer; i, l: Integer; rf: TResampleFilter; tempproc: TImageEnProc; bDoLayer: Boolean; begin tempproc := TImageEnProc.Create(nil); try l := fLayersCurrent; for i := 0 to fLayers.Count - 1 do begin lyr := TIELayer(fLayers[i]); case layer of LYR_ALL_LAYERS : bDoLayer := true; LYR_SELECTED_LAYERS : bDoLayer := lyr.Selected; else bDoLayer := i = layer; end; if bDoLayer and (( lyr.WidthD <> 0 ) or ( lyr.HeightD <> 0 )) and ( lyr is TIEImageLayer ) then begin LayersCurrent := i; if TIEImageLayer( lyr ).UseResampleFilter then rf := TIEImageLayer( lyr ).ResampleFilter else rf := fLayersMergeFilter; tempproc.AttachedIEBitmap := lyr.Bitmap; tempproc.Resample(lyr.Width, lyr.Height, rf); lyr.WidthD := 0; lyr.HeightD := 0; end; end; LayersCurrent := l; finally tempproc.Free(); end; end; {!! TImageEnView.LayersFixBorders Declaration procedure LayersFixBorders(layer: Integer = LYR_ALL_LAYERS); Description Removes the transparent border around the bitmap of a layer, which typically occurs after multiple rotations. The index of a specific layer can be specified, or LYR_ALL_LAYERS (-1) to process all layers, or LYR_SELECTED_LAYERS (-2) to process selected layers. Note: This can be called automatically using loAutoFixBorders of Example // Remove border of top-most layer ImageEnView1.LayersFixBorders( ImageEnView1.LayersCount - 1 ); // Remove border of all layers ImageEnView1.LayersFixBorders( LYR_ALL_LAYERS ); // Remove border of selected layers ImageEnView1.LayersFixBorders( LYR_SELECTED_LAYERS ); !!} procedure TImageEnView.LayersFixBorders(layer: Integer = LYR_ALL_LAYERS); var lyr: TIELayer; i: Integer; p: TImageEnProc; doLayer: Boolean; begin p := TImageEnProc.Create(nil); try for i := 0 to fLayers.Count-1 do begin lyr := TIELayer(fLayers[i]); case layer of LYR_ALL_LAYERS : doLayer := true; LYR_SELECTED_LAYERS : doLayer := lyr.Selected; else doLayer := i = layer; end; if doLayer and ( lyr.Kind = ielkImage ) then begin p.AttachedIEBitmap := lyr.Bitmap; p.CropTransparentBorder(); end; end; finally p.Free(); end; end; {!! TImageEnView.LayersFixRotations Declaration procedure LayersFixRotations(layer: Integer = LYR_ALL_LAYERS); Description Rotates the bitmap of a layer to its actual rotation angle. This will improve the quality of the layer. The index of a specific layer can be specified, or LYR_ALL_LAYERS (-1) to process all layers, or LYR_SELECTED_LAYERS (-2) to process selected layers. Notes: - This can be called automatically using loAutoFixRotation of - This method will also call Example // Improve rotation of top-most layer ImageEnView1.LayersFixRotations( ImageEnView1.LayersCount - 1 ); // Improve rotation of all layers ImageEnView1.LayersFixRotations( LYR_ALL_LAYERS ); // Improve rotation of selected layers ImageEnView1.LayersFixRotations( LYR_SELECTED_LAYERS ); !!} // layer = -1 : all layers procedure TImageEnView.LayersFixRotations(layer: Integer = LYR_ALL_LAYERS); var lyr: TIELayer; i, l: Integer; pts: array [0..3] of TPoint; lposx, lposy, lresw, lresh: Integer; r: TRect; tempproc: TImageEnProc; bDoLayer: Boolean; begin tempproc := TImageEnProc.Create(nil); try tempproc.Background := fBackground; l := fLayersCurrent; for i := 0 to fLayers.Count - 1 do begin lyr := TIELayer(fLayers[i]); case layer of LYR_ALL_LAYERS : bDoLayer := true; LYR_SELECTED_LAYERS : bDoLayer := lyr.Selected; else bDoLayer := i = layer; end; if bDoLayer and ( lyr.Rotate <> 0 ) and ( lyr.Kind = ielkImage ) then begin LayersFixSizes(i); LayersCurrent := i; lresw := lyr.Width; lresh := lyr.Height; pts[0].X := 0; pts[0].Y := 0; pts[1].X := lyr.Width; pts[1].Y := 0; pts[2].X := lyr.Width; pts[2].Y := lyr.height; pts[3].X := 0; pts[3].Y := lyr.Height; lposx := lyr.PosX; lposy := lyr.PosY; lyr.Bitmap.AlphaChannel; // creates alpha channel tempproc.AttachedIEBitmap := lyr.Bitmap; if fLayersRotationAntialias then tempproc.Rotate(lyr.Rotate, fLayersRotationFilter, -1) else tempproc.Rotate(lyr.Rotate, ierNone, -1); IERotatePoints(pts, 4, lyr.Rotate, trunc(lyr.RotateCenterX*lresw), trunc(lyr.RotateCenterY*lresh)); lyr.PosX := lposx + imin(imin(imin(pts[0].X, pts[1].X), pts[2].X), pts[3].X); lyr.PosY := lposy + imin(imin(imin(pts[0].Y, pts[1].Y), pts[2].Y), pts[3].Y); lyr.WidthD := 0; lyr.HeightD := 0; lyr.Rotate := 0; if i = 0 then begin lyr.PosX := lposx; lyr.PosY := lposy; end else begin r := IEGetVisibleArea(fIEBitmap, nil, nil); tempproc.Crop(r); lyr.PosX := lyr.PosX + r.Left; lyr.PosY := lyr.posY + r.Top; end; end; end; LayersCurrent := l; finally tempproc.Free(); end; end; {!! TImageEnView.SoftCrop Declaration property SoftCrop: ; Description Specifies the operation to perform when a layer is outside of the background layer (layer 0). I.e. to provide a visual indication to the user. Portion of layers that are outside the background layer are shown as: Value Description iesfNone Normal iesfAlphaBlend Partially transparent (to the level specified by ) iesfGrid Grayed (Grid matrix pattern) iesfAdd Color shifted/washed out (to the level specified by )
!!} procedure TImageEnView.SetSoftCrop(v: TIESoftCropMode); begin fSoftCrop := v; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.SoftCropValue Declaration property SoftCropValue: Integer; Description If is iesfAlphaBlend then the SoftCropValue specifies the level of transparency from 0 (minimal) to 255 (fully) If is iesfAdd then the SoftCropValue specifies the amount of color shift from 0 (minimal) to 255 (extreme) !!} procedure TImageEnView.SetSoftCropValue(v: Integer); begin fSoftCropValue := v; UpdateReason := ieurComponentStuffChanged; Update; end; {!! TImageEnView.SetInteractionHint Declaration procedure SetInteractionHint(const Text: String; x, y: Integer; const minText: String); Description Specify a text hint to appear over the ImageEnView (which will be displayed at the next painting event). Parameter Description Text Text to draw x Horizontal position y Vertical position minText Example (dummy) text to calculate the minimum text size
Example // display current position in pixels procedure TForm1.ImageEnVect1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var xx, yy: integer; begin xx := ImageEnView1.XScr2Bmp(X); yy := ImageEnView1.yscr2bmp(Y); if (xx >= 0) and (xx < ImageEnView1.IEBitmap.Width) and (yy >= 0) and (yy < ImageEnView1.IEBitmap.Height) then begin ImageEnView1.SetInteractionHint(Format('%d %d', [xx, yy]), X, Y, '0000 0000'); ImageEnView1.Paint(); end; end; !!} procedure TImageEnView.SetInteractionHint(const Text: String; x, y: Integer; const minText: String); begin fInteractionHint := Text; fInteractionHintX := x; fInteractionHintY := y; fInteractionHintMinText := minText; end; {!! TImageEnView.HighlightedPixel Declaration property HighlightedPixel: TPoint; Description Specify a pixel within your image and it will be highlighted by a colored box (to draw attention to it). Set it to (-1, -1) to disable. Demo Demos\Display\ImageComp\ImageComp.dpr !!} procedure TImageEnView.SetHighlightedPixel(v: TPoint); var x1, y1, x2, y2: Integer; begin if (fHighlightedPixel.X > -1) and (fHighlightedPixel.Y > -1) then begin x1 := XBmp2Scr( fHighlightedPixel.X, True ); y1 := YBmp2Scr( fHighlightedPixel.Y, True ); x2 := XBmp2Scr( fHighlightedPixel.X + 1, True ); y2 := YBmp2Scr( fHighlightedPixel.Y + 1, True ); fHighlightedPixel := Point(-1, -1); UpdateRect(Rect(x1-5, y1-5, x2+5, y2+5)); end; fHighlightedPixel := v; Paint; end; {!! TImageEnView.MoveContentTo Declaration procedure TImageEnView.MoveContentTo(Destination:
); Description Transfers the current image, all layers and input/output parameters to the destination TImageEnView component. Note: - This method doesn't copy the images, but transfers pointers to the image buffer - After the operation the source component will be empty, and all previous images will be removed from "Destination" - To "Copy" the content to another TImageEnView use the method !!} procedure TImageEnView.MoveContentTo(Destination: TImageEnView); var src_oldnav, dst_oldnav: TImageEnView; i: integer; begin if Destination = self then exit; // Select base layer SetLayersCurrent( 0 ); // disable navigator src_oldnav := fNavigator; SetNavigator(nil); dst_oldnav := Destination.fNavigator; Destination.SetNavigator(nil); // assign IO params Destination.IO.Params.Assign( IO.Params ); // free destination images for i := 0 to Destination.fLayers.Count - 1 do TIELayer(Destination.fLayers[i]).Free; FreeAndNil(Destination.fLayers); // copy pointers to destination Destination.fLayers := fLayers; Destination.fIEBitmap := fIEBitmap; Destination.fBitmap := fBitmap; Destination.fLayersCurrent := fLayersCurrent; // change destination layers owner for i := 0 to Destination.fLayers.Count-1 do TIELayer(Destination.fLayers[i]).fOwner := Destination; // create empty images in source fIEBitmap := TIEBitmap.Create; if fLegacyBitmap then begin fBitmap := TBitmap.create; fBitmap.pixelformat := pf24bit; fIEBitmap.EncapsulateTBitmap(fBitmap, true); end; fLayers := TList.Create; fLayers.Add(TIEImageLayer.Create(self, fIEBitmap, true)); with TIELayer(fLayers[0]) do begin VisibleBox := false; Locked := true; end; fLayersCurrent := 0; Destination.CallBitmapChangeEvents; CallBitmapChangeEvents; Destination.Update; Update; // enable navigators SetNavigator(src_oldnav); Destination.SetNavigator(dst_oldnav); end; //////////////////////////////////////////////////////////////////////////////////////////////////////// // Smooth scroll {!! TImageEnView.SetViewXYSmooth Declaration procedure SetViewXYSmooth(x, y: Integer); Description Repositions the image view (i.e. by setting and ), but does so with smooth scrolling (image will slowly pan to the new location). To control the smoothness set . See Also - - !!} procedure TImageEnView.SetViewXYSmooth(x, y: Integer); begin if fSmoothScrollValue = 0 then SetViewXY(x, y) else begin fSmoothScrollDestX := x; fSmoothScrollDestY := y; if not assigned(fSmoothScrollTimer) then begin fSmoothScrollTimer := TTimer.Create(self); fSmoothScrollTimer.OnTimer := OnSmoothSetView; fSmoothScrollTimer.Interval := 30; fSmoothScrollTimer.Enabled := true; OnSmoothSetView(self); // first call done manually end; end; end; {!! TImageEnView.SmoothScrollValue Declaration property SmoothScrollValue: Integer; Description Specifies the smoothness (speed) of scrolling when is called or contains miMovingScroll. A large values increases the smoothness. "0" disables smoothing (i.e. so that it acts like ). Default: 8. !!} procedure TImageEnView.SetSmoothScrollValue(v: Integer); begin fSmoothScrollValue := v; end; procedure TImageEnView.OnSmoothSetView(Sender: TObject); var x, y: Integer; lx, ly: Integer; begin if assigned(fSmoothScrollTimer) then begin lx := fViewX; ly := fViewY; x := round(fViewX - (fViewX - fSmoothScrollDestX) / fSmoothScrollValue); y := round(fViewY - (fViewY - fSmoothScrollDestY) / fSmoothScrollValue); SetViewXY(x, y); if ((fViewX = lx) and (fViewY = ly)) or IEIsLeftMouseButtonPressed then StopSmoothScroll(); end; end; procedure TImageEnView.StopSmoothScroll(); begin FreeAndNil(fSmoothScrollTimer); if assigned(fOnFinishSmoothTask) then OnFinishSmoothTask(self, iestScroll); end; //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// // Smooth zoom {!! TImageEnView.SetZoomSmooth Declaration procedure SetZoomSmooth(Zoom: Double); Description Sets the image zoom (i.e. by setting ), but does so with smooth zoom (image will slowly zoom to the new value). To control the smoothness set . See Also - - !!} procedure TImageEnView.SetZoomSmooth(Zoom: Double); begin if fSmoothZoomValue = 0 then self.SetZoom(Zoom) else begin fSmoothZoomDest := Zoom; if not assigned(fSmoothZoomTimer) then begin fSmoothZoomTimer := TTimer.Create(self); fSmoothZoomTimer.OnTimer := OnSmoothZoom; fSmoothZoomTimer.Interval := 30; fSmoothZoomTimer.Enabled := true; OnSmoothZoom(self); // first call done manually end; end; end; {!! TImageEnView.SmoothZoomValue Declaration property SmoothZoomValue: Integer; Description Specifies the smoothness (speed) of zooming when is called. A large values increases the smoothness. "0" disables smoothing (i.e. so that it acts like ). Default: 8. !!} procedure TImageEnView.SetSmoothZoomValue(v: Integer); begin fSmoothZoomValue := v; end; procedure TImageEnView.OnSmoothZoom(Sender: TObject); var delta: double; begin if assigned(fSmoothZoomTimer) then begin delta := (Zoom - fSmoothZoomDest) / fSmoothZoomValue; SetZoom(Zoom - delta); if (abs(delta) <= (1 / fSmoothZoomValue)) then begin SetZoom(fSmoothZoomDest); StopSmoothZoom(); end else if IEIsLeftMouseButtonPressed then StopSmoothZoom(); end; end; procedure TImageEnView.StopSmoothZoom(); begin FreeAndNil(fSmoothZoomTimer); if assigned(fOnFinishSmoothTask) then OnFinishSmoothTask(self, iestZoom); end; //////////////////////////////////////////////////////////////////////////////////////////////////////// procedure IEInitialize_imageenview; begin InitImageEnView; end; procedure IEFinalize_imageenview; begin if assigned(IEGlobalSettings().GridPen) then begin IEGlobalSettings().GridPen.Free(); IEGlobalSettings().GridPen := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // PostFrames support type TIEPostFramesTarget = class public FSource: TImageEnView; FTarget: TImageEnView; FDelay: integer; // in ms FInterval: integer; // in ms FTimer: TTimer; FBuffers: TList; // a list of TIEBitmap objects (Delay/Interval+1) FElapsed: integer; // in ms FNextToRead: integer; FNextToWrite: integer; constructor Create(source, target: TImageEnView; delay: Integer; interval: Integer); destructor Destroy; override; private procedure PostFrames(Sender: TObject); end; constructor TIEPostFramesTarget.Create(source, target: TImageEnView; delay: Integer; interval: Integer); var i, c: Integer; begin inherited Create; FSource := source; FTarget := target; FDelay := delay; FInterval := interval; FTimer := TTimer.Create(nil); FTimer.OnTimer := PostFrames; FBuffers := TList.Create; c := delay div interval +2; for i := 0 to c-1 do FBuffers.Add( TIEBitmap.Create ); FElapsed := 0; FTimer.Interval := interval; FTimer.Enabled := true; FNextToRead := 0; FNextToWrite := 0; end; destructor TIEPostFramesTarget.Destroy; var i: Integer; begin FTimer.Free; for i := 0 to FBuffers.Count-1 do TIEBitmap(FBuffers[i]).Free; FBuffers.Free; inherited; end; procedure TIEPostFramesTarget.PostFrames(Sender: TObject); begin inc(FElapsed, FInterval); if FElapsed > FDelay then begin // move first frame to target viewer if FTarget.IEBitmap <> nil then FTarget.IEBitmap.Assign( TIEBitmap(FBuffers[FNextToRead]) ); FTarget.Update; inc(FNextToRead); if FNextToRead = FBuffers.Count-1 then FNextToRead := 0; end; if FSource.IEBitmap <> nil then TIEBitmap(FBuffers[FNextToWrite]).Assign( FSource.IEBitmap ); inc(FNextToWrite); if FNextToWrite = FBuffers.Count-1 then FNextToWrite := 0; end; {!! TImageEnView.BeginPostFrames Declaration procedure BeginPostFrames(target: TImageEnView; delay: Integer; interval: Integer); Description Sends the current image to a target , after "delay" milliseconds and then after each "interval" milliseconds. This is useful to display captured frames to another control with delay (See the VideoCapture\DirectShow5 demo). You can (but don't need to) end frame sending by calling . Multiple calls to BeginPostFrames are possible. Example // send the current image to ImageEnView2 after 5 seconds, and to ImageEnView3 after 10 seconds, at 50 ms for each frame ImageEnView1.BeginPostFrames(ImageEnView2, 5000, 50); ImageEnView1.BeginPostFrames(ImageEnView3, 10000, 50); !!} procedure TImageEnView.BeginPostFrames(target: TImageEnView; delay: Integer; interval: Integer); begin // removes if already exists EndPostFrames( target ); // add new fPostFrames.Add( TIEPostFramesTarget.Create(self, target, delay, interval) ); end; procedure TImageEnView.RemovePostFrames(index: Integer); begin if assigned(fPostFrames) and (index>-1) then begin TIEPostFramesTarget(fPostFrames[index]).Free; fPostFrames.Delete(index); end; end; {!! TImageEnView.EndPostFrames Declaration procedure EndPostFrames(target: TImageEnView); Description Stops sending of the current image to a target that has been commenced using . Example ImageEnView1.EndPostFrames(ImageEnView2); ImageEnView1.EndPostFrames(ImageEnView3); !!} procedure TImageEnView.EndPostFrames(target: TImageEnView); var i: Integer; begin for i := 0 to fPostFrames.Count-1 do if TIEPostFramesTarget(fPostFrames[i]).FTarget = target then begin RemovePostFrames( i ); break; end; end; // End of PostFrames support //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// {!! TImageEnView.LayersCropBackground Declaration procedure TImageEnView.LayersCropBackground(SelectedOnly: Boolean = False; FillAlpha: Integer = 255; AllowReduce: Boolean = True; AllowEnlarge : Boolean = True); Description Resize the background (layer 0) to fit all layers (the image is sized, but its content is not stretched). Parameter Description SelectedOnly The background will be cropped to fit selected layers only FillAlpha Alpha value used to fill added regions (0: Fully Transparent - 255: Opaque) AllowReduce Parts of the image can be cut so layers will align with image edges AllowEnlarge Parts will be added to the image so layers are not beyond hte image area
Note: The color of added background is specified by
Example // Crop the background so that it matches the size of all layers ImageEnView1.LayersCropBackground(); // Crop the background so that it matches the size of selected layers ImageEnView1.LayersCropBackground( True ); // Crop the background to match layers, but do not cut any part of the image (new border area may be added) ImageEnView1.LayersCropBackground( True, 255, False, True ); // Crop the background to match layers, but do not add to the image (some layers may be outside the image area) ImageEnView1.LayersCropBackground( True, 255, True, False ); !!} procedure TImageEnView.LayersCropBackground(SelectedOnly: Boolean = False; FillAlpha: Integer = 255; AllowReduce: Boolean = True; AllowEnlarge : Boolean = True); var layer0Rect, outLayersRect: TIERectangle; addLeft, addTop, addRight, addBottom: Integer; zoomX, zoomY: Double; begin if not ( AllowReduce or AllowEnlarge ) then exit; if Proc.AutoUndo and ( loAutoUndoChangesbyCode in fLayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_CropBackgroundToSelection ), ieuObjectsAndLayers, True, IEOP_CROP ); zoomX := 1; zoomY := 1; if Layers[0].Bitmap.Width > 1 then zoomX := Layers[0].Width / Layers[0].Bitmap.Width; if Layers[0].Bitmap.Height > 1 then zoomY := Layers[0].Height / Layers[0].Bitmap.Height; layer0Rect := IERectangle( 0, 0, Layers[0].Width, Layers[0].Height ); outLayersRect := LayersRect( SelectedOnly, True ); if ( outLayersRect.Width <= 0 ) or ( outLayersRect.Height <= 0 ) then exit; LockUpdate(); try addLeft := Round(( layer0Rect.X - outLayersRect.X ) / zoomX ); addTop := Round(( layer0Rect.Y - outLayersRect.Y ) / zoomY ); addRight := Round(( outLayersRect.X + outLayersRect.Width - layer0Rect.X - layer0Rect.Width ) / zoomX ); addBottom := Round(( outLayersRect.Y + outLayersRect.Height - layer0Rect.Y - layer0Rect.Height ) / zoomY ); if not AllowReduce then begin // Don't adjust if within layer 0 if outLayersRect.X > 0 then outLayersRect.X := 0; if outLayersRect.Y > 0 then outLayersRect.Y := 0; // Don't allow resizing smaller if addLeft < 0 then addLeft := 0; if addTop < 0 then addTop := 0; if addRight < 0 then addRight := 0; if addBottom < 0 then addBottom := 0; end; if not AllowEnlarge then begin // Don't adjust if outside layer 0 if outLayersRect.X < 0 then outLayersRect.X := 0; if outLayersRect.Y < 0 then outLayersRect.Y := 0; // Don't allow resizing larger if addLeft > 0 then addLeft := 0; if addTop > 0 then addTop := 0; if addRight > 0 then addRight := 0; if addBottom > 0 then addBottom := 0; end; // Move all layers to the top left of layer 0 LayersRepositionAll( -1 * outLayersRect.X, -1 * outLayersRect.Y, SelectedOnly ); Layers[ 0 ].PosX := 0; Layers[ 0 ].PosY := 0; if ( Layers[0].Bitmap.Width + addLeft + addRight <= 0 ) or ( Layers[0].Bitmap.Height + addTop + addBottom <= 0 ) then begin // Background is completely outside the area of the layer zoomX := 1; zoomY := 1; Layers[0].Bitmap.Clear; Layers[0].Bitmap.Resize( outLayersRect.Width, outLayersRect.Height, Background, FillAlpha ); end else Layers[0].Bitmap.Resize( addLeft, addTop, addRight, addBottom, Background, FillAlpha ); Layers[0].Width := Round( Layers[0].Bitmap.Width * zoomX ); Layers[0].Height := Round( Layers[0].Bitmap.Height * zoomY ); finally UnlockUpdate(); end; end; {!! TImageEnView.LayersCopyToAlpha Declaration procedure LayersCopyToAlpha(DestLayer: Integer); Description Copies the current layer to the alpha channel of the specified destination layer. This is useful to handle alpha channel of other bitmaps, applying the same image processing algorithms. See also: Example ImageEnView1.IO.LoadFromFile('C:\image.jpg'); ImageEnView1.LayersCreateFromAlpha; ImageEnView1.Proc.BumpMapping( 300, 300, 150, 150, 0, CreateRgb(255, 255, 255)); ImageEnView1.LayersCopyToAlpha(0); ImageEnView1.LayersRemove(1); !!} procedure TImageEnView.LayersCopyToAlpha(DestLayer: Integer); var dst_w, dst_h: Integer; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); dst_w := Layers[DestLayer].Bitmap.Width; dst_h := Layers[DestLayer].Bitmap.Height; with Layers[DestLayer].Bitmap.AlphaChannel do begin AssignImage( fIEBitmap ); Resize(dst_w, dst_h); PixelFormat := ie8g; end; Update; end; {!! TImageEnView.LayersCreateFromAlpha Declaration function LayersCreateFromAlpha: Integer; Description Creates a new image layer with the content of current bitmap's alpha channel. This is useful to handle alpha channel of other bitmaps, applying the same image processing algorithms. See also: Example ImageEnView1.IO.LoadFromFile('C:\image.jpg'); ImageEnView1.LayersCreateFromAlpha; ImageEnView1.Proc.BumpMapping( 300, 300, 150, 150, 0, CreateRgb(255, 255, 255)); ImageEnView1.LayersCopyToAlpha(0); ImageEnView1.LayersRemove(1); !!} function TImageEnView.LayersCreateFromAlpha: Integer; begin if fIEBitmapValid = False then raise EIEException.create( 'Method only supported for image layers' ); result := LayersAdd( fIEBitmap.AlphaChannel ); // Use LayersAdd so it saves Undo if needed end; procedure TImageEnView.TextEditorKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin inherited; if assigned( fOnTextEditorKeyDown ) then fOnTextEditorKeyDown( Sender, Key, Shift ); case Key of VK_ESCAPE: begin Key := 0; if Sender is TEdit then SendMessage((Sender as TEdit).Handle, WM_UNDO, 0, 0); LayersCancelEditor(); end; VK_RETURN: if not ( Sender is TIETextControl ) then begin Key := 0; LayersCancelEditor(); end; end; end; procedure TImageEnView.TextEditorOnChange(Sender: TObject); var tw, mm: integer; begin if Layers[ fEditingLayer ] is TIETextLayer then begin with TIETextLayer( Layers[ fEditingLayer ]) do if AutoSize then begin Canvas.Font.Assign( fTextEditor.Font ); tw := Canvas.TextWidth( fTextEditor.Text ); mm := Canvas.TextWidth( 'M' ); fTextEditor.Width := tw; tw := trunc((tw + mm) / fZoomD100X); Width := tw; Update(); end end else if Layers[ fEditingLayer ] is TIELineLayer then begin with TIELineLayer( Layers[ fEditingLayer ]) do begin Canvas.Font.Assign( fTextEditor.Font ); fTextEditor.Width := Canvas.TextWidth( fTextEditor.Text ); end; end; end; // Instead use: TIETextLayer.ActivateEditor(); or TIELineLayer.ActivateEditor(); procedure TImageEnView.LayersActivateTextEditor(LayerIdx: integer); begin if ( LayerIdx < 0 ) or ( LayerIdx >= fLayers.Count ) or (( Layers[ LayerIdx ].Kind in [ ielkText, ielkLine ]) = False ) then exit; fEditingLayer := LayerIdx; if fTextEditor = nil then fTextEditor := TIEEdit.Create( self ); with fTextEditor do begin Parent := self; fTextEditor.BorderStyle := bsNone; Ctl3D := false; end; UpdateTextEditor(); windows.SetFocus(fTextEditor.handle); case syslocale.PriLangID of LANG_GREEK: Font.Charset := GREEK_CHARSET; LANG_RUSSIAN: Font.Charset := RUSSIAN_CHARSET; end; fTextEditor.OnKeyDown := TextEditorKeyDown; fTextEditor.OnChange := TextEditorOnChange; if Layers[ fEditingLayer ] is TIETextLayer then with TIETextLayer( fLayers[ fEditingLayer ]) do begin fTextEditor.Text := Text; fTextEditor.Font.assign( Font ); end else if Layers[ fEditingLayer ] is TIELineLayer then with TIELineLayer( fLayers[ fEditingLayer ]) do begin fTextEditor.Text := LabelText; fTextEditor.Font.assign( LabelFont ); end; fTextEditor.Visible := True; if assigned( fOnActivateTextEditor ) then fOnActivateTextEditor( Self, fEditingLayer, fTextEditor ); end; {!! TImageEnView.LayersCancelEditor Declaration procedure LayersCancelEditor(SaveChanges: Boolean = True); Description Terminates any active text editors. Users can edit the text of a or by double-clicking or selecting F2. They can then cancel it clicking "Esc" (or "Enter" to enact the change). LayersCancelEditor is the programmatic equivalent of clicking "Esc". If SaveChanges is False, any text the user has specified will be lost. Set to true to enact their changes. !!} procedure TImageEnView.LayersCancelEditor(SaveChanges: Boolean = True); var isCanvasAvail: boolean; begin if fEditingLayer < 0 then exit; isCanvasAvail := not (csDestroying in ComponentState); if SaveChanges and Proc.AutoUndo and ( loAutoUndoChangesbyUser in LayerOptions ) then Proc.SaveUndo( IEMsg( IEMsg_EditLayerText ), ieuLayer, True, IEOP_LAYERPROPS ); if SaveChanges and ( Layers[ fEditingLayer ] is TIETextLayer ) then TIETextLayer( fLayers[ fEditingLayer ]).Text := fTextEditor.Text else if SaveChanges and ( Layers[ fEditingLayer ] is TIELineLayer ) then TIELineLayer( fLayers[ fEditingLayer ]).LabelText := fTextEditor.Text; fTextEditor.Visible := false; if assigned(fOnDeactivateTextEditor) then fOnDeactivateTextEditor( Self, fEditingLayer, fTextEditor ); if isCanvasAvail then SetFocus; if SaveChanges then DoLayerNotify( fEditingLayer, ielEdited ); fEditingLayer := -1; Update(); end; // updates text edit position procedure TImageEnView.UpdateTextEditor(); begin if fEditingLayer = -1 then exit; if Layers[ fEditingLayer ] is TIETextLayer then with TIETextLayer( Layers[ fEditingLayer ]) do begin fTextEditor.Left := ClientAreaBox.Left; fTextEditor.Top := ClientAreaBox.Top; fTextEditor.Width := ClientAreaBox.Right - ClientAreaBox.Left; fTextEditor.Height := ClientAreaBox.Bottom - ClientAreaBox.Top; end else if Layers[ fEditingLayer ] is TIELineLayer then with TIELineLayer( Layers[ fEditingLayer ]) do begin fTextEditor.Left := ClientAreaBox.Left + Round( LabelRect.Left * fZoomD100X ); fTextEditor.Top := ClientAreaBox.Top + Round( LabelRect.Top * fZoomD100X ); fTextEditor.Width := LabelRect.Right - LabelRect.Left; // don't scale fTextEditor.Height := LabelRect.Bottom - LabelRect.Top; end; end; {!! TImageEnView.SetSelectionMarkOuterStyle Declaration procedure SetSelectionMarkOuterStyle(Alpha: Integer; Color: TColor); Description When is iesoMarkOuter, this method specifies how the outer area will be drawn. If Alpha = -1 (default) a gray grid is displayed. If Alpha >= 0 and <= 255 a solid color is painted. Example // Areas outside the selection will be marked with red (with 50% transparency) ImageEnView1.SelectionOptions := ImageEnView1.SelectionOptions+[iesoMarkOuter]; ImageEnView1.SetSelectionMarkOuterStyle(128, clRed); !!} procedure TImageEnView.SetSelectionMarkOuterStyle(Alpha: Integer; Color: TColor); begin fMarkOuterAlpha := Alpha; fMarkOuterColor := Color; end; {!! TImageEnView.SaveState Declaration procedure SaveState(const FileName: String); procedure SaveState(Stream: TStream); Description Saves layers, selection and some other parameters such as Zoom and Scroll position. See also: method. !!} procedure TImageEnView.SaveState(const FileName: String); var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmCreate); try SaveState(fs); finally fs.Free; end; end; const ImageEnView_File_Version = 3; ImageEnView_File_State : AnsiString = 'IMAGEENVIEWSTATE'; { // Versions: v3: Support for fDisplayGridKind } procedure TImageEnView.SaveState(Stream: TStream); var ver: Integer; vi: Integer; begin // write magic string Stream.Write(ImageEnView_File_State[1], length( ImageEnView_File_State )); // write version ver := ImageEnView_File_Version; Stream.Write(ver, sizeof(integer)); // selection SaveSelectionToStream(Stream); // view and zoom Stream.Write(fZoomX, sizeof(fZoomX)); Stream.Write(fZoomY, sizeof(fZoomY)); Stream.Write(fViewX, sizeof(fViewX)); Stream.Write(fViewY, sizeof(fViewY)); // others Stream.Write(fLegacyBitmap, sizeof(boolean)); Stream.Write(fImageHorizAlignment, sizeof(TIEHAlign)); Stream.Write(fImageVertAlignment, sizeof(TIEVAlign)); Stream.Write(fZoomFilter, sizeof(TResampleFilter)); Stream.Write(fBackgroundStyle, sizeof(TIEBackgroundStyle)); Stream.Write(fDisplayGridKind, sizeof(TIEGridKind)); Stream.Write(fAutoFit, sizeof(boolean)); Stream.Write(fAutoStretch, sizeof(boolean)); Stream.Write(fAutoShrink, sizeof(boolean)); Stream.Write(fSelectionOptions, sizeof(TIESelectionOptions)); Stream.Write(fMouseInteract, sizeof(TIEMouseInteract)); Stream.Write(fScrollBarsAlwaysVisible, sizeof(boolean)); Stream.Write(fEnableAlphaChannel, sizeof(boolean)); Stream.Write(fScrollBars, sizeof(TIEScrollStyle)); // for debugging vi := ClientWidth; Stream.Write(vi, sizeof(integer)); vi := ClientHeight; Stream.Write(vi, sizeof(integer)); vi := Width; Stream.Write(vi, sizeof(integer)); vi := Height; Stream.Write(vi, sizeof(integer)); // LAST: layers SaveSelection; LayersSaveToStream(Stream); RestoreSelection; end; {!! TImageEnView.LoadState Declaration procedure LoadState(const FileName: String); procedure LoadState(Stream: TStream); Description Loads layers, selection and some other parameters such as Zoom and Scroll position. See also: method. !!} procedure TImageEnView.LoadState(const FileName: String); var fs: TFileStream; begin fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); try LoadState(fs); finally fs.Free; end; end; procedure TImageEnView.LoadState(Stream: TStream); var ver: Integer; magic: AnsiString; r_ViewX, r_ViewY: Integer; r_ZoomX, r_ZoomY: Double; r_LegacyBitmap, r_Center: Boolean; r_ZoomFilter: TResampleFilter; r_BackgroundStyle: TIEBackgroundStyle; r_Dummy: Boolean; r_DisplayGrid: TIEGridKind; r_ClientWidth, r_ClientHeight, r_Width, r_Height: Integer; r_AutoFit, r_AutoStretch, r_AutoShrink: Boolean; r_SelectionOptions: TIESelectionOptions; r_MouseInteract: TIEMouseInteract; r_ScrollBarsAlwaysVisible, r_EnableAlphaChannel: Boolean; r_ScrollBars: TIEScrollStyle; r_ImageHorizAlignment: TIEHAlign; r_ImageVertAlignment: TIEVAlign; begin // read magic string SetLength(magic, length( ImageEnView_File_State )); Stream.Read(magic[1], length( ImageEnView_File_State )); // read version Stream.Read(ver, sizeof(integer)); if (magic = ImageEnView_File_State) and (ver > 0) then begin // selection LoadSelectionFromStream(Stream); SaveSelection; // view and zoom Stream.Read(r_ZoomX, sizeof(r_ZoomX)); Stream.Read(r_ZoomY, sizeof(r_ZoomY)); Stream.Read(r_ViewX, sizeof(r_ViewX)); Stream.Read(r_ViewY, sizeof(r_ViewY)); // others Stream.Read(r_LegacyBitmap, sizeof(boolean)); if ver >= 2 then begin Stream.Read(r_ImageHorizAlignment, sizeof(TIEHAlign)); Stream.Read(r_ImageVertAlignment, sizeof(TIEVAlign)); end else begin Stream.Read(r_Center, sizeof(boolean)); if r_Center then begin r_ImageHorizAlignment := iehCenter; r_ImageVertAlignment := ievCenter; end else begin r_ImageHorizAlignment := iehLeft; r_ImageVertAlignment := ievTop; end; end; Stream.Read(r_ZoomFilter, sizeof(TResampleFilter)); Stream.Read(r_BackgroundStyle, sizeof(TIEBackgroundStyle)); if ver < 3 then Stream.Read(r_Dummy, sizeof(boolean)) else Stream.Read(r_DisplayGrid, sizeof(TIEGridKind)); Stream.Read(r_AutoFit, sizeof(boolean)); Stream.Read(r_AutoStretch, sizeof(boolean)); Stream.Read(r_AutoShrink, sizeof(boolean)); Stream.Read(r_SelectionOptions, sizeof(TIESelectionOptions)); Stream.Read(r_MouseInteract, sizeof(TIEMouseInteract)); Stream.Read(r_ScrollBarsAlwaysVisible, sizeof(boolean)); Stream.Read(r_EnableAlphaChannel, sizeof(boolean)); Stream.Read(r_ScrollBars, sizeof(TIEScrollStyle)); // for debugging Stream.Read(r_ClientWidth, sizeof(integer)); Stream.Read(r_ClientHeight, sizeof(integer)); Stream.Read(r_Width, sizeof(integer)); Stream.Read(r_Height, sizeof(integer)); // LAST: layers LayersLoadFromStream(Stream); // Settings LockPaint; LegacyBitmap := r_LegacyBitmap; ImageHorizAlignment := r_ImageHorizAlignment; ImageVertAlignment := r_ImageVertAlignment; ZoomX := r_ZoomX; ZoomY := r_ZoomY; ViewX := r_ViewX; ViewY := r_ViewY; ZoomFilter := r_ZoomFilter; BackgroundStyle := r_BackgroundStyle; DisplayGridKind := r_DisplayGrid; AutoFit := r_AutoFit; AutoStretch := r_AutoStretch; AutoShrink := r_AutoShrink; SelectionOptions := r_SelectionOptions; MouseInteract := r_MouseInteract; ScrollBarsAlwaysVisible := r_ScrollBarsAlwaysVisible; EnableAlphaChannel := r_EnableAlphaChannel; ScrollBars := r_ScrollBars; RestoreSelection; UnLockPaint; end; end; {!! TImageEnView.ResetState Declaration procedure ResetState(); Description Resets some TImageEnView properties to their defaults. ResetState will remove selection, empty layers, set input/output parameters to their defaults, reset Zoom and Scroll and clear the Undo buffer. Leaves unchanged. !!} procedure TImageEnView.ResetState(); begin Playing := False; DeSelect(); LayersClear(); Blank(); IO.Params.SetDefaultParams(); Zoom := 100.0; ViewX := 0; ViewY := 0; ImageHorizAlignment := iehCenter; ImageVertAlignment := ievCenter; Proc.ClearAllUndo(); Proc.ClearAllRedo(); if ( LegacyBitmap = false ) and ( IEBitmap <> nil ) then IEBitmap.Location := ieMemory; Update(); end; procedure TImageEnView.UserInteractions_VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); var i: integer; begin for i := 0 to fUserInteractions.Count - 1 do if (fUserInteractions[i] as TIEUserInteraction).Enabled then (fUserInteractions[i] as TIEUserInteraction).VirtualKey(VKey, KeyData, KeyDown); end; { KEYBOARD: Move 1 pixel: Arrow keys Move 10 pixels: Shift + arrow keys Size 1 pixel: Ctrl + Arrow keys Size 10 pixels: Ctrl + Shift + arrow keys } // If rectangular selection then it is moved, otherwise if layer > 0 active then it is moved // VKey is one of VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN procedure TImageEnView.MoveSelByKey(VKey: Word; ss: TShiftState); var sizing: Boolean; moveBy: integer; begin if not VKey in [ VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN ] then exit; moveBy := 1; if EnableShiftKey and ( ssShift in ss ) then moveBy := 10; sizing := ssCtrl in ss; if fSel then begin // MOVE SELECTION case VKey of VK_LEFT : MoveSelection( -1 * moveBy, 0, sizing ); VK_RIGHT : MoveSelection( moveBy, 0, sizing ); VK_UP : MoveSelection( 0, -1 * moveBy, sizing ); VK_DOWN : MoveSelection( 0, moveBy, sizing ); end; end else if fLayersCurrent > 0 then begin case VKey of VK_LEFT : LayersRepositionAll( -1 * moveBy, 0, True, sizing ); VK_RIGHT : LayersRepositionAll( moveBy, 0, True, sizing ); VK_UP : LayersRepositionAll( 0, -1 * moveBy, True, sizing ); VK_DOWN : LayersRepositionAll( 0, moveBy, True, sizing ); end; if Sizing then DoLayerNotify( fLayersCurrent, ielResized ) else DoLayerNotify( fLayersCurrent, ielMoved ); end; end; // this could not fired if the component is on TForm. Putting TImageEnView on TPanel it works. procedure TImageEnView.CMWantSpecialKey(var Msg: TCMWantSpecialKey); var handled: Boolean; begin inherited; handled := false; if assigned(fOnSpecialKey) then fOnSpecialKey(self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData), handled); if handled then begin msg.Result := 1; exit; end; {$IFDEF OCXVERSION} case msg.CharCode of VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_HOME, VK_END: begin msg.Result := 1; KeyUp( Msg.CharCode, KeyDataToShiftState( Msg.KeyData )); end; end; {$ELSE} case msg.CharCode of VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN: if (iesoAllowMoveByKeyboard in fSelectionOptions) and IEIsKeyPressed(msg.CharCode) then begin msg.Result := 1; MoveSelByKey( Msg.CharCode, KeyDataToShiftState( Msg.KeyData )); if fShowRulers <> [] then fRulerParams.HandleSpecialKey( Msg.CharCode, KeyDataToShiftState( Msg.KeyData )); {$IFDEF IEDEBUG} outputdebugstringA(pansichar(string( Format('CMWantSpecialKey %d %d', [Msg.Msg, Msg.CharCode]) ))); {$ENDIF} end; end; {$ENDIF} end; procedure TImageEnView.CNKEYDOWN(var Message: TMessage); begin inherited; UserInteractions_VirtualKey(Message.wParam, Message.lParam, true); if assigned(fOnVirtualKey) then fOnVirtualKey(self, Message.wParam, Message.lParam, true); end; procedure TImageEnView.CNKEYUP(var Message: TMessage); begin inherited; UserInteractions_VirtualKey(Message.wParam, Message.lParam, false); if assigned(fOnVirtualKey) then fOnVirtualKey(self, Message.wParam, Message.lParam, false); end; procedure TImageEnView.WMSYSKEYDOWN(var Message: TMessage); begin inherited; UserInteractions_VirtualKey(Message.wParam, Message.lParam, true); if assigned(fOnVirtualKey) then fOnVirtualKey(self, Message.wParam, Message.lParam, true); end; procedure TImageEnView.WMSYSKEYUP(var Message: TMessage); begin inherited; UserInteractions_VirtualKey(Message.wParam, Message.lParam, false); if assigned(fOnVirtualKey) then fOnVirtualKey(self, Message.wParam, Message.lParam, false); end; {!! TImageEnView.HighlightedPixelColor Declaration property HighlightedPixelColor: TColor; Description Colored box color. See Also - !!} procedure TImageEnView.SetHighlightedPixelColor(c: TColor); begin fHighlightedPixelColor := c; end; {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 6.2.2 (2015-12-15) function TImageEnView.GetDPIX() : integer; begin Result := GetImageEnIO.Params.DpiX; end; function TImageEnView.GetDPIY() : integer; begin Result := GetImageEnIO.Params.DpiY; end; procedure TImageEnView.SetDPIX(dpiX: integer); begin GetImageEnIO.Params.DpiX := dpiX; end; procedure TImageEnView.SetDPIY(dpiY: integer); begin GetImageEnIO.Params.DpiY := dpiY; end; procedure TImageEnView.SetDPI(dpiX, dpiY: integer); begin GetImageEnIO.Params.DpiX := dpiX; GetImageEnIO.Params.DpiY := dpiY; end; {$endif} {$ifdef IEIncludeDeprecatedInV6} // Deprecated in 7.0.0 (8/11/2016) function TImageEnView.GetLayersRotationDelayFilterOnPreview(): boolean; begin Result := fLayersFastDrawing = iefDelayed; end; procedure TImageEnView.SetLayersRotationDelayFilterOnPreview(value: Boolean); begin if value then fLayersFastDrawing := iefDelayed else fLayersFastDrawing := iefNormal; end; {$endif} {!! TImageEnView.OnRulerClick Declaration property OnRulerClick: ; Description Occurs when the user clicks on a ruler. Example procedure TForm1.ImageEnView1RulerClick(Sender: TObject; RulerDir: TRulerDir; Ps: double); begin case RulerDir of rdHorizontal : ShowMessage( 'Horizontal ruler clicked at: ' + FloatToStr( Ps )); rdVertical : ShowMessage( 'Vertical ruler clicked at: ' + FloatToStr( Ps )); end; end; !!} function TImageEnView.GetOnRulerClick: TRulerClickEvent; begin result := fRulerParams.OnRulerClick; end; procedure TImageEnView.SetOnRulerClick(const Value: TRulerClickEvent); begin fRulerParams.OnRulerClick := Value; end; {!! TImageEnView.OnRulerGripClick Declaration property OnRulerGripClick: ; Description Occurs when the user clicks a grip on a ruler. Example procedure TForm1.ImageEnView1RulerGripClick(Sender: TObject; RulerDir: TRulerDir; Grip: integer; GripPos: Double); begin case RulerDir of rdHorizontal : ShowMessage( format( 'Grip %d clicked on horizontal ruler', [ Grip ])); rdVertical : ShowMessage( format( 'Grip %d clicked on vertical ruler', [ Grip ])); end; end; !!} function TImageEnView.GetOnRulerGripClick: TRulerGripClickEvent; begin result := fRulerParams.OnRulerGripClick; end; procedure TImageEnView.SetOnRulerGripClick(const Value: TRulerGripClickEvent); begin fRulerParams.OnRulerGripClick := Value; end; {!! TImageEnView.OnRulerGripDblClick Declaration property OnRulerGripDblClick: ; Description Occurs when the user double-clicks a grip on a ruler. Example procedure TForm1.ImageEnView1RulerGripDblClick(Sender: TObject; RulerDir: TRulerDir; Grip: integer; GripPos: Double); begin case RulerDir of rdHorizontal : ShowMessage( format( 'Grip %d double-clicked on horizontal ruler', [ Grip ])); rdVertical : ShowMessage( format( 'Grip %d double-clicked on vertical ruler', [ Grip ])); end; end; !!} function TImageEnView.GetOnRulerGripDblClick: TRulerGripClickEvent; begin result := fRulerParams.OnRulerGripDblClick; end; procedure TImageEnView.SetOnRulerGripDblClick(const Value: TRulerGripClickEvent); begin fRulerParams.OnRulerGripDblClick := Value; end; {!! TImageEnView.OnRulerGripPosChange Declaration property OnRulerGripPosChange: ; Description Occurs when a grip is moved on a ruler. Example procedure TForm1.ImageEnView1RulerGripPosChange(Sender: TObject; RulerDir: TRulerDir; Grip: integer; NewPos: Double); begin case RulerDir of rdHorizontal : ShowMessage( format( 'Grip %d moved on horizontal ruler', [ Grip ])); rdVertical : ShowMessage( format( 'Grip %d moved on vertical ruler', [ Grip ])); end; end; !!} function TImageEnView.GetOnRulerGripPosChange: TRulerGripPosChangeEvent; begin result := fRulerParams.OnRulerGripPosChange; end; procedure TImageEnView.SetOnRulerGripPosChange(const Value: TRulerGripPosChangeEvent); begin fRulerParams.OnRulerGripPosChange := Value; end; procedure TImageEnView.WMGestureNotify(var Msg: TIEWMGestureNotify); var c: integer; gc: array of TIEGESTURECONFIG; begin inherited; if fGestures.Enabled and IEHasGestures() then begin IEUnregisterTouchWindow(Handle); if fGestures.fPan.Enabled or fGestures.fLayerMove.Enabled then begin c := length(gc); SetLength(gc, c + 1); gc[c].dwID := IEGID_PAN; gc[c].dwWant := IEGC_PAN or IEGC_PAN_WITH_INERTIA; if fGestures.fPan.PanWithSingleFingerVertically then gc[c].dwWant := gc[c].dwWant or IEGC_PAN_WITH_SINGLE_FINGER_VERTICALLY; if fGestures.fPan.PanWithSingleFingerHorizontally then gc[c].dwWant := gc[c].dwWant or IEGC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY; gc[c].dwBlock := IEGC_PAN_WITH_GUTTER; end; if fGestures.fZoom.Enabled then begin c := length(gc); SetLength(gc, c + 1); gc[c].dwID := IEGID_ZOOM; gc[c].dwWant := IEGC_ALLGESTURES; gc[c].dwBlock := 0; end; if fGestures.fLayerRotate.Enabled then begin c := length(gc); SetLength(gc, c + 1); gc[c].dwID := IEGID_ROTATE; gc[c].dwWant := IEGC_ROTATE; gc[c].dwBlock := 0; end; IESetGestureConfig(Handle, 0, length(gc), @gc[0], sizeof(TIEGESTURECONFIG)); end; end; function GID_ROTATE_ANGLE_FROM_ARGUMENT(arg: integer): double; begin result := ((arg / 65535.0) * 4.0 * 3.14159265) - 2.0 * 3.14159265; end; procedure TImageEnView.DoImageEnGestureEvent(const GInfo: TIEGESTUREINFO; var Handled: boolean); var Flags: TIEGestureFlags; ID: TIEGestureID; begin if assigned(fOnImageEnGesture) then begin Flags := []; if (IEGF_BEGIN and GInfo.dwFlags) <> 0 then Flags := Flags + [iegfBegin]; if (IEGF_INERTIA and GInfo.dwFlags) <> 0 then Flags := Flags + [iegfInertia]; if (IEGF_END and GInfo.dwFlags) <> 0 then Flags := Flags + [iegfEnd]; ID := TIEGestureID(GInfo.dwID - 1); fOnImageEnGesture(self, Flags, ID, GInfo.ptsLocation, GInfo.ullArguments and $FFFFFFFF, (GInfo.ullArguments shr 32) and $FFFF, (GInfo.ullArguments shr 48) and $FFFF, (GInfo.ullArguments shr 32), Handled); end; end; function TImageEnView.PerformRotateSnap(Value: double): double; var i: integer; begin result := Value; if fGestures.fLayerRotate.SnapValues then for i := 0 to 8 do if result >= 0 then begin if (abs(45 * i - IEGetReferenceAngle(result)) <= fGestures.fLayerRotate.SnapDelta) then result := 45 * i; end else begin if (abs(-45 * i - IEGetReferenceAngle(result)) <= fGestures.fLayerRotate.SnapDelta) then result := - 45 * i; end; end; function TImageEnView.PerformLayerMoveSnap(Value: double): double; begin result := Value; if fGestures.fLayerMove.SnapValues then begin if abs(result) <= fGestures.fLayerMove.SnapDelta then result := 0.0 end; end; function TImageEnView.PerformZoomSnap(Value: double): double; begin result := Value; if fGestures.fZoom.SnapValues then begin if abs(result - 100.0) <= fGestures.fZoom.SnapDelta then result := 100; end; end; procedure TImageEnView.WMGesture(var Msg: TMessage); var gInfo: TIEGESTUREINFO; value: integer; v: double; isBegin: boolean; isInertia: boolean; handled: boolean; begin Msg.Result := 1; // not handled if fGestures.Enabled and IEHasGestures() then begin FillChar(gInfo, sizeof(gInfo), 0); gInfo.cbSize := sizeof(gInfo); if IEGetGestureInfo(Msg.LParam, @gInfo) then begin try handled := false; DoImageEnGestureEvent(gInfo, handled); if not handled then begin value := gInfo.ullArguments and $FFFFFFFF; isBegin := (IEGF_BEGIN and gInfo.dwFlags) <> 0; isInertia := (IEGF_INERTIA and gInfo.dwFlags) <> 0; case gInfo.dwID of IEGID_ZOOM: begin // begin zoom if isBegin then begin fGestureStartValue := value; fGestureBaseZoom := Zoom; end // perform zoom else if fGestures.fZoom.Enabled and (not isInertia or fGestures.fZoom.Inertia) then begin v := fGestureBaseZoom * (value / fGestureStartValue); v := dmax(v, fGestures.fZoom.Min); v := dmin(v, fGestures.fZoom.Max); v := v * fGestures.fZoom.Multiplier; Zoom := PerformZoomSnap(v); Msg.Result := 0; // handled end end; IEGID_PAN: begin // begin pan if isBegin then begin fGestureStartX := gInfo.ptsLocation.x; fGestureStartY := gInfo.ptsLocation.y; fGestureBaseViewX := ViewX; fGestureBaseViewY := ViewY; fGestureBasePosX := CurrentLayer.PosX; fGestureBasePosY := CurrentLayer.PosY; end // perform pan else if fGestures.fPan.Enabled and (not isInertia or fGestures.fPan.Inertia) then begin v := fGestureBaseViewX + (fGestureStartX - gInfo.ptsLocation.x); v := dmax(v, fGestures.fPan.BoundingBox.Left); v := dmin(v, fGestures.fPan.BoundingBox.Right); v := v * fGestures.fPan.Multiplier; ViewX := trunc(v); v := fGestureBaseViewY + (fGestureStartY - gInfo.ptsLocation.y); v := dmax(v, fGestures.fPan.BoundingBox.Top); v := dmin(v, fGestures.fPan.BoundingBox.Bottom); v := v * fGestures.fPan.Multiplier; ViewY := trunc(v); Msg.Result := 0; // handled end // perform layer move else if fGestures.fLayerMove.Enabled and (not isInertia or fGestures.fLayerMove.Inertia) then begin v := fGestureBasePosX - trunc((fGestureStartX - gInfo.ptsLocation.x) / (ZoomX / 100)); v := dmax(v, fGestures.fLayerMove.BoundingBox.Left); v := dmin(v, fGestures.fLayerMove.BoundingBox.Right); v := v * fGestures.fLayerMove.Multiplier; CurrentLayer.PosX := trunc(PerformLayerMoveSnap(v)); v := fGestureBasePosY - trunc((fGestureStartY - gInfo.ptsLocation.y) / (ZoomY / 100)); v := dmax(v, fGestures.fLayerMove.BoundingBox.Top); v := dmin(v, fGestures.fLayerMove.BoundingBox.Bottom); v := v * fGestures.fLayerMove.Multiplier; CurrentLayer.PosY := trunc(PerformLayerMoveSnap(v)); Update(); Msg.Result := 0; // handled end; end; IEGID_ROTATE: begin // begin rotate if isBegin then begin fGestureBaseRotate := CurrentLayer.Rotate; end // perform layer rotate else if fGestures.fLayerRotate.Enabled and (not isInertia or fGestures.fLayerRotate.Inertia) then begin v := fGestureBaseRotate + GID_ROTATE_ANGLE_FROM_ARGUMENT(value) * 180 / PI; v := dmax(v, fGestures.fLayerRotate.Min); v := dmin(v, fGestures.fLayerRotate.Max); v := v * fGestures.fLayerRotate.Multiplier; CurrentLayer.Rotate := PerformRotateSnap(v); Update(); Msg.Result := 0; // handled end; end; end; end else begin // handled by user (in OnImageEnGesture event) Msg.Result := 0; // handled end; finally if Msg.Result = 0 then IECloseGestureInfoHandle(Msg.LParam); end; end end; if Msg.Result <> 0 then inherited; end; constructor TIEViewerGestures.Create(); begin inherited; fPan := TIEGesturePanOptions.Create(); fZoom := TIEGestureZoomOptions.Create(); fLayerRotate := TIEGestureLayerRotateOptions.Create(); fLayerMove := TIEGestureLayerMoveOptions.Create(); // Pan defaults fPan.Enabled := false; fPan.Inertia := true; fPan.BoundingBox := Rect(Low(integer), Low(integer), High(integer), High(integer)); fPan.Multiplier := 1.0; fPan.SnapValues := false; fPan.SnapDelta := 0.0; fPan.PanWithSingleFingerVertically := True; fPan.PanWithSingleFingerHorizontally := True; fPan.AddDisables(fLayerMove); // Zoom defaults fZoom.Enabled := false; fZoom.Inertia := true; fZoom.Min := 1.0; fZoom.Max := 8000.0; fZoom.Multiplier := 1.0; fZoom.SnapValues := true; fZoom.SnapDelta := 5.0; // LayerRotate defaults fLayerRotate.Enabled := false; fLayerRotate.Inertia := false; fLayerRotate.Min := - MaxDouble; fLayerRotate.Max := MaxDouble; fLayerRotate.Multiplier := 1.0; fLayerRotate.SnapValues := true; fLayerRotate.SnapDelta := 5.0; // LayerMove defaults fLayerMove.Enabled := false; fLayerMove.Inertia := false; fLayerMove.BoundingBox := Rect(Low(integer), Low(integer), High(integer), High(integer)); fLayerMove.Multiplier := 1.0; fLayerMove.SnapValues := true; fLayerMove.SnapDelta := 5.0; fLayerMove.AddDisables(fPan); end; destructor TIEViewerGestures.Destroy(); begin fPan.Free(); fZoom.Free(); fLayerRotate.Free(); fLayerMove.Free(); inherited; end; function TIEViewerGestures.GetEnabled(): boolean; begin result := fPan.Enabled or fZoom.Enabled or fLayerRotate.Enabled or fLayerMove.Enabled; end; procedure TIEGestureOptions.SetEnabled(Value: boolean); var i: integer; begin fEnabled := Value; if Value then for i := 0 to high(fDisables) do fDisables[i].Enabled := false; end; procedure TIEGestureOptions.AddDisables(Value: TIEGestureOptions); var l: integer; begin l := length(fDisables); SetLength(fDisables, l + 1); fDisables[l] := Value; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIEUserInteraction constructor TIEUserInteraction.Create(Parent: TImageEnView); begin inherited Create; fParent := Parent; fEnabled := false; end; destructor TIEUserInteraction.Destroy(); begin inherited; end; function TIEUserInteraction.GetParent(): TImageEnView; begin result := fParent; end; procedure TIEUserInteraction.SetTempCursor(Value: TCursor); begin fParent.SetTempCursor(Value); end; procedure TIEUserInteraction.RestoreCursor(); begin fParent.RestoreCursor(); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIECropToolInteraction constructor TIECropToolInteraction.Create(Parent: TImageEnView); begin inherited Create(Parent); fState := iectisUNSELECTED; fRotation := 0; fLockAspectRatio := -1; fLockWidth := 0; fLockHeight := 0; fOptions := [ iecoAllowResizing, iecoAllowRotating, iecoAllowMoving ]; SetLength(fScreenPolygon, 4); SetLength(fBitmapPolygon, 4); SetLength(fRotatedPolygon, 4); // crop processing properties fAntialiasMode := ierFast; fMode := iectmRECTANGLE; // visual appearance fDrawGuides := true; fGripSize := 8; end; {!! TIECropToolInteraction.SetBitmapPolygon Declaration procedure SetBitmapPolygon(Rect: TRect); Description Sets the area of the image selected for cropping. This is the programatic equivalent of the user dragging the grips of the crop tool selection. Note: You must call TImageEnView.Invalidate if you change this property when the crop selection is visible Example // Select 80% of image ARect := Rect( MulDiv( ImageEnView1.IEBitmap.Width, 10, 100 ), MulDiv( ImageEnView1.IEBitmap.Height, 10, 100 ), MulDiv( ImageEnView1.IEBitmap.Width, 90, 100 ), MulDiv( ImageEnView1.IEBitmap.Height, 90, 100 )); ImageEnView1.CropToolInteraction.SetBitmapPolygon( ARect ); ImageEnView1.Invalidate(); See Also - - !!} procedure TIECropToolInteraction.SetBitmapPolygon(Rect: TRect); begin // TL fBitmapPolygon[0] := IE2DPoint(Rect.Left, Rect.Top); // TR fBitmapPolygon[1] := IE2DPoint(Rect.Right, Rect.Top); // BR fBitmapPolygon[2] := IE2DPoint(Rect.Right, Rect.Bottom); // BL fBitmapPolygon[3] := IE2DPoint(Rect.Left, Rect.Bottom); fState := iectisSELECTED; end; {!! TIECropToolInteraction.Mode Declaration property Mode: ; Description Specifies the shape of cropping area. Value Description iectmRECTANGLE The cropping area is rectangular (for standard cropping) iectmPERSPECTIVE All corners of the cropping area can be adjusted as a quadrilateral to allow perspective distortion, i.e. the selected quadrilateral will be scaled to a rectangle when cropping is enacted.
Note: You must call TImageEnView.Invalidate if you change this property when the crop selection is visible Default: iectmRECTANGLE Example // Enable perspective correction tool ImageEnView1.CropToolInteraction.Mode := iectmPERSPECTIVE; ImageEnView1.Invalidate(); !!} procedure TIECropToolInteraction.SetMode(const Value: TIECropToolInteractionMode); var Rect: TRect; begin if ( fMode = iectmPERSPECTIVE ) and ( Value = iectmRECTANGLE ) then begin // Reset any perspetive in selection Rect.Left := Round( dmax( fBitmapPolygon[ 0 ].X, fBitmapPolygon[ 3 ].X )); Rect.Top := Round( dmax( fBitmapPolygon[ 0 ].Y, fBitmapPolygon[ 1 ].Y )); Rect.Right := Round( dmax( fBitmapPolygon[ 1 ].X, fBitmapPolygon[ 2 ].X )); Rect.Bottom := Round( dmax( fBitmapPolygon[ 2 ].Y, fBitmapPolygon[ 3 ].Y )); SetBitmapPolygon( Rect ); end; fMode := Value; end; {!! TIECropToolInteraction.Selected Declaration property TIECropToolInteraction.Selected: Boolean; Description Returns true if a selection is active. !!} function TIECropToolInteraction.GetSelected(): Boolean; begin Result := fState = iectisSELECTED; end; procedure TIECropToolInteraction.SetSelected(const Value: Boolean); begin if ( fState = iectisSELECTED ) and ( value = False ) then Cancel(); end; {!! TIECropToolInteraction.Cancel Declaration procedure TIECropToolInteraction.Cancel(); Description Clears the crop selection. This is the same as the user clicking the "Esc" key. Example // "Cancel Crop" button clicked procedure TMainForm.btnCancelCropClick(Sender: TObject); begin ImageEnView1.CropToolInteraction.Cancel(); end; See Also -
!!} procedure TIECropToolInteraction.Cancel(); begin fState := iectisUNSELECTED; fRotation := 0; Refresh(); RestoreCursor; end; {!! TIECropToolInteraction.Crop Declaration procedure TIECropToolInteraction.Crop(); Description Crop the image to the selection. This is the same as the user clicking the "Enter" key. Example // "Apply Crop" button clicked procedure TMainForm.btnApplyCropClick(Sender: TObject); begin ImageEnView1.CropToolInteraction.Crop(); end; See Also - !!} procedure TIECropToolInteraction.Crop(); begin if fState = iectisUNSELECTED then exit; case fMode of iectmRECTANGLE: GetParent().Proc.Crop(Rect(trunc(fBitmapPolygon[0].X), trunc(fBitmapPolygon[0].Y), trunc(fBitmapPolygon[2].X), trunc(fBitmapPolygon[2].Y)), fRotation, fAntialiasMode); iectmPERSPECTIVE: GetParent().Proc.Crop(GetRotatedBitmapPolygon()); end; Cancel(); end; procedure TIECropToolInteraction.Refresh(); begin GetParent().Paint(); Draw(GetParent().GetCanvas()); end; // x,y: screen coordinates function TIECropToolInteraction.GetGrip(x, y: integer): TIECropToolInteractionState; var g: TIECropToolInteractionState; begin result := iectisUNSELECTED; if fState <> iectisUNSELECTED then begin // try rotated grips for g := iectisTOP_LEFT_SIZE to iectisLEFT_SIZE do if IEPointInRect(x, y, fGripRects[g][0].X, fGripRects[g][0].Y, fGripRects[g][1].X, fGripRects[g][1].Y) then begin if iecoAllowResizing in fOptions then result := g; exit; end; // try rotated polygon if IEDISPointInPoly(x, y, fRotatedPolygon) then begin if iecoAllowMoving in fOptions then result := iectisMOVING; exit; end; // default is iectisROTATE (out of polygon area and grips) if iecoAllowRotating in fOptions then result := iectisROTATE; end; end; function TIECropToolInteraction.ScreenToBitmap(const P: TIE2DPoint): TIE2DPoint; var lyr: TIELayer; zx, zy: double; begin lyr := GetParent().CurrentLayer; zx := GetParent().ZoomX / 100.0; zy := GetParent().ZoomY / 100.0; result.X := 1.0 * (((P.X - lyr.PosX * zx) - lyr.DrawingInfo.XDst) / zx + lyr.DrawingInfo.XSrc) * lyr.OriginalWidth / lyr.Width; result.Y := 1.0 * (((P.Y - lyr.PosY * zy) - lyr.DrawingInfo.YDst) / zy + lyr.DrawingInfo.YSrc) * lyr.OriginalHeight / lyr.Height; end; function TIECropToolInteraction.BitmapToScreen(const P: TIE2DPoint): TIE2DPoint; var lyr: TIELayer; zx, zy: double; begin lyr := GetParent().CurrentLayer; zx := GetParent().ZoomX / 100.0; zy := GetParent().ZoomY / 100.0; result.X := lyr.DrawingInfo.XDst + (P.X * lyr.Width / lyr.OriginalWidth - GetParent().ViewX / zx) * zx + lyr.PosX * zx; result.Y := lyr.DrawingInfo.YDst + (P.Y * lyr.Height / lyr.OriginalHeight - GetParent().ViewY / zy) * zy + lyr.PosY * zy; end; function TIECropToolInteraction.GetRotatedBitmapPolygon(): TIE2DPointArray; var i: integer; begin SetLength(result, length(fRotatedPolygon)); for i := 0 to high(fRotatedPolygon) do result[i] := ScreenToBitmap(fRotatedPolygon[i]); end; procedure TIECropToolInteraction.UpdateBitmapPolygon(); var i: integer; begin for i := 0 to high(fScreenPolygon) do fBitmapPolygon[i] := ScreenToBitmap(fScreenPolygon[i]); end; procedure TIECropToolInteraction.UpdateScreenPolygon(); var i: integer; begin for i := 0 to high(fScreenPolygon) do fScreenPolygon[i] := BitmapToScreen(fBitmapPolygon[i]); end; function TIECropToolInteraction.MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; var grip: TIECropToolInteractionState; begin if Button = mbLeft then begin fMouseDownCoords := Point(X, Y); fMouseDownScreenPolygon := Copy(fScreenPolygon, 0, length(fScreenPolygon)); fMouseDownRotation := fRotation; fMouseDownRotatedPolygon := Copy(fRotatedPolygon, 0, length(fRotatedPolygon)); grip := GetGrip(X, Y); // Locked aspect ratio enabled in parent if fLockAspectRatio > 0 then fAspectRatio := fLockAspectRatio; // If user has no selection then allow creation of one if fState = iectisUNSELECTED then begin // create selection fState := iectisCREATING; fScreenPolygon[0] := IE2DPoint(X, Y); // initial aspect ratio from bitmap instead of selection if fLockAspectRatio <= 0 then fAspectRatio := GetParent().CurrentLayer.OriginalWidth / GetParent().CurrentLayer.OriginalHeight; end else if grip <> iectisUNSELECTED then begin // resize, move, rotate fState := grip; end; result := true; end else result := false; end; procedure TIECropToolInteraction.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin { // } end; function TIECropToolInteraction.MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; {} procedure _UpdatePolySize(HAlign: TIEHAlign; VAlign: TIEVAlign); var dx, dy: Integer; begin if ( fLockAspectRatio <= 0 ) or ( iecoSizeLocksAreMinimums in fOptions ) then begin dx := round( fLockWidth * GetParent().ZoomX / 100.0 ); dy := round( fLockHeight * GetParent().ZoomY / 100.0 ); if fLockWidth > 0 then if (( iecoSizeLocksAreMinimums in fOptions ) = False ) or ( abs( fScreenPolygon[2].X - fScreenPolygon[0].X ) < dx ) then case HAlign of iehLeft : fScreenPolygon[2].X := fScreenPolygon[0].X + dx; iehRight : fScreenPolygon[0].X := fScreenPolygon[2].X - dx; end; if fLockHeight > 0 then if (( iecoSizeLocksAreMinimums in fOptions ) = False ) or ( abs( fScreenPolygon[2].Y - fScreenPolygon[0].Y ) < dy ) then case VAlign of ievTop : fScreenPolygon[2].Y := fScreenPolygon[0].Y + dy; ievBottom : fScreenPolygon[0].Y := fScreenPolygon[2].Y - dy; end; fScreenPolygon[1] := IE2DPoint( fScreenPolygon[2].X, fScreenPolygon[0].Y ); fScreenPolygon[3] := IE2DPoint( fScreenPolygon[0].X, fScreenPolygon[2].Y ); end; end; {} const GRIPCURSORBASEROTATION: array [iectisTOP_LEFT_SIZE..iectisLEFT_SIZE] of integer = (-45, 0, 45, 90, -45, 0, 45, 90); var cx, cy: double; offX, offY: double; angle, angleStart: double; grip: TIECropToolInteractionState; rotOffset: double; doRefresh: boolean; i: integer; bLockAspect: Boolean; HAlign: TIEHAlign; VAlign: TIEVAlign; begin if fState = iectisUNSELECTED then begin result := false; exit; end; if not Captured then begin // set mouse pointer grip := GetGrip(X, Y); case grip of iectisTOP_LEFT_SIZE, iectisBOTTOM_RIGHT_SIZE, iectisTOP_RIGHT_SIZE, iectisBOTTOM_LEFT_SIZE, iectisRIGHT_SIZE, iectisLEFT_SIZE, iectisTOP_SIZE, iectisBOTTOM_SIZE: begin Screen.Cursors[IEENTRYFORVARIABLECURSOR] := IECreateRotatedCursor(13, -fRotation + GRIPCURSORBASEROTATION[grip]); SetTempCursor(IEENTRYFORVARIABLECURSOR); end; iectisMOVING: SetTempCursor(crIESizeAll); iectisROTATE: begin cx := (fScreenPolygon[0].X + fScreenPolygon[2].X) / 2.0; cy := (fScreenPolygon[0].Y + fScreenPolygon[2].Y) / 2.0; if (X < cx) and (Y < cy) then SetTempCursor(crIERotateSE) else if (X < cx) and (Y > cy) then SetTempCursor(crIERotateNE) else if (X > cx) and (Y < cy) then SetTempCursor(crIERotateSW) else if (X > cx) and (Y > cy) then SetTempCursor(crIERotateNW); end; else RestoreCursor(); end; end; if Captured then begin doRefresh := true; bLockAspect := (( fMode <> iectmPERSPECTIVE ) and ( fLockAspectRatio > 0 )) or ( IEIsKeyPressed( VK_MENU { ALT } )) or ( GetParent().ForceALTkey ); case fState of iectisCREATING: begin // creating fScreenPolygon[1] := IE2DPoint(X, fScreenPolygon[0].Y); fScreenPolygon[2] := IE2DPoint(X, Y); fScreenPolygon[3] := IE2DPoint(fScreenPolygon[0].X, Y); HAlign := iehLeft; if X < fScreenPolygon[0].X then HAlign := iehRight; VAlign := ievTop; if Y < fScreenPolygon[0].Y then VAlign := ievBottom; _UpdatePolySize( HAlign, VAlign ); if bLockAspect then AdjustAspectRatio(fScreenPolygon, iectisBOTTOM_RIGHT_SIZE); UpdateBitmapPolygon(); end; iectisTOP_SIZE: begin // top resize IEOrthogonalTranslate(fMouseDownRotatedPolygon[0], fMouseDownRotatedPolygon[1], IE2DPoint(X, Y), offX, offY); fScreenPolygon[0] := IE2DPoint(fMouseDownRotatedPolygon[0].X + offX, fMouseDownRotatedPolygon[0].Y + offY); fScreenPolygon[1] := IE2DPoint(fMouseDownRotatedPolygon[1].X + offX, fMouseDownRotatedPolygon[1].Y + offY); fScreenPolygon[2] := fMouseDownRotatedPolygon[2]; fScreenPolygon[3] := fMouseDownRotatedPolygon[3]; IEDRotatePoints(fScreenPolygon, -fRotation); _UpdatePolySize( iehCenter, ievBottom ); if bLockAspect and ( iecoSideGripsRespectLocks in fOptions ) then AdjustAspectRatio(fScreenPolygon, iectisTOP_SIZE); UpdateBitmapPolygon(); end; iectisRIGHT_SIZE: begin // right resize IEOrthogonalTranslate(fMouseDownRotatedPolygon[1], fMouseDownRotatedPolygon[2], IE2DPoint(X, Y), offX, offY); fScreenPolygon[0] := fMouseDownRotatedPolygon[0]; fScreenPolygon[1] := IE2DPoint(fMouseDownRotatedPolygon[1].X + offX, fMouseDownRotatedPolygon[1].Y + offY); fScreenPolygon[2] := IE2DPoint(fMouseDownRotatedPolygon[2].X + offX, fMouseDownRotatedPolygon[2].Y + offY); fScreenPolygon[3] := fMouseDownRotatedPolygon[3]; IEDRotatePoints(fScreenPolygon, -fRotation); _UpdatePolySize( iehLeft, ievCenter ); if bLockAspect and ( iecoSideGripsRespectLocks in fOptions ) then AdjustAspectRatio(fScreenPolygon, iectisRIGHT_SIZE); UpdateBitmapPolygon(); end; iectisBOTTOM_SIZE: begin // bottom resize IEOrthogonalTranslate(fMouseDownRotatedPolygon[2], fMouseDownRotatedPolygon[3], IE2DPoint(X, Y), offX, offY); fScreenPolygon[0] := fMouseDownRotatedPolygon[0]; fScreenPolygon[1] := fMouseDownRotatedPolygon[1]; fScreenPolygon[2] := IE2DPoint(fMouseDownRotatedPolygon[2].X + offX, fMouseDownRotatedPolygon[2].Y + offY); fScreenPolygon[3] := IE2DPoint(fMouseDownRotatedPolygon[3].X + offX, fMouseDownRotatedPolygon[3].Y + offY); IEDRotatePoints(fScreenPolygon, -fRotation); _UpdatePolySize( iehCenter, ievTop ); if bLockAspect and ( iecoSideGripsRespectLocks in fOptions ) then AdjustAspectRatio(fScreenPolygon, iectisBOTTOM_SIZE); UpdateBitmapPolygon(); end; iectisLEFT_SIZE: begin // left resize IEOrthogonalTranslate(fMouseDownRotatedPolygon[3], fMouseDownRotatedPolygon[0], IE2DPoint(X, Y), offX, offY); fScreenPolygon[0] := IE2DPoint(fMouseDownRotatedPolygon[0].X + offX, fMouseDownRotatedPolygon[0].Y + offY); fScreenPolygon[1] := fMouseDownRotatedPolygon[1]; fScreenPolygon[2] := fMouseDownRotatedPolygon[2]; fScreenPolygon[3] := IE2DPoint(fMouseDownRotatedPolygon[3].X + offX, fMouseDownRotatedPolygon[3].Y + offY); IEDRotatePoints(fScreenPolygon, -fRotation); _UpdatePolySize( iehRight, ievCenter ); if bLockAspect and ( iecoSideGripsRespectLocks in fOptions ) then AdjustAspectRatio(fScreenPolygon, iectisLEFT_SIZE); UpdateBitmapPolygon(); end; iectisTOP_LEFT_SIZE: begin // top-left resize if fMode = iectmPERSPECTIVE then begin fScreenPolygon := copy(fMouseDownRotatedPolygon, 0, length(fMouseDownRotatedPolygon)); fScreenPolygon[0] := IE2DPoint(X, Y); IEDRotatePoints(fScreenPolygon, -fRotation); end else begin IEDRotateTwoPoints(-fRotation, IE2DPoint(X, Y), fMouseDownRotatedPolygon[2], fScreenPolygon[0], fScreenPolygon[2]); fScreenPolygon[1] := IE2DPoint(fScreenPolygon[2].X, fScreenPolygon[0].Y); fScreenPolygon[3] := IE2DPoint(fScreenPolygon[0].X, fScreenPolygon[2].Y); end; _UpdatePolySize( iehRight, ievBottom ); if bLockAspect then AdjustAspectRatio(fScreenPolygon, iectisTOP_LEFT_SIZE); UpdateBitmapPolygon(); end; iectisTOP_RIGHT_SIZE: begin // top-right resize if fMode = iectmPERSPECTIVE then begin fScreenPolygon := copy(fMouseDownRotatedPolygon, 0, length(fMouseDownRotatedPolygon)); fScreenPolygon[1] := IE2DPoint(X, Y); IEDRotatePoints(fScreenPolygon, -fRotation); end else begin IEDRotateTwoPoints(-fRotation, IE2DPoint(X, Y), fMouseDownRotatedPolygon[3], fScreenPolygon[1], fScreenPolygon[3]); fScreenPolygon[0] := IE2DPoint(fScreenPolygon[3].X, fScreenPolygon[1].Y); fScreenPolygon[2] := IE2DPoint(fScreenPolygon[1].X, fScreenPolygon[3].Y); end; _UpdatePolySize( iehLeft, ievBottom ); if bLockAspect then AdjustAspectRatio(fScreenPolygon, iectisTOP_RIGHT_SIZE); UpdateBitmapPolygon(); end; iectisBOTTOM_RIGHT_SIZE: begin // bottom-right resize if fMode = iectmPERSPECTIVE then begin fScreenPolygon := copy(fMouseDownRotatedPolygon, 0, length(fMouseDownRotatedPolygon)); fScreenPolygon[2] := IE2DPoint(X, Y); IEDRotatePoints(fScreenPolygon, -fRotation); end else begin IEDRotateTwoPoints(-fRotation, IE2DPoint(X, Y), fMouseDownRotatedPolygon[0], fScreenPolygon[2], fScreenPolygon[0]); fScreenPolygon[1] := IE2DPoint(fScreenPolygon[2].X, fScreenPolygon[0].Y); fScreenPolygon[3] := IE2DPoint(fScreenPolygon[0].X, fScreenPolygon[2].Y); end; _UpdatePolySize( iehLeft, ievTop ); if bLockAspect then AdjustAspectRatio(fScreenPolygon, iectisBOTTOM_RIGHT_SIZE); UpdateBitmapPolygon(); end; iectisBOTTOM_LEFT_SIZE: begin // bottom-left resize if fMode = iectmPERSPECTIVE then begin fScreenPolygon := copy(fMouseDownRotatedPolygon, 0, length(fMouseDownRotatedPolygon)); fScreenPolygon[3] := IE2DPoint(X, Y); IEDRotatePoints(fScreenPolygon, -fRotation); end else begin IEDRotateTwoPoints(-fRotation, IE2DPoint(X, Y), fMouseDownRotatedPolygon[1], fScreenPolygon[3], fScreenPolygon[1]); fScreenPolygon[0] := IE2DPoint(fScreenPolygon[3].X, fScreenPolygon[1].Y); fScreenPolygon[2] := IE2DPoint(fScreenPolygon[1].X, fScreenPolygon[3].Y); end; _UpdatePolySize( iehRight, ievTop ); if bLockAspect then AdjustAspectRatio(fScreenPolygon, iectisBOTTOM_LEFT_SIZE); UpdateBitmapPolygon(); end; iectisMOVING: begin // moving offX := X - fMouseDownCoords.X; // offset X offY := Y - fMouseDownCoords.Y; // offset Y for i := 0 to high(fScreenPolygon) do fScreenPolygon[i] := IE2DPoint(fMouseDownScreenPolygon[i].X + offX, fMouseDownScreenPolygon[i].Y + offY); UpdateBitmapPolygon(); end; iectisROTATE: begin // rotate cx := (fScreenPolygon[0].X + fScreenPolygon[1].X) / 2.0; cy := (fScreenPolygon[0].Y + fScreenPolygon[1].Y) / 2.0; angleStart := ArcTan2(fMouseDownCoords.Y - cy, fMouseDownCoords.X - cx); angle := ArcTan2(Y - cy, X - cx); rotOffset := - (angle - angleStart) * 180.0 / PI; // shift pressed? Rotate by 15 degrees steps if ssShift in Shift then begin rotOffset := trunc(rotOffset / 15) * 15; if fMouseDownRotation + rotOffset = fRotation then begin // avoid flickering doRefresh := false; end; end; fRotation := fMouseDownRotation + rotOffset end; else doRefresh := false; // Nothing to do end; if doRefresh then Refresh(); end; result := true; end; procedure TIECropToolInteraction.AdjustAspectRatio(quad: TIE2DPointArray; grip: TIECropToolInteractionState); var NewPt: TIE2DPoint; begin case grip of iectisTOP_LEFT_SIZE: begin quad[0] := IECalcOrthogonalLinesIntersectingPoint(quad[2], 1.0 / fAspectRatio, quad[0]); quad[1] := IE2DPoint(quad[2].X, quad[0].Y); quad[3] := IE2DPoint(quad[0].X, quad[2].Y); end; iectisTOP_RIGHT_SIZE: begin quad[1] := IECalcOrthogonalLinesIntersectingPoint(quad[3], -1.0 / fAspectRatio, quad[1]); quad[0] := IE2DPoint(quad[3].X, quad[1].Y); quad[2] := IE2DPoint(quad[1].X, quad[3].Y); end; iectisBOTTOM_RIGHT_SIZE: begin quad[2] := IECalcOrthogonalLinesIntersectingPoint(quad[0], 1.0 / fAspectRatio, quad[2]); quad[1] := IE2DPoint(quad[2].X, quad[0].Y); quad[3] := IE2DPoint(quad[0].X, quad[2].Y); end; iectisBOTTOM_LEFT_SIZE: begin quad[3] := IECalcOrthogonalLinesIntersectingPoint(quad[1], -1.0 / fAspectRatio, quad[3]); quad[0] := IE2DPoint(quad[3].X, quad[1].Y); quad[2] := IE2DPoint(quad[1].X, quad[3].Y); end; iectisLEFT_SIZE: begin NewPt := IECalcOrthogonalLinesIntersectingPoint(quad[2], 1.0 / fAspectRatio, quad[0]); quad[0] := IE2DPoint( NewPt.X, quad[0].Y + ( NewPt.Y - quad[0].Y ) / 2 ); quad[1] := IE2DPoint( quad[1].X, quad[0].Y ); quad[3] := IE2DPoint( NewPt.X, quad[3].Y - ( NewPt.Y - quad[0].Y ) / 2 ); quad[2] := IE2DPoint( quad[2].X, quad[3].Y ); end; iectisRIGHT_SIZE: begin NewPt := IECalcOrthogonalLinesIntersectingPoint(quad[3], -1.0 / fAspectRatio, quad[1]); quad[1] := IE2DPoint( NewPt.X, quad[1].Y + ( NewPt.Y - quad[1].Y ) / 2 ); quad[0] := IE2DPoint( quad[0].X, quad[1].Y ); quad[2] := IE2DPoint( NewPt.X, quad[2].Y - ( NewPt.Y - quad[1].Y ) / 2 ); quad[3] := IE2DPoint( quad[3].X, quad[2].Y ); end; iectisTOP_SIZE: begin NewPt := IECalcOrthogonalLinesIntersectingPoint(quad[2], 1.0 / fAspectRatio, quad[0]); quad[0] := IE2DPoint( quad[0].X + ( NewPt.X - quad[0].X ) / 2, NewPt.Y ); quad[3] := IE2DPoint( quad[0].X, quad[3].Y ); quad[1] := IE2DPoint( quad[1].X - ( NewPt.X - quad[0].X ) / 2, NewPt.Y ); quad[2] := IE2DPoint( quad[1].X, quad[2].Y ); end; iectisBOTTOM_SIZE: begin NewPt := IECalcOrthogonalLinesIntersectingPoint(quad[1], -1.0 / fAspectRatio, quad[3]); quad[3] := IE2DPoint( quad[3].X + ( NewPt.X - quad[3].X ) / 2, NewPt.Y ); quad[0] := IE2DPoint( quad[3].X, quad[0].Y ); quad[2] := IE2DPoint( quad[2].X - ( NewPt.X - quad[3].X ) / 2, NewPt.Y ); quad[1] := IE2DPoint( quad[2].X, quad[1].Y ); end; end; end; procedure TIECropToolInteraction.MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); begin { // } end; function TIECropToolInteraction.MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; begin result := false; end; procedure TIECropToolInteraction.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var tmp: TIE2DPointArray; w, h: double; begin tmp := nil; if (fState <> iectisUNSELECTED) then begin fState := iectisSELECTED; if fMode = iectmRECTANGLE then begin // in case the polygon has inverted X, Y (only when it is a rectangle) tmp := Copy(fScreenPolygon, 0, length(fScreenPolygon)); fScreenPolygon[0].X := dmin(tmp[0].X, tmp[2].X); fScreenPolygon[0].Y := dmin(tmp[0].Y, tmp[2].Y); fScreenPolygon[2].X := dmax(tmp[0].X, tmp[2].X); fScreenPolygon[2].Y := dmax(tmp[0].Y, tmp[2].Y); fScreenPolygon[1] := IE2DPoint(fScreenPolygon[2].X, fScreenPolygon[0].Y); fScreenPolygon[3] := IE2DPoint(fScreenPolygon[0].X, fScreenPolygon[2].Y); UpdateBitmapPolygon(); // update aspect ratio (now uses rectangle instead of original bitmap) w := fBitmapPolygon[2].X - fBitmapPolygon[0].X + 1; h := fBitmapPolygon[2].Y - fBitmapPolygon[0].Y + 1; if h <> 0 then fAspectRatio := w / h; end; end; end; procedure TIECropToolInteraction.VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); begin if KeyDown then begin case VKey of VK_ESCAPE: Cancel(); VK_RETURN: Crop(); end; end; end; procedure TIECropToolInteraction.Paint(const UpdateRect: TRect); begin if fState = iectisSELECTED then Draw(GetParent().GetCanvas()); end; procedure TIECropToolInteraction.Draw(Canvas: TCanvas); var g: TIECropToolInteractionState; i: integer; poly: array [0..3] of TPoint; halfGSize: double; begin if fState <> iectisUNSELECTED then begin if fState = iectisSELECTED then begin // update fScreenPolygon because Zoom or Pan may be changed UpdateScreenPolygon(); end; // calc rotated polygon fRotatedPolygon := copy(fScreenPolygon, 0, length(fScreenPolygon)); IEDRotatePoints(fRotatedPolygon, fRotation); // calc grips coordinates halfGSize := fGripSize / 2.0; i := 0; for g := iectisTOP_LEFT_SIZE to iectisLEFT_SIZE do begin case g of iectisTOP_LEFT_SIZE, iectisTOP_RIGHT_SIZE, iectisBOTTOM_RIGHT_SIZE, iectisBOTTOM_LEFT_SIZE: begin fGripRects[g][0] := Point(trunc(fRotatedPolygon[i].X - fGripSize / 2.0), trunc(fRotatedPolygon[i].Y - halfGSize)); fGripRects[g][1] := Point(trunc(fRotatedPolygon[i].X + fGripSize / 2.0), trunc(fRotatedPolygon[i].Y + halfGSize)); end; iectisTOP_SIZE, iectisRIGHT_SIZE, iectisBOTTOM_SIZE, iectisLEFT_SIZE: begin fGripRects[g][0].X := trunc((fRotatedPolygon[i].X + fRotatedPolygon[(i + 1) mod 4].X) / 2.0 - halfGSize); fGripRects[g][0].Y := trunc((fRotatedPolygon[i].Y + fRotatedPolygon[(i + 1) mod 4].Y) / 2.0 - halfGSize); fGripRects[g][1].X := trunc((fRotatedPolygon[i].X + fRotatedPolygon[(i + 1) mod 4].X) / 2.0 + halfGSize); fGripRects[g][1].Y := trunc((fRotatedPolygon[i].Y + fRotatedPolygon[(i + 1) mod 4].Y) / 2.0 + halfGSize); inc(i); end; end; end; //// drawings Canvas.Brush.Style := bsClear; Canvas.Pen.Mode := pmNot; Canvas.Pen.Color := clWhite; Canvas.Pen.Style := psSolid; Canvas.Pen.Width := 2; // grips for g := iectisTOP_LEFT_SIZE to iectisLEFT_SIZE do Canvas.Rectangle(fGripRects[g][0].X, fGripRects[g][0].Y, fGripRects[g][1].X, fGripRects[g][1].Y); Canvas.Pen.Style := psDash; Canvas.Pen.Width := 1; // main polygon for i := 0 to high(fRotatedPolygon) do poly[i] := Point(trunc(fRotatedPolygon[i].X), trunc(fRotatedPolygon[i].Y)); Canvas.Polygon(poly); if fDrawGuides then begin // vertical 1/3 guide Canvas.MoveTo(trunc((2 * fRotatedPolygon[0].X + fRotatedPolygon[1].X) / 3), trunc((2 * fRotatedPolygon[0].Y + fRotatedPolygon[1].Y) / 3)); Canvas.LineTo(trunc((2 * fRotatedPolygon[3].X + fRotatedPolygon[2].X) / 3), trunc((2 * fRotatedPolygon[3].Y + fRotatedPolygon[2].Y) / 3)); // vertical 2/3 guide Canvas.MoveTo(trunc((fRotatedPolygon[0].X + 2 * fRotatedPolygon[1].X) / 3), trunc((fRotatedPolygon[0].Y + 2 * fRotatedPolygon[1].Y) / 3)); Canvas.LineTo(trunc((fRotatedPolygon[3].X + 2 * fRotatedPolygon[2].X) / 3), trunc((fRotatedPolygon[3].Y + 2 * fRotatedPolygon[2].Y) / 3)); // horizontal 1/3 guide Canvas.MoveTo(trunc((2 * fRotatedPolygon[0].X + fRotatedPolygon[3].X) / 3), trunc((2 * fRotatedPolygon[0].Y + fRotatedPolygon[3].Y) / 3)); Canvas.LineTo(trunc((2 * fRotatedPolygon[1].X + fRotatedPolygon[2].X) / 3), trunc((2 * fRotatedPolygon[1].Y + fRotatedPolygon[2].Y) / 3)); // horizontal 2/3 guide Canvas.MoveTo(trunc((fRotatedPolygon[0].X + 2 * fRotatedPolygon[3].X) / 3), trunc((fRotatedPolygon[0].Y + 2 * fRotatedPolygon[3].Y) / 3)); Canvas.LineTo(trunc((fRotatedPolygon[1].X + 2 * fRotatedPolygon[2].X) / 3), trunc((fRotatedPolygon[1].Y + 2 * fRotatedPolygon[2].Y) / 3)); end; end; end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TIECreateLayerInteraction constructor TIECreateLayerInteraction.Create(Parent: TImageEnView); begin inherited Create(Parent); fLockAspectRatio := -1; fLockWidth := 0; fLockHeight := 0; fCreatingRect := False; end; function TIECreateLayerInteraction.MouseDownExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; begin Result := False; fCreatingRect := False; if ( Button <> mbLeft ) or // Cursor is over a grip (( miResizeLayers in GetParent().fMouseInteract ) and ( GetParent().FindLayerGripAnySel( X, Y, True ) <> ieNone )) or // Cursor is over another layer (( miMoveLayers in GetParent().fMouseInteract ) and ( GetParent().FindLayerAt( X, Y ) > -1 )) then exit; {$ifdef IEDEBUG} OutputDebugString( PWideChar( Format( 'No object at %d, %d, ', [ X, Y ]))); {$endif} fMouseDownCoords := Point(X, Y); fCreatingRect := True; fScreenPt1 := IE2DPoint(X, Y); fScreenPt2 := IE2DPoint(X, Y); {$IFNDEF IEIncludeDeprecatedInV6} // Avoid exceptions due to invalid layer index in older ImageEn versions GetParent().DoLayerNotify( -1, ielBeginCreating ); {$ENDIF} Result := True; end; procedure TIECreateLayerInteraction.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin { // } end; function TIECreateLayerInteraction.MouseMoveExclusive(Shift: TShiftState; X, Y: Integer; Captured: boolean): boolean; {} procedure _UpdatePolySize(HAlign: TIEHAlign; VAlign: TIEVAlign); const Size_Locks_Are_Minimums = False; var dx, dy: Integer; begin if ( fLockAspectRatio <= 0 ) or Size_Locks_Are_Minimums then begin dx := round( fLockWidth * GetParent().ZoomX / 100.0 ); dy := round( fLockHeight * GetParent().ZoomY / 100.0 ); if fLockWidth > 0 then if ( Size_Locks_Are_Minimums = False ) or ( abs( fScreenPt2.X - fScreenPt1.X ) < dx ) then case HAlign of iehLeft : fScreenPt2.X := fScreenPt1.X + dx; iehRight : fScreenPt1.X := fScreenPt2.X - dx; end; if fLockHeight > 0 then if ( Size_Locks_Are_Minimums = False ) or ( abs( fScreenPt2.Y - fScreenPt1.Y ) < dy ) then case VAlign of ievTop : fScreenPt2.Y := fScreenPt1.Y + dy; ievBottom : fScreenPt1.Y := fScreenPt2.Y - dy; end; end; end; {} var HAlign: TIEHAlign; VAlign: TIEVAlign; newPosX, newPosY, newWidth, newHeight: Double; begin result := false; if fCreatingRect = False then exit; if Captured then begin // Creating Layer fScreenPt2 := IE2DPoint(X, Y); HAlign := iehLeft; if X < fScreenPt1.X then HAlign := iehRight; VAlign := ievTop; if Y < fScreenPt1.Y then VAlign := ievBottom; _UpdatePolySize( HAlign, VAlign ); {$IFNDEF IEIncludeDeprecatedInV6} // Avoid exceptions due to invalid layer index in older ImageEn versions GetParent().DoLayerNotify( -1, ielCreating ); {$ENDIF} if assigned( GetParent().fOnLayerMoveSize ) then begin newPosX := SelX; newPosY := SelY; newWidth := SelWidth; newHeight := SelHeight; GetParent().fOnLayerMoveSize( Self, -1, ielCreating, newPosX, newPosY, newWidth, newHeight ); SetSel( Round( newPosX ), Round( newPosY ), Round( newWidth ), Round( newHeight )); end; if ( SelWidth > 0 ) and ( SelHeight > 0 ) then GetParent().SetInteractionHint( IntToStr( SelWidth ) + ' x ' + IntToStr( SelHeight ), X, Y, '0000 x 0000' ); Refresh(); end; result := true; end; procedure TIECreateLayerInteraction.MouseMove(Shift: TShiftState; X, Y: Integer; Captured: boolean); begin { // } end; function TIECreateLayerInteraction.MouseUpExclusive(Button: TMouseButton; Shift: TShiftState; X, Y: Integer): boolean; begin result := false; end; procedure TIECreateLayerInteraction.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if fCreatingRect then Enact(); end; procedure TIECreateLayerInteraction.VirtualKey(VKey: Dword; KeyData: Dword; KeyDown: Boolean); begin if KeyDown then begin case VKey of VK_ESCAPE: Cancel(); end; end; end; procedure TIECreateLayerInteraction.Paint(const UpdateRect: TRect); begin { // } end; procedure TIECreateLayerInteraction.Draw(Canvas: TCanvas); begin if fCreatingRect = False then exit; Canvas.Brush.Style := bsClear; Canvas.Pen.Mode := pmNot; Canvas.Pen.Color := clWhite; Canvas.Pen.Style := psDash; Canvas.Pen.Width := 1; Canvas.Rectangle( Rect( trunc( fScreenPt1.X ), trunc( fScreenPt1.Y ), trunc( fScreenPt2.X ), trunc( fScreenPt2.Y ))); end; procedure TIECreateLayerInteraction.Cancel(); begin fCreatingRect := False; Refresh(); RestoreCursor; end; procedure TIECreateLayerInteraction.Enact(); const Minimum_Size = 5; var doSaveUndo: Boolean; imgFilename: WideString; begin if ( fCreatingRect = False ) or ( SelWidth < Minimum_Size ) or ( SelHeight < Minimum_Size ) then exit; imgFilename := ''; if ( fLayerKind = ielkImage ) and ( loAutoPromptForImage in GetParent().LayerOptions ) then begin imgFilename := GetParent().IO.ExecuteOpenDialog(''); if imgFilename = '' then exit; end; doSaveUndo := GetParent().Proc.AutoUndo and ( loAutoUndoChangesByUser in GetParent().fLayerOptions ); GetParent().LayersAddEx( fLayerKind, SelX, SelY, SelWidth, SelHeight, nil, True, doSaveUndo, True ); if imgFilename <> '' then begin GetParent().IO.LoadFromFile( imgFilename ); TIEImageLayer( GetParent().CurrentLayer ).RestoreAspectRatio(); end; if assigned( GetParent().fOnNewLayer ) then GetParent().fOnNewLayer( GetParent(), GetParent().LayersCurrent, fLayerKind ); GetParent().DoLayerNotify( GetParent().fLayersCurrent, ielCreated ); Cancel(); end; function TIECreateLayerInteraction.GetSelX(): Integer; begin result := GetParent().XScr2Bmp( Round( dmin( fScreenPt1.X, fScreenPt2.X )), False ); end; function TIECreateLayerInteraction.GetSelY(): Integer; begin result := GetParent().YScr2Bmp( Round( dmin( fScreenPt1.Y, fScreenPt2.Y )), False ); end; function TIECreateLayerInteraction.GetSelWidth(): Integer; begin result := Abs( GetParent().XScr2Bmp( Round( fScreenPt2.X ), False ) - GetParent().XScr2Bmp( Round( fScreenPt1.X ), False )); end; function TIECreateLayerInteraction.GetSelHeight(): Integer; begin result := Abs( GetParent().YScr2Bmp( Round( fScreenPt2.Y ), False ) - GetParent().YScr2Bmp( Round( fScreenPt1.Y ), False )); end; procedure TIECreateLayerInteraction.SetSel(X, Y, Width, Height: Integer); var reverseX, reverseY: Boolean; begin reverseX := fScreenPt1.X > fScreenPt2.X; reverseY := fScreenPt1.Y > fScreenPt2.Y; fScreenPt1.X := GetParent().XBmp2Scr( X, False ); fScreenPt1.Y := GetParent().YBmp2Scr( Y, False ); fScreenPt2.X := GetParent().XBmp2Scr( X + Width, False ); fScreenPt2.Y := GetParent().YBmp2Scr( Y + Height, False ); if reverseX then IESwap( fScreenPt1.X, fScreenPt2.X ); if reverseY then IESwap( fScreenPt1.Y, fScreenPt2.Y ); end; procedure TIECreateLayerInteraction.Refresh(); begin GetParent().Paint(); Draw(GetParent().GetCanvas()); end; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// end.