23703 lines
764 KiB
Plaintext
23703 lines
764 KiB
Plaintext
(* 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
|
||
|
||
{!!
|
||
<FS>TIEGrip
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEGrip = (ieNone, ieTopLeft, ieTopRight, ieBottomRight, ieBottomLeft, ieLeftSide, ieRightSide, ieTopSide, ieBottomSide, ieRotationCenter);
|
||
{!!}
|
||
|
||
{!!
|
||
<FS>TIEFastDrawing
|
||
|
||
<FM>Declaration<FC>
|
||
TIEFastDrawing = (iefFast, iefDelayed, iefNormal);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Item</H> <H>Description</H> </R>
|
||
<R> <C><FC>iefFast<FN></C> <C>Layer draw quality is reduced to speed up display (only affects drawing)</C> </R>
|
||
<R> <C><FC>iefDelayed<FN></C> <C>Fast drawing (iefFast) is used while rotating, moving or resizing layers. After a delay, layers are then drawn at normal quality (iefNormal)</C> </R>
|
||
<R> <C><FC>iefNormal<FN></C> <C>Layers are drawn at normal quality</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEFastDrawing = (iefFast, iefDelayed, iefNormal);
|
||
|
||
|
||
{!!
|
||
<FS>TIEGridKind
|
||
|
||
<FM>Declaration<FC>
|
||
TIEGridKind = (iedgNone, iedgPixelGrid, iedgGuideLines);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Item</H> <H>Description</H> </R>
|
||
<R> <C><FC>iedgNone<FN></C> <C>No guide lines are shown</C> </R>
|
||
<R> <C><FC>iedgPixelGrid<FN></C> <C>A grid is shown marking each pixel when the image is zoomed in (e.g. for pixel editing in an image editor)</C> </R>
|
||
<R> <C><FC>iedgGuideLines<FN></C> <C>Guide lines are shown horizontally and vertically over the image (e.g. to help align objects when rotating)</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
|
||
TIEGridKind = (iedgNone, iedgPixelGrid, iedgGuideLines);
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIEAlignLayers
|
||
|
||
<FM>Declaration<FC>
|
||
TIEAlignLayers = (ilaAlignToLeft, ilaAlignToRight, ilaAlignToTop, ilaAlignToBottom, ilaAlignToHorizontalCenter, ilaAlignToVerticalCenter,
|
||
ilaAlignLeftEdges, ilaAlignRightEdges, ilaAlignTopEdges, ilaAlignBottomEdges, ilaAlignHorizontalCenters, ilaAlignVerticalCenters,
|
||
ilaMatchWidth, ilaMatchHeight);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Item</H> <H>Description</H> </R>
|
||
<R> <C><FC>ilaAlignToLeft<FN></C> <C>Align selected layers to the left side of the image</C> </R>
|
||
<R> <C><FC>ilaAlignToRight<FN></C> <C>Align selected layers to the right side of the image</C> </R>
|
||
<R> <C><FC>ilaAlignToTop<FN></C> <C>Align selected layers to the top of the image</C> </R>
|
||
<R> <C><FC>ilaAlignToBottom<FN></C> <C>Align selected layers to the bottom of the image</C> </R>
|
||
<R> <C><FC>ilaAlignToHorizontalCenter<FN></C> <C>Align selected layers along the horizon of the image</C> </R>
|
||
<R> <C><FC>ilaAlignToVerticalCenter<FN></C> <C>Align selected layers to the vertical center of the image</C> </R>
|
||
<R> <C><FC>ilaAlignLeftEdges<FN></C> <C>Align selected layers to the edge of the left-most layer</C> </R>
|
||
<R> <C><FC>ilaAlignRightEdges<FN></C> <C>Align selected layers to the edge of the right-most layer</C> </R>
|
||
<R> <C><FC>ilaAlignTopEdges<FN></C> <C>Align selected layers to the edge of the top-most layer</C> </R>
|
||
<R> <C><FC>ilaAlignBottomEdges<FN></C> <C>Align selected layers to the edge of the bottom-most layer</C> </R>
|
||
<R> <C><FC>ilaAlignHorizontalCenters<FN></C> <C>Align selected layers to have the same horizontal center</C> </R>
|
||
<R> <C><FC>ilaAlignVerticalCenters<FN></C> <C>Align selected layers to have the same vertical center</C> </R>
|
||
<R> <C><FC>ilaMatchWidth<FN></C> <C>Resize all selected layers to the width of the widest layer</C> </R>
|
||
<R> <C><FC>ilaMatchHeight<FN></C> <C>Resize all selected layers to the height of the tallest layer</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
|
||
TIEAlignLayers = (ilaAlignToLeft, ilaAlignToRight, ilaAlignToTop, ilaAlignToBottom, ilaAlignToHorizontalCenter, ilaAlignToVerticalCenter,
|
||
ilaAlignLeftEdges, ilaAlignRightEdges, ilaAlignTopEdges, ilaAlignBottomEdges, ilaAlignHorizontalCenters, ilaAlignVerticalCenters,
|
||
ilaMatchWidth, ilaMatchHeight);
|
||
|
||
|
||
{!!
|
||
<FS>TIELayerOptions
|
||
|
||
<FM>Declaration<FC>
|
||
TIELayerOptions = set of (loAllowMultiSelect, loAutoSelectMask, loAutoUndoChangesByUser, loAutoUndoChangesByCode, loAutoPromptForImage, loFitToLayersWhenZooming, loAutoFixBorders, loAutoFixRotation, loDynamicCanvas);
|
||
|
||
<FM>Description<FN>
|
||
Options to control layer behavior:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>loAllowMultiSelect</C> <C>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</C> </R>
|
||
<R> <C>loAutoSelectMask</C> <C>If you have enabled a <A TIEImageLayer.IsMask>mask</L> 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)</C> </R>
|
||
<R> <C>loAutoUndoChangesByUser</C> <C>If you have enabled <A TImageEnProc.AutoUndo>, then changes to layers made by users (using <L TImageEnView.MouseInteract>layer interactions<L> or <L TImageEnView Actions>layer TActions<L>) will be saved to the undo stack</C> </R>
|
||
<R> <C>loAutoUndoChangesByCode</C> <C>If you have enabled <A TImageEnProc.AutoUndo>, then programmatic changes to layers will be saved to the undo stack. This applies to the methods: <A TImageEnView.LayersAdd>, <A TImageEnView.LayersInsert>, <A TImageEnView.LayersCreateFromSelection>, <A TImageEnView.LayersCreateFromFile>, <A TImageEnView.LayersCreateFromEdge>, <A TImageEnView.LayersCreateFromAlpha>, <A TImageEnView.LayersRemove>, <A TImageEnView.LayersMerge>, <A TImageEnView.LayersMergeAll>, <A TImageEnView.LayersAlign>, <A TImageEnView.LayersMove>, <A TImageEnView.LayersRotateAll>, <A TImageEnView.LayersGroup>, <A TImageEnView.LayersUngroup>, <A TImageEnView.LayersCropBackground> </C> </R>
|
||
<R> <C>loAutoPromptForImage</C> <C>When setting <A TImageEnView.MouseInteract> to <FC>miCreateImageLayers<FN>, the user can drag select to create an <A TIEImageLayer> If <FC>loAutoPromptForImage<FN> 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.</C> </R>
|
||
<R> <C>loAutoFixBorders</C> <C>If enabled, <A TImageEnView.LayersFixBorders> will be called prior to rotation to removes any transparency around the edges of the image.</C> </R>
|
||
<R> <C>loAutoFixRotation</C> <C>If enabled, <A TImageEnView.LayersFixRotations> will be called after rotation to lock in the rotation angle of image layers.</C> </R>
|
||
<R> <C>loDynamicCanvas</C> <C>If enabled, ImageEn will align the view to the bounds of all layers (i.e. by <A TImageEnView.LayersRect>). 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 <A TImageEnView.Center>=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.</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Examples<FC>
|
||
// 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
|
||
);
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TViewChangeEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TViewChangeEvent = procedure(Sender: TObject; Change: integer) of object;
|
||
|
||
<FM>Description<FN>
|
||
If Change = 0 the event is <A TImageEnView.ViewX> or <A TImageEnView.ViewY> modification.
|
||
If Change = 1 the event is <A TImageEnView.Zoom> modification.
|
||
|
||
Note: Zoom could also modify ViewX/Y.
|
||
|
||
!!}
|
||
TViewChangeEvent = procedure(Sender: TObject; Change: integer) of object;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIEMediaFoundationNotifyEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIEMediaFoundationNotifyEvent = procedure(Sender: TObject; MediaFoundationObject: TObject; NotifyType: <A TIEMediaFountationNotifyType>) of object;
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Sender<FN></C> <C>Sender object. For <A TImageEnView.OnMediaFoundationNotify> this is a <A TImageEnView> object</C> </R>
|
||
<R> <C><FC>MediaFoundationObject<FN></C> <C>Media foundation object. This could be a <A TIEMediaFoundationSourceReader> object</C> </R>
|
||
<R> <C><FC>NotifyType<FN></C> <C>Notification type</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEMediaFoundationNotifyEvent = procedure(Sender: TObject; MediaFoundationObject: TObject; NotifyType: TIEMediaFountationNotifyType) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TIETextEditorEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIETextEditorEvent = procedure(Sender: TObject; Layer: integer; Editor: TObject) of object;
|
||
|
||
<FM>Description<FN>
|
||
<FC>Layer<FN> is the index of the layer being edited.
|
||
<FC>Editor<FN> is a <A TIEEdit>, which handles the editing operation for a <A TIETextLayer> or <A TIELineLayer>.
|
||
!!}
|
||
TIETextEditorEvent = procedure(Sender: TObject; Layer: integer; Editor: TObject) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TIESmoothTask
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIESmoothTask = (iestScroll, iestZoom);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEFinishSmoothTaskEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIEFinishSmoothTaskEvent = procedure(Sender: TObject; Task: <A TIESmoothTask>) of object;
|
||
|
||
<FM>Description<FN>
|
||
Event called when a smooth task has finished (smooth scroll, smooth zoom, etc...).
|
||
!!}
|
||
TIEFinishSmoothTaskEvent = procedure(Sender: TObject; Task: TIESmoothTask) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TViewChangingEvent
|
||
|
||
<FM>Declaration<FC>
|
||
type TViewChangingEvent = procedure(Sender: TObject; Change: integer; newValue: Double) of object;
|
||
|
||
<FM>Description<FN>
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Change<FN> = 0<FN></C> <C><A TImageEnView.ViewX> modification.</C> </R>
|
||
<R> <C><FC>Change<FN> = 1<FN></C> <C><A TImageEnView.ViewY> modification.</C> </R>
|
||
<R> <C><FC>Change<FN> = 2<FN></C> <C><A TImageEnView.Zoom> modification.</C> </R>
|
||
</TABLE>
|
||
|
||
<FC>newValue<FN> contains the new value that will be set.
|
||
|
||
Note: <FC>Zoom<FN> could also modify <FC>ViewX/Y<FN>.
|
||
!!}
|
||
TViewChangingEvent = procedure(Sender: TObject; Change: integer; newValue: double) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TIEMouseInResizingGripEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIEMouseInResizingGripEvent = procedure(Sender: TObject; Grip: <A TIEGrip>) of object;
|
||
!!}
|
||
TIEMouseInResizingGripEvent = procedure(Sender: TObject; Grip: TIEGrip) of object;
|
||
|
||
{!!
|
||
<FS>TIEZoomEvent
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEZoomEvent = procedure(Sender: TObject; var NewZoom: double) of object;
|
||
{!!}
|
||
|
||
{!!
|
||
<FS>TIESpecialKeyEvent
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIESpecialKeyEvent = procedure(Sender: TObject; CharCode: word; Shift: TShiftState; var Handled: Boolean) of object;
|
||
{!!}
|
||
|
||
TIEScrollCommand = (iescPosition, iescBottom, iescTop, iescLineDown, iescLineUp, iescPageDown, iescPageUp);
|
||
|
||
|
||
{!!
|
||
<FS>TIEOnDrawCanvas
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEOnDrawCanvas = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect) of object;
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEOnDrawBackground
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEOnDrawBackground = procedure(Sender: TObject; ACanvas: TCanvas; ARect: TRect; var Handled: boolean) of object;
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEOnDrawPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEOnDrawPolygon = procedure(Sender: TObject; polygon: Integer; point: Integer; Canvas: TCanvas; x, y: Integer) of object;
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEWallpaperStyle
|
||
|
||
<FM>Declaration<FC>
|
||
TIEWallpaperStyle = (iewoNormal, iewoStretch, iewoTile);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iewoNormal</C> <C>Draw the wallpaper image at the top left</C> </R>
|
||
<R> <C>iewoStretch</C> <C>Stretch the wallpaper to the ImageEnView size</C> </R>
|
||
<R> <C>iewoTile</C> <C>Tile the wallpaper over the background</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// Tile a bitmap over the background
|
||
ImageEnView1.WallpaperStyle := iewoTile;
|
||
ImageEnView1.Wallpaper.LoadFromFile('D:\MyWallpaper.bmp');
|
||
!!}
|
||
TIEWallpaperStyle = (iewoNormal, iewoStretch, iewoTile);
|
||
|
||
{!!
|
||
<FS>TIEMouseInteractItems
|
||
|
||
<FM>Declaration<FC>
|
||
TIEMouseInteractItems = (miZoom, miScroll, miSelect, miSelectPolygon, miSelectCircle, miSelectZoom, miSelectMagicWand, miSelectLasso, miMoveLayers, miResizeLayers, miRotateLayers, miMovingScroll, miCropTool, miCreateImageLayers, miCreateShapeLayers, miCreateLineLayers, miCreatePolylineLayers, miCreateTextLayers);
|
||
|
||
<FM>Description<FN>
|
||
What actions does the mouse perform:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>miZoom</C> <C>A left mouse click zooms into the image. A right click zooms out</C> </R>
|
||
<R> <C>miScroll</C> <C>The image can be navigated by clicking with the left mouse button and dragging</C> </R>
|
||
<R> <C>miSelect</C> <C>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</C> </R>
|
||
<R> <C>miSelectZoom</C> <C>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</C> </R>
|
||
<R> <C>miSelectPolygon</C> <C>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 <A TImageEnView.SelectionOptions></C> </R>
|
||
<R> <C>miSelectCircle</C> <C>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</C> </R>
|
||
<R> <C>miSelectMagicWand</C> <C>Selects an irregular region of similar colors. Click the left mouse button upon a pixel and similar colors surrounding it are selected (see <A TImageEnView.MagicWandTolerance>). Simultaneously holding down the Shift key allows the selection of multiple regions</C> </R>
|
||
<R> <C>miSelectLasso</C> <C>A polygonal area can be selected by continous movement. Click the left button and move the mouse to select a continuous irregular region</C> </R>
|
||
<R> <C>miMoveLayers</C> <C>User can move layers</C> </R>
|
||
<R> <C>miResizeLayers</C> <C>User can resize layers using grips</C> </R>
|
||
<R> <C>miRotateLayers</C> <C>User can rotate layers using grips</C> </R>
|
||
<R> <C>miMovingScroll</C> <C>Moving the mouse over the image (without requiring any clicking) will cause the image to automatically scroll (pan) (see <A TImageEnView.SmoothScrollValue>)</C> </R>
|
||
<R> <C>miCropTool</C> <C> User can select a particular area of an image and discards the portions outside the chosen section (See <A TImageEnView.CropToolInteraction>)</C> </R>
|
||
<R> <C>miCreateImageLayers</C> <C>Click and move the mouse to create a <A TIEImageLayer> * </C> </R>
|
||
<R> <C>miCreateShapeLayers</C> <C>Click and move the mouse to create a <A TIEShapeLayer> * </C> </R>
|
||
<R> <C>miCreateLineLayers</C> <C>Click and move the mouse to create a <A TIELineLayer> * </C> </R>
|
||
<R> <C>miCreatePolylineLayers</C> <C>Click and move the mouse to create a <A TIEPolylineLayer> * </C> </R>
|
||
<R> <C>miCreateTextLayers</C> <C>Click and move the mouse to create a <A TIETextLayer> * </C> </R>
|
||
</TABLE>
|
||
* Note: If you are unable to create layers on the background, ensure that ImageEnView1.Layers[0].<A TIELayer.Selectable> = False.
|
||
|
||
<FM>Examples<FC>
|
||
// 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:
|
||
<IMG help_images\text_Selected.gif>
|
||
|
||
// 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 ];
|
||
|
||
<IMG help_images\Selection.gif>
|
||
|
||
// 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' );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectionOptions>
|
||
- <A TImageEnView.LayerDefaults>
|
||
!!}
|
||
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
|
||
);
|
||
|
||
|
||
{!!
|
||
<FS>TIEMouseInteract
|
||
|
||
<FM>Declaration<FC>
|
||
type TIEMouseInteract = set of <A TIEMouseInteractItems>;
|
||
!!}
|
||
TIEMouseInteract = set of TIEMouseInteractItems;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions
|
||
|
||
<FM>Description<FN>
|
||
Options for ImageEn gesture support.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Inertia></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Multiplier></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapValues></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapDelta></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
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
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions.Enabled
|
||
|
||
<FM>Declaration<FC>
|
||
property Enabled: boolean;
|
||
|
||
<FM>Description<FN>
|
||
Enables/disables the gesture.
|
||
!!}
|
||
property Enabled: boolean read fEnabled write SetEnabled;
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions.Inertia
|
||
|
||
<FM>Declaration<FC>
|
||
property Inertia: boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions.Multiplier
|
||
|
||
<FM>Declaration<FC>
|
||
property Multiplier: double;
|
||
|
||
<FM>Description<FN>
|
||
Specifies a multiplier for the controlled viewer property.
|
||
!!}
|
||
property Multiplier: double read fMultiplier write fMultiplier;
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions.SnapValues
|
||
|
||
<FM>Declaration<FC>
|
||
property SnapValues: boolean;
|
||
|
||
<FM>Description<FN>
|
||
If enabled, then values will change only in amounts specified by the <A TIEGestureOptions.SnapDelta>. For example, when performing a small rotation of less than a <A TIEGestureOptions.SnapDelta> of 90 degrees, it will "snap" to 90.
|
||
!!}
|
||
property SnapValues: boolean read fSnapValues write fSnapValues;
|
||
|
||
{!!
|
||
<FS>TIEGestureOptions.SnapDelta
|
||
|
||
<FM>Declaration<FC>
|
||
property SnapDelta: double;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the amount to snap values by when <A TIEGestureOptions.SnapValues> is enabled.
|
||
!!}
|
||
property SnapDelta: double read fSnapDelta write fSnapDelta;
|
||
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIEGesturePanOptions
|
||
|
||
<FM>Description<FN>
|
||
Specify options for the Zoom gesture.
|
||
|
||
Note: Inherites from the <A TIEGestureOptions> class.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGesturePanOptions.BoundingBox> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Inertia></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Multiplier></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGesturePanOptions.PanWithSingleFingerHorizontally></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGesturePanOptions.PanWithSingleFingerVertically></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapValues></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapDelta></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEGesturePanOptions = class(TIEGestureOptions)
|
||
private
|
||
fBoundingBox: TRect;
|
||
fPanWithSingleFingerVertically: Boolean;
|
||
fPanWithSingleFingerHorizontally: Boolean;
|
||
|
||
public
|
||
|
||
{!!
|
||
<FS>TIEGesturePanOptions.BoundingBox
|
||
|
||
<FM>Declaration<FC>
|
||
property BoundingBox: TRect;
|
||
|
||
<FM>Description<FN>
|
||
Contains the minimum/maximum values for the left, top and right and bottom.
|
||
!!}
|
||
property BoundingBox: TRect read fBoundingBox write fBoundingBox;
|
||
|
||
{!!
|
||
<FS>TIEGesturePanOptions.PanWithSingleFingerVertically
|
||
|
||
<FM>Declaration<FC>
|
||
PanWithSingleFingerVertically: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Enables/disables vertical pans with one finger.
|
||
|
||
Default: True
|
||
!!}
|
||
property PanWithSingleFingerVertically: Boolean read fPanWithSingleFingerVertically write fPanWithSingleFingerVertically;
|
||
|
||
{!!
|
||
<FS>TIEGesturePanOptions.PanWithSingleFingerHorizontally
|
||
|
||
<FM>Declaration<FC>
|
||
property PanWithSingleFingerHorizontally: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Enables/disables horizontal pans with one finger.
|
||
|
||
Default: True
|
||
!!}
|
||
property PanWithSingleFingerHorizontally: Boolean read fPanWithSingleFingerHorizontally write fPanWithSingleFingerHorizontally;
|
||
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureZoomOptions
|
||
|
||
<FM>Description<FN>
|
||
Specifies options for the Zoom gesture.
|
||
|
||
Note: Inherites from the <A TIEGestureOptions> class.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureZoomOptions.Max> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureZoomOptions.Min> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Inertia></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Multiplier></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapValues></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapDelta></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEGestureZoomOptions = class(TIEGestureOptions)
|
||
private
|
||
fMax: double;
|
||
fMin: double;
|
||
|
||
public
|
||
|
||
{!!
|
||
<FS>TIEGestureZoomOptions.Max
|
||
|
||
<FM>Declaration<FC>
|
||
property Max: double;
|
||
|
||
<FM>Description<FN>
|
||
Specify the maximum allowed Zoom.
|
||
!!}
|
||
property Max: double read fMax write fMax;
|
||
|
||
{!!
|
||
<FS>TIEGestureZoomOptions.Min
|
||
|
||
<FM>Declaration<FC>
|
||
property Min: double;
|
||
|
||
<FM>Description<FN>
|
||
Specify the minimum allowed Zoom.
|
||
!!}
|
||
property Min: double read fMin write fMin;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureLayerMoveOptions
|
||
|
||
<FM>Description<FN>
|
||
Specifies options for the layer movement gesture.
|
||
|
||
Note: Inherites from the <A TIEGestureOptions> class.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureLayerMoveOptions.BoundingBox> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Inertia></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Multiplier></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapValues></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapDelta></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEGestureLayerMoveOptions = class(TIEGestureOptions)
|
||
private
|
||
fBoundingBox: TRect;
|
||
|
||
public
|
||
|
||
{!!
|
||
<FS>TIEGestureLayerMoveOptions.BoundingBox
|
||
|
||
<FM>Declaration<FC>
|
||
property BoundingBox: TRect;
|
||
|
||
<FM>Description<FN>
|
||
Contains the minimum/maximum values for the left, top and right and bottom.
|
||
!!}
|
||
property BoundingBox: TRect read fBoundingBox write fBoundingBox;
|
||
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureLayerRotateOptions
|
||
|
||
<FM>Description<FN>
|
||
Specifies options for the layer rotation gesture.
|
||
|
||
Note: Inherites from the <A TIEGestureOptions> class.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureLayerRotateOptions.Min> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureLayerRotateOptions.Max> <IMG help_images\Star.gif></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Inertia></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.Multiplier></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapValues></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEGestureOptions.SnapDelta></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEGestureLayerRotateOptions = class(TIEGestureOptions)
|
||
private
|
||
fMax: double;
|
||
fMin: double;
|
||
|
||
public
|
||
|
||
{!!
|
||
<FS>TIEGestureLayerRotateOptions.Max
|
||
|
||
<FM>Declaration<FC>
|
||
property Max: double;
|
||
|
||
<FM>Description<FN>
|
||
Specify the maximum allowed Zoom.
|
||
!!}
|
||
property Max: double read fMax write fMax;
|
||
|
||
{!!
|
||
<FS>TIEGestureLayerRotateOptions.Min
|
||
|
||
<FM>Declaration<FC>
|
||
property Min: double;
|
||
|
||
<FM>Description<FN>
|
||
Specify the minimum allowed Zoom.
|
||
!!}
|
||
property Min: double read fMin write fMin;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures
|
||
|
||
<FM>Description<FN>
|
||
TImageEnView supports native Windows gestures, allowing pan, zoom, layer rotation and movement.
|
||
|
||
This class contains the properties to configure the gestures.
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEViewerGestures.Enabled></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEViewerGestures.LayerMove></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEViewerGestures.LayerRotate></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEViewerGestures.Pan></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIEViewerGestures.Zoom></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEViewerGestures = class
|
||
private
|
||
fPan: TIEGesturePanOptions;
|
||
fZoom: TIEGestureZoomOptions;
|
||
fLayerRotate: TIEGestureLayerRotateOptions;
|
||
fLayerMove: TIEGestureLayerMoveOptions;
|
||
|
||
function GetEnabled(): boolean;
|
||
|
||
public
|
||
constructor Create();
|
||
destructor Destroy(); override;
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures.Enabled
|
||
|
||
<FM>Declaration<FC>
|
||
property Enabled: boolean; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns true whenever at least one gesture is enabled.
|
||
|
||
!!}
|
||
property Enabled: boolean read GetEnabled;
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures.Pan
|
||
|
||
<FM>Declaration<FC>
|
||
property Pan: <A TIEGesturePanOptions>;
|
||
|
||
<FM>Description<FN>
|
||
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 <L TIEViewerGestures.Pan>Pan</L> and <L TIEViewerGestures.LayerMove>layer movement</L> gestures are mutually exclusive (i.e. you cannot use both).
|
||
!!}
|
||
property Pan: TIEGesturePanOptions read fPan;
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures.Zoom
|
||
|
||
<FM>Declaration<FC>
|
||
property Zoom: <A TIEGestureZoomOptions>;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures.LayerRotate
|
||
|
||
<FM>Declaration<FC>
|
||
property LayerRotate: <A TIEGestureLayerRotateOptions>;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TIEViewerGestures.LayerMove
|
||
|
||
<FM>Declaration<FC>
|
||
property LayerMove: <A TIEGestureLayerMoveOptions>;
|
||
|
||
<FM>Description<FN>
|
||
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 <L TIEViewerGestures.Pan>Pan</L> and <L TIEViewerGestures.LayerMove>layer movement</L> gestures are mutually exclusive (i.e. you cannot use both).
|
||
!!}
|
||
property LayerMove: TIEGestureLayerMoveOptions read fLayerMove;
|
||
end;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIENavigatorOptions
|
||
|
||
<FM>Declaration<FC>
|
||
TIENavigatorOptions = set of (ienoMouseWheelZoom, ienoMarkOuter, ienoDontAssignNavBitmap, ienoDontPaintSrcBitmap, ienoDontRefreshSrcIfNavNotFocused);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C><FC>ienoMouseWheelZoom<FN></C> <C>Zoom is possible with mouse-wheel</C> </R>
|
||
<R> <C><FC>ienoMarkOuter<FN></C> <C>Marks as grayed non visible area</C> </R>
|
||
<R> <C><FC>ienoDontAssignNavBitmap<FN></C> <C>Doesn't assign automatically navigator bitmap</C> </R>
|
||
<R> <C><FC>ienoDontPaintSrcBitmap<FN></C> <C>Doesn't repaint source image on moving nav rect</C> </R>
|
||
<R> <C><FC>ienoDontRefreshSrcIfNavNotFocused<FN></C> <C>Doesn't refresh main viewer when navigator isn't focused</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIENavigatorOptions = set of (ienoMouseWheelZoom, ienoMarkOuter, ienoDontAssignNavBitmap, ienoDontPaintSrcBitmap, ienoDontRefreshSrcIfNavNotFocused);
|
||
|
||
|
||
{!!
|
||
<FS>TIESelectionBase
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
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)
|
||
);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIESelectionOptions
|
||
|
||
<FM>Declaration<FC>
|
||
TIESelectionOptions = set of (
|
||
iesoAnimated,
|
||
iesoSizeable,
|
||
iesoMoveable,
|
||
iesoFilled,
|
||
iesoCutBorders,
|
||
iesoMarkOuter,
|
||
iesoCanScroll,
|
||
iesoSelectTranspLayers,
|
||
iesoRightButtonSelectLayers,
|
||
iesoRightButtonTerminatePolySelect,
|
||
iesoDisableOneClickDeselect,
|
||
iesoDisableNewSelection,
|
||
iesoShowCenter,
|
||
iesoAutoTerminatePolySelect,
|
||
iesoAllowMoveByKeyboard);
|
||
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iesoAnimated</C> <C>Enable animation of the selection</C> </R>
|
||
<R> <C>iesoSizeable</C> <C>Allow the user to resize the selection (with grips)</C> </R>
|
||
<R> <C>iesoMoveable</C> <C>Allow the user to move the selection (with grips)</C> </R>
|
||
<R> <C>iesoFilled</C> <C>The image within the selection is displayed with inverted colors</C> </R>
|
||
<R> <C>iesoCutBorders</C> <C>The user is allowed to drag the selection outside the borders (the selection borders will be cut)</C> </R>
|
||
<R> <C>iesoMarkOuter</C> <C>Areas of the image outside the selection are shown as grayed or with alpha blending (see <A TImageEnView.SetSelectionMarkOuterStyle>)</C> </R>
|
||
<R> <C>iesoCanScroll</C> <C>Automatically scroll the image when selecting outside the visible area</C> </R>
|
||
<R> <C>iesoSelectTranspLayers</C> <C>Allow transparent areas of a layer to be selectable</C> </R>
|
||
<R> <C>iesoRightButtonSelectLayers</C> <C>Allow selection of layers with the right button (other than left button)</C> </R>
|
||
<R> <C>iesoRightButtonTerminatePolySelect</C> <C>Allow <L TImageEnView.MouseInteract>polygon selection</L> to be cancelled with the right mouse button</C> </R>
|
||
<R> <C>iesoDisableOneClickDeselect</C> <C>Prevent the selection from being cleared when clicking outside the selection</C> </R>
|
||
<R> <C>iesoDisableNewSelection</C> <C>Once a selection has been made (programatically using <A TImageEnView.Select> or by the user using <A TImageEnView.MouseInteract>) then the user cannot make a new selection (though they can still move or resize the selection if iesoSizeable or iesoMoveable is specified)</C> </R>
|
||
<R> <C>iesoShowCenter</C> <C>A cross shows the center of the rectangle, circle or polygon while making a selection</C> </R>
|
||
<R> <C>iesoAutoTerminatePolySelect</C> <C><L TImageEnView.MouseInteract>Polygon selection</L> will be automatically cancelled when the user clicks close to the start of the selection (i.e. closes the polygon)</C> </R>
|
||
<R> <C>iesoAllowMoveByKeyboard</C> <C>Allow rectangular selections and layers to be moved by the cursor keys (Hold Ctrl key to resize selections. Hold Shift to speed up movement)</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIESelectionOptions = set of (
|
||
iesoAnimated,
|
||
iesoSizeable,
|
||
iesoMoveable,
|
||
iesoFilled,
|
||
iesoCutBorders,
|
||
iesoMarkOuter,
|
||
iesoCanScroll,
|
||
iesoSelectTranspLayers,
|
||
iesoRightButtonSelectLayers,
|
||
iesoRightButtonTerminatePolySelect,
|
||
iesoDisableOneClickDeselect,
|
||
iesoDisableNewSelection,
|
||
iesoShowCenter,
|
||
iesoAutoTerminatePolySelect,
|
||
iesoAllowMoveByKeyboard
|
||
);
|
||
|
||
{!!
|
||
<FS>TIESelOp
|
||
|
||
<FM>Declaration<FC>
|
||
TIESelOp = (iespReplace, iespAdd);
|
||
|
||
<FM>Description<FN>
|
||
iespReplace: replaces all previous selections.
|
||
iespAdd: adds a new selection.
|
||
!!}
|
||
TIESelOp = (iespReplace, iespAdd);
|
||
|
||
{!!
|
||
<FS>TIEMagicWandMode
|
||
|
||
<FM>Declaration<FC>
|
||
TIEMagicWandMode=(iewInclusive, iewExclusive, iewGlobal);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iewInclusive</C> <C>the selection is a closed polygon</C> </R>
|
||
<R> <C>iewExclusive</C> <C>the selection includes only points that match the initial pixel, similar to a flood fill</C> </R>
|
||
<R> <C>iewGlobal</C> <C>the selection includes all points that match the initial pixel, examining all pixels of the image</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEMagicWandMode = (iewInclusive, iewExclusive, iewGlobal);
|
||
|
||
|
||
{!!
|
||
<FS>TIELayerEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIELayerEvent = (ielSelected, ielMoved, ielResized, ielMoving, ielResizing, ielRotating, ielRotated, ielBeginResizing, ielBeginMoving, ielDeselected, ielEdited, ielBeginCreating, ielCreating, ielCreated, ielAction);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>ielSelected</C> <C>User selected the layer</C> </R>
|
||
<R> <C>ielMoved</C> <C>User moved the layer</C> </R>
|
||
<R> <C>ielResized</C> <C>User resized the layer</C> </R>
|
||
<R> <C>ielMoving</C> <C>User is moving the layer</C> </R>
|
||
<R> <C>ielResizing</C> <C>User is resizing the layer</C> </R>
|
||
<R> <C>ielRotating</C> <C>User is rotating the layer</C> </R>
|
||
<R> <C>ielRotated</C> <C>User rotated the layer</C> </R>
|
||
<R> <C>ielBeginResizing</C> <C>User began to resize the layer (click down)</C> </R>
|
||
<R> <C>ielBeginMoving</C> <C>User began to move the layer (click down)</C> </R>
|
||
<R> <C>ielDeselected</C> <C>User deselected the layer</C> </R>
|
||
<R> <C>ielEdited</C> <C>User edited the text of a layer</C> </R>
|
||
<R> <C>ielBeginMoving</C> <C>User began creating a layer (click down)</C> </R>
|
||
<R> <C>ielCreating</C> <C>User is creating a layer</C> </R>
|
||
<R> <C>ielCreated</C> <C>User had created a new layer</C> </R>
|
||
<R> <C>ielAction</C> <C>User has used an <L TImageEnView Actions>ImageEn Action</L> that has changed the layers</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIELayerEvent = (ielSelected, ielMoved, ielResized, ielMoving, ielResizing, ielRotating, ielRotated, ielBeginResizing, ielBeginMoving, ielDeselected, ielEdited, ielBeginCreating, ielCreating, ielCreated, ielAction);
|
||
|
||
{!!
|
||
<FS>TIELayerNotify
|
||
|
||
<FM>Declaration<FC>
|
||
TIELayerNotify = procedure(Sender: TObject; layer: integer; event: <A TIELayerEvent>) of object;
|
||
|
||
<FM>Description<FN>
|
||
<FC>layer<FN> is the layer index that is selected, moved or resized.
|
||
<FC>event<FN> specifies the event type.
|
||
|
||
Notes:
|
||
- This event only occurs once for each change, even if <L TImageEnView.LayerOptions>multiple layers are selected</L>. 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, <FC>layer<FN> will return -1
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TIENewLayerEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIENewLayerEvent = procedure(Sender: TObject; LayerIdx: integer; LayerKind: <A TIELayerKind>) of object;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a layer is added. It is useful to assign default properties to the layer.
|
||
Both programmatic methods (e.g. using <A TImageEnView.LayersAdd>) and user methods (e.g. <L TImageEnView.MouseInteract>using miCreateShapeLayers</L>) trigger this event.
|
||
|
||
<FC>LayerIdx<FN> is the index of the new layer.
|
||
<FC>LayerKind<FN> is the kind of layer that was added.
|
||
|
||
Note: <A TImageEnView.CurrentLayer> will represent the new layer
|
||
|
||
<FM>Examples<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnNewLayer>
|
||
!!}
|
||
TIENewLayerEvent = procedure(Sender: TObject; LayerIdx: integer; LayerKind: TIELayerKind) of object;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIELayerMoveSizeEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIELayerMoveSizeEvent = procedure(Sender: TObject; layer: integer; event: <A TIELayerEvent>; var PosX, PosY, Width, Height: Double) of object;
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>layer</C> <C>The layer index that is moved or resized (it will be -1 for ielCreating).</C> </R>
|
||
<R> <C>event</C> <C>The event type (will be ielMoving, ielResizing or ielCreating).</C> </R>
|
||
<R> <C>PosX, PosY</C> <C>The new left and top position of the layer</C> </R>
|
||
<R> <C>Width, Height</C> <C>The new width and height of the layer</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TIEVirtualKeyEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIEVirtualKeyEvent = procedure(Sender: TObject; VirtualKey: Dword; KeyData: Dword) of object;
|
||
|
||
<FM>Description<FN>
|
||
Event type for <A TImageEnView.OnVirtualKey> event.
|
||
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>VirtualKey</C> <C>Specifies the virtual key code (the same as wParam of WM_KEYWODN, WM_KEYUP, WM_SYSKEYDOWN and WM_SYSKEYUP)</C> </R>
|
||
<R> <C>KeyData</C> <C>Specifies additional info about the key (the same as lParam of WM_KEYWODN, WM_KEYUP, WM_SYSKEYDOWN and WM_SYSKEYUP)</C> </R>
|
||
<R> <C>KeyDown</C> <C>This is true on keydown, false on keyup</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIEVirtualKeyEvent = procedure(Sender: TObject; VirtualKey: Dword; KeyData: Dword; KeyDown: Boolean) of object;
|
||
|
||
{!!
|
||
<FS>TIESetCursorEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIESetCursorEvent = procedure(Sender: TObject; var Cursor: TCursor) of object;
|
||
|
||
<FM>Description<FN>
|
||
Used by the <A TImageEnView.OnSetCursor> event.
|
||
!!}
|
||
TIESetCursorEvent = procedure(Sender: TObject; var Cursor: TCursor) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureFlags
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEGestureFlags = set of (iegfBegin, iegfInertia, iegfEnd);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEGestureID
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEGestureID = (iegiBegin, iegiEnd, iegiZoom, iegiPan, iegiRotate, iegiTwoFingerTap, iegiPressAndTap);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEImageEnGestureEvent
|
||
|
||
<FM>Declaration<FC>
|
||
TIEImageEnGestureEvent = procedure(Sender: TObject; Flags: <A TIEGestureFlags>; ID: <A TIEGestureID>; Location: TSmallPoint; Value: integer; InertiaX: integer; InertiaY: integer; PressAndTapDistance: integer; var Handled: boolean) of object;
|
||
|
||
<FM>Description<FN>
|
||
Used by the <A TImageEnView.OnImageEnGesture> event.
|
||
!!}
|
||
TIEImageEnGestureEvent = procedure(Sender: TObject; Flags: TIEGestureFlags; ID: TIEGestureID; Location: TSmallPoint; Value: integer; InertiaX: integer; InertiaY: integer; PressAndTapDistance: integer; var Handled: boolean) of object;
|
||
|
||
|
||
{!!
|
||
<FS>TIERSOptions
|
||
|
||
<FM>Declaration<FC>
|
||
TIERSOptions = (iersNone, iersMoveToAdapt, iersSyncLayers);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iersNone</C> <C>no adaption</C> </R>
|
||
<R> <C>iersMoveToAdapt</C> <C>move the selection to fit inside the new size</C> </R>
|
||
<R> <C>iersSyncLayers</C> <C>used to maintain the selection in the same position among layers</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIERSOptions = (iersNone, iersMoveToAdapt, iersSyncLayers);
|
||
|
||
{!!
|
||
<FS>TIESoftCropMode
|
||
|
||
<FM>Declaration<FC>
|
||
TIESoftCropMode = (iesfNone, iesfAlphaBlend, iesfGrid, iesfAdd);
|
||
|
||
<FM>Description<FN>
|
||
Portion of layers that are outside the background layer are shown as:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iesfNone</C> <C>Normal</C> </R>
|
||
<R> <C>iesfAlphaBlend</C> <C>Partially transparent (to the level specified by <A TImageEnView.SoftCropValue>)</C> </R>
|
||
<R> <C>iesfGrid</C> <C>Grayed (Grid matrix pattern)</C> </R>
|
||
<R> <C>iesfAdd</C> <C>Color shifted/washed out (to the level specified by <A TImageEnView.SoftCropValue>)</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIESoftCropMode = (iesfNone, iesfAlphaBlend, iesfGrid, iesfAdd);
|
||
|
||
|
||
{!!
|
||
<FS>TIEGripShape
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEGripShape = (iegsBox, iegsCircle);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIEUpdateReason
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIEUpdateReason = (ieurDefault, ieurScrolled, ieurZoomed, ieurSelectionChanged, ieurComponentStuffChanged);
|
||
{!!}
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIELayersResizeAspectRatio
|
||
|
||
<FM>Declaration<FC>
|
||
TIELayersResizeAspectRatio = (iearDisabled, iearALTKey, iearAlways, iearAlwaysOnCornerGrip, iearLayerDefaultOnCornerGrip);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iearDisabled</C> <C>Doesn't maintain the aspect ratio even when pressing ALT or setting <A TImageEnView.ForceALTKey>)</C> </R>
|
||
<R> <C>iearALTKey</C> <C>Maintains the aspect ratio only when pressing ALT or setting <A TImageEnView.ForceALTKey></C> </R>
|
||
<R> <C>iearAlways</C> <C>The aspect ratio is always maintained (using any grips)</C> </R>
|
||
<R> <C>iearAlwaysOnCornerGrip</C> <C>The aspect ratio is always maintained if the corner grips are used</C> </R>
|
||
<R> <C>iearLayerDefaultOnCornerGrip</C> <C>If the layer has a <L TIELayer.PreferredAspectRatio>preferred aspect ratio</L> then dragging the corner grip will maintain the aspect ratio, for side grips and other layer types the aspect ratio is not maintained</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
TIELayersResizeAspectRatio = (iearDisabled, iearALTKey, iearAlways, iearAlwaysOnCornerGrip, iearLayerDefaultOnCornerGrip);
|
||
|
||
TIECropToolInteraction = class; // forward declaration
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// TImageEnView
|
||
|
||
{!!
|
||
<FS>TImageEnView
|
||
|
||
<FM>Declaration<FC>
|
||
TImageEnView = class(<A TIEView>);
|
||
|
||
<FM>Description<FN>
|
||
TImageEnView is an image container, viewer and editor. It supports zooming, scrolling, selections and layers.
|
||
|
||
TImageEnView encapsulates a <A TImageEnIO> (<A TImageEnView.IO> property) for loading/saving/acquisition and a <A TImageEnProc> (<A TImageEnView.Proc> 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 <L TImageEnView Actions>actions</L> is also available.
|
||
|
||
|
||
<IMG help_images\IEView_Component.gif>
|
||
|
||
<FM>Example<FC>
|
||
// 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);
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<FI>Display<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.AutoShrink></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.AutoStretch></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.Center></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.CenterImage></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.DisplayGridKind></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.DisplayGridLyr></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.DelayTimer></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.DelayZoomFilter></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.DelayZoomTime></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ExtentX></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ExtentY></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Fit></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.FitToHeight></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.FitToWidth></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.GetIdealZoom></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.GetMaxViewXY></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.GetRenderRectangles></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IdealComponentHeight></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IdealComponentWidth></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IdealImageHeight></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IdealImageWidth></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ImageHorizAlignment></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ImageVertAlignment></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LockPaint></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LockPaintCount></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LockUpdate></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LockUpdateCount></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.OffScreenPaint></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.OffsetX></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.OffsetY></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.PaintRect></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.RulerParams></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetViewXY></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetViewXYSmooth></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetZoomSmooth></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.ShowRulers></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SmoothScrollValue></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SmoothZoomValue></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Stretch></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.UnLockPaint></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.UnLockUpdate></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.UnLockUpdateEx></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Update></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.UpdateNoPaint></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.UpdateReason></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.UpdateRect></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ViewX></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ViewY></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.VisibleBitmapRect></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.XBmp2Scr></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.XScr2Bmp></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.YBmp2Scr></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.YScr2Bmp></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Zoom></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ZoomAt></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ZoomIn></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.ZoomFilter></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ZoomOut></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ZoomSelection></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ZoomX></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ZoomY></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Background<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.BackgroundStyle></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.Background></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.GradientEndColor></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetChessboardStyle></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.WallpaperStyle></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.Wallpaper></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Scrollbars<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.FlatScrollBars></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.HScrollBarParams></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ScrollBarsAlwaysVisible></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.ScrollBars></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.VScrollBarParams></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Image Processing<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Proc></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Input/Output<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IO></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Bitmap<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Bitmap></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Blank></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ChangeResolution></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Clear></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ClearAll></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.CopyFromPolygon></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.CopyToPolygon></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.DrawTo></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IEBitmap></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.IsEmpty></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.IsEmpty2></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.LegacyBitmap></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetExternalBitmap></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetSelectedPixelsColor></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>User Actions<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.CropToolInteraction></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.EnableInteractionHints></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ForceALTkey> (Lock Aspect Ratio)</C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Gestures></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.MagicWandMaxFilter></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.MagicWandMode></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.MagicWandTolerance></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.MouseInteract></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.MouseScrollRate></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.MouseWheelParams></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetInteractionHint></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.ZoomSelectionAspectRatio></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Selections<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AddSelBreak></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AddSelPoint></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ApplyBitmapToSelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AssignSelTo></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.CopySelectionToBitmap></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.DelayDisplaySelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.DelLastSelPoint></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Deselect></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.DiscardSavedSelection></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.EnableShiftKey> (Multiple selections)</C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.EndSelect></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.GetSelectionGripStyle></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.InvertSelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.IsPointInsideSelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LoadSelectionFromFile></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LoadSelectionFromStream></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MakeSelectionFeather></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MergeSelectionFromFile></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MergeSelectionFromStream></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MoveSelection></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.PolySel></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.PolySelCount></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.PolySelPoints></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.RestoreSelection></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SavedSelectionsCount></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SaveSelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SaveSelectionToFile></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SaveSelectionToStream></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelColor1></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelColor2></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Select></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectColors></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectCustom></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectNonAlpha></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Selected></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectedRect></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectEllipse></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionAbsHeight></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionAbsWidth></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionAspectRatio></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.SelectionBase></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionGridHeight></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionGridSize></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionGridWidth></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionIntensity></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionMask></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelectionMaskDepth></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.SelectionOptions></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectMagicWand></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SelectRoundRect></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelX1></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelX2></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelY1></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SelY2></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetSelectionGripStyle></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetSelectionMarkOuterStyle></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.VisibleSelection></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Alpha Channel (Transparency)<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.AlphaChannel></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.CopyToBitmapWithAlpha></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.EnableAlphaChannel></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.HasAlphaChannel></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.RemoveAlphaChannel></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetAlphaRangePixelsColor></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetSelectedAreaAlpha></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Layers<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.CurrentLayer></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.FindLayerAt></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayerDefaults></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayerOptions></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Layers></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersAdd></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersAlign></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersClear></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCaching></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCancelEditor></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCopyToAlpha></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersConvertToImageLayers></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersCount></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCreateFromAlpha></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCreateFromClipboard></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCreateFromEdge></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCreateFromFile></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCreateFromSelection></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersCropBackground></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersCropped></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersCurrent></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersDeselectAll></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersDrawBox></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersDrawTo></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersFastDrawing></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersFixBorders></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersFixRotations></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersFixSizes></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersGroup></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersImport></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersInsert></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersMerge></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersMergeAll></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersMergeFilter></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersMergeTo></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersMove> (Arrange)</C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersRect></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersRepositionAll></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersRemove></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersResizeAspectRatio></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersRotateAll></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersRotateStep></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersRotationAntialias></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersRotationFilter></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersRotationUseFilterOnPreview></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersSaveMergedTo></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersSelCount></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersSelectAll></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.LayersSelectConstrains></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersSetProperties></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersSizeAll></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LayersUngroup></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MaxLayerHeight></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MaxLayerWidth></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetLayersBoxStyle></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetLayersGripStyle></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SoftCrop></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.SoftCropValue></C> </R>
|
||
</TABLE>
|
||
Also: <L TImageEnIO.LoadFromFileIEN>Layer Loading</L> and <L TImageEnIO.SaveToFileIEN>Layer Saving</L>
|
||
|
||
<FI>Animations and Transitions<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AbortTransition></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.PrepareTransition></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.RunTransition></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.TransitionRunning></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.TransitionTiming></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.Playing></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.PlayLoop></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Navigator<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.IsNavigator></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SetNavigator></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Animated Polygons<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AnimPolygonAddPt></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AnimPolygonClear></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AnimPolygonDel></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.AnimPolygonNew></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Other<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.Assign></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.AutoCursors></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.Cursor></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TIEView.GetCanvas></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.BackBuffer></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.BeginPostFrames></C> </R>
|
||
<R> <C_IMG_PUBLISHED> <C><A TImageEnView.DrawVersion></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.EndPostFrames></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.GetGripAt></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.HighlightedPixel></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.LoadState></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TImageEnView.Modified></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.MoveContentTo></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.ResetState></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TImageEnView.SaveState></C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Events<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnActivateTextEditor></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnAcquireBitmap></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnBeforeSelectionChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDeactivateTextEditor></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawBackBuffer></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawBackground></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawCanvas></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawLayer></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawLayerBox></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawLayerGrip></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDrawPolygon></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDShowEvent></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnDShowNewFrame></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnFinishSmoothTask></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnFinishWork></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnImageChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnImageEnGesture></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnLayerNotify></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnLayerMoveSize></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnLayerSelectionChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TIEView.OnMouseEnter></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnMediaFoundationNotify></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnMouseInResizingGrip></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnMouseInSel></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TIEView.OnMouseLeave></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnNewLayer></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnPaint></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnProgress></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnRulerClick></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnRulerGripClick></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnRulerGripDblClick></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnRulerGripPosChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnSaveUndo></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnSelectionChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnSelectionChanging></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnSetCursor></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnSpecialKey></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnTextEditorKeyDown></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnTransitionPaint></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnTransitionStep></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnTransitionStop></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnViewChange></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnViewChanging></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnVirtualKey></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnZoomIn></C> </R>
|
||
<R> <C_IMG_EVENT> <C><A TImageEnView.OnZoomOut></C> </R>
|
||
</TABLE>
|
||
!!}
|
||
{$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);
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionAbsWidth
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionAbsWidth: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Locks the selection to a specific width, when <A TImageEnView.SelectionAspectRatio> is 0.
|
||
|
||
<FM>Example<FC>
|
||
// we want a fixed selection of 100 x 100 pixels
|
||
ImageEnView.SelectionAbsWidth := 100;
|
||
ImageEnView.SelectionAbsHeight := 100;
|
||
ImageEnView.SelectionAspectRatio := 0;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectionAbsHeight>
|
||
- <A TImageEnView.SelectionAspectRatio>
|
||
- <A TIECropToolInteraction.LockWidth>
|
||
!!}
|
||
property SelectionAbsWidth: integer read fSelectionAbsWidth write fSelectionAbsWidth;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionAbsHeight
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionAbsHeight: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Locks the selection to a specific height, when <A TImageEnView.SelectionAspectRatio> is 0.
|
||
|
||
<FM>Example<FC>
|
||
// we want a fixed selection of 100 x 100 pixels
|
||
ImageEnView.SelectionAbsWidth := 100;
|
||
ImageEnView.SelectionAbsHeight := 100;
|
||
ImageEnView.SelectionAspectRatio := 0;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectionAbsWidth>
|
||
- <A TImageEnView.SelectionAspectRatio>
|
||
- <A TIECropToolInteraction.LockHeight>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Selected
|
||
|
||
<FM>Declaration<FC>
|
||
property Selected: boolean;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.Deselect> method.
|
||
If Selected is True, the properties <A TImageEnView.SelX1>, <A TImageEnView.SelY1>, <A TImageEnView.SelX2>, <A TImageEnView.SelY2> are valid.
|
||
|
||
Read-only
|
||
!!}
|
||
property Selected: boolean read fSel;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectedRect
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectedRect: <A TIERectangle>;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageenView.Zoom> and <A TImageenView.ViewX>, <A TImageenView.ViewY> values).
|
||
You can programatically make a selection using the <A TImageEnView.Select> method.
|
||
|
||
Read-only
|
||
!!}
|
||
property SelectedRect: TIERectangle read GetSelectedRect;
|
||
|
||
property VisibleSelection: boolean read GetVisibleSelection write SetVisibleSelection;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MagicWandMaxFilter
|
||
|
||
<FM>Declaration<FC>
|
||
property MagicWandMaxFilter: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Set to True to apply a maximum filter to the magic wand selection (remove the "black hole").
|
||
|
||
Default: False
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MagicWandMode>
|
||
- <A TImageEnView.MagicWandTolerance>
|
||
- <A TImageEnView.MouseInteract>
|
||
!!}
|
||
property MagicWandMaxFilter: boolean read fMagicWandMaxFilter write fMagicWandMaxFilter;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MagicWandTolerance
|
||
|
||
<FM>Declaration<FC>
|
||
property MagicWandTolerance: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the color difference of original point and region point when using <L TIEMouseInteractItems>miSelectMagicWand</L>. A low number selects colors of a very close match, whereas a higher value allows much broader color differences.
|
||
|
||
Default: 15
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MagicWandMaxFilter>
|
||
- <A TImageEnView.MagicWandMode>
|
||
- <A TImageEnView.MouseInteract>
|
||
!!}
|
||
property MagicWandTolerance: integer read fMagicWandTolerance write fMagicWandTolerance;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MagicWandMode
|
||
|
||
<FM>Declaration<FC>
|
||
property MagicWandMode: <A TIEMagicWandMode>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies how magic wand selection <L TIEMagicWandMode>works</L>.
|
||
|
||
Default: iewInclusive
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MagicWandMaxFilter>
|
||
- <A TImageEnView.MagicWandTolerance>
|
||
- <A TImageEnView.MouseInteract>
|
||
!!}
|
||
property MagicWandMode: TIEMagicWandMode read fMagicWandMode write fMagicWandMode;
|
||
|
||
function IsPointInsideSelection(x, y: integer): boolean;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionMask
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionMask: <A TIEMask>;
|
||
|
||
<FM>Description<FN>
|
||
SelectionMask contains the current selection as a bit mask of 1 bit per pixel (zero is unselected, 1 is selected).
|
||
|
||
<FM>Example<FC>
|
||
// 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();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectCustom>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.EnableShiftKey
|
||
|
||
<FM>Declaration<FC>
|
||
property EnableShiftKey: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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);
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRotationFilter
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersRotationFilter: <A TIEAntialiasMode>;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.LayersRotationAntialias> := True;
|
||
|
||
Default: ierFast
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRotationAntialias>
|
||
- <A TImageEnView.LayersRotationUseFilterOnPreview>
|
||
- <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
property LayersRotationFilter: TIEAntialiasMode read fLayersRotationFilter write fLayersRotationFilter;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRotationAntialias
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersRotationAntialias: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Enables rotation anti-aliasing when layer rotation has completed (to improve their quality). Use <A TImageEnView.LayersRotationFilter> to specify the anti-aliasing algorithm.
|
||
|
||
Default: False
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRotationFilter>
|
||
- <A TImageEnView.LayersRotationUseFilterOnPreview>
|
||
- <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
property LayersRotationAntialias: Boolean read fLayersRotationAntialias write fLayersRotationAntialias;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRotationUseFilterOnPreview
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersRotationUseFilterOnPreview: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Displays the user's rotation with the selected <L TImageEnView.LayersRotationFilter>anti-alias effect</L> immediately (i.e. before calling <A TImageEnView.LayersFixRotations>).
|
||
|
||
Note: Preview of large rotated images at high quality can be slow, so it is recommended that you also use <A TImageEnView.LayersFastDrawing>.
|
||
|
||
Default: False
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRotationFilter>
|
||
- <A TImageEnView.LayersRotationAntialias>
|
||
- <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.UpdateReason
|
||
|
||
<FM>Declaration<FC>
|
||
property UpdateReason: <A TIEUpdateReason>;
|
||
|
||
<FM>Description<FN>
|
||
Advises the reason for the next <A TImageEnView.Update>. 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OffScreenPaint
|
||
|
||
<FM>Declaration<FC>
|
||
property OffScreenPaint: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
When the component is not visible (i.e. Visible=False) the back buffer <A TImageEnView.BackBuffer> is not painted.
|
||
If you need the back buffer to be paint correctly set OffScreenPaint to true.
|
||
!!}
|
||
property OffScreenPaint: Boolean read fOffscreenPaint write fOffscreenPaint;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionGridSize
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionGridSize: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIEImageEnGlobalSettings.SelectionGridColor>.
|
||
|
||
This property can be used in place of <A TImageEnView.SelectionGridWidth> and <A TImageEnView.SelectionGridHeight>.
|
||
|
||
Default: 1
|
||
!!}
|
||
property SelectionGridSize: Integer read GetSelectionGridSize write SetSelectionGridSize;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionGridWidth
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionGridWidth: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIEImageEnGlobalSettings.SelectionGridColor>.
|
||
|
||
This property can be used in place of <A TImageEnView.SelectionGridSize>.
|
||
|
||
Default: 1
|
||
|
||
See also: <A TImageEnView.SelectionGridHeight>
|
||
!!}
|
||
property SelectionGridWidth: Integer read fSelectionGridWidth write fSelectionGridWidth;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionGridHeight
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionGridHeight: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIEImageEnGlobalSettings.SelectionGridColor>.
|
||
|
||
This property can be used in place of <A TImageEnView.SelectionGridSize>.
|
||
|
||
Default: 1
|
||
|
||
See also: <A TImageEnView.SelectionGridWidth>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LockPaintCount
|
||
|
||
<FM>Declaration<FC>
|
||
property LockPaintCount: Integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the lock painting state. 0=no lock, > 0 locking (the image will not be painted).
|
||
<A TImageEnView.LockPaint> increases LockPaintCount, <A TImageEnView.UnLockPaint> decreases it.
|
||
!!}
|
||
property LockPaintCount: integer read fLockPaint;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LockUpdateCount
|
||
|
||
<FM>Declaration<FC>
|
||
property LockUpdateCount: Integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the lock updating state. 0 = no lock, > 0 locking (the image will not be updated).
|
||
<A TImageEnView.LockUpdate> increases LockUpdateCount, <A TImageEnView.UnLockUpdate> decreases it.
|
||
!!}
|
||
property LockUpdateCount: integer read fUpdateLocked;
|
||
|
||
|
||
procedure DrawTo(Canvas: TCanvas);
|
||
|
||
{!!
|
||
<FS>TImageEnView.OffsetX
|
||
|
||
<FM>Declaration<FC>
|
||
property OffsetX: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the horizontal position where the image has been drawn. If <A TImageEnView.ImageHorizAlignment> is iehLeft, <FC>OffsetX<FN> will be zero, whereas for <FC>iehCenter<FN> 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 <A TImageEnView.ViewX>).
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OffsetY>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
property OffsetX: integer read fOffX;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OffsetY
|
||
|
||
<FM>Declaration<FC>
|
||
property OffsetY: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the vertical position where the image has been drawn. If <A TImageEnView.ImageVertAlignment> is ievTop, <FC>OffsetY<FN> will be zero, whereas for <FC>ievCenter<FN> 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 <A TImageEnView.ViewY>).
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OffsetX>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
property OffsetY: integer read fOffY;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ExtentX
|
||
|
||
<FM>Declaration<FC>
|
||
property ExtentX: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the width of the area used to show the current image (i.e. the width of the image as it appears onscreen).
|
||
|
||
<FM>Example<FC>
|
||
// 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);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ExtentY>
|
||
- <A TImageEnView.ViewX>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
property ExtentX: integer read fExtX;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ExtentY
|
||
|
||
<FM>Declaration<FC>
|
||
property ExtentY: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the height of the area used to show the current image (i.e. the height of the image as it appears onscreen).
|
||
|
||
<FM>Example<FC>
|
||
// 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);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ExtentX>
|
||
- <A TImageEnView.ViewY>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
property ExtentY: integer read fExtY;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ScrollBarsAlwaysVisible
|
||
|
||
<FM>Declaration<FC>
|
||
property ScrollBarsAlwaysVisible: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
When the ScrollBarsAlwaysVisible property is True, the scrollbars specified in <A TImageEnView.ScrollBars> property will be displayed, even if when not required.
|
||
|
||
!!}
|
||
property ScrollBarsAlwaysVisible: boolean read GetScrollBarsAlwaysVisible write SetScrollBarsAlwaysVisible default false;
|
||
|
||
{!!
|
||
<FS>TImageEnView.VScrollBarParams
|
||
|
||
<FM>Declaration<FC>
|
||
property VScrollBarParams: <A TIEScrollBarParams>;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
// disable tracking
|
||
ImageEnView1.VScrollBarParams.Tracking := False;
|
||
!!}
|
||
property VScrollBarParams: TIEScrollBarParams read fVScrollBarParams;
|
||
|
||
{!!
|
||
<FS>TImageEnView.HScrollBarParams
|
||
|
||
<FM>Declaration<FC>
|
||
property HScrollBarParams: <A TIEScrollBarParams>;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
// 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 = []);
|
||
|
||
{!!
|
||
<FS>TImageEnView.IsNavigator
|
||
|
||
<FM>Declaration<FC>
|
||
property IsNavigator: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Returns <FC>true<FN> 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: <A TImageEnView.SetNavigator>.
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRotateStep
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersRotateStep: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersMergeFilter
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersMergeFilter: <A TResampleFilter>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the quality that is used when merging layers.
|
||
|
||
It applies to:
|
||
- <A TImageEnView.LayersMerge>
|
||
- <A TImageEnView.LayersMergeAll>
|
||
- <A TImageEnView.LayersMergeTo>
|
||
- <A TImageEnView.LayersSaveMergedTo>
|
||
|
||
Note: Has no effect on image layers, if they have a custom <A TIEImageLayer.UseResampleFilter>
|
||
|
||
Default: rfLanczos3
|
||
!!}
|
||
property LayersMergeFilter: TResampleFilter read fLayersMergeFilter write fLayersMergeFilter;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSelectConstrains
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersSelectConstrains: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
If true, selection constraints are active, i.e. whether the layer itself can be selected is controlled at the layer level by <A TIELayer.Selectable>.
|
||
|
||
Default: True
|
||
!!}
|
||
property LayersSelectConstrains: Boolean read fLayersSelectConstrains write fLayersSelectConstrains;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Layers
|
||
|
||
<FM>Declaration<FC>
|
||
property Layers[idx: Integer]: <A TIELayer>;
|
||
|
||
<FM>Description<FN>
|
||
The Layers property provides access to properties related to a specified <L TIELayer>layer</L>.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersResizeAspectRatio
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersResizeAspectRatio: <A TIELayersResizeAspectRatio>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies whether ImageEn respects the aspect ratio of layers when resizing.
|
||
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iearDisabled</C> <C>Doesn't maintain the aspect ratio even when pressing ALT or setting <A TImageEnView.ForceALTKey>)</C> </R>
|
||
<R> <C>iearALTKey</C> <C>Maintains the aspect ratio only when pressing ALT or setting <A TImageEnView.ForceALTKey></C> </R>
|
||
<R> <C>iearAlways</C> <C>The aspect ratio is always maintained (using any grips)</C> </R>
|
||
<R> <C>iearAlwaysOnCornerGrip</C> <C>The aspect ratio is always maintained if the corner grips are used</C> </R>
|
||
<R> <C>iearLayerDefaultOnCornerGrip</C> <C>If the layer has a <L TIELayer.PreferredAspectRatio>preferred aspect ratio</L> then dragging the corner grip will maintain the aspect ratio, for side grips and other layer types the aspect ratio is not maintained</C> </R>
|
||
</TABLE>
|
||
|
||
Default: iearALTKey
|
||
|
||
Note: ImageEn will always enforce the aspect ratio if <A TIELayer.AspectRatioLocked> = true
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIELayer.AspectRatioLocked>
|
||
- <A TIELayer.PreferredAspectRatio>
|
||
- <A TIELayer.RestoreAspectRatio>
|
||
!!}
|
||
property LayersResizeAspectRatio: TIELayersResizeAspectRatio read fLayersResizeAspectRatio write fLayersResizeAspectRatio;
|
||
|
||
property LayersCropped: Boolean read fLayersCropped write SetLayersCropped;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersFastDrawing
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersFastDrawing: <A TIEFastDrawing>;
|
||
|
||
<FM>Description<FN>
|
||
Improves the performance of <L TIELayer>layer</L> rendering by delayed or disabling slow operations.
|
||
<TABLE>
|
||
<R> <H>Item</H> <H>Description</H> </R>
|
||
<R> <C><FC>iefFast<FN></C> <C>Layer draw quality is reduced to speed up display (only affects drawing)</C> </R>
|
||
<R> <C><FC>iefDelayed<FN></C> <C>Fast drawing (iefFast) is used while rotating, moving or resizing layers. After a delay, layers are then drawn at normal quality (iefNormal)</C> </R>
|
||
<R> <C><FC>iefNormal<FN></C> <C>Layers are drawn at normal quality</C> </R>
|
||
</TABLE>
|
||
|
||
When fast drawing is active:
|
||
- Does not render <A TIELayer.AlphaEdgeFeathering> or <A TIELayer.SoftShadow>
|
||
- Zoom filters are not used for display (<A TImageEnView.ZoomFilter> and <A TIEImageLayer.ResampleFilter>)
|
||
- <A TIELayer.AntiAlias> is not rendered
|
||
- Anti-alias filters are not used for rotation preview (<A TImageEnView.LayersRotationAntialias>)
|
||
|
||
Default: iefDelayed
|
||
|
||
Note: <FC>LayersFastDrawing<FN> only affects what is displayed. It has no effect on the quality of the image when saved
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersCaching>
|
||
!!}
|
||
property LayersFastDrawing: TIEFastDrawing read fLayersFastDrawing write fLayersFastDrawing;
|
||
function LayersFastDrawingActive: Boolean;
|
||
|
||
// Not exposed in doc index
|
||
{!!
|
||
<FS>TImageEnView.LayersFastOutput
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersFastOutput: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Improves the performance of <L TIELayer>layer</L> output operations, such as merging, by disabling anti-aliasing and other quality properties.
|
||
|
||
Default: False
|
||
|
||
Note: <FC>LayersFastOutput<FN> only affects output. Drawing is controlled by <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
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_);
|
||
|
||
{!!
|
||
<FS>TImageEnView.ForceALTkey
|
||
|
||
<FM>Declaration<FC>
|
||
property ForceALTkey: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnVect> component).
|
||
|
||
Default: False
|
||
!!}
|
||
property ForceALTkey: boolean read fForceALTkey write fForceALTkey;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DelayDisplaySelection
|
||
|
||
<FM>Declaration<FC>
|
||
property DelayDisplaySelection: Boolean
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DelayZoomTime
|
||
|
||
<FM>Declaration<FC>
|
||
property DelayZoomTime: Integer;
|
||
|
||
<FM>Description<FN>
|
||
ImageEn has a timer that decrements a counter at each tick (you can set the tick delay using <A TImageEnView.DelayTimer> property). This timer controls the selection animation and the application of filters on scrolling (when <A TImageEnView.DelayZoomFilter> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomSelectionAspectRatio
|
||
|
||
<FM>Declaration<FC>
|
||
property ZoomSelectionAspectRatio: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MouseScrollRate
|
||
|
||
<FM>Declaration<FC>
|
||
property MouseScrollRate: Double;
|
||
|
||
<FM>Description<FN>
|
||
If <A TImageEnView.MouseInteract> contains miScroll then MouseScrollRate specifies the relationship between mouse movement and image scrolling.
|
||
|
||
Default: 1 (one mouse point is one pixel at 100%).
|
||
|
||
<FM>Example<FC>
|
||
// set double rate scroll
|
||
ImageEnView1.MouseScrollRate := 2;
|
||
ImageEnView1.MouseInteract := [miScroll];
|
||
!!}
|
||
property MouseScrollRate: Double read fMouseScrollRate write fMouseScrollRate;
|
||
|
||
// encapsulated components
|
||
|
||
{!!
|
||
<FS>TImageEnView.IO
|
||
|
||
<FM>Declaration<FC>
|
||
property IO: <A TImageEnIO>;
|
||
|
||
<FM>Description<FN>
|
||
The IO property encapsulates the TImageEnIO component inside TImageEnView (The TImageEnIO component is automatically created the first time you access the IO property).
|
||
|
||
<A TImageEnIO> provides all functionality for loading and saving images, and other I/O functions.
|
||
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Proc
|
||
|
||
<FM>Declaration<FC>
|
||
property Proc: <A TImageEnProc>;
|
||
|
||
<FM>Description<FN>
|
||
Provides access to the TImageEnProc component inside TImageEnView (The TImageEnProc component is automatically created the first time you access the Proc property).
|
||
|
||
<A TImageEnProc> provides functionality for editing and manipulating images, clipboard and analysis.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Gestures
|
||
|
||
<FM>Declaration<FC>
|
||
property Gestures: <A TIEViewerGestures>;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\Gestures\Gestures.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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
|
||
|
||
{!!
|
||
<FS>TImageEnView.RulerParams
|
||
|
||
<FM>Declaration<FC>
|
||
property RulerParams: <A TIEViewRulerParams>;
|
||
|
||
<FM>Description<FN>
|
||
Allows you to configure the properties of your <L TImageEnView.ShowRulers>rulers</L>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\ImageEnViewRulers\ImageEnViewRulers.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnViewChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnViewChange: <A TViewChangeEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Notifies of changes to <A TImageEnView.Zoom>, <A TImageEnView.ViewX> or <A TImageEnView.ViewY>.
|
||
!!}
|
||
property OnViewChange: TViewChangeEvent read fOnViewChange write fOnViewChange;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnImageEnGesture
|
||
|
||
<FM>Declaration<FC>
|
||
property OnImageEnGesture: <A TIEImageEnGestureEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a gesture is handled by ImageEn.
|
||
!!}
|
||
property OnImageEnGesture: TIEImageEnGestureEvent read fOnImageEnGesture write fOnImageEnGesture;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnFinishSmoothTask
|
||
|
||
<FM>Declaration<FC>
|
||
property OnFinishSmoothTask: <A TIEFinishSmoothTaskEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Notifies that a smooth task has finished (smooth scroll, smooth zoom, etc...).
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SetZoomSmooth>
|
||
- <A TImageEnView.SetViewXYSmooth>
|
||
!!}
|
||
property OnFinishSmoothTask: TIEFinishSmoothTaskEvent read fOnFinishSmoothTask write fOnFinishSmoothTask;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnViewChanging
|
||
|
||
<FM>Declaration<FC>
|
||
property OnViewChanging: <A TViewChangeEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Notifies that <A TImageEnView.Zoom>, <A TImageEnView.ViewX> or <A TImageEnView.ViewY> is going to change.
|
||
!!}
|
||
property OnViewChanging: TViewChangingEvent read fOnViewChanging write fOnViewChanging;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnImageChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnImageChange: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs after the image is modified using <A TImageEnProc> (<A TImageEnView.Proc> property) or <A TImageEnIO> (<A TImageEnView.IO> property).
|
||
|
||
If you are using multiple <A TImageEnView.Layers>, then layer changes will also trigger <FC>OnImageChange<FN>.
|
||
|
||
Note: <A TImageEnProc> calls <A TImageEnView.ImageChange> after a modification which actuates <FC>OnImageChange<FN>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Modified>
|
||
- <A TIEBitmap.Modified>
|
||
- <A TIELayer.Modified>
|
||
!!}
|
||
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 [];
|
||
|
||
{!!
|
||
<FS>TImageEnView.AutoFit
|
||
|
||
<FM>Declaration<FC>
|
||
property AutoFit: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
If AutoFit is True and the image is updated (<A TImageEnView.Update> method) then <A TImageEnView.Fit> 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 <A TImageEnView.AutoStretch> and <A TImageEnView.AutoShrink> to true.
|
||
|
||
<FM>Example<FC>
|
||
procedure TForm1.chkAutoFitClick(Sender: TObject);
|
||
begin
|
||
ImageEnView1.AutoFit := chkAutoFit.Checked;
|
||
if not chkAutoFit.Checked then
|
||
ImageEnView1.Zoom := 100
|
||
else
|
||
ImageEnView1.Fit();
|
||
end;
|
||
|
||
<FM>See Also<FN>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
!!}
|
||
property AutoFit: boolean read fAutoFit write fAutoFit default false;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionBase
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionBase: <A TIESelectionBase>;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Select>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
!!}
|
||
property SelectionBase: TIESelectionBase read fSelectionBase write fSelectionBase default iesbClientArea;
|
||
|
||
property BackgroundStyle: TIEBackgroundStyle read fBackgroundStyle write SetBackgroundStyle default iebsSolid;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnSelectionChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnSelectionChange: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever the user finishes a change of the current selection.
|
||
Methods such as <A TImageEnView.AddSelPoint> or <A TImageEnView.Select> do not call the OnSelectionChange event.
|
||
|
||
<FM>Example 1<FC>
|
||
// 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;
|
||
|
||
<FM>Example 2<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnSelectionChanging
|
||
|
||
<FM>Declaration<FC>
|
||
property OnSelectionChanging: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever the user is modifying the current selection.
|
||
|
||
Note: Methods such as <A TImageEnView.AddSelPoint> or <A TImageEnView.Select> do not call the OnSelectionChanging event.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnMouseInSel
|
||
|
||
<FM>Declaration<FC>
|
||
property OnMouseInSel: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
OnMouseInSel is called whenever the mouse is inside a selection or over its contours.
|
||
!!}
|
||
property OnMouseInSel: TNotifyEvent read fOnMouseInSel write fOnMouseInSel;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DelayZoomFilter
|
||
|
||
<FM>Declaration<FC>
|
||
property DelayZoomFilter: Boolean
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
property DelayZoomFilter: boolean read fDelayZoomFilter write fDelayZoomFilter default false;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnPaint
|
||
|
||
<FM>Declaration<FC>
|
||
property OnPaint: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnMouseInResizingGrip
|
||
|
||
<FM>Declaration<FC>
|
||
property OnMouseInResizingGrip: <A TIEMouseInResizingGripEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnZoomIn
|
||
|
||
<FM>Declaration<FC>
|
||
property OnZoomIn: <A TIEZoomEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>NewZoom<FN> parameter.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnZoomOut
|
||
|
||
<FM>Declaration<FC>
|
||
property OnZoomOut: <A TIEZoomEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>NewZoom<FN> parameter.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AutoStretch
|
||
|
||
<FM>Declaration<FC>
|
||
property AutoStretch: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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
|
||
|
||
<FM>Example<FC>
|
||
procedure TForm1.chkAutoStretchClick(Sender: TObject);
|
||
begin
|
||
ImageEnView1.AutoStretch := chkAutoStretch.Checked;
|
||
if not chkAutoStretch.Checked then
|
||
ImageEnView1.Zoom := 100
|
||
else
|
||
ImageEnView1.Fit();
|
||
end;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.AutoShrink>
|
||
- <A TImageEnView.AutoFit>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
!!}
|
||
property AutoStretch: boolean read fAutoStretch write fAutoStretch default false;
|
||
|
||
{!!
|
||
<FS>TImageEnView.AutoShrink
|
||
|
||
<FM>Declaration<FC>
|
||
property AutoShrink: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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%
|
||
|
||
<FM>Example<FC>
|
||
procedure TForm1.chkAutoShrinkClick(Sender: TObject);
|
||
begin
|
||
ImageEnView1.AutoShrink := chkAutoShrink.Checked;
|
||
if not chkAutoShrink.Checked then
|
||
ImageEnView1.Zoom := 100
|
||
else
|
||
ImageEnView1.Fit();
|
||
end;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.AutoStretch>
|
||
- <A TImageEnView.AutoFit>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
!!}
|
||
property AutoShrink: boolean read fAutoShrink write fAutoShrink default false;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnBeforeSelectionChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnBeforeSelectionChange: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawBackBuffer
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawBackBuffer: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.BackBuffer> by handling the OnDrawBackBuffer event to paint onto the Backbuffer canvas.
|
||
<A TImageEnView.BackBuffer> is updated whenever <A TImageEnView.Update> is called.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnLayerNotify
|
||
|
||
<FM>Declaration<FC>
|
||
property OnLayerNotify: <A TIELayerNotify>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a layer is selected, moved or resized. This event only fires on user actions (not programatic changes).
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnLayerSelectionChange>
|
||
- <A TImageEnView.OnLayerMoveSize>
|
||
- <A TImageEnView.OnNewLayer>
|
||
!!}
|
||
property OnLayerNotify: TIELayerNotify read fOnLayerNotify write fOnLayerNotify;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnLayerMoveSize
|
||
|
||
<FM>Declaration<FC>
|
||
property OnLayerMoveSize: <A TIELayerMoveSizeEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnNewLayer>
|
||
- <A TImageEnView.OnLayerNotify>
|
||
- <A TIELayer.AspectRatioLocked>
|
||
- <A TImageEnView.LayersResizeAspectRatio>
|
||
!!}
|
||
property OnLayerMoveSize: TIELayerMoveSizeEvent read fOnLayerMoveSize write fOnLayerMoveSize;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnNewLayer
|
||
|
||
<FM>Declaration<FC>
|
||
property OnNewLayer: <A TIENewLayerEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a layer is added. It is useful to assign default properties to the layer.
|
||
Both programmatic methods (e.g. using <A TImageEnView.LayersAdd>) and user methods (e.g. <L TImageEnView.MouseInteract>using miCreateShapeLayers</L>) trigger this event.
|
||
|
||
<FC>LayerIdx<FN> is the index of the new layer.
|
||
<FC>LayerKind<FN> is the kind of layer that was added.
|
||
|
||
Notes:
|
||
- <A TImageEnView.CurrentLayer> will represent the new layer
|
||
- You can also use <A TImageEnView.LayerDefaults> to assign properties to new layers
|
||
|
||
<FM>Examples<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnLayerMoveSize>
|
||
- <A TImageEnView.OnLayerNotify>
|
||
- <A TImageEnView.OnLayerSelectionChange>
|
||
- <A TImageEnView.LayerDefaults>
|
||
!!}
|
||
property OnNewLayer: TIENewLayerEvent read fOnNewLayer write fOnNewLayer;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnLayerSelectionChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnLayerSelectionChange: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a layer is selected or deselected. This event only fires on user actions (not programatic changes).
|
||
|
||
A selected text layer:
|
||
<IMG help_images\text_Selected.gif>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnLayerNotify>
|
||
- <A TImageEnView.OnNewLayer>
|
||
!!}
|
||
property OnLayerSelectionChange: TNotifyEvent read fOnLayerSelectionChange write fOnLayerSelectionChange;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnSpecialKey
|
||
|
||
<FM>Declaration<FC>
|
||
property OnSpecialKey: <A TIESpecialKeyEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawBackground
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawBackground: <A TIEOnDrawBackground>;
|
||
|
||
<FM>Description<FN>
|
||
OnDrawBackground occurs whenever background needs to be painted.
|
||
!!}
|
||
property OnDrawBackground: TIEOnDrawBackground read fOnDrawBackground write fOnDrawBackground;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawCanvas
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawCanvas: <A TIEOnDrawCanvas>;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawLayerBox
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawLayerBox: <A TIEDrawLayerBoxEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when a layer box must be painted (<A TImageEnView.LayersDrawBox> must be enabled). If you handle this event the default behavior is disabled.
|
||
<FC>ABitmap<FN> is the destination bitmap and <FC>layer<FN> is the layer index that we are drawing.
|
||
Use <A TImageEnView.Layers>[].<A TIELayer.ClientAreaBox> rectangle to get actual rectangle coordinates.
|
||
|
||
See the ImageEditing\Layers demo for more details.
|
||
|
||
Note: You can also use <A TImageEnView.SetLayersBoxStyle> to customize the layer box style
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawLayer
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawLayer: <A TIEDrawLayerEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs immediately after a layer is painted.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Dest<FN></C> <C>The destination bitmap (usually the back buffer)</C> </R>
|
||
<R> <C><FC>LayerIndex<FN></C> <C>The layer index that we are drawing</C> </R>
|
||
</TABLE>
|
||
|
||
Use <A TImageEnView.Layers>[].<A TIELayer.ClientAreaBox> rectangle to know actual rectangle coordinates.
|
||
!!}
|
||
property OnDrawLayer: TIEDrawLayerEvent read fOnDrawLayer write fOnDrawLayer;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawLayerGrip
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawLayerGrip: <A TIEDrawLayerGrip>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when a layer grip is painted. If you handle this event the default behavior is disabled.
|
||
<FC>ABitmap<FN> is the destination bitmap and layer is the layer index that we are drawing.
|
||
<FC>Rect<FN> specifies the actual grip rectangle.
|
||
|
||
See the ImageEditing\Layers demo for more details.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDrawPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDrawPolygon: <A TIEOnDrawPolygon>;
|
||
|
||
<FM>Description<FN>
|
||
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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDShowNewFrame
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDShowNewFrame: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a new frame is ready (when using the DirectShow functionality of TImageEnView). This event is active when you are using IO.<A TImageEnIO.DShowParams> and <A TIEDirectShow.EnableSampleGrabber> is True.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDShowEvent
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDShowEvent: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when one or more events are ready (when using the DirectShow functionality of TImageEnView).
|
||
You should call <A TImageEnView.IO>.<A TImageEnIO.DShowParams>.<A TIEDirectShow.GetEventCode> until it returns false (no more events are available).
|
||
|
||
<FM>Example<FC>
|
||
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}
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnSetCursor
|
||
|
||
<FM>Declaration<FC>
|
||
property OnSetCursor: <A TIESetCursorEvent>;
|
||
|
||
<FM>Description<FN>
|
||
OnSetCursor occurs whenever the mouse cursor needs to be changed. You can set your custom cursor by setting the <FC>Cursor<FN> parameter.
|
||
This event may be called multiple times for the same cursor shape.
|
||
!!}
|
||
property OnSetCursor: TIESetCursorEvent read fOnSetCursor write fOnSetCursor;
|
||
|
||
|
||
|
||
{$IFDEF IEINCLUDEMEDIAFOUNDATION}
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnMediaFoundationNotify
|
||
|
||
<FM>Declaration<FC>
|
||
property OnMediaFoundationNotify: <A TIEMediaFoundationNotifyEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever Media Foundation sends a new frame or a notification to TImageEnView.
|
||
|
||
<FM>Example<FC>
|
||
// 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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnVirtualKey
|
||
|
||
<FM>Declaration<FC>
|
||
property OnVirtualKey: <A TIEVirtualKeyEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever the component receives WM_KEYDOWN, WM_SYSKEYDOWN, WM_KEYUP or WM_SYSKEYUP message.
|
||
!!}
|
||
property OnVirtualKey: TIEVirtualKeyEvent read fOnVirtualKey write fOnVirtualKey;
|
||
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnTextEditorKeyDown
|
||
|
||
<FM>Declaration<FC>
|
||
property OnTextEditorKeyDown: TKeyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a key is pressed when editing the text of a <A TIETextLayer> or <A TIELineLayer>.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnActivateTextEditor
|
||
|
||
<FM>Declaration<FC>
|
||
property OnActivateTextEditor: <A TIETextEditorEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a text editor is activated for a <A TIETextLayer> or <A TIELineLayer>.
|
||
!!}
|
||
property OnActivateTextEditor: TIETextEditorEvent read fOnActivateTextEditor write fOnActivateTextEditor;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnDeactivateTextEditor
|
||
|
||
<FM>Declaration<FC>
|
||
property OnDeactivateTextEditor: <A TIETextEditorEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a text editor is closed after editing of a <A TIETextLayer> or <A TIELineLayer>.
|
||
|
||
!!}
|
||
property OnDeactivateTextEditor: TIETextEditorEvent read fOnDeactivateTextEditor write fOnDeactivateTextEditor;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.EnableInteractionHints
|
||
|
||
<FM>Declaration<FC>
|
||
property EnableInteractionHints: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.PlayLoop
|
||
|
||
<FM>Declaration<FC>
|
||
property PlayLoop: boolean;
|
||
|
||
<FM>Description<FN>
|
||
Set to True to continuously loop playback of animated GIF and AVI files (when <A TImageEnView.Playing> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.MouseWheelParams
|
||
|
||
<FM>Declaration<FC>
|
||
property MouseWheelParams: <A TIEMouseWheelParams>;
|
||
|
||
<FM>Description<FN>
|
||
Properties to customize the behavior of the mouse wheel.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\MouseWheel\MouseWheelParams.dpr </C> </R>
|
||
</TABLE>
|
||
!!}
|
||
property MouseWheelParams: TIEMouseWheelParams read fMouseWheelParams write SetMouseWheelParams;
|
||
|
||
|
||
property ShowRulers: TRulerDirs read fShowRulers write SetShowRulers default [];
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AutoCursors
|
||
|
||
<FM>Declaration<FC>
|
||
property AutoCursors: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Cursor>
|
||
!!}
|
||
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);
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteractionMode
|
||
|
||
<FM>Declaration<FC>
|
||
}
|
||
TIECropToolInteractionMode = (iectmRECTANGLE,
|
||
iectmPERSPECTIVE);
|
||
{!!}
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolOptions
|
||
|
||
<FM>Declaration<FC>
|
||
TIECropToolOptions = set of (iecoAllowResizing, iecoAllowRotating, iecoAllowMoving, iecoSideGripsRespectLocks, iecoSizeLocksAreMinimums);
|
||
|
||
<FM>Description<FN>
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iecoAllowResizing</C> <C>The user can resize the crop selection by dragging the corner or side grips </C> </R>
|
||
<R> <C>iecoAllowRotating</C> <C>The user can rotate the crop selection by dragging outside the corner grips </C> </R>
|
||
<R> <C>iecoAllowMoving</C> <C>The user can move the crop selection by clicking within the selection area </C> </R>
|
||
<R> <C>iecoSideGripsRespectLocks</C> <C>Determines whether the specified <L TIECropToolInteraction.LockAspectRatio>aspect ratio lock</L> 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</C> </R>
|
||
<R> <C>iecoSizeLocksAreMinimums</C> <C>If included, then the specified <A TIECropToolInteraction.LockWidth> or <A TIECropToolInteraction.LockHeight> are treated as minimum values, i.e. the user can make the selection larger than the specified values, but not smaller</C> </R>
|
||
</TABLE>
|
||
|
||
Default: [iecoAllowResizing, iecoAllowRotating, iecoAllowMoving]
|
||
|
||
<FM>Examples<FC>
|
||
// 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);
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction
|
||
|
||
<FM>Declaration<FC>
|
||
TIECropToolInteraction = class(TIEUserInteraction);
|
||
|
||
<FM>Description<FN>
|
||
A class of TIEUserInteraction that is used to control interaction for the crop tool (when <A TImageEnView.MouseInteract> is <FC>miCropTool<FN>).
|
||
|
||
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
|
||
|
||
<FM>Rotated Crop<FN>
|
||
<IMG help_images\croptool.jpg>
|
||
|
||
<FM>Perspective Fix<FN>
|
||
<IMG help_images\Perspective2.jpg>
|
||
|
||
<FM>Example<FC>
|
||
// 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();
|
||
|
||
<FM>Methods and Properties<FN>
|
||
<FI>General Properties<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.AntialiasMode></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.DrawGuides></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.GripSize></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.LockAspectRatio></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.LockWidth></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.LockHeight></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.Mode></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.Options></C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Selection<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.BitmapPolygon></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.Rotation> (Same as rotating selection)</C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.RotatedPolygon></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.ScreenPolygon></C> </R>
|
||
<R> <C_IMG_PROPERTY> <C><A TIECropToolInteraction.Selected></C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TIECropToolInteraction.SetBitmapPolygon> (Same as resizing selection)</C> </R>
|
||
</TABLE>
|
||
|
||
<FI>Command Methods<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_METHOD> <C><A TIECropToolInteraction.Cancel> (Same as clicking "Esc")</C> </R>
|
||
<R> <C_IMG_METHOD> <C><A TIECropToolInteraction.Crop> (Same as clicking "Enter")</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView Actions>
|
||
!!}
|
||
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
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.GripSize
|
||
|
||
<FM>Declaration<FC>
|
||
property GripSize: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the size of the grips that appear around the crop selection (which can be dragged to enlarge).
|
||
|
||
Note: You must call <FC>TImageEnView.Invalidate<FN> if you change this property when the crop selection is visible
|
||
|
||
Default: 8
|
||
|
||
<FM>Example<FC>
|
||
// Make larger grips
|
||
ImageEnView1.CropToolInteraction.GripSize := 12;
|
||
!!}
|
||
property GripSize: integer read fGripSize write fGripSize;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.DrawGuides
|
||
|
||
<FM>Declaration<FC>
|
||
property DrawGuides: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Displays guide lines on the horizontal and vertical thirds of the crop selection.
|
||
|
||
Note: You must call <FC>TImageEnView.Invalidate<FN> if you change this property when the crop selection is visible
|
||
|
||
Default: True
|
||
|
||
<FM>Example<FC>
|
||
// Disable guide lines
|
||
ImageEnView1.CropToolInteraction.DrawGuides := False;
|
||
!!}
|
||
property DrawGuides: boolean read fDrawGuides write fDrawGuides;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.LockAspectRatio
|
||
|
||
<FM>Declaration<FC>
|
||
property LockAspectRatio: Double;
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>iecoSideGripsRespectLocks<FN> to <A TIECropToolInteraction.Options> to force all grips to respect the ratio
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIECropToolInteraction.Options>
|
||
- <A TImageEnView.SelectionAspectRatio>
|
||
- <A TIECropToolInteraction.LockHeight>
|
||
- <A TIECropToolInteraction.LockWidth>
|
||
!!}
|
||
property LockAspectRatio: Double read fLockAspectRatio write fLockAspectRatio;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.LockWidth
|
||
|
||
<FM>Declaration<FC>
|
||
property LockWidth: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIECropToolInteraction.LockHeight>
|
||
- if <FC>iecoSizeLocksAreMinimums<FN> is specified in <A TIECropToolInteraction.Options>, then this value is a minimum only
|
||
- Has no effect if <A TImageEnView.SelectionAspectRatio> > 0 (unless <FC>iecoSizeLocksAreMinimums<FN> is used)
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIECropToolInteraction.LockHeight>
|
||
- <A TIECropToolInteraction.LockAspectRatio>
|
||
- <A TIECropToolInteraction.Options>
|
||
- <A TImageEnView.SelectionAbsWidth>
|
||
!!}
|
||
property LockWidth: Integer read fLockWidth write fLockWidth;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.LockHeight
|
||
|
||
<FM>Declaration<FC>
|
||
property LockHeight: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIECropToolInteraction.LockWidth>
|
||
- if <FC>iecoSizeLocksAreMinimums<FN> is specified in <A TIECropToolInteraction.Options>, then this value is a minimum only
|
||
- Has no effect if <A TImageEnView.SelectionAspectRatio> > 0 (unless <FC>iecoSizeLocksAreMinimums<FN> is used)
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIECropToolInteraction.LockWidth>
|
||
- <A TIECropToolInteraction.LockAspectRatio>
|
||
- <A TIECropToolInteraction.Options>
|
||
- <A TImageEnView.SelectionAbsHeight>
|
||
!!}
|
||
property LockHeight: Integer read fLockHeight write fLockHeight;
|
||
|
||
// CURRENT SELECTION
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.BitmapPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
property BitmapPolygon: <A TIE2DPointArray>; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the area of the image the user has selected for cropping.
|
||
|
||
Note:
|
||
- <FC>BitmapPolygon<FN> does not consider the <A TIECropToolInteraction.Rotation>
|
||
- <FC>BitmapPolygon<FN> is an array [0..3] of type, <A TIE2DPoint>. Item 0 is Top-Left, item 1 is Top-Right, item 2 is Bottom-Right and item 3 is Bottom-Left
|
||
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FC>
|
||
- <A TIECropToolInteraction.SetBitmapPolygon>
|
||
- <A TIECropToolInteraction.RotatedPolygon>
|
||
- <A TIECropToolInteraction.Rotation>
|
||
!!}
|
||
{$ifdef IESUPPORTPROPERTYOFARRAYTYPE}
|
||
property BitmapPolygon: TIE2DPointArray read fBitmapPolygon;
|
||
{$endif}
|
||
|
||
property RotatedBitmapPolygon: TIE2DPointArray read GetRotatedBitmapPolygon;
|
||
|
||
procedure SetBitmapPolygon(Rect: TRect);
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.ScreenPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
property ScreenPolygon: <A TIE2DPointArray>; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the area of the image the user has selected for cropping, using screen coordinates.
|
||
|
||
Note: <FC>ScreenPolygon<FN> is an array [0..3] of type, <A TIE2DPoint>. 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}
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.RotatedPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
property RotatedPolygon: <A TIE2DPointArray>; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the area of the image the user has selected for cropping with support for rotation (returning the four corners of the rotated polygon)
|
||
|
||
<FM>See Also<FC>
|
||
- <A TIECropToolInteraction.BitmapPolygon>
|
||
- <A TIECropToolInteraction.SetBitmapPolygon>
|
||
- <A TIECropToolInteraction.Rotation>
|
||
!!}
|
||
{$ifdef IESUPPORTPROPERTYOFARRAYTYPE}
|
||
property RotatedPolygon: TIE2DPointArray read fRotatedPolygon;
|
||
{$endif}
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Rotation
|
||
|
||
<FM>Declaration<FC>
|
||
property Rotation: Double;
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>TImageEnView.Invalidate<FN> if you change this property when the crop selection is visible
|
||
|
||
<IMG help_images\croptool.jpg>
|
||
|
||
<FM>Example<FC>
|
||
// Change rotation to 45 deg. CCW
|
||
ImageEnView1.CropToolInteraction.Rotation := 45;
|
||
ImageEnView1.Invalidate();
|
||
!!}
|
||
property Rotation: double read fRotation write fRotation;
|
||
|
||
|
||
// OTHER PROPERTIES
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.AntialiasMode
|
||
|
||
<FM>Declaration<FC>
|
||
property AntialiasMode: <A TIEAntialiasMode>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the quality of a rotated crop.
|
||
|
||
Default: ierFast
|
||
|
||
<FM>Example<FC>
|
||
// High quality cropping
|
||
ImageEnView1.CropToolInteraction.AntialiasMode := ierBicubic;
|
||
!!}
|
||
property AntialiasMode: TIEAntialiasMode read fAntialiasMode write fAntialiasMode;
|
||
|
||
property Mode: TIECropToolInteractionMode read fMode write SetMode;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Options
|
||
|
||
<FM>Declaration<FC>
|
||
property Options: <A TIECropToolOptions>;
|
||
|
||
<FM>Description<FN>
|
||
Options that control the behaviour of the crop tool.
|
||
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iecoAllowResizing</C> <C>The user can resize the crop selection by dragging the corner or side grips </C> </R>
|
||
<R> <C>iecoAllowRotating</C> <C>The user can rotate the crop selection by dragging outside the corner grips </C> </R>
|
||
<R> <C>iecoAllowMoving</C> <C>The user can move the crop selection by clicking within the selection area </C> </R>
|
||
<R> <C>iecoSideGripsRespectLocks</C> <C>Determines whether the specified <L TIECropToolInteraction.LockAspectRatio>aspect ratio lock</L> 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</C> </R>
|
||
<R> <C>iecoSizeLocksAreMinimums</C> <C>If included, then the specified <A TIECropToolInteraction.LockWidth> or <A TIECropToolInteraction.LockHeight> are treated as minimum values, i.e. the user can make the selection larger than the specified values, but not smaller</C> </R>
|
||
</TABLE>
|
||
|
||
Default: [iecoAllowResizing, iecoAllowRotating, iecoAllowMoving]
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIECropToolInteraction.LockAspectRatio>
|
||
- <A TIECropToolInteraction.LockWidth>
|
||
- <A TIECropToolInteraction.LockHeight>
|
||
!!}
|
||
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 <A TImageEnView.LayersMove>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Background
|
||
|
||
<FM>Declaration<FC>
|
||
property Background: TColor;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIEImageEnGlobalSettings.EnableTheming> is enabled.
|
||
|
||
Default: clBtnFace
|
||
|
||
<FM>Example<FC>
|
||
// Rotate of 30 degrees and fill blank spaces with clBlack color
|
||
ImageEnView1.Background := clBlack;
|
||
ImageEnView1.Proc.Rotate(30, False);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.BackgroundStyle>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ScrollBars
|
||
|
||
<FM>Declaration<FC>
|
||
property ScrollBars: TScrollType;
|
||
|
||
<FM>Description<FN>
|
||
ScrollBars determines whether the TImageEnView control displays scroll bars (they are only shown if they are needed unless <A TImageEnView.ScrollBarsAlwaysVisible> is true).
|
||
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C><FC>ssNone<FN></C> <C>The control has no scroll bars</C> </R>
|
||
<R> <C><FC>ssHorizontal<FN></C> <C>The control has a single scroll bar on the bottom edge when needed</C> </R>
|
||
<R> <C><FC>ssVertical<FN></C> <C>The control has a single scroll bar on the right edge when needed</C> </R>
|
||
<R> <C><FC>ssBoth<FN></C> <C>The control has a scroll bar on both the bottom and right edges when needed</C> </R>
|
||
</TABLE>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Zoom
|
||
|
||
<FM>Declaration<FC>
|
||
property Zoom: double;
|
||
|
||
<FM>Description<FN>
|
||
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: <FC>Zoom<FN> will have no effect if <A TImageEnView.AutoFit>, <A TImageEnView.AutoShrink> or <A TImageEnView.AutoStretch> are enabled.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ZoomX>
|
||
- <A TImageEnView.ZoomY>
|
||
- <A TImageEnView.ZoomIn>
|
||
- <A TImageEnView.ZoomOut>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomX
|
||
|
||
<FM>Declaration<FC>
|
||
property ZoomX: Double;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.Zoom>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Zoom>
|
||
- <A TImageEnView.ZoomY>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomY
|
||
|
||
<FM>Declaration<FC>
|
||
property ZoomY: Double;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.ZoomX> and ZoomY to the same value is equivalent to setting <A TImageEnView.Zoom>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Zoom>
|
||
- <A TImageEnView.ZoomX>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.IdealComponentWidth
|
||
|
||
<FM>Declaration<FC>
|
||
property IdealComponentWidth: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the width that the TImageEnView component should be to exactly fit the current image.
|
||
|
||
<FM>Example<FC>
|
||
// Resize ImageEnView to fully contain Carlotta.jpg
|
||
ImageEnView.LoadFromFile('C:\Carlotta.jpg');
|
||
ImageEnView1.Width := ImageEnView1.IdealComponentWidth;
|
||
ImageEnView1.Height := ImageEnView1.IdealComponentHeight;
|
||
|
||
<FM>See Also<FN>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
- <A TImageEnView.IdealComponentHeight>
|
||
!!}
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IdealComponentHeight
|
||
|
||
<FM>Declaration<FC>
|
||
property IdealComponentHeight: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the height that the TImageEnView component should be to exactly fit the current image.
|
||
|
||
<FM>Example<FC>
|
||
// Resize ImageEnView to fully contains Carlotta.jpg
|
||
ImageEnView.LoadFromFile('C:\Carlotta.jpg');
|
||
ImageEnView1.Width := ImageEnView1.IdealComponentWidth;
|
||
ImageEnView1.Height := ImageEnView1.IdealComponentHeight;
|
||
|
||
<FM>See Also<FN>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
- <A TImageEnView.IdealComponentWidth>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IdealImageWidth
|
||
|
||
<FM>Declaration<FC>
|
||
property IdealImageWidth: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the width that an image should be to fill the entire TImageEnView without requiring a scrollbar
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.IdealImageHeight>
|
||
!!}
|
||
function TImageEnView.GetIdealImageWidth: integer;
|
||
var
|
||
edgeLeft, edgeTop, edgeRight, edgeBottom: integer;
|
||
begin
|
||
CalcEdges( edgeLeft, edgeTop, edgeRight, edgeBottom, true, true );
|
||
Result := ( Width - edgeLeft - edgeRight )
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IdealImageHeight
|
||
|
||
<FM>Declaration<FC>
|
||
property IdealImageHeight: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the width that an image should be to fill the entire TImageEnView without requiring a scrollbar
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.IdealImageWidth>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetViewXY
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetViewXY(x, y: integer);
|
||
|
||
<FM>Description<FN>
|
||
Sets <A TImageEnView.ViewX> and <A TImageEnView.ViewY> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ViewX
|
||
|
||
<FM>Declaration<FC>
|
||
property ViewX: integer;
|
||
|
||
<FM>Description<FN>
|
||
ViewX and <A TImageEnView.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.
|
||
|
||
<FM>Example<FC>
|
||
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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ViewY>
|
||
- <A TImageEnView.ExtentX>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ViewY
|
||
|
||
<FM>Declaration<FC>
|
||
property ViewY: integer;
|
||
|
||
<FM>Description<FN>
|
||
<A TImageEnView.ViewX> 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.
|
||
|
||
<FM>Example<FC>
|
||
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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ViewX>
|
||
- <A TImageEnView.ExtentY>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.GetMaxViewXY
|
||
|
||
<FM>Declaration<FC>
|
||
procedure GetMaxViewXY(var mx, my: integer);
|
||
|
||
<FM>Description<FN>
|
||
Returns the maximum values for <A TImageEnView.ViewX> and <A TImageEnView.ViewY> (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
|
||
{!!
|
||
<FS>TImageEnView.ImageChange
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ImageChange; virtual;
|
||
|
||
<FM>Description<FN>
|
||
Generates an <A TImageEnView.OnImageChange> event and sets <A TImageEnView.Modified> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Clear
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Clear;
|
||
|
||
<FM>Description<FN>
|
||
Fills the current image with the <A TImageEnView.Background> color.
|
||
|
||
<FM>Comparison of Methods<FN>
|
||
<TABLE>
|
||
<R> <H>Method</H> <H>Description</H> </R>
|
||
<R> <C> <A TImageEnView.Clear> </C> <C> Fills the current image with the <A TImageEnView.Background>background color</L> and <L TImageEnView.RemoveAlphaChannel>removes</L> the alpha channel </C> </R>
|
||
<R> <C> <A TImageEnView.Blank> </C> <C> Calls <A TImageEnView.Clear> and resets the image size to 1 x 1</C> </R>
|
||
<R> <C> <A TImageEnView.LayersClear> </C> <C> Removes all of the <A TImageEnView.Layers>layers</L> </C> </R>
|
||
<R> <C> <A TImageEnView.ClearAll> </C> <C> Resets the image (calling <A TImageEnView.Blank>) and removes all layers (calling <A TImageEnView.LayersClear>) </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// Clear the image
|
||
ImageEn1.Background := clWhite;
|
||
ImageEn1.Clear;
|
||
|
||
// Clear the top-most layer
|
||
ImageEnView1.LayersCurrent := ImageEnView1.LayersCount - 1;
|
||
ImageEnView1.Clear;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Blank>
|
||
- <A TImageEnView.ClearAll>
|
||
!!}
|
||
procedure TImageEnView.Clear;
|
||
begin
|
||
if fIEBitmapValid then
|
||
fIEBitmap.Fill(Background);
|
||
RemoveAlphaChannel(false);
|
||
Update;
|
||
ImageChange();
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ClearAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ClearAll;
|
||
|
||
<FM>Description<FN>
|
||
Removes all content from the control, by removing all layers (with <A TImageEnView.LayersClear>) and resetting the background image (with <A TImageEnView.Blank>).
|
||
|
||
<FM>Comparison of Methods<FN>
|
||
<TABLE>
|
||
<R> <H>Method</H> <H>Description</H> </R>
|
||
<R> <C> <A TImageEnView.Clear> </C> <C> Fills the current image with the <A TImageEnView.Background>background color</L> and <L TImageEnView.RemoveAlphaChannel>removes</L> the alpha channel </C> </R>
|
||
<R> <C> <A TImageEnView.Blank> </C> <C> Calls <A TImageEnView.Clear> and resets the image size to 1 x 1</C> </R>
|
||
<R> <C> <A TImageEnView.LayersClear> </C> <C> Removes all of the <A TImageEnView.Layers>layers</L> </C> </R>
|
||
<R> <C> <A TImageEnView.ClearAll> </C> <C> Resets the image (calling <A TImageEnView.Blank>) and removes all layers (calling <A TImageEnView.LayersClear>) </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
ImageEn1.ClearAll;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersClear>
|
||
- <A TImageEnView.Clear>
|
||
- <A TImageEnView.Blank>
|
||
!!}
|
||
procedure TImageEnView.ClearAll;
|
||
begin
|
||
LockUpdate;
|
||
LayersClear;
|
||
Blank;
|
||
UnlockUpdate;
|
||
end;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Blank
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Blank;
|
||
|
||
<FM>Description<FN>
|
||
Resets the image size to 1x1 (Width x Height).
|
||
|
||
Note: <FC>Blank<FN> also calls <A TImageEnView.Clear>
|
||
|
||
<FM>Comparison of Methods<FN>
|
||
<TABLE>
|
||
<R> <H>Method</H> <H>Description</H> </R>
|
||
<R> <C> <A TImageEnView.Clear> </C> <C> Fills the current image with the <A TImageEnView.Background>background color</L> and <L TImageEnView.RemoveAlphaChannel>removes</L> the alpha channel </C> </R>
|
||
<R> <C> <A TImageEnView.Blank> </C> <C> Calls <A TImageEnView.Clear> and resets the image size to 1 x 1</C> </R>
|
||
<R> <C> <A TImageEnView.LayersClear> </C> <C> Removes all of the <A TImageEnView.Layers>layers</L> </C> </R>
|
||
<R> <C> <A TImageEnView.ClearAll> </C> <C> Resets the image (calling <A TImageEnView.Blank>) and removes all layers (calling <A TImageEnView.LayersClear>) </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView1.IO.LoadFromFile('image.tif'); // Load image
|
||
...
|
||
ImageEnView1.Blank; // free memory
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersClear>
|
||
- <A TImageEnView.Clear>
|
||
- <A TImageEnView.ClearAll>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IsEmpty
|
||
|
||
<FM>Declaration<FC>
|
||
property IsEmpty: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Returns True if the size of the image is less than 2 x 2 pixels.
|
||
|
||
Also, see <A TImageenView.IsEmpty2> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IsEmpty2
|
||
|
||
<FM>Declaration<FC>
|
||
property IsEmpty2 : boolean;
|
||
|
||
<FM>Description<FN>
|
||
Returns True if the image is empty, i.e. no image has been assigned or loaded.
|
||
|
||
Also, see <A TImageenView.IsEmpty> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelX1
|
||
|
||
<FM>Declaration<FC>
|
||
property SelX1: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
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 (<A TImageenView.ViewX> and <A TImageenView.ViewY>) and <A TImageenView.Zoom> (e.g. you will get the same result whether the zoom is 50% or 100%).
|
||
|
||
Note:
|
||
- The selected area can be specified using <A TImageEnView.Select>
|
||
- You can convert the returned value to a screen value using <A TImageEnView.XBmp2Scr>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelY1>
|
||
- <A TImageEnView.SelX2>
|
||
- <A TImageEnView.SelY2>
|
||
- <A TImageEnView.Select>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelY1
|
||
|
||
<FM>Declaration<FC>
|
||
property SelY1: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
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 (<A TImageenView.ViewX> and <A TImageenView.ViewY>) and <A TImageenView.Zoom> (e.g. you will get the same result whether the zoom is 50% or 100%).
|
||
|
||
Note:
|
||
- The selected area can be specified using <A TImageEnView.Select>
|
||
- You can convert the returned value to a screen value using <A TImageEnView.YBmp2Scr>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelX1>
|
||
- <A TImageEnView.SelX2>
|
||
- <A TImageEnView.SelY2>
|
||
- <A TImageEnView.Select>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelX2
|
||
|
||
<FM>Declaration<FC>
|
||
property SelX2: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
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 (<A TImageenView.ViewX> and <A TImageenView.ViewY>) and <A TImageenView.Zoom> (e.g. you will get the same result whether the zoom is 50% or 100%).
|
||
|
||
Note:
|
||
- The selected area can be specified using <A TImageEnView.Select>
|
||
- You can convert the returned value to a screen value using <A TImageEnView.XBmp2Scr>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelX1>
|
||
- <A TImageEnView.SelY1>
|
||
- <A TImageEnView.SelY2>
|
||
- <A TImageEnView.Select>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelY2
|
||
|
||
<FM>Declaration<FC>
|
||
property SelY2: integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
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 (<A TImageenView.ViewX> and <A TImageenView.ViewY>) and <A TImageenView.Zoom> (e.g. you will get the same result whether the zoom is 50% or 100%).
|
||
|
||
Note:
|
||
- The selected area can be specified using <A TImageEnView.Select>
|
||
- You can convert the returned value to a screen value using <A TImageEnView.YBmp2Scr>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelX1>
|
||
- <A TImageEnView.SelY1>
|
||
- <A TImageEnView.SelX2>
|
||
- <A TImageEnView.Select>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.XBmp2Scr
|
||
|
||
<FM>Declaration<FC>
|
||
function XBmp2Scr(x: Integer; CurrentLayer: Boolean): Integer;
|
||
|
||
<FM>Description<FN>
|
||
The XBmp2Scr and <A TImageEnView.YBmp2Scr> 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 <A TImageEnView.Zoom>, <A TImageEnView.ViewX> and <A TImageEnView.ViewY> properties.
|
||
|
||
<FC>x<FN> is a bitmap coordinate.
|
||
If <FC>CurrentLayer<FN> is true, then <FC>x<FN> is assumed to be a coordinate of the <L TImageEnView.CurrentLayer>current layer</L>. 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[].<A TIELayer.ConvXBmp2Scr>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\PixelView\PixelView.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.YBmp2Scr
|
||
|
||
<FM>Declaration<FC>
|
||
function YBmp2Scr(y: Integer; CurrentLayer: Boolean): Integer;
|
||
|
||
<FM>Description<FN>
|
||
The YBmp2Scr and <A TImageEnView.XBmp2Scr> 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 <A TImageEnView.Zoom>, <A TImageEnView.ViewX> and <A TImageEnView.ViewY> properties.
|
||
|
||
<FC>y<FN> is a bitmap coordinate.
|
||
If <FC>CurrentLayer<FN> is true, then <FC>y<FN> is assumed to be a coordinate of the <L TImageEnView.CurrentLayer>current layer</L>. 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[].<A TIELayer.ConvYBmp2Scr>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\PixelView\PixelView.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.XScr2Bmp
|
||
|
||
<FM>Declaration<FC>
|
||
function XScr2Bmp(x: integer; CurrentLayer: Boolean): integer;
|
||
|
||
<FM>Description<FN>
|
||
The XScr2Bmp and <A TImageEnView.YScr2Bmp> methods convert a window coordinate to the corresponding bitmap coordinate (considering <A TImageEnView.Zoom> and <A TImageEnView.ViewX>, <A TImageEnView.ViewY> status).
|
||
|
||
<FC>x<FN> is a window coordinate.
|
||
If <FC>CurrentLayer<FN> is true, then the result will be a coordinate relative to the <L TImageEnView.CurrentLayer>current layer</L>. 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 <FC>x<FN> is beyond the displayed image's boundaries
|
||
- To convert a coordinate of a non-current layer, use TImageEnView.Layers[].<A TIELayer.ConvXScr2Bmp>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\PixelView\PixelView.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.YScr2Bmp>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.YScr2Bmp
|
||
|
||
<FM>Declaration<FC>
|
||
function YScr2Bmp(y: integer; CurrentLayer: Boolean): integer;
|
||
|
||
<FM>Description<FN>
|
||
The XScr2Bmp and <A TImageEnView.YScr2Bmp> methods convert a window coordinate to the corresponding bitmap coordinate (considering <A TImageEnView.Zoom> and <A TImageEnView.ViewX>, <A TImageEnView.ViewY> status).
|
||
|
||
<FC>y<FN> is a window coordinate.
|
||
If <FC>CurrentLayer<FN> is true, then the result will be a coordinate relative to the <L TImageEnView.CurrentLayer>current layer</L>. 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 <FC>y<FN> is beyond the displayed image's boundaries
|
||
- To convert a coordinate of a non-current layer, use TImageEnView.Layers[].<A TIELayer.ConvYScr2Bmp>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\PixelView\PixelView.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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)
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.XScr2Bmp>
|
||
- <A TImageEnView.XBmp2Scr>
|
||
- <A TImageEnView.YBmp2Scr>
|
||
- <A TImageEnView.VisibleBitmapRect>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.GetIdealZoom
|
||
|
||
<FM>Declaration<FC>
|
||
function TImageEnView.GetIdealZoom: Double;
|
||
|
||
<FM>Description<FN>
|
||
Returns the best zoom value to stretch the image to fit within the component.
|
||
|
||
Note: If the image is empty, result will be zero.
|
||
|
||
<FM>Example<FC>
|
||
// Both the following code snippets will have the same result
|
||
ImageEnView.Zoom := ImageEnView.GetIdealZoom;
|
||
|
||
// or
|
||
ImageEnView.Fit;
|
||
|
||
<FM>See Also<FN>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Fit
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Fit(StretchSmall : Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
This method adjusts <A TImageEnView.Zoom> so that the image fits within the client area of the component (while respecting the aspect ratio).
|
||
If <FC>StretchSmall<FN> is false, then images that are smaller than the window are shown 1:1 (i.e. are not zoomed more than 100%).
|
||
|
||
<FM>Example<FC>
|
||
// Display the entire image (including outlying layers) within the view
|
||
ImageEnView1.LayerOptions := ImageEnView1.LayerOptions + [ loFitToLayersWhenZooming ];
|
||
ImageEnView1.Fit( False );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.FitToHeight>
|
||
- <A TImageEnView.FitToWidth>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
- <A TImageEnView.Stretch>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Stretch
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Stretch;
|
||
|
||
<FM>Description<FN>
|
||
This method sets <A TImageEnView.ZoomX> and <A TImageEnView.ZoomY> 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.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Fit>
|
||
- <A TImageEnView.FitToWidth>
|
||
- <A TImageEnView.FitToHeight>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.FitToWidth
|
||
|
||
<FM>Declaration<FC>
|
||
procedure FitToWidth;
|
||
|
||
<FM>Description<FN>
|
||
FitToWidth adjust the image display size (<A TImageEnView.Zoom>) so that it fits within the width of the control window.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Fit>
|
||
- <A TImageEnView.FitToHeight>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
- <A TImageEnView.Stretch>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.FitToHeight
|
||
|
||
<FM>Declaration<FC>
|
||
procedure FitToHeight;
|
||
|
||
<FM>Description<FN>
|
||
FitToHeight adjust the image display size (<A TImageEnView.Zoom>) so that it fits within the height of the control window.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Fit>
|
||
- <A TImageEnView.FitToWidth>
|
||
- <L TImageEnView.LayerOptions>loFitToLayersWhenZooming</L>
|
||
- <A TImageEnView.Stretch>
|
||
!!}
|
||
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
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomSelection
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ZoomSelection(AspectRatio: Boolean);
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LockPaint
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LockPaint;
|
||
|
||
<FM>Description<FN>
|
||
The LockPaint method increases the lock counter's value. The ImageEnView window will not be repainted while <A TImageEnView.LockPaintCount> > 0.
|
||
|
||
See also: <A TImageEnView.UnlockPaint>.
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView1.LockPaint;
|
||
ImageEnView1.ViewX := 10;
|
||
ImageEnView1.ViewY := 20;
|
||
ImageEnView1.Zoom := 300;
|
||
ImageEnView1.UnLockPaint;
|
||
|
||
!!}
|
||
// Inc fLockPaint counter
|
||
procedure TImageEnView.LockPaint;
|
||
begin
|
||
inc(fLockPaint);
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.UnlockPaint
|
||
|
||
<FM>Declaration<FC>
|
||
function UnlockPaint: integer;
|
||
|
||
<FM>Description<FN>
|
||
Use the UnlockPaint method to decrease the lock counter's value. The ImageEnView window will not be repainted while <A TImageEnView.LockPaintCount> > 0.
|
||
|
||
If calling UnlockPaint resets <A TImageEnView.LockPaintCount> to zero then the <A TImageEnView.Update> method is automatically called.
|
||
|
||
Returns the lock count.
|
||
|
||
See also: <A TImageEnView.LockPaint>
|
||
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomAt
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ZoomAt(x, y: integer; ZoomVal: double; Center: Boolean=true);
|
||
|
||
<FM>Description<FN>
|
||
Zooms by the percentage specified by ZoomVal.
|
||
If the optional <FC>Center<FN> parameter if False, the zooming center is <FC>x, y<FN>, 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomIn
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ZoomIn;
|
||
|
||
<FM>Description<FN>
|
||
Provides a convenient method to handle clicking of a "Zoom In" button. Each time <FC>ZoomIn<FN> 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: <FC>ZoomIn<FN> will have no effect if <A TImageEnView.AutoFit>, <A TImageEnView.AutoShrink> or <A TImageEnView.AutoStretch> are enabled.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Zoom>
|
||
- <A TImageEnView.ZoomOut>
|
||
!!}
|
||
procedure TImageEnView.ZoomIn;
|
||
begin
|
||
Zoom := GetNextZoomValue(Zoom, True, GetIdealZoom);
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomOut
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ZoomOut;
|
||
|
||
<FM>Description<FN>
|
||
Provides as a convenient method to handle clicking of a "Zoom Out" button. Each time <FC>ZoomOut<FN> 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: <FC>ZoomOut<FN> will have no effect if <A TImageEnView.AutoFit>, <A TImageEnView.AutoShrink> or <A TImageEnView.AutoStretch> are enabled.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Zoom>
|
||
- <A TImageEnView.ZoomIn>
|
||
!!}
|
||
procedure TImageEnView.ZoomOut;
|
||
begin
|
||
Zoom := GetNextZoomValue(Zoom, False, GetIdealZoom);
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DrawTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure DrawTo(Canvas: TCanvas);
|
||
|
||
<FM>Description<FN>
|
||
This method draws the current view to the specified Canvas.
|
||
|
||
Note: The background is not painted, and the image has an up-left alignment.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.UpdateNoPaint
|
||
|
||
<FM>Declaration<FC>
|
||
procedure UpdateNoPaint;
|
||
|
||
<FM>Description<FN>
|
||
The Update method refreshes the TImageEnView component view with the current state of the image.
|
||
You must call <A TImageEnView.Update> or UpdateNoPaint() whenever the <A TImageEnView.Bitmap> or <A TImageEnView.IEBitmap> property is modified by your code.
|
||
Unlike <A TImageEnView.Update>, 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Update
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Update;
|
||
|
||
<FM>Description<FN>
|
||
The Update method refreshes the TImageEnView component view with the current state of the image and redraws the client area.
|
||
You must call <A TImageEnView.Update> or UpdateNoPaint() whenever the <A TImageEnView.Bitmap> or <A TImageEnView.IEBitmap> property is modified by your code.
|
||
Update is called automatically when an image processing or I/O operation is executed.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Center
|
||
|
||
<FM>Declaration<FC>
|
||
property Center: boolean;
|
||
|
||
<FM>Description<FN>
|
||
If Center is True, the image is displayed in the center of the ImageEnViews client area.
|
||
|
||
Default: True, which is equivalent to <A TImageEnView.ImageHorizAlignment> = iehCenter and <A TImageEnView.ImageVertAlignment> = ievCenter.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ImageHorizAlignment>
|
||
- <A TImageEnView.ImageVertAlignment>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ImageHorizAlignment
|
||
|
||
<FM>Declaration<FC>
|
||
property ImageHorizAlignment: <A TIEHAlign>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies where to align horizontally the image inside the component.
|
||
|
||
Default: iehCenter
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ImageVertAlignment>
|
||
- <A TImageEnView.Center>
|
||
!!}
|
||
procedure TImageEnView.SetImageHorizAlignment(value: TIEHAlign);
|
||
begin
|
||
if value <> fImageHorizAlignment then
|
||
begin
|
||
fImageHorizAlignment := value;
|
||
UpdateReason := ieurScrolled;
|
||
Update();
|
||
end;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ImageVertAlignment
|
||
|
||
<FM>Declaration<FC>
|
||
property ImageVertAlignment: <A TIEVAlign>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies where to align vertically the image inside the component.
|
||
|
||
Default: ievCenter
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ImageHorizAlignment>
|
||
- <A TImageEnView.Center>
|
||
!!}
|
||
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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.PaintRect
|
||
|
||
<FM>Declaration<FC>
|
||
procedure PaintRect(const rc: TRect);
|
||
|
||
<FM>Description<FN>
|
||
PaintRect repaints only the rectangle <FC>rc<FN> without waiting for the Windows Paint message.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.PolySelPoints
|
||
|
||
<FM>Declaration<FC>
|
||
property PolySelPoints: <A PPointArray>;
|
||
|
||
<FM>Description<FN>
|
||
PolySelPoints returns the current selection as a pointer to an array of TPoint.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.PolySel
|
||
|
||
|
||
<FM>Declaration<FC>
|
||
property PolySel[idx: Integer]: TPoint; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the idx point of the current polygonal selection. The point is specified in bitmap coordinates.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.PolySelCount>
|
||
- <A TImageEnView.PolySelPoints>
|
||
- <A TImageEnView.AddSelPoint>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.PolySelCount
|
||
|
||
<FM>Declaration<FC>
|
||
property PolySelCount: Integer; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns the points number of the current polygonal selection (size of <A TImageEnView.PolySel> array).
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.PolySel>
|
||
- <A TImageEnView.AddSelPoint>
|
||
!!}
|
||
function TImageEnView.GetPolySelCount: integer;
|
||
begin
|
||
result := PIEAnimPoly(fHPolySel)^.PolyCount;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Deselect
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Deselect;
|
||
|
||
<FM>Description<FN>
|
||
This method removes current selection. After Deselect is called, the <A TImageEnView.Selected> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Select
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Select(x1, y1, x2, y2: integer; Op: <A TIESelOp> = iespReplace); virtual;
|
||
|
||
<FM>Description<FN>
|
||
This method selects a portion of the image.
|
||
The selected area will be outlined with an animated rectangle.
|
||
If <A TImageEnView.SelectionBase> is <FC>iesbClientArea<FN> (default) all coordinates depend on actual zoom and scrolling.
|
||
If <FC>SelectionBase<FN> is <FC>iesbBitmap<FN>, all coordinates refer to bitmap pixels.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>x1<FN></C> <C>Top-left horizontal position</C> </R>
|
||
<R> <C><FC>y1<FN></C> <C>Top-left vertical position</C> </R>
|
||
<R> <C><FC>x2<FN></C> <C>Bottom-right horizontal position. Last column not selected</C> </R>
|
||
<R> <C><FC>y2<FN></C> <C>Bottom-right vertical position. Last row not selected</C> </R>
|
||
<R> <C><FC>Op<FN></C> <C>Selection operation (add or replace selection). If <FC>Op<FN> is <FC>iespReplace<FN>, <FC>Select<FN> replaces all previous selections. If Op is <FC>iespAdd<FN>, <FC>Select<FN> adds a new selection</C> </R>
|
||
</TABLE>
|
||
|
||
<FC>x2, y2<FN> 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).
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectEllipse>
|
||
- <A TImageEnView.SelectMagicWand>
|
||
- <A TImageEnView.SelectRoundRect>
|
||
- <A TImageEnView.InvertSelection>
|
||
- <A TImageEnView.Deselect>
|
||
- <A TImageEnView.SelX1>
|
||
- <A TImageEnView.SelY1>
|
||
- <A TImageEnView.SelX2>
|
||
- <A TImageEnView.SelY2>
|
||
!!}
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectEllipse
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectEllipse(CenterX, CenterY, Width, Height: Integer; Op: <A TIESelOp> = iespReplace);
|
||
|
||
<FM>Description<FN>
|
||
SelectEllipse makes an elliptical selection, centered at <FC>CenterX<FN> and <FC>CenterY<FN>, and with size specified by <FC>Width<FN> and <FC>Height<FN>.
|
||
<FC>Op<FN> specifies whether to add a new selection (<FC>iespAdd<FN>) or replace the current one (<FC>iespReplace<FN>).
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectRoundRect
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectRoundRect(Left, Top, Right, Bottom, RoundWidth, RoundHeight: integer; Op: <A TIESelOp> = iespReplace);
|
||
|
||
<FM>Description<FN>
|
||
Creates a rounded selection.
|
||
<FC>Left, Top, Right, Bottom<FN> are the rectangle coordinates.
|
||
<FC>RoundWidth<FN> and <FC>RoundHeight<FN> specify the size of the rounding (in pixels).
|
||
<FC>Op<FN> specifies whether to add a new selection (<FC>iespAdd<FN>) or replace the current one (<FC>iespReplace<FN>).
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectCustom
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectCustom;
|
||
|
||
<FM>Description<FN>
|
||
|
||
Call SelectCustom after you have specified a pixmap of selected pixels of the image.
|
||
To select a pixmap use <A TImageEnView.SelectionMask> methods like <A TIEMask.SetPixel>.
|
||
|
||
<FM>Example<FC>
|
||
// only pixels at 10,10 and 15,15 are selected
|
||
ImageEnView.SelectionMask.SetPixel(10, 10, 1);
|
||
ImageEnView.SelectionMask.SetPixel(15, 15, 1);
|
||
ImageEnView.SelectCustom();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectionMask>
|
||
!!}
|
||
procedure TImageEnView.SelectCustom;
|
||
begin
|
||
fSel := not fSelectionMask.IsEmpty;
|
||
ShowSelectionEx(true);
|
||
fUpdateBackBuffer := true;
|
||
Paint;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectMagicWand
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectMagicWand(x, y: Integer; Op: <A TIESelOp>);
|
||
|
||
<FM>Description<FN>
|
||
SelectMagicWand selects an irregular region that has similar colors.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>x<FN></C> <C>Starting horizontal coordiante</C> </R>
|
||
<R> <C><FC>y<FN></C> <C>Starting vertical coordinate</C> </R>
|
||
<R> <C><FC>Op<FN></C> <C>If <FC>Op<FN> is <FC>iespReplace<FN> the region replaces the existing selection, otherwise if <FC>Op<FN> is <FC>iespAdd<FN>, the region is appended to the existing selection</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectColors
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectColors(StartColor, FinalColor: <A TRGB>; Op: <A TIESelOp> = iespReplace);
|
||
procedure SelectColors(Color: <A TRGB>; Op: <A TIESelOp> = iespReplace);
|
||
procedure SelectColors(ColorIndex: integer; Op: <A TIESelOp> = iespReplace);
|
||
|
||
<FM>Description<FN>
|
||
Selects all colors inside the range <FC>StartColor<FN> up to <FC>FinalColor<FN>, or specific color or a color index.
|
||
If <FC>Op<FN> is <FC>iespReplace<FN> the region replaces the existing selection, otherwise if <FC>Op<FN> is <FC>iespAdd<FN>, the region is appended to the existing selection.
|
||
|
||
Third overload accepts <FC>ColorIndex<FN>, which is the index of a color in image colormap: the bitmat pixelformat must be ie8p (palette).
|
||
|
||
<FM>Example<FC>
|
||
// 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);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectNonAlpha>
|
||
- <A CreateRGB>
|
||
- <A TRGB2TColor>
|
||
- <A TColor2TRGB>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectNonAlpha
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SelectNonAlpha(Op: <A TIESelOp> = iespReplace);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>Op<FN> is <FC>iespReplace<FN> the region replaces the existing selection, otherwise if <FC>Op<FN> is <FC>iespAdd<FN>, the region is appended to the existing selection.
|
||
|
||
<FM>Example<FC>
|
||
// Load a transparent PNG file and select the non-alpha pixels
|
||
ImageEnView1.IO.LoadFromFile( 'D:\Transparent.png' );
|
||
ImageEnView1.SelectNonAlpha();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectColors>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MoveSelection
|
||
|
||
<FM>Declaration<FC>
|
||
procedure MoveSelection(MoveX, MoveY: Integer; Sizing: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
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).
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AddSelPoint
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AddSelPoint(x, y: Integer);
|
||
|
||
<FM>Description<FN>
|
||
AddSelPoint adds a point to the current polygonal selection.
|
||
If <A TImageEnView.SelectionBase> is <FC>iesbClientArea<FN> (default), all coordinates depend upon actual zoom and scrolling.
|
||
Otherwise, if <FC>SelectionBase<FN> is <FC>iesbBitmap<FN> all coordinates refer to bitmap pixels.
|
||
|
||
Use <A TImageEnView.EndSelect> to terminate selection by code.
|
||
|
||
<FM>Example<FC>
|
||
// 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();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.EndSelect>
|
||
- <A TImageEnView.PolySel>
|
||
- <A TImageEnView.PolySelPoints>
|
||
|
||
!!}
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.DelLastSelPoint
|
||
|
||
<FM>Declaration<FC>
|
||
procedure DelLastSelPoint();
|
||
|
||
<FM>Description<FN>
|
||
Removes the last inserted selection point.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AddSelBreak
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AddSelBreak;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.VisibleSelection
|
||
|
||
<FM>Declaration<FC>
|
||
property VisibleSelection: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionOptions
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionOptions: <A TIESelectionOptions>;
|
||
|
||
<FM>Description<FN>
|
||
Provides access to <L TIESelectionOptions>selection behavior options</L>.
|
||
|
||
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"
|
||
|
||
{!!
|
||
<FS>TImageEnView.AnimPolygonClear
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AnimPolygonClear(ap: pointer);
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AnimPolygonAddPt
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AnimPolygonAddPt(ap: pointer; x, y: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Adds a new point to the polygon <FC>ap<FN>.
|
||
<FC>x, y<FN> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AnimPolygonNew
|
||
|
||
<FM>Declaration<FC>
|
||
function TImageEnView.AnimPolygonNew(VColor1, VColor2: TColor; VAnimated: Boolean; VSizeable: Boolean): pointer;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AnimPolygonDel
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AnimPolygonDel(ap: pointer);
|
||
|
||
<FM>Description<FN>
|
||
Removes the animated polygon <FC>ap<FN> (value returned from <A TImageEnView.AnimPolygonNew>).
|
||
!!}
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.GetGripAt
|
||
|
||
<FM>Declaration<FC>
|
||
function GetGripAt(x, y: Integer): <A TIEGrip>;
|
||
|
||
<FM>Description<FN>
|
||
Returns the selection grip at mouse position specified by <FC>x, y<FN> (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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRepositionAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersRepositionAll(MoveX, MoveY: Integer; SelectedOnly: Boolean = False; Sizing: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Updates <A TIELayer.PosX> and <A TIELayer.PosY> of all layers (or just selected if <FC>SelectedOnly<FN> = 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 <FC>MoveX<FN>:
|
||
<TABLE>
|
||
<R> <H>Const</H> <H>Description</H> </R>
|
||
<R> <C><FC>IELayer_Pos_Left<FN></C> <C>Adjust PosX so layer is aligned to the left of the background layer</C> </R>
|
||
<R> <C><FC>IELayer_Pos_HCenter<FN></C> <C>Adjust PosX so layer is aligned to the horizontal center of the background layer</C> </R>
|
||
<R> <C><FC>IELayer_Pos_Right<FN></C> <C>Adjust PosX so layer is aligned to the right of the background layer</C> </R>
|
||
</TABLE>
|
||
|
||
These consts are also <FC>MoveY<FN>:
|
||
<TABLE>
|
||
<R> <H>Const</H> <H>Description</H> </R>
|
||
<R> <C><FC>IELayer_Pos_Top<FN></C> <C>Adjust PosY so layer is aligned to the top of the background layer</C> </R>
|
||
<R> <C><FC>IELayer_Pos_VCenter<FN></C> <C>Adjust PosY so layer is aligned to the vertical center of the background layer</C> </R>
|
||
<R> <C><FC>IELayer_Pos_Bottom<FN></C> <C>Adjust PosY so layer is aligned to the bottom of the background layer</C> </R>
|
||
</TABLE>
|
||
|
||
Note: Use <A TImageEnView.LayersSizeAll> to resize layers by percentage
|
||
|
||
<FM>Examples<FC>
|
||
// 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 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRotateAll>
|
||
- <A TImageEnView.LayersSizeAll>
|
||
- <A TImageEnView.LayersAlign>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRotateAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersRotateAll(Value: Double; bSelectedOnly: Boolean = False; bFixRotations: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Rotates all layers (or just selected if <FC>bSelectedOnly<FN> = True) by the specified angle (negative or positive degrees counter-clockwise). This method updates <A TIELayer.Rotate>.
|
||
If <FC>bFixRotations<FN> = True, then <A TImageEnView.LayersFixRotations> is called to finalize the rotation of the layer and improve quality.
|
||
|
||
<FM>Examples<FC>
|
||
// Rotate all layers 45<34> clockwise
|
||
ImageEnView1.LayersRotateAll( 315 );
|
||
|
||
// Rotate selected layers 90<39> clockwise
|
||
ImageEnView1.LayersRotateAll( 270, true );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRepositionAll>
|
||
- <A TImageEnView.LayersSizeAll>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSizeAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersSizeAll(HorzSizing, VertSizing: Double; bSelectedOnly: Boolean = False; bFixSizes: Boolean = False; ScalePosition: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Scales the <A TIELayer.Width> and <A TIELayer.Height> values for all layers (or just selected if <FC>bSelectedOnly<FN> = True). <FC>HorzSizing<FN> and <FC>VertSizing<FN> are percentage values, so 2 will double the layer size, and 0.5 will halve it.
|
||
If <FC>bFixSizes<FN> = True, then <A TImageEnView.LayersFixSizes> is called to resample the layer to the new sizes.
|
||
If <FC>ScalePosition<FN> is True, then <A TIELayer.PosX> and <A TIELayer.PosY> 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 <A TImageEnView.LayersRepositionAll>
|
||
|
||
<FM>Examples<FC>
|
||
// 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 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRepositionAll>
|
||
- <A TImageEnView.LayersRotateAll>
|
||
!!}
|
||
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)+'<27>', X, Y, '0000<30>');
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IsPointInsideSelection
|
||
|
||
<FM>Declaration<FC>
|
||
function IsPointInsideSelection(x, y: Integer): Boolean;
|
||
|
||
<FM>Description<FN>
|
||
IsPointInsideSelection returns true if the point specified with <FC>x, y<FN> is inside the current selection.
|
||
If <A TImageEnView.SelectionBase> is <FC>iesbClientArea<FN> (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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ZoomFilter
|
||
|
||
<FM>Declaration<FC>
|
||
property ZoomFilter: <A TResampleFilter>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the filter to apply when the image is not displayed at normal size (i.e. <A TImageEnView.Zoom> is not 100). It improves the quality of the image display.
|
||
For fastest display the ZoomFilter should be set to <FC>rfNone<FN> (default), but better quality is achieved with a filter such as <FC>rfLancoz3<FN>.
|
||
|
||
Default: rfNone
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\ZoomFilter\ZoomFilter.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Assign
|
||
|
||
<FM>Declaration<FC>
|
||
procedure Assign(Source: TObject); reintroduce; overload;
|
||
|
||
<FM>Description<FN>
|
||
Copy the content of a TBitmap, <A TIEBitmap>, <A TImageEnView> or <A TImageEnVect> to the current control.
|
||
|
||
<FM>Example<FC>
|
||
// Copy content from another TImageEnView, including layers and IO params
|
||
ImageEnView1.Assign(ImageEnView2);
|
||
|
||
// Copy only the image of another TImageEnView
|
||
ImageEnView1.Assign(ImageEnView2.IEBitmap);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnVect.CopyAllObjectsTo>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MouseInteract
|
||
|
||
<FM>Declaration<FC>
|
||
property MouseInteract: <A TIEMouseInteract>;
|
||
|
||
<FM>Description<FN>
|
||
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
|
||
|
||
<FM>Examples<FC>
|
||
// 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:
|
||
<IMG help_images\text_Selected.gif>
|
||
|
||
// 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 ];
|
||
|
||
<IMG help_images\Selection.gif>
|
||
|
||
// 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' );
|
||
|
||
<FM>Demos<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\FullApps\PhotoEn3\ImageEx.dpr </C> </R>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\SoftPan\SoftPan.dpr </C> </R>
|
||
<R> <C_IMG_DEMO> <C>Demos\ImageEditing\RotateLayers\RotateLayers.dpr </C> </R>
|
||
<R> <C_IMG_DEMO> <C>Demos\ImageEditing\Layers_AllTypes\Layers.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.SelectionOptions>
|
||
- <A TImageEnView.LayerDefaults>
|
||
!!}
|
||
function TImageEnView.GetMouseInteract: TIEMouseInteract;
|
||
begin
|
||
result := fMouseInteract;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.CropToolInteraction
|
||
|
||
<FM>Declaration<FC>
|
||
property CropToolInteraction: <A TIECropToolInteraction>;
|
||
|
||
<FM>Description<FN>
|
||
Provides access to the methods and properties of the <A TIECropToolInteraction> class, which is used when <A TImageEnView.MouseInteract> is <FC>miCropTool<FN>.
|
||
|
||
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
|
||
|
||
<FM>Rotated Crop<FN>
|
||
<IMG help_images\croptool.jpg>
|
||
|
||
<FM>Perspective Fix<FN>
|
||
<IMG help_images\Perspective2.jpg>
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\ImageEditing\CropTool\CropTool.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.BackgroundStyle
|
||
|
||
<FM>Declaration<FC>
|
||
property BackgroundStyle: <A TIEBackgroundStyle>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the style of the image background (the region of the ImageEnView window that is not filled by the image).
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView1.BackgroundStyle := iebsPhotoLike;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Background>
|
||
- <A TImageEnView.GradientEndColor>
|
||
- <A TImageEnView.Wallpaper>
|
||
- <A TImageEnView.WallpaperStyle>
|
||
!!}
|
||
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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.CopyFromPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
procedure CopyFromPolygon(Source: TBitmap; const Polygon: array of TPoint; PolygonLen: Integer; const Position: TPoint);
|
||
|
||
<FM>Description<FN>
|
||
CopyFromPolygon copies a region (Polygon) of source bitmap to current image.
|
||
CopyFromPolygon enlarges current bitmap when needed.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Source<FN></C> <C>Source bitmap</C> </R>
|
||
<R> <C><FC>Polygon<FN></C> <C>Array of polygon vertexes (pixel coordinates related to Source bitmap)</C> </R>
|
||
<R> <C><FC>PolygonLen<FN></C> <C>Number of vertexes in polygon</C> </R>
|
||
<R> <C><FC>Position<FN></C> <C>Destination point (pixel coordinate related to current image). The destination point is the top-left side of the rectangle that encloses source polygon</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.CopyToPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
procedure CopyToPolygon(Dest: TBitmap; const Polygon: array of TPoint; PolygonLen: Integer; const Position: TPoint);
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DisplayGridKind
|
||
|
||
<FM>Declaration<FC>
|
||
property DisplayGridKind: <A TIEGridKind>;
|
||
|
||
<FM>Description<FN>
|
||
Enables the display of helper lines over the image.
|
||
<TABLE>
|
||
<R> <H>Item</H> <H>Description</H> </R>
|
||
<R> <C><FC>iedgNone<FN></C> <C>No guide lines are shown</C> </R>
|
||
<R> <C><FC>iedgPixelGrid<FN></C> <C>A grid is shown marking each pixel when the image is zoomed in (e.g. for pixel editing in an image editor)</C> </R>
|
||
<R> <C><FC>iedgGuideLines<FN></C> <C>Guide lines are shown horizontally and vertically over the image (e.g. to help align objects when rotating)</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIEImageEnGlobalSettings.MinZoomDisplayGrid>
|
||
- <A TIEImageEnGlobalSettings.GridPen>
|
||
- <A TIEImageEnGlobalSettings.GridMajorStep>
|
||
- <A TIEImageEnGlobalSettings.GuidelineCount>
|
||
- <A TImageEnView.DisplayGridLyr>
|
||
!!}
|
||
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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.DisplayGridLyr
|
||
|
||
<FM>Declaration<FC>
|
||
property DisplayGridLyr: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies where to draw the grid if <A TImageEnView.DisplayGridKind> is <FC>iedgPixelGrid<FN>.
|
||
-1 : current layer (default behavior)
|
||
>= 0 : specific layer
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.DisplayGridKind>
|
||
- <A TIEImageEnGlobalSettings.MinZoomDisplayGrid>
|
||
- <A TIEImageEnGlobalSettings.GridPen>
|
||
- <A TIEImageEnGlobalSettings.GridMajorStep>
|
||
!!}
|
||
procedure TImageEnView.SetDisplayGridLyr(v: integer);
|
||
begin
|
||
fDisplayGridLyr := v;
|
||
UpdateReason := ieurComponentStuffChanged;
|
||
Update;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ShowRulers
|
||
|
||
<FM>Declaration<FC>
|
||
property ShowRulers: <A TRulerDirs>;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.RulerParams> to configure the ruler properties.
|
||
|
||
Default: [] (No rulers)
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Other\ImageEnViewRulers\ImageEnViewRulers.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.EndSelect
|
||
|
||
<FM>Declaration<FC>
|
||
procedure EndSelect;
|
||
|
||
<FM>Description<FN>
|
||
Terminates a selection specified by code using the <A TImageEnView.AddSelPoint> and <A TImageEnView.AddSelBreak> methods.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelColor1
|
||
|
||
<FM>Declaration<FC>
|
||
property SelColor1: TColor
|
||
|
||
<FM>Description<FN>
|
||
SelColor1 and <A TImageEnView.SelColor2> set the two colors of the animated selection polygon.
|
||
!!}
|
||
procedure TImageEnView.SetSelColor1(v: TColor);
|
||
begin
|
||
PIEAnimPoly(fHPolySel)^.Color1 := v;
|
||
fSelColor1 := v;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelColor2
|
||
|
||
<FM>Declaration<FC>
|
||
property SelColor2: TColor
|
||
|
||
<FM>Description<FN>
|
||
<A TImageEnView.SelColor1> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnProgress
|
||
|
||
<FM>Declaration<FC>
|
||
property OnProgress: <A TIEProgressEvent>;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.OnFinishWork> event.
|
||
|
||
Note: To determine what type of work is in progress, check the class of the Sender, e.g.
|
||
<FC>
|
||
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 ]);
|
||
<FN>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnAcquireBitmap
|
||
|
||
<FM>Declaration<FC>
|
||
property OnAcquireBitmap: <A TIEAcquireBitmapEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever a new bitmap is acquired during an acquisition.
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C>Sender</C> <C>Will be either a TImageEnIO or TImageEnMIO control</C> </R>
|
||
<R> <C>ABitmap</C> <C>A <A TIEBitmap> object that contains the acquired image</C> </R>
|
||
<R> <C>DpiX, DpiY</C> <C>Tne DPI of the acquired image</C> </R>
|
||
<R> <C>Handled</C> <C>Has no effect when acquiring via a TImageEnView/TImageEnIO</C> </R>
|
||
</TABLE>
|
||
|
||
!!}
|
||
function TImageEnView.GetOnAcquireBitmap: TIEAcquireBitmapEvent;
|
||
begin
|
||
result := fOnAcquireBitmap;
|
||
end;
|
||
|
||
procedure TImageEnView.SetOnAcquireBitmap(v: TIEAcquireBitmapEvent);
|
||
begin
|
||
fOnAcquireBitmap := v;
|
||
if assigned(fImageEnIO) then
|
||
fImageEnIO.OnAcquireBitmap := v;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnFinishWork
|
||
|
||
<FM>Declaration<FC>
|
||
property OnFinishWork: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs whenever an image processing or input/output task terminates.
|
||
It is always called after <A TImageEnView.OnProgress> 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.
|
||
<FC>
|
||
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!' )
|
||
<FN>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.TransitionRunning
|
||
|
||
<FM>Declaration<FC>
|
||
property TransitionRunning: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
TransitionRunning is True whenever a transition effect is being displayed.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.PrepareTransition>
|
||
- <A TImageEnView.RunTransition>
|
||
- <A TImageEnView.AbortTransition>
|
||
!!}
|
||
function TImageEnView.GetTransitionRunning: boolean;
|
||
begin
|
||
result := assigned(fTransition) and fTransition.Running;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.PrepareTransition
|
||
|
||
<FM>Declaration<FC>
|
||
procedure PrepareTransition;
|
||
|
||
<FM>Description<FN>
|
||
PrepareTransition must be called prior to <L TImageEnView.RunTransition>running</L> 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 <A TImageEnView.RunTransition>.
|
||
|
||
<FM>Example<FC>
|
||
// 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
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.RunTransition>
|
||
- <A TImageEnView.TransitionRunning>
|
||
- <A TImageEnView.AbortTransition>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.RunTransition
|
||
|
||
<FM>Declaration<FC>
|
||
procedure RunTransition(Effect : <A TIETransitionType>; Duration : integer); overload;
|
||
procedure RunTransition(Effect : <A TIETransitionType>; Duration : integer; StartRect, EndRect : TRect; bMaintainAspectRatio : Boolean; Smoothing: Integer = 96); overload;
|
||
procedure RunTransition(Effect : <A TIETransitionType>; Duration : integer; PanZoomEffect : <A TIEPanZoomType>; iZoomLevel : Integer; Smoothing: Integer = 96); overload;
|
||
|
||
<FM>Description<FN>
|
||
RunTransition starts the transition using <FC>Effect<FN> and <FC>Duration<FN> 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:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>StartRect</C> <C>The starting rectangle of an iettPanZoom transition (specified in bitmap points)</C> </R>
|
||
<R> <C>EndRect</C> <C>The ending rectangle of an iettPanZoom transition (specified in bitmap points)</C> </R>
|
||
<R> <C>bMaintainAspectRatio</C> <C>StartRect and EndRect will be automatically adjusted to ensure the image appears with the correct aspect ratio</C> </R>
|
||
<R> <C><FC>Smoothing<FN></C> <C>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</C> </R>
|
||
</TABLE>
|
||
|
||
Pan-Zoom Overload 2:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>PanZoomEffect</C> <C>One of ImageEn's <L TIEPanZoomType>built-in Pan Zoom effects</L></C> </R>
|
||
<R> <C>iZoomLevel</C> <C>If the specified <FC>PanZoomEffect<FN> is a "Zoom" type, then this specifies the maximum amount to zoom in, e.g. 20%</C> </R>
|
||
<R> <C><FC>Smoothing<FN></C> <C>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</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>iettShreddedFromLeft<FN>
|
||
<IMG help_images\Transition.jpg>
|
||
|
||
<FM>iettCubeRotateFromTop2<FN>
|
||
<IMG help_images\CubeTransition.jpg>
|
||
|
||
|
||
<FM>Demos<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\Transitions\Transitions.dpr </C> </R>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\PanZoomEffects\PanZoomEffects.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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);
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.PrepareTransition>
|
||
- <A TImageEnView.TransitionRunning>
|
||
- <A TImageEnView.AbortTransition>
|
||
!!}
|
||
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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.AbortTransition
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AbortTransition;
|
||
|
||
<FM>Description<FN>
|
||
This method aborts current transition started with <A TImageEnView.RunTransition>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.PrepareTransition>
|
||
- <A TImageEnView.RunTransition>
|
||
- <A TImageEnView.TransitionRunning>
|
||
!!}
|
||
procedure TImageEnView.AbortTransition;
|
||
begin
|
||
if assigned(fTransition) then
|
||
fTransition.Stop;
|
||
end;
|
||
|
||
procedure TImageEnView.SetOnTransitionStop(value: TNotifyEvent);
|
||
begin
|
||
SetupTransition;
|
||
fTransition.OnTransitionStop := value;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnTransitionStop
|
||
|
||
<FM>Declaration<FC>
|
||
property OnTransitionStop: TNotifyEvent;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when the transition (that was started by using <A TImageEnView.RunTransition>) 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnTransitionStep
|
||
|
||
<FM>Declaration<FC>
|
||
property OnTransitionStep: <A TIETransitionStepEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs prior to the painting of each transition frame. <FC>Step<FN> is a value from 0 to 1024.
|
||
!!}
|
||
function TImageEnView.GetOnTransitionStep: TIETransitionStepEvent;
|
||
begin
|
||
if assigned(fTransition) then
|
||
result := fTransition.OnTransitionStep
|
||
else
|
||
result := nil;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnTransitionPaint
|
||
|
||
<FM>Declaration<FC>
|
||
property OnTransitionPaint: <A TIEOnTransitionPaint>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs immediately before a new transition frame is painted. <FC>Step<FN> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.TransitionTiming
|
||
|
||
<FM>Declaration<FC>
|
||
property TransitionTiming: <A TIETransitionTiming>;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Playing
|
||
|
||
<FM>Declaration<FC>
|
||
property Playing : boolean;
|
||
|
||
<FM>Description<FN>
|
||
Set Playing to True to animate GIF and AVI files. If <A TImageEnView.PlayLoop> 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.<A TImageEnMView.Playing> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.AlphaChannel
|
||
|
||
<FM>Declaration<FC>
|
||
property AlphaChannel: <A TIEBitmap>;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.IEBitmap>.<A TIEBitmap.AlphaChannel> property.
|
||
!!}
|
||
function TImageEnView.GetAlphaChannel: TIEBitmap;
|
||
begin
|
||
result := nil;
|
||
if fIEBitmapValid then
|
||
result := fIEBitmap.AlphaChannel;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.HasAlphaChannel
|
||
|
||
<FM>Declaration<FC>
|
||
property HasAlphaChannel: Boolean; (Read-only)
|
||
|
||
<FM>Description<FN>
|
||
Returns True if the current image has an alpha channel.
|
||
|
||
!!}
|
||
function TImageEnView.GetHasAlphaChannel: boolean;
|
||
begin
|
||
result := False;
|
||
if fIEBitmapValid then
|
||
result := fIEBitmap.HasAlphaChannel;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.InvertSelection
|
||
|
||
<FM>Declaration<FC>
|
||
procedure InvertSelection;
|
||
|
||
<FM>Description<FN>
|
||
InvertSelection changes the selection to everything except the current selection.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.EnableAlphaChannel
|
||
|
||
<FM>Declaration<FC>
|
||
property EnableAlphaChannel: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.AlphaChannel> property (a <A TIEBitmap> object) and in TIEBitmap.<A TIEBitmap.AlphaChannel> property.
|
||
!!}
|
||
procedure TImageEnView.SetEnableAlphaChannel(v: boolean);
|
||
begin
|
||
if fEnableAlphaChannel <> v then
|
||
begin
|
||
fEnableAlphaChannel := v;
|
||
Update;
|
||
end;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.UpdateRect
|
||
|
||
<FM>Declaration<FC>
|
||
procedure UpdateRect(rclip: TRect);
|
||
|
||
<FM>Description<FN>
|
||
UpdateRect updates the rectangle, rclip. Use this function instead of Update when only a portion of the image has changed.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetSelectedAreaAlpha
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetSelectedAreaAlpha(Alpha: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Sets the Alpha value (transparency) for all pixels inside current selection.
|
||
|
||
To activate the alpha channel (transparency), set <A TImageEnView.EnableAlphaChannel> to True.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetSelectionGripStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetSelectionGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: Integer; ExtendedGrips: Boolean; boolean; Shape: <A TIEGripShape>);
|
||
|
||
<FM>Description<FN>
|
||
SetSelectionGripStyle determines the appearance of selection grips.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>GripColor1<FN></C> <C>grip border color (default clBlack)</C> </R>
|
||
<R> <C><FC>GripColor2<FN></C> <C>grip brush color (default clWhite)</C> </R>
|
||
<R> <C><FC>GripBrushStyle<FN></C> <C>brush style (default bsSolid)</C> </R>
|
||
<R> <C><FC>GripSize<FN></C> <C>size in pixels of the grip (default 5)</C> </R>
|
||
<R> <C><FC>ExtendedGrips<FN></C> <C>if true enables grips on border with 8 resizing grips (deault true)</C> </R>
|
||
<R> <C><FC>Shape<FN></C> <C>specifies the grip shape</C> </R>
|
||
</TABLE>
|
||
|
||
Use <A TImageEnView.GetSelectionGripStyle> to know current values.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.GetSelectionGripStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure GetSelectionGripStyle(var GripColor1: TColor; var GripColor2: TColor; var GripBrushStyle: TBrushStyle; var GripSize: integer; var ExtendedGrips: boolean; var Shape: TIEGripShape);
|
||
|
||
<FM>Description<FN>
|
||
GetSelectionGripStyle returns properties which determines the appearance of selection grips.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>GripColor1<FN></C> <C>grip border color (default clBlack)</C> </R>
|
||
<R> <C><FC>GripColor2<FN></C> <C>grip brush color (default clWhite)</C> </R>
|
||
<R> <C><FC>GripBrushStyle<FN></C> <C>brush style (default bsSolid)</C> </R>
|
||
<R> <C><FC>GripSize<FN></C> <C>size in pixels of the grip (default 5)</C> </R>
|
||
<R> <C><FC>ExtendedGrips<FN></C> <C>if true enables grips on border with 8 resizing grips (default: false)</C> </R>
|
||
<R> <C><FC>Shape<FN></C> <C>specifies the grip shape</C> </R>
|
||
</TABLE>
|
||
|
||
Use <A TImageEnView.SetSelectionGripStyle> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetLayersGripStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetLayersGripStyle(GripColor1, GripColor2: TColor; GripBrushStyle: TBrushStyle; GripSize: Integer; Shape: <A TIEGripShape>);
|
||
|
||
<FM>Description<FN>
|
||
SetLayersGripStyle determines the appearance of layers grips.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>GripColor1<FN></C> <C>grip border color</C> </R>
|
||
<R> <C><FC>GripColor2<FN></C> <C>grip brush color</C> </R>
|
||
<R> <C><FC>GripBrushStyle<FN></C> <C>brush style</C> </R>
|
||
<R> <C><FC>GripSize<FN></C> <C>size in pixels of the grip</C> </R>
|
||
<R> <C><FC>Shape<FN></C> <C>specifies the grip shape</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetChessboardStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetChessboardStyle(Size: Integer; BrushStyle: TBrushStyle = bsSolid; Color1: TColor = clNone; Color2: TColor = clNone);
|
||
|
||
<FM>Description<FN>
|
||
Sets the size and brush of the chessboard background (when <A TImageEnView.BackgroundStyle> is iebsChessboard).
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Size<FN></C> <C>Specifies the box size (default 16)</C> </R>
|
||
<R> <C><FC>BrushStyle<FN></C> <C>Specifies the brush style of the boxes (default bsSolid)</C> </R>
|
||
<R> <C><FC>Color1<FN></C> <C>Color 1 of chessboard. Specifying this as something other than clNone will set <A TImageEnView.Background></C> </R>
|
||
<R> <C><FC>Color2<FN></C> <C>Color 2 of chessboard. If specified as clNone, then color 2 will be a reverse of Color 1</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.ApplyBitmapToSelection
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ApplyBitmapToSelection(SrcBitmap: TBitmap; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False);
|
||
procedure ApplyBitmapToSelection(SrcBitmap: <A TIEBitmap>; MergeAlpha: Boolean = True; MaintainAspectRatio: Boolean = True; CanStretch: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Applies a bitmap to the selected region, stretching the image to the selection size.
|
||
<FC>MergeAlpha<FN> will merge the alpha channel of the pasted bitmap with the background bitmap.
|
||
If <FC>MaintainAspectRatio<FN> is False the inserted image will fill the entire selection. Set <FC>MaintainAspectRatio<FN> to true to maintain the aspect ratio of the original bitmap. <FC>CanStretch<FN> determines whether a source image smaller than the selection is enlarged or maintains its original size.
|
||
|
||
Note: <FC>CanStretch<FN> has no effect if <FC>MaintainAspectRatio<FN> is False (image will always be stretched)
|
||
|
||
<FM>Example<FC>
|
||
// 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' );
|
||
<IMG help_images\PasteSource.png>
|
||
|
||
ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, False, False );
|
||
<IMG help_images\PasteStretch.png>
|
||
|
||
ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, True, False );
|
||
<IMG help_images\PasteAR.png>
|
||
|
||
ImageEnView1.ApplyBitmapToSelection( aIEBitmap, True, True, True );
|
||
<IMG help_images\PasteStretchAR.png>
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.CopySelectionToBitmap>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.CopySelectionToBitmap
|
||
|
||
<FM>Declaration<FC>
|
||
procedure CopySelectionToBitmap(DestBitmap: TBitmap; FillBackground: Boolean = True); overload;
|
||
procedure CopySelectionToBitmap(DestBitmap: <A TIEBitmap>; FillBackground: Boolean = True); overload;
|
||
|
||
<FM>Description<FN>
|
||
Copies the current selection to the specified bitmap.
|
||
|
||
If <FC>FillBackground<FN> is enabled, then non-selected areas of the copied rectangle of the image will be filled with the <L TImageEnView.Background>background color</L>. Otherwise, it is transferred as alpha.
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ApplyBitmapToSelection>
|
||
!!}
|
||
// 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}
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.AssignSelTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure AssignSelTo(Dest: TPersistent);
|
||
|
||
<FM>Description<FN>
|
||
Assigns the selected area to the <FC>Dest<FN> object (can be a <A TImageEnView>, TBitmap or TImage).
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.CopyToBitmapWithAlpha
|
||
|
||
<FM>Declaration<FC>
|
||
procedure TImageEnView.CopyToBitmapWithAlpha(Dest: TBitmap; DestX, DestY: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Copies the current image to the <FC>Dest<FN> bitmap, at <FC>DestX, DestY<FN> 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.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetSelectedPixelsColor
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetSelectedPixelsColor(color: <A TRGB>);
|
||
|
||
<FM>Description<FN>
|
||
Sets selected pixels to the specified color.
|
||
|
||
<FM>Example<FC>
|
||
// 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) );
|
||
|
||
<FM>See Also<FN>
|
||
- <A CreateRGB>
|
||
- <A TRGB2TColor>
|
||
- <A TColor2TRGB>
|
||
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetAlphaRangePixelsColor
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetAlphaRangePixelsColor(alphaMin, alphaMax: Integer; color: <A TRGB>);
|
||
|
||
<FM>Description<FN>
|
||
Sets all pixels that have an alpha channel value between alphaMin and alphaMax to the specified color.
|
||
|
||
<FM>Example<FC>
|
||
// 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');
|
||
|
||
<FM>See Also<FN>
|
||
- <A CreateRGB>
|
||
- <A TRGB2TColor>
|
||
- <A TColor2TRGB>
|
||
|
||
!!}
|
||
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
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCount
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersCount: Integer;
|
||
|
||
<FM>Description<FN>
|
||
LayersCount returns the number of layers.
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.CurrentLayer
|
||
|
||
<FM>Declaration<FC>
|
||
property CurrentLayer: <A TIELayer>;
|
||
|
||
<FM>Description<FN>
|
||
Provides access to the currently active layer.
|
||
|
||
This is equivalent to:
|
||
<FC>ImageEnView.Layers[ ImageEnView.LayersCurrent ]<FN>
|
||
|
||
See the <A TImageEnView.Layers> property for more info.
|
||
|
||
Note: Use <A TImageEnView.LayersCurrent> to get or set the current layer index. Use <FC>CurrentLayer<FN> to return the layer object.
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView.LayersAdd;
|
||
ImageEnView.CurrentLayer.Transparency := 200;
|
||
|
||
// Remove the fill from the current layer
|
||
ImageEnView1.CurrentLayer.FillColor := clNone;
|
||
ImageEnView1.Update();
|
||
|
||
<IMG help_images\Shape_NoFill.jpg>
|
||
|
||
!!}
|
||
function TImageEnView.GetCurrentLayer: TIELayer;
|
||
begin
|
||
result := TIELayer(fLayers[fLayersCurrent]);
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCurrent
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersCurrent: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Use <FC>LayersCurrent<FC> to get/set the active layer.
|
||
The first layer has the index of 0, the last is <A TImageEnView.LayersCount> - 1.
|
||
Making a layer current changes the <A TImageEnView.IEBitmap> and <A TImageEnView.Bitmap> properties, so they point to the current layer (allowing specification of which layer is active for input/output and image processing operations).
|
||
|
||
Notes:
|
||
- Use <A TImageEnView.CurrentLayer> to return the layer object. Use <FC>LayersCurrent<FC> to get or set the current layer index
|
||
- Setting LayersCurrent does NOT deselect existing layers (if <L TImageEnView.LayerOptions>multiple layer selection</L> is enabled)
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersAdd
|
||
|
||
<FM>Declaration<FC>
|
||
// General overload
|
||
function LayersAdd(Kind: <A TIELayerKind> = ielkImage): integer; overload;
|
||
|
||
// Blank image overload (creates <A TIEImageLayer>)
|
||
function LayersAdd(Width: Integer; Height: Integer; PixelFormat: <A TIEPixelFormat> = ie24RGB; PosX: Integer = -1; PosY: Integer = -1): Integer;
|
||
|
||
// Assign bitmap overload (creates <A TIEImageLayer>)
|
||
function LayersAdd(Bitmap: <A TIEBitmap>): integer;
|
||
|
||
// Loads image overload (creates <A TIEImageLayer>)
|
||
function LayersAdd(FileName: String; PosX: Integer = -1; PosY: Integer = -1): integer;
|
||
|
||
// Shape overload (creates <A TIEShapeLayer>)
|
||
function LayersAdd(Shape: <A TIEShape>; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0): integer;
|
||
|
||
// Text overload (creates <A TIETextLayer>)
|
||
function LayersAdd(Text: String; FontSize : Integer; FontColor : TColor; FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1): integer;
|
||
|
||
<FM>Description<FN>
|
||
Appends a new layer to the layers list. The new layer will become the current layer.
|
||
First overload allows you to specify the <A TIELayer.Kind>layer type</L>, all others create a <A TIEImageLayer>.
|
||
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.
|
||
|
||
<FM>Examples<FC>
|
||
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();
|
||
|
||
<IMG help_images\Polyline_NoBorder.gif>
|
||
|
||
// 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;
|
||
|
||
<IMG help_images\Image_withBorder.gif>
|
||
|
||
// 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();
|
||
|
||
<IMG help_images\TextLayer.gif>
|
||
|
||
<FM>See Also<FN>
|
||
-<A TIELayer>
|
||
-<A TImageEnView.LayersInsert>
|
||
-<A TImageEnView.LayersCreateFromSelection>
|
||
-<A TImageEnView.LayersCreateFromClipboard>
|
||
-<A TImageEnView.LayersCreateFromFile>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersInsert
|
||
|
||
<FM>Declaration<FC>
|
||
// General overload
|
||
procedure LayersInsert(Position: Integer; Kind: <A TIELayerKind> = ielkImage); overload;
|
||
|
||
// Blank image overload (creates <A TIEImageLayer>)
|
||
procedure LayersInsert(Position: Integer; Width: Integer; Height: Integer; PixelFormat: <A TIEPixelFormat> = ie24RGB; PosX: Integer = 0; PosY: Integer = 0);
|
||
|
||
// Assign bitmap overload (creates <A TIEImageLayer>)
|
||
procedure LayersInsert(Position: Integer; Bitmap: <A TIEBitmap>);
|
||
|
||
// Loads image overload (creates <A TIEImageLayer>)
|
||
procedure LayersInsert(Position: Integer; FileName: String; PosX: Integer = -1; PosY: Integer = -1);
|
||
|
||
// Shape overload (creates <A TIEShapeLayer>)
|
||
procedure LayersInsert(Position: Integer; Shape: <A TIEShape>; PosX: Integer = -1; PosY: Integer = -1; Width: Integer = 0; Height: Integer = 0);
|
||
|
||
// Text overload (creates <A TIETextLayer>)
|
||
procedure LayersInsert(Position: Integer; Text: String; FontSize : Integer; FontColor : TColor; FontName : string; FontStyle : TFontStyles = []; PosX: Integer = -1; PosY: Integer = -1);
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIELayer.Kind>layer type</L>, all others create a <A TIEImageLayer>.
|
||
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 <A TIEImageLayer> 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
|
||
|
||
<FM>Examples<FC>
|
||
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();
|
||
|
||
<IMG help_images\Polyline_NoBorder.gif>
|
||
|
||
// 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;
|
||
|
||
<IMG help_images\Image_withBorder.gif>
|
||
|
||
// 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();
|
||
|
||
<IMG help_images\TextLayer.gif>
|
||
|
||
<FM>See Also<FN>
|
||
-<A TIELayer>
|
||
-<A TImageEnView.LayersAdd>
|
||
-<A TImageEnView.LayersCreateFromSelection>
|
||
-<A TImageEnView.LayersCreateFromClipboard>
|
||
-<A TImageEnView.LayersCreateFromFile>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRemove
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersRemove(LyrIndex: Integer = LYR_SELECTED_LAYERS);
|
||
|
||
<FM>Description<FN>
|
||
Removes a layer and frees the related bitmap. You can specify the index of a layer of <FC>LYR_SELECTED_LAYERS<FN> to remove all selected layers.
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>idx<FN></C> <C>Index of the layer to remove (0 = background/first layer). You can also specify <FC>LYR_SELECTED_LAYERS<FN> or <FC>LYR_ALL_LAYERS<FN> </C> </R>
|
||
</TABLE>
|
||
|
||
Note: At least one layer must be present. Attempting to remove the final layer will empty its content.
|
||
|
||
<FM>Example<FC>
|
||
// Remove all selected layers
|
||
ImageEnView1.LayersRemove();
|
||
|
||
// Remove the top-most layer
|
||
ImageEnView1.LayersRemove( ImageEnView1.LayersCount - 1 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersClear>
|
||
!!}
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersClear
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersClear;
|
||
|
||
<FM>Description<FN>
|
||
Removes all layers.
|
||
|
||
Note: After completion only the background layer will remain (as an ImageEnView always requires at least one layer).
|
||
|
||
<FM>Comparison of Methods<FN>
|
||
<TABLE>
|
||
<R> <H>Method</H> <H>Description</H> </R>
|
||
<R> <C> <A TImageEnView.Clear> </C> <C> Fills the current image with the <A TImageEnView.Background>background color</L> and <L TImageEnView.RemoveAlphaChannel>removes</L> the alpha channel </C> </R>
|
||
<R> <C> <A TImageEnView.Blank> </C> <C> Calls <A TImageEnView.Clear> and resets the image size to 1 x 1</C> </R>
|
||
<R> <C> <A TImageEnView.LayersClear> </C> <C> Removes all of the <A TImageEnView.Layers>layers</L> </C> </R>
|
||
<R> <C> <A TImageEnView.ClearAll> </C> <C> Resets the image (calling <A TImageEnView.Blank>) and removes all layers (calling <A TImageEnView.LayersClear>) </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRemove>
|
||
!!}
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersMove
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersMove(CurIndex, NewIndex: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Moves the layer at index, <FC>CurIndex<FN>, to the position, <FC>NewIndex<FN>.
|
||
|
||
You can specify <FC>LYR_SELECTED_LAYERS<FN> (-2) for <FC>CurIndex<FN> to move all selected layers.
|
||
|
||
<FC>NewIndex<FN> can be one of the following:
|
||
<TABLE>
|
||
<R> <C>>= 0</C> <C>The new insertion index</C> </R>
|
||
<R> <C>IEN_Send_To_Back</C> <C>The layer will become the new background layer (layer 0)</C> </R>
|
||
<R> <C>IEN_Send_Backward</C> <C>The layer will move closer to the background</C> </R>
|
||
<R> <C>IEN_Bring_Forward</C> <C>The layer will move closer to the foreground</C> </R>
|
||
<R> <C>IEN_Bring_To_Front</C> <C>The layer will become the topmost one (in front of all others)</C> </R>
|
||
</TABLE>
|
||
|
||
Notes:
|
||
- If the layer has a mask it will be moved too
|
||
- Only a <A TIEImageLayer> 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 <FC>LayersMove<FN> to arrange layer order. Use <A TImageEnView.LayersRepositionAll> to change the position of layers
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSetProperties
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersSetProperties(LayerIndex: integer; Props: TStrings); overload;
|
||
procedure LayersSetProperties(LayerIndex: integer; const PropName, Value: Variant); overload;
|
||
|
||
<FM>Description<FN>
|
||
Sets properties of multiple layers in a batch (by calling <A TIELayer.SetProperties>).
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>LayerIndex<FN></C> <C>Index of the layer to update. Generally this will be <FC>LYR_SELECTED_LAYERS<FN> or <FC>LYR_ALL_LAYERS<FN> </C> </R>
|
||
<R> <C><FC>Props<FN></C> <C>A list of properties in Name=Value pairs </C> </R>
|
||
<R> <C><FC>PropName<FN></C> <C>A <L TIELayer Property Consts>property</L> to update </C> </R>
|
||
<R> <C><FC>Value<FN></C> <C>New value for the property </C> </R>
|
||
</TABLE>
|
||
|
||
Names will be drawn from the <A TIELayer Property Consts>. Properties can be retrieved using <A TIELayer.GetProperties>.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIELayer.SetProperties>
|
||
- <A TIELayer.GetProperties>
|
||
!!}
|
||
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Modified
|
||
|
||
<FM>Declaration<FC>
|
||
property Modified: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Returns true if the image has been changed since it was loaded.
|
||
Modified will be set when there are changes to the using <A TImageEnProc> (<A TImageEnView.Proc> property), or to <A TImageEnView.Layers>.
|
||
|
||
<FM>Example<FC>
|
||
btnSave.Enabled := ImageEnView1.Modified;
|
||
|
||
// Reset modified after saving
|
||
ImageEnView1.IO.SaveToFile( Filename );
|
||
ImageEnView1.Modified := False;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIEBitmap.Modified>
|
||
- <A TIELayer.Modified>
|
||
- <A TImageEnView.OnImageChange>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.FindLayerAt
|
||
|
||
<FM>Declaration<FC>
|
||
function FindLayerAt(x, y: Integer; SelectablesOnly: Boolean = true): Integer;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersConvertToImageLayers
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersConvertToImageLayers(LayerIdx: Integer = LYR_SELECTED_LAYERS; QualityFactor: Double = 2; CropAlpha: Boolean = True; ConvertImages: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Changes the <A TIELayer.Kind>type</L> of the specified layer to <A TIEImageLayer>.
|
||
This will change it from a vector-based layer to a standard bitmap layer. Bitmap layers can be edited using <L TImageEnProc>standard image modification features</L>, but the quality will be lost if you resize the layer.
|
||
<FC>QualityFactor<FN> determines the size that the layer bitmap is created. A <FC>QualityFactor<FN> of 1 will create the bitmap at the current display size, whereas a <FC>QualityFactor<FN> of 2 would create it at double the display size (allowing it to be zoomed up 200% without loss of quality).
|
||
If <FC>CropAlpha<FN> is true, then it remove any alpha from the edges of the layer.
|
||
<FC>ConvertImages<FN> affects only image layers. By default image layers are ignored, if <FC>ConvertImages<FN> is true, the rotated images are fixed using <A TImageEnView.LayersFixRotations>
|
||
|
||
Note:
|
||
- For text layers, a QualityFactor of 1 usually works best
|
||
- To convert an individual layers, you can also use <A TIELayer.ConvertToImageLayer>
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersMergeTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersMergeTo(Layer1, Layer2: integer; Destination: <A TIEBitmap>);
|
||
|
||
<FM>Description<FN>
|
||
Merges Layer1 and Layer2 into a TIEBitmap object.
|
||
The new bitmap will inherit the <A TImageEnView.Layers>[].<A TIELayer.Transparency> and alpha channels.
|
||
The resulting bitmap will always be 24 bit (ie24RGB).
|
||
|
||
Notes:
|
||
- If either layer is not a <A TIEImageLayer>, it will be <L TImageEnView.LayersConvertToImageLayers>converted to a TIEImageLayer</L>
|
||
- LayersMergeTo can merge a layer with its own layer mask (to create a layer with the transparency of the mask).
|
||
- <A TImageEnView.LayersMergeFilter> will specify the quality of image layers, if they do not have a custom <A TIEImageLayer.UseResampleFilter>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersMerge
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersMerge(); overload;
|
||
procedure LayersMerge(Layer1, Layer2: integer; RemoveUpperLayer: Boolean = true); overload;
|
||
procedure LayersMerge(LayerList: array of integer); overload;
|
||
procedure LayersMerge(LayerList: <A TIEArrayOfInteger>); overload;
|
||
|
||
<FM>Description<FN>
|
||
Merges two or more layers into one layer. The new layer has the lesser index.
|
||
The new layer will inherit the <A TImageEnView.Layers>.<A TIELayer.Transparency> 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 <A TIEImageLayer>, they will be <L TImageEnView.LayersConvertToImageLayers>converted to a TIEImageLayer</L>
|
||
- <A TImageEnView.LayersMergeFilter> will specify the quality of image layers, if they do not have a custom <A TIEImageLayer.UseResampleFilter>
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Layer1<FN></C> <C>Index of the first layer to merge.</C> </R>
|
||
<R> <C><FC>Layer2<FN></C> <C>Index of the second layer to merge.</C> </R>
|
||
<R> <C><FC>RemoveUpperLayer<FN></C> <C>If <FC>RemoveUpperLayer<FN> is <FC>false<FN>, the upper layer will not be removed.</C> </R>
|
||
<R> <C><FC>LayerList<FN></C> <C>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".</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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<fLayers.Count - 1) and Layers[lamax + 1].IsMask then
|
||
begin
|
||
// remove layer mask
|
||
Layers[lamax + 1].Free;
|
||
fLayers.Delete(lamax + 1);
|
||
end;
|
||
Layers[lamax].Free;
|
||
fLayers.Delete(lamax);
|
||
end;
|
||
Layers[lamin].Free;
|
||
fLayers.Delete(lamin);
|
||
// insert new one
|
||
fLayersCurrent := -1;
|
||
fLayers.Insert(lamin, outlayer);
|
||
//
|
||
|
||
{$IFDEF UNITTESTING}
|
||
if fDebugUpdatedCount > 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
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
{!!
|
||
<FS>TImageEnView.Bitmap
|
||
|
||
<FM>Declaration<FC>
|
||
property Bitmap: TBitmap;
|
||
|
||
<FM>Description<FN>
|
||
Bitmap contains the image (current layer) to display.
|
||
If <A TImageEnView.LegacyBitmap> is <FC>True<FN>, <A TImageEnView.IEBitmap> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.IEBitmap
|
||
|
||
<FM>Declaration<FC>
|
||
property IEBitmap: <A TIEBitmap>;
|
||
|
||
<FM>Description<FN>
|
||
Contains the image (current layer) to display. The object TIEBitmap also contains the alpha channel of the image.
|
||
If your image contains <L TImageEnView.Layers>multiple layers</L> then <FC>IEBitmap<FN> is the bitmap of the selected <L TIEImageLayer>image layer</L>. If a non-image layer is selected then IEBitmap will be the background layer (Layer 0).
|
||
|
||
Notes:
|
||
- You must call <A TImageEnView.Update> if you modify <FC>IEBitmap<FN> directly
|
||
- If <A TImageEnView.LegacyBitmap> 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LegacyBitmap
|
||
|
||
<FM>Declaration<FC>
|
||
property LegacyBitmap: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
If LegacyBitmap is <FC>True<FN>, ImageEn uses TBitmap to store the image, otherwise ImageEn uses <A TIEBitmap>.
|
||
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 (<A TIEPixelFormat>).
|
||
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.GetRenderRectangles
|
||
|
||
<FM>Declaration<FC>
|
||
procedure GetRenderRectangles(var xDst, yDst, dxDst, dyDst: integer; var xSrc, ySrc, dxSrc, dySrc: integer);
|
||
|
||
<FM>Description<FN>
|
||
Returns the rendered rectangle related to the client area and the source rectangle related to the bitmap of current layer.
|
||
|
||
<FC>xDst, yDst, dxDst, dyDst<FN> : the destination x, y and width, height where the image has been rendered
|
||
|
||
<FC>xSrc, ySrc, dxSrc, dySrc<FN> : 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersMergeAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersMergeAll(AlphaCompositing: Boolean = False);
|
||
|
||
<FM>Description<FN>
|
||
Call LayersMergeAll to merge all layers in one step.
|
||
When <FC>AlphaCompositing<FN> is False then this method performs the same task as <A TImageEnView.LayersDrawTo>, 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 <FC>AlphaCompositing<FN> is True the result is equivalent to calling <A TImageEnView.LayersMerge>([]). <A TImageEnView.LayersMergeFilter> will specify the quality of image layers, if they do not have a custom <A TIEImageLayer.UseResampleFilter>
|
||
|
||
<FM>Example<FN>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersSaveMergedTo>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersDrawTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersDrawTo(Destination: <A TIEBitmap>; AdjustBitmap: Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Merges all layers and draws the result to <FC>Destination<FN> bitmap.
|
||
This function should replace a sequence of <A TImageEnView.LayersMerge> calls. The destination bitmap will not have a transparency channel.
|
||
If <FC>AdjustBitmap<FN> is true the <FC>Destination<FN> bitmap will be sized to display all layers.
|
||
<FM>Example<FC>
|
||
// draws all layers of ImageEnView1 to ImageEnView2
|
||
ImageEnView1.LayersDrawTo( ImageEnView2.IEBitmap );
|
||
ImageEnView2.Update;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersSaveMergedTo>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSaveMergedTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersSaveMergedTo(Destination: <A TIEBitmap>; FastOutput: Boolean = False); overload;
|
||
procedure LayersSaveMergedTo(const Filename: string; FastOutput: Boolean = False); overload;
|
||
procedure LayersSaveMergedTo(const Stream: TStream; FileType: <A TIOFileType>; FastOutput: Boolean = False); overload;
|
||
|
||
<FM>Description<FN>
|
||
Output a merged version of all layers to a <A TIEBitmap>, file or stream.
|
||
This method will preserve any alpha channel in the image.
|
||
Pass <FC>FastOutput<FN> 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:
|
||
- <A TImageEnView.LayersMergeFilter> will specify the quality of image layers, if they do not have a custom <A TIEImageLayer.UseResampleFilter>
|
||
- The existing image is not changed.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnIO.SaveToFileIEN>
|
||
- <A TImageEnIO.SaveToStreamIEN>
|
||
- <A TImageEnView.LayersMergeAll>
|
||
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayerOptions
|
||
|
||
<FM>Declaration<FC>
|
||
property LayerOptions: <A TIELayerOptions>;
|
||
|
||
<FM>Description<FN>
|
||
Options to control layer behavior:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>loAllowMultiSelect</C> <C>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</C> </R>
|
||
<R> <C>loAutoSelectMask</C> <C>If you have enabled a <L TIEImageLayer.IsMask>mask</L> 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)</C> </R>
|
||
<R> <C>loAutoUndoChangesByUser</C> <C>If you have enabled <A TImageEnProc.AutoUndo>, then changes to layers made by users (using <L TImageEnView.MouseInteract>layer interactions<L> or <L TImageEnView Actions>layer TActions<L>) will be saved to the undo stack</C> </R>
|
||
<R> <C>loAutoUndoChangesByCode</C> <C>If you have enabled <A TImageEnProc.AutoUndo>, then programmatic changes to layers will be saved to the undo stack. This applies to the methods: <A TImageEnView.LayersAdd>, <A TImageEnView.LayersInsert>, <A TImageEnView.LayersCreateFromSelection>, <A TImageEnView.LayersCreateFromFile>, <A TImageEnView.LayersCreateFromEdge>, <A TImageEnView.LayersCreateFromAlpha>, <A TImageEnView.LayersRemove>, <A TImageEnView.LayersMerge>, <A TImageEnView.LayersMergeAll>, <A TImageEnView.LayersAlign>, <A TImageEnView.LayersMove>, <A TImageEnView.LayersRotateAll>, <A TImageEnView.LayersGroup>, <A TImageEnView.LayersUngroup>, <A TImageEnView.LayersCropBackground> </C> </R>
|
||
<R> <C>loAutoPromptForImage</C> <C>When setting <A TImageEnView.MouseInteract> to <FC>miCreateImageLayers<FN>, the user can drag select to create an <A TIEImageLayer> If <FC>loAutoPromptForImage<FN> 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.</C> </R>
|
||
<R> <C>loAutoFixBorders</C> <C>If enabled, <A TImageEnView.LayersFixBorders> will be called prior to rotation to removes any transparency around the edges of the image.</C> </R>
|
||
<R> <C>loAutoFixRotation</C> <C>If enabled, <A TImageEnView.LayersFixRotations> will be called after rotation to lock in the rotation angle of image layers.</C> </R>
|
||
<R> <C>loDynamicCanvas</C> <C>If enabled, ImageEn will align the view to the bounds of all layers (i.e. by <A TImageEnView.LayersRect>). 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 <A TImageEnView.Center>=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.</C> </R>
|
||
</TABLE>
|
||
|
||
Default: [loAllowMultiSelect, loAutoUndoChangesByUser, loAutoPromptForImage, loAutoFixBorders]
|
||
|
||
Note: To disable movement of layers by the keyboard, see <FC>iesoAllowMoveByKeyboard<FN> of <A TImageEnView.SelectionOptions>
|
||
|
||
<FM>Examples<FC>
|
||
// 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 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.Layers>
|
||
- <A TImageEnView.LayersCurrent>
|
||
- <A TImageEnView.LayersSelectAll>
|
||
- <A TImageEnView.LayersDeselectAll>
|
||
- <A TIELayer.Selected>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayerDefaults
|
||
|
||
<FM>Declaration<FC>
|
||
property LayerDefaults: TStringList;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TIELayer Property Consts>.
|
||
|
||
Notes:
|
||
- These properties apply to layers created programmatically (e.g. using <A TImageEnView.LayersAdd>) and by the user (e.g. <L TImageEnView.MouseInteract>using miCreateShapeLayers</L>).
|
||
- The <A TImageEnView.OnNewLayer> event can also be used to apply default properties
|
||
|
||
<FM>Sample Output<FC>
|
||
IELP_BorderColor=clNone
|
||
IELP_BorderWidth=0
|
||
IELP_FillColor=clYellow
|
||
IELP_FillColor2=clRed
|
||
IELP_FillGradient=1
|
||
IELP_Rotate=0
|
||
|
||
<FM>Example<FC>
|
||
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
|
||
|
||
<IMG help_images\Image_withBorder.gif>
|
||
|
||
// 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 ];
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIEImageEnGlobalSettings.DefaultLayerText>
|
||
- <A TImageEnView.OnNewLayer>
|
||
- <A TIELayer.GetProperties>
|
||
- <A TIELayer.SetProperties>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCropped
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersCropped: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
When enabled, any part of layers that are outside the background image (layer 0) area will not be displayed.
|
||
If true, it overrides the <A TIELayer.Cropped> property of individual layers.
|
||
|
||
Default: False
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetLayersBoxStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetLayersBoxStyle(PenStyle: TPenStyle = psDot; PenMode: TPenMode = pmNot; PenWidth: Integer = 1; PenColor: TColor = clBlack);
|
||
|
||
<FM>Description<FN>
|
||
Specifies the style of layer box border, if <A TImageEnView.LayersDrawBox> is enabled.
|
||
|
||
For more control, use <A TImageEnView.OnDrawLayerBox>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SaveSelectionToStream
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SaveSelectionToStream(Stream: TStream);
|
||
|
||
<FM>Description<FN>
|
||
Saves the current selection to the specified stream (just the user selection, not the image content)
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LoadSelectionFromStream
|
||
|
||
<FM>Declaration<FC>
|
||
function LoadSelectionFromStream(Stream: TStream; Options: <A TIERSOptions> = iersMoveToAdapt): boolean;;
|
||
|
||
<FM>Description<FN>
|
||
Loads a selection from a stream (saved using <A TImageEnView.SaveSelectionToStream> or <A TImageEnView.SaveSelectionToFile>). 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.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SaveSelectionToFile
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SaveSelectionToFile(const FileName: String);
|
||
|
||
<FM>Description<FN>
|
||
Saves the current selection to the specified file (just the user selection, not the image content).
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LoadSelectionFromFile
|
||
|
||
<FM>Declaration<FC>
|
||
function LoadSelectionFromFile(const FileName: String; Options: <A TIERSOptions> = iersMoveToAdapt): boolean;
|
||
|
||
<FM>Description<FN>
|
||
Loads a selection from a file (saved using <A TImageEnView.SaveSelectionToStream> or <A TImageEnView.SaveSelectionToFile>).
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MergeSelectionFromFile
|
||
|
||
<FM>Declaration<FC>
|
||
function MergeSelectionFromFile(const FileName: String): Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Loads a selection from a file (saved using <A TImageEnView.SaveSelectionToStream> or <A TImageEnView.SaveSelectionToFile>) merging it with the currently one.
|
||
Returns False if it fails.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MergeSelectionFromStream
|
||
|
||
<FM>Declaration<FC>
|
||
function MergeSelectionFromStream(Stream: TStream): Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Loads a selection from a stream (saved using <A TImageEnView.SaveSelectionToStream> or <A TImageEnView.SaveSelectionToFile>) merging it with the currently one.
|
||
Returns False if it fails.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SavedSelectionsCount
|
||
|
||
<FM>Declaration<FC>
|
||
property SavedSelectionsCount: Integer
|
||
|
||
<FM>Description<FN>
|
||
Returns the number of saved selections.
|
||
!!}
|
||
function TImageEnView.GetSavedSelectionsCount: Integer;
|
||
begin
|
||
result := fSavedSelection.Count;
|
||
end;
|
||
|
||
// push current selection in fSavedSelection list
|
||
|
||
{!!
|
||
<FS>TImageEnView.SaveSelection
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SaveSelection;
|
||
|
||
<FM>Description<FN>
|
||
Adds the current selection to the stack (selections list).
|
||
|
||
<FM>Example<FC>
|
||
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
|
||
|
||
{!!
|
||
<FS>TImageEnView.RestoreSelection
|
||
|
||
<FM>Declaration<FC>
|
||
function RestoreSelection(Remove: Boolean=true; Options: <A TIERSOptions> = iersMoveToAdapt): boolean;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DiscardSavedSelection
|
||
|
||
<FM>Declaration<FC>
|
||
function DiscardSavedSelection: boolean;
|
||
|
||
<FM>Description<FN>
|
||
Removes the last saved selection from the stack (saved using <A TImageEnView.SaveSelection>).
|
||
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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.RemoveAlphaChannel
|
||
|
||
<FM>Declaration<FC>
|
||
procedure RemoveAlphaChannel(Merge: Boolean=false);
|
||
|
||
<FM>Description<FN>
|
||
Removes the alpha channel and its allocated memory. <A TImageEnView.HasAlphaChannel> will be set to false.
|
||
If <FC>Merge<FN> is true the image will be merged with the background color using its alpha channel.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.Cursor
|
||
|
||
<FM>Declaration<FC>
|
||
property Cursor: TCursor;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the image used for the mouse pointer when it passes over the control.
|
||
|
||
Note: If you have enabled <A TImageEnView.AutoCursors> then ImageEn will automatically change the cursor when relevant.
|
||
|
||
<FM>ImageEn Cursors<FN>
|
||
<TABLE>
|
||
<R> <H>Constant</H> <H>Value</H> <H>Cursor</H> </R>
|
||
<R> <C><FC>crIEZoomOut<FN></C> <C>1778</C> <C><IMG help_images\2.bmp></C> </R>
|
||
<R> <C><FC>crIEZoomIn<FN></C> <C>1779</C> <C><IMG help_images\3.bmp></C> </R>
|
||
<R> <C><FC>crIEThickCross2<FN></C> <C>1780</C> <C><IMG help_images\4.bmp></C> </R>
|
||
<R> <C><FC>crIEEraser<FN></C> <C>1781</C> <C><IMG help_images\5.bmp></C> </R>
|
||
<R> <C><FC>crIEHandDrag<FN></C> <C>1782</C> <C><IMG help_images\6.bmp></C> </R>
|
||
<R> <C><FC>crIEPencil<FN></C> <C>1783</C> <C><IMG help_images\7.bmp></C> </R>
|
||
<R> <C><FC>crIECross<FN></C> <C>1784</C> <C><IMG help_images\8.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSight<FN></C> <C>1785</C> <C><IMG help_images\9.bmp></C> </R>
|
||
<R> <C><FC>crIESizeNWSE<FN></C> <C>1786</C> <C><IMG help_images\10.bmp></C> </R>
|
||
<R> <C><FC>crIESizeNS<FN></C> <C>1787</C> <C><IMG help_images\11.bmp></C> </R>
|
||
<R> <C><FC>crIESizeNESW<FN></C> <C>1788</C> <C><IMG help_images\12.bmp></C> </R>
|
||
<R> <C><FC>crIESizeWE<FN></C> <C>1789</C> <C><IMG help_images\13.bmp></C> </R>
|
||
<R> <C><FC>crIESizeAll<FN></C> <C>1790</C> <C><IMG help_images\14.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSightPlus<FN></C> <C>1791</C> <C><IMG help_images\15.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSightMinus<FN></C> <C>1792</C> <C><IMG help_images\16.bmp></C> </R>
|
||
<R> <C><FC>crIEThickCross<FN></C> <C>1793</C> <C><IMG help_images\17.bmp></C> </R>
|
||
<R> <C><FC>crIEThickCrossPlus<FN></C> <C>1794</C> <C><IMG help_images\18.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSightMinus2<FN></C> <C>1795</C> <C><IMG help_images\19.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSightMinus3<FN></C> <C>1796</C> <C><IMG help_images\20.bmp></C> </R>
|
||
<R> <C><FC>crIEBrush<FN></C> <C>1797</C> <C><IMG help_images\21.bmp></C> </R>
|
||
<R> <C><FC>crIEEyeDropper3<FN></C> <C>1798</C> <C><IMG help_images\29.bmp></C> </R>
|
||
<R> <C><FC>crIEPaintFill<FN></C> <C>1799</C> <C><IMG help_images\23.bmp></C> </R>
|
||
<R> <C><FC>crIEStamp<FN></C> <C>1800</C> <C><IMG help_images\24.bmp></C> </R>
|
||
<R> <C><FC>crIECrop<FN></C> <C>1801</C> <C><IMG help_images\25.bmp></C> </R>
|
||
<R> <C><FC>crIECrossSmallPlus<FN></C> <C>1802</C> <C><IMG help_images\26.bmp></C> </R>
|
||
<R> <C><FC>crIESmallArrow<FN></C> <C>1803</C> <C><IMG help_images\27.bmp></C> </R>
|
||
<R> <C><FC>crIEMultipleArrow<FN></C> <C>1804</C> <C><IMG help_images\28.bmp></C> </R>
|
||
<R> <C><FC>crIEEyeDropper2<FN></C> <C>1805</C> <C><IMG help_images\29.bmp></C> </R>
|
||
<R> <C><FC>crIEEyeDropper<FN></C> <C>1806</C> <C><IMG help_images\30.bmp></C> </R>
|
||
<R> <C><FC>crIECut<FN></C> <C>1807</C> <C><IMG help_images\31.bmp></C> </R>
|
||
<R> <C><FC>crIESelectArrow<FN></C> <C>1808</C> <C><IMG help_images\32.bmp></C> </R>
|
||
<R> <C><FC>crIEPen<FN></C> <C>1809</C> <C><IMG help_images\33.bmp></C> </R>
|
||
<R> <C><FC>crIEPlusMinus<FN></C> <C>1810</C> <C><IMG help_images\34.bmp></C> </R>
|
||
<R> <C><FC>crIERotateNE<FN></C> <C>1811</C> <C><IMG help_images\CursorRotateNE.bmp></C> </R>
|
||
<R> <C><FC>crIERotateSW<FN></C> <C>1812</C> <C><IMG help_images\CursorRotateSW.bmp></C> </R>
|
||
<R> <C><FC>crIERotateNW<FN></C> <C>1813</C> <C><IMG help_images\CursorRotateNW.bmp></C> </R>
|
||
<R> <C><FC>crIERotateSE<FN></C> <C>1814</C> <C><IMG help_images\CursorRotateSE.bmp></C> </R>
|
||
</TABLE>
|
||
|
||
<FM>System Cursors<FN>
|
||
<TABLE>
|
||
<R> <H>Constant</H> <H>Value</H> <H>Cursor</H> </R>
|
||
<R> <C><FC>crNone<FN></C> <C>-1</C> <C><IMG help_images\35.bmp></C> </R>
|
||
<R> <C><FC>crArrow<FN></C> <C>-2</C> <C><IMG help_images\36.bmp></C> </R>
|
||
<R> <C><FC>crCross<FN></C> <C>-3</C> <C><IMG help_images\37.bmp></C> </R>
|
||
<R> <C><FC>crIBeam<FN></C> <C>-4</C> <C><IMG help_images\38.bmp></C> </R>
|
||
<R> <C><FC>crSizeNESW<FN></C> <C>-6</C> <C><IMG help_images\39.bmp></C> </R>
|
||
<R> <C><FC>crSizeNS<FN></C> <C>-7</C> <C><IMG help_images\40.bmp></C> </R>
|
||
<R> <C><FC>crSizeNWSE<FN></C> <C>-8</C> <C><IMG help_images\41.bmp></C> </R>
|
||
<R> <C><FC>crSizeWE<FN></C> <C>-9</C> <C><IMG help_images\42.bmp></C> </R>
|
||
<R> <C><FC>crUpArrow<FN></C> <C>-10</C> <C><IMG help_images\43.bmp></C> </R>
|
||
<R> <C><FC>crHourGlass<FN></C> <C>-11</C> <C><IMG help_images\44.bmp></C> </R>
|
||
<R> <C><FC>crDrag<FN></C> <C>-12</C> <C><IMG help_images\45.bmp></C> </R>
|
||
<R> <C><FC>crNoDrop<FN></C> <C>-13</C> <C><IMG help_images\46.bmp></C> </R>
|
||
<R> <C><FC>crHSplit<FN></C> <C>-14</C> <C><IMG help_images\47.bmp></C> </R>
|
||
<R> <C><FC>crVSplit<FN></C> <C>-15</C> <C><IMG help_images\48.bmp></C> </R>
|
||
<R> <C><FC>crMultiDrag<FN></C> <C>-16</C> <C><IMG help_images\49.bmp></C> </R>
|
||
<R> <C><FC>crSQLWait<FN></C> <C>-17</C> <C><IMG help_images\50.bmp></C> </R>
|
||
<R> <C><FC>crNo<R> <C><FC><FN></C> <C>-18</C> <C><IMG help_images\51.bmp></C> </R>
|
||
<R> <C><FC>crAppStart<FN></C> <C>-19</C> <C><IMG help_images\52.bmp></C> </R>
|
||
<R> <C><FC>crHelp<FN></C> <C>-20</C> <C><IMG help_images\53.bmp></C> </R>
|
||
<R> <C><FC>crHandPoint<FN></C> <C>-21</C> <C><IMG help_images\54.bmp></C> </R>
|
||
<R> <C><FC>crSizeAll<FN></C> <C>-22</C> <C><IMG help_images\55.bmp></C> </R>
|
||
</TABLE>
|
||
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DelayTimer
|
||
|
||
<FM>Declaration<FC>
|
||
property DelayTimer: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.DelayZoomFilter> 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:
|
||
<FC>ImageEnView.DelayTimer := -10;<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.GradientEndColor
|
||
|
||
<FM>Declaration<FC>
|
||
property GradientEndColor: TColor
|
||
|
||
<FM>Description<FN>
|
||
Specifies the ending color of the gradient when <A TImageEnView.BackgroundStyle> is <FC>iebsGradient<FN>. The gradient start color is set using <A TImageEnView.Background>.
|
||
|
||
Note: This value may be overridden if <A TIEImageEnGlobalSettings.EnableTheming> is enabled.
|
||
|
||
Default: clBtnShadow
|
||
!!}
|
||
procedure TImageEnView.SetGradientEndColor(Value: TColor);
|
||
begin
|
||
fGradientEndColor := Value;
|
||
UpdateReason := ieurComponentStuffChanged;
|
||
Update;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.CenterImage
|
||
|
||
<FM>Declaration<FC>
|
||
procedure CenterImage;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LockUpdate
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LockUpdate;
|
||
|
||
<FM>Description<FN>
|
||
Disables all calls to the <A TImageEnView.Update> method (increasing <A TImageEnView.LockUpdateCount>. LockUpdate and <A TImageEnView.UnlockUpdate> are useful, for example, when resampling multiple layers.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.UnlockUpdate
|
||
|
||
<FM>Declaration<FC>
|
||
procedure UnlockUpdate;
|
||
|
||
<FM>Description<FN>
|
||
Re-enables all calls to the <A TImageEnView.Update> method, after a call to <A TImageEnView.LockUpdate>.
|
||
LockUpdate and UnLockUpdate are useful, for example, when you need to resample multiple layers.
|
||
UnLockUpdate descreases <A TImageEnView.LockUpdateCount> and calls <A TImageEnView.Update> when the count reverts to zero.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.UnLockUpdateEx
|
||
|
||
<FM>Declaration<FC>
|
||
procedure UnLockUpdateEx;
|
||
|
||
<FM>Description<FN>
|
||
UnLockUpdateEx re-enables all calls to the <A TImageEnView.Update> method, after a call to <A TImageEnView.LockUpdate>.
|
||
LockUpdate and UnLockUpdateEx are useful, for example, when you need to resample multiple layers.
|
||
UnLockUpdateEx doesn't call <A TImageEnView.Update> when the update can be unlocked.
|
||
!!}
|
||
procedure TImageEnView.UnLockUpdateEx;
|
||
begin
|
||
if fUpdateLocked>0 then
|
||
dec(fUpdateLocked);
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.DrawVersion
|
||
|
||
<FM>Declaration<FC>
|
||
property DrawVersion: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionMaskDepth
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionMaskDepth: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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: <A TImageEnView.SelectionOptions>=<FC>iesoFilled<FN> is not supported when the SelectionMaskDepth = 8
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView.SelectionMaskDepth := 8;
|
||
ImageEnView.SelectionIntensity := 128;
|
||
ImageEnView.Select( 10, 10, 100, 100 );
|
||
ImageEnView.Proc.Negative; // the negative is applied at 50 % (128=semi selected)
|
||
|
||
<IMG help_images\MaskDepth.jpg>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionIntensity
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionIntensity: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the selection intensity and is valid only when the <A TImageEnView.SelectionMaskDepth> 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: <A TImageEnView.SelectionMaskDepth>.
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\ImageEditing\SoftSelections\SoftSel.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MakeSelectionFeather
|
||
|
||
<FM>Declaration<FC>
|
||
procedure MakeSelectionFeather(radius: Double);
|
||
|
||
<FM>Description<FN>
|
||
Modifies the current selection by applying a blur effect to make soften the borders.
|
||
This property works only if <A TImageEnView.SelectionMaskDepth> is 8.
|
||
Radius specifies the feathering intensity (amount of blur).
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\ImageEditing\SoftSelections\SoftSel.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView.SelectionMaskDepth := 8;
|
||
ImageEnView.Select( 10, 10, 100, 100 );
|
||
ImageEnView.MakeSelectionFeather( 4 );
|
||
|
||
<IMG help_images\SelFeather.jpg>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersRect
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersRect(SelOnly: Boolean = False; ExcludeLayer0: Boolean = False): <A TIERectangle>;
|
||
|
||
<FM>Description<FN>
|
||
Returns the coverage area of all or selected layers.
|
||
The result will include any layers outside the background layer (if <A TImageEnView.LayersCropped> and <A TIELayer.Cropped> are not set).
|
||
If <FC>ExcludeLayer0<FN> 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 <A TImageEnView.IEBitmap>
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MaxLayerWidth>
|
||
- <A TImageEnView.MaxLayerHeight>
|
||
!!}
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.MaxLayerWidth
|
||
|
||
<FM>Declaration<FC>
|
||
function MaxLayerWidth() : integer;
|
||
|
||
<FM>Description<FN>
|
||
Returns the maximum width of all layers.
|
||
The result will include any layers outside the background layer (if <A TImageEnView.LayersCropped> and <A TIELayer.Cropped> are not set).
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MaxLayerHeight>
|
||
- <A TImageEnView.LayersRect>
|
||
!!}
|
||
function TImageEnView.MaxLayerWidth() : integer;
|
||
begin
|
||
result := LayersRect().width;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MaxLayerHeight
|
||
|
||
<FM>Declaration<FC>
|
||
function MaxLayerHeight() : integer;
|
||
|
||
<FM>Description<FN>
|
||
Returns the maximum height of all layers.
|
||
The result will include any layers outside the background layer (if <A TImageEnView.LayersCropped> and <A TIELayer.Cropped> are not set).
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.MaxLayerWidth>
|
||
- <A TImageEnView.LayersRect>
|
||
!!}
|
||
function TImageEnView.MaxLayerHeight() : integer;
|
||
begin
|
||
result := LayersRect().height
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersDrawBox
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersDrawBox: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
Specify whether a box is displayed around layers.
|
||
This option has no effect if <A TImageEnView.Layers>[].<A TIELayer.VisibleBox> 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 <A TImageEnView.SetLayersBoxStyle>, or for more control, <A TImageEnView.OnDrawLayerBox>
|
||
|
||
!!}
|
||
procedure TImageEnView.SetLayersDrawBox(value: boolean);
|
||
begin
|
||
if value <> fLayersDrawBox then
|
||
begin
|
||
fLayersDrawBox := value;
|
||
UpdateReason := ieurComponentStuffChanged;
|
||
Update;
|
||
end;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCaching
|
||
|
||
<FM>Declaration<FC>
|
||
property LayersCaching: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Whether a cached view of every layer is stored in memory.
|
||
|
||
Supported values:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>-1</C> <C>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</C> </R>
|
||
<R> <C>0</C> <C>No cached views of layers are stored. This uses the least memory </C> </R>
|
||
<R> <C>>0</C> <C>Specifies a maximum number of cached views to store </C> </R>
|
||
</TABLE>
|
||
|
||
Default: 0
|
||
|
||
<FM>Example<FC>
|
||
// Cache all layers
|
||
ImageEnView1.LayersCaching := -1;
|
||
|
||
// Cache a maximum of 30 layers
|
||
ImageEnView1.LayersCaching := 30;
|
||
|
||
// Disable all layer caching
|
||
ImageEnView1.LayersCaching := 0;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersFastDrawing>
|
||
!!}
|
||
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}
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SelectionAspectRatio
|
||
|
||
<FM>Declaration<FC>
|
||
property SelectionAspectRatio: Double;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.SelectionAbsWidth> and <A TImageEnView.SelectionAbsHeight> properties.
|
||
If SelectionAspectRatio is >0, ImageEn locks the selection to the specified aspect ratio.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TIECropToolInteraction.LockAspectRatio>
|
||
!!}
|
||
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}
|
||
{!!
|
||
<FS>TImageEnView.FlatScrollBars
|
||
|
||
<FM>Declaration<FC>
|
||
property FlatScrollBars: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetNavigator
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetNavigator(nav: <A TImageEnView>; options: <A TIENavigatorOptions>);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>options<FN> to fine-tune navigator behavior.
|
||
|
||
<FM>Demos<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\Navigator\Navigator.dpr </C> </R>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\Navigator2\Navigator.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetExternalBitmap
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetExternalBitmap(bmp: <A TIEBitmap>);
|
||
|
||
<FM>Description<FN>
|
||
Allows you to connect the TImageEnView component to another <A TIEBitmap>, 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.
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\ExternalBitmap\ExternalBMP.dpr </C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ImageEnVersion
|
||
|
||
<FM>Declaration<FC>
|
||
property ImageEnVersion: String;
|
||
|
||
<FM>Description<FN>
|
||
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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.ChangeResolution
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ChangeResolution(NewDPI: Integer; ResampleFilter: <A TResampleFilter>);
|
||
|
||
<FM>Description<FN>
|
||
Modifies the DPI of the image (<L TIOParams.DpiX>IO.Params.DpiX</L> and <L TIOParams.DpiY>IO.Params.DpiY</L>), 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.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersImport
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersImport(const FileName: String; Stream: TStream = nil; FileFormat: <A TIOFileType> = ioUnknown; Append: Boolean = False): Integer;
|
||
|
||
<FM>Description<FN>
|
||
Imports layers from a file or stream in IEV, ALL or DXF format.
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>FileName<FN></C> <C>The full path to a file to import (or '' if importing from a stream)</C> </R>
|
||
<R> <C><FC>Stream<FN></C> <C>A stream to import from (or nil if importing from file)</C> </R>
|
||
<R> <C><FC>FileFormat<FN></C> <C>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)</C> </R>
|
||
<R> <C><FC>Append<FN></C> <C>When false the existing content is cleared before importing</C> </R>
|
||
</TABLE>
|
||
|
||
Result is -1 in the case of an error, otherwise returns the number of layers added.
|
||
|
||
IEV and ALL are object formats of <A TImageEnVect>. Conversion is as follows:
|
||
<TABLE>
|
||
<R> <H>Object Kind</H> <H>Converted To</H> <H>Notes</H> </R>
|
||
<R> <C><FC>iekLINE<FN></C> <C><A TIELineLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekBOX<FN></C> <C><A TIEShapeLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekELLIPSE<FN></C> <C><A TIEShapeLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekARC<FN></C> <C>Skipped</C> <C> - </C> </R>
|
||
<R> <C><FC>iekBITMAP<FN></C> <C><A TIEImageLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekTEXT<FN></C> <C><A TIETextLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekRULER<FN></C> <C>Skipped</C> <C> - </C> </R>
|
||
<R> <C><FC>iekPOLYLINE<FN></C> <C><A TIEPolylineLayer></C> <C> - </C> </R>
|
||
<R> <C><FC>iekANGLE<FN></C> <C>Skipped</C> <C> - </C> </R>
|
||
<R> <C><FC>iekMEMO<FN></C> <C><A TIETextLayer></C> <C>Text formatting is lost </C> </R>
|
||
<R> <C><FC>iekLINELABEL<FN></C> <C><A TIELineLayer></C> <C>Inward arrows are converted to outward arrows </C> </R>
|
||
</TABLE>
|
||
|
||
DXF is an Autocad vector format. DXF file can only be imported from file and only lines and ellipses objects are supported.
|
||
|
||
<FM>Example<FC>
|
||
// 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 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnVect.CopyAllObjectsTo>
|
||
- <A TImageEnIO.LoadFromFileIEN>
|
||
- <A TImageEnIO.LoadFromStreamIEN>
|
||
- <A TImageEnVect.LoadFromFileIEV>
|
||
- <A TImageEnVect.LoadFromStreamIEV>
|
||
- <A TImageEnVect.LoadFromFileAll>
|
||
- <A TImageEnVect.LoadFromStreamAll>
|
||
- <A TImageEnVect.ImportDXF>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersAlign
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersAlign(Alignment: <A TIEAlignLayers>; Index: Integer = LYR_SELECTED_LAYERS);
|
||
|
||
<FM>Description<FN>
|
||
Aligns all selected layers relative to the image or other layers.
|
||
The index of a specific layer can be specified, or <FC>LYR_ALL_LAYERS<FN> (-1) to process all layers, or <FC>LYR_SELECTED_LAYERS<FN> (-2)
|
||
|
||
<FM>Example<FC>
|
||
// 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 );
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersRepositionAll>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSelectAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersSelectAll(bIncludeLocked: Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Enables the <A TIELayer.Selected> property of all layers. If <FM>bIncludeLocked<FC> = False then <A TIELayer.Locked> layers are not selected.
|
||
|
||
Notes:
|
||
- Does not select the background layer (layer 0)
|
||
- Has no effect if <L TImageEnView.LayerOptions>multiple layer selection</L> is not enabled.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersDeselectAll
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersDeselectAll();
|
||
|
||
<FM>Description<FN>
|
||
Sets the <A TIELayer.Selected> property of all layers to false.
|
||
|
||
<FM>Example<FC>
|
||
ImageEnView1.LayersDeselectAll();
|
||
|
||
!!}
|
||
procedure TImageEnView.LayersDeselectAll();
|
||
var
|
||
i: Integer;
|
||
begin
|
||
for i := 0 to LayersCount - 1 do
|
||
TIELayer( fLayers[ I ]).fSelected := False;
|
||
Update;
|
||
end;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersSelCount
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersSelCount(bCountBackgroundLayer: Boolean = True): Integer;
|
||
|
||
<FM>Description<FN>
|
||
Return number of layers that are selected. If <FC>bCountBackgroundLayer<FN> is false, then the background layer (layer 0) is not included in the count.
|
||
If <L TImageEnView.LayerOptions>multiple layer selection</L> is enabled then it counts any layer that has <A TIELayer.Selected> set to true. Otherwise it just checks whether <A TImageEnView.LayersCurrent> is not -1.
|
||
|
||
A selected text layer:
|
||
<IMG help_images\text_Selected.gif>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersGroup
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersGroup(bSelectedOnly: Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Sets the <L TIELayer.GroupIndex>group index</L> of layers so they selected as a group (selecting one layer of the group will select all of them).
|
||
If <FC>bSelectedOnly<FN> is true, grouping only affects layers that are selected. If false, it applies to all layers.
|
||
|
||
Note: LayersGroup has no effect if <L TImageEnView.LayerOptions>multiple layer selection</L> is not enabled
|
||
|
||
<FM>Example<FC>
|
||
// Add all selected layers to a group
|
||
ImageEnView1.LayersGroup();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersUngroup>
|
||
- <A TIELayer.GroupIndex>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersUngroup
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersUngroup(bSelectedOnly: Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Resets the <L TIELayer.GroupIndex>group index</L> of layers so they are not selected as a group.
|
||
If <FC>bSelectedOnly<FN> is true, ungrouping only affects layers that are selected. If false, it applies to all layers.
|
||
|
||
Note: LayersGroup has no effect if <L TImageEnView.LayerOptions>multiple layer selection</L> is not enabled
|
||
|
||
<FM>Example<FC>
|
||
// Remove grouping from selected layers
|
||
ImageEnView1.LayersUngroup();
|
||
// Unselect the layers
|
||
ImageEnView1.LayersDeselectAll();
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.LayersGroup>
|
||
- <A TIELayer.GroupIndex>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.Wallpaper
|
||
|
||
<FM>Declaration<FC>
|
||
property Wallpaper: TPicture;
|
||
|
||
<FM>Description<FN>
|
||
The Wallpaper property allows you to use an image for your background (behind the main image and layers).
|
||
Use <A TImageEnView.WallpaperStyle> to specify how to paint the wallpaper.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.WallpaperStyle
|
||
|
||
<FM>Declaration<FC>
|
||
property WallpaperStyle: <A TIEWallpaperStyle>;
|
||
|
||
<FM>Description<FN>
|
||
If you are using an image for your background (specified by <A TImageEnView.Wallpaper>), then WallpaperStyle defines how it will be painted.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.VisibleBitmapRect
|
||
|
||
<FM>Declaration<FC>
|
||
property VisibleBitmapRect : TRect; (read/write)
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.ViewX>
|
||
- <A TImageEnView.ViewY>
|
||
- <A TImageEnView.ExtentX>
|
||
- <A TImageEnView.ExtentY>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCreateFromSelection
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersCreateFromSelection(): Integer;
|
||
|
||
<FM>Description<FN>
|
||
Creates a new <L TIEImageLayer>image layer</L> from the current selection. This might be used to copy & paste selections, for example.
|
||
Returns the index of the new layer.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCreateFromClipboard
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersCreateFromClipboard: Integer;
|
||
|
||
<FM>Description<FN>
|
||
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.<A TImageEnProc.PasteFromClipboard>( iecpLayer ); However it returns an index of the new layer.
|
||
!!}
|
||
function TImageEnView.LayersCreateFromClipboard: Integer;
|
||
begin
|
||
Result := Proc.PasteFromClipboard_Layer();
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCreateFromFile
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersCreateFromFile(Filename : string = '') : Integer;
|
||
|
||
<FM>Description<FN>
|
||
Loads an image from a file and adds it as a new <L TIEImageLayer>image layer</L>.
|
||
If Filename is '' then an open dialog is displayed (using <A TImageEnIO.ExecuteOpenDialog>) 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.
|
||
|
||
<FM>Examples<FC>
|
||
// 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;
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCreateFromEdge
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersCreateFromEdge(ScreenX, ScreenY: integer; Tolerance: integer; MaxFilter: boolean = False): Integer;
|
||
|
||
<FM>Description<FN>
|
||
Creates a new <L TIEPolylineLayer>Polyline layer</L> 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
|
||
|
||
<FM>Examples<FC>
|
||
// 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}
|
||
|
||
{!!
|
||
<FS>TImageEnView.BackBuffer
|
||
|
||
<FM>Declaration<FC>
|
||
property BackBuffer: TBitmap;
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.OnDrawBackBuffer> event to paint onto the Backbuffer canvas.
|
||
BackBuffer is updated whenever <A TImageEnView.Update> is called.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnSaveUndo
|
||
|
||
<FM>Declaration<FC>
|
||
property OnSaveUndo: <A TIESaveUndoEvent>;
|
||
|
||
<FM>Description<FN>
|
||
OnSaveUndo occurs after <A TImageEnProc.SaveUndo> is called by user action or your code.
|
||
<FC>source<FN> is the same parameter used when calling <A TImageEnProc.SaveUndo>.
|
||
|
||
!!}
|
||
function TImageEnView.GetOnSaveUndo: TIESaveUndoEvent;
|
||
begin
|
||
result := fOnSaveUndo;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersFixSizes
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersFixSizes(layer: Integer = LYR_ALL_LAYERS);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>LYR_ALL_LAYERS<FN> (-1) to process all layers, or <FC>LYR_SELECTED_LAYERS<FN> (-2) to process selected layers.
|
||
|
||
Note: <A TImageEnView.LayersMergeFilter> will specify the quality of image layers, if they do not have a custom <A TIEImageLayer.UseResampleFilter>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersFixBorders
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersFixBorders(layer: Integer = LYR_ALL_LAYERS);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>LYR_ALL_LAYERS<FN> (-1) to process all layers, or <FC>LYR_SELECTED_LAYERS<FN> (-2) to process selected layers.
|
||
|
||
Note: This can be called automatically using <FC>loAutoFixBorders<FN> of <A TImageEnView.LayerOptions>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersFixRotations
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersFixRotations(layer: Integer = LYR_ALL_LAYERS);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>LYR_ALL_LAYERS<FN> (-1) to process all layers, or <FC>LYR_SELECTED_LAYERS<FN> (-2) to process selected layers.
|
||
|
||
Notes:
|
||
- This can be called automatically using <FC>loAutoFixRotation<FN> of <A TImageEnView.LayerOptions>
|
||
- This method will also call <A TImageEnView.LayersFixSizes>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SoftCrop
|
||
|
||
<FM>Declaration<FC>
|
||
property SoftCrop: <A TIESoftCropMode>;
|
||
|
||
<FM>Description<FN>
|
||
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:
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C>iesfNone</C> <C>Normal</C> </R>
|
||
<R> <C>iesfAlphaBlend</C> <C>Partially transparent (to the level specified by <A TImageEnView.SoftCropValue>)</C> </R>
|
||
<R> <C>iesfGrid</C> <C>Grayed (Grid matrix pattern)</C> </R>
|
||
<R> <C>iesfAdd</C> <C>Color shifted/washed out (to the level specified by <A TImageEnView.SoftCropValue>)</C> </R>
|
||
</TABLE>
|
||
|
||
!!}
|
||
procedure TImageEnView.SetSoftCrop(v: TIESoftCropMode);
|
||
begin
|
||
fSoftCrop := v;
|
||
UpdateReason := ieurComponentStuffChanged;
|
||
Update;
|
||
end;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SoftCropValue
|
||
|
||
<FM>Declaration<FC>
|
||
property SoftCropValue: Integer;
|
||
|
||
<FM>Description<FN>
|
||
If <A TImageEnView.SoftCrop> is iesfAlphaBlend then the SoftCropValue specifies the level of transparency from 0 (minimal) to 255 (fully)
|
||
If <A TImageEnView.SoftCrop> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetInteractionHint
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetInteractionHint(const Text: String; x, y: Integer; const minText: String);
|
||
|
||
<FM>Description<FN>
|
||
Specify a text hint to appear over the ImageEnView (which will be displayed at the next painting event).
|
||
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>Text<FN></C> <C>Text to draw</C> </R>
|
||
<R> <C><FC>x<FN></C> <C>Horizontal position</C> </R>
|
||
<R> <C><FC>y<FN></C> <C>Vertical position</C> </R>
|
||
<R> <C><FC>minText<FN></C> <C>Example (dummy) text to calculate the minimum text size</C> </R>
|
||
</TABLE>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.HighlightedPixel
|
||
|
||
<FM>Declaration<FC>
|
||
property HighlightedPixel: TPoint;
|
||
|
||
<FM>Description<FN>
|
||
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.
|
||
|
||
<FM>Demo<FN>
|
||
<TABLE2>
|
||
<R> <C_IMG_DEMO> <C>Demos\Display\ImageComp\ImageComp.dpr </C> </R>
|
||
</TABLE>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.MoveContentTo
|
||
|
||
<FM>Declaration<FC>
|
||
procedure TImageEnView.MoveContentTo(Destination: <A TImageEnView>);
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.Assign> 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
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetViewXYSmooth
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetViewXYSmooth(x, y: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Repositions the image view (i.e. by setting <A TImageEnView.ViewX> and <A TImageEnView.ViewY>), but does so with smooth scrolling (image will slowly pan to the new location).
|
||
To control the smoothness set <A TImageEnView.SmoothScrollValue>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnFinishSmoothTask>
|
||
- <A TImageEnView.SmoothScrollValue>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SmoothScrollValue
|
||
|
||
<FM>Declaration<FC>
|
||
property SmoothScrollValue: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the smoothness (speed) of scrolling when <A TImageEnView.SetViewXYSmooth> is called or <A TImageEnView.MouseInteract> contains miMovingScroll.
|
||
A large values increases the smoothness. "0" disables smoothing (i.e. so that it acts like <A TImageEnView.SetViewXY>).
|
||
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
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetZoomSmooth
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetZoomSmooth(Zoom: Double);
|
||
|
||
<FM>Description<FN>
|
||
Sets the image zoom (i.e. by setting <A TImageEnView.Zoom>), but does so with smooth zoom (image will slowly zoom to the new value).
|
||
To control the smoothness set <A TImageEnView.SmoothZoomValue>.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.OnFinishSmoothTask>
|
||
- <A TImageEnView.SmoothZoomValue>
|
||
!!}
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.SmoothZoomValue
|
||
|
||
<FM>Declaration<FC>
|
||
property SmoothZoomValue: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the smoothness (speed) of zooming when <A TImageEnView.SetZoomSmooth> is called.
|
||
A large values increases the smoothness. "0" disables smoothing (i.e. so that it acts like <A TImageEnView.Zoom>).
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.BeginPostFrames
|
||
|
||
<FM>Declaration<FC>
|
||
procedure BeginPostFrames(target: TImageEnView; delay: Integer; interval: Integer);
|
||
|
||
<FM>Description<FN>
|
||
Sends the current image to a target <A TImageEnView>, 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 <A TImageEnView.EndPostFrames>.
|
||
|
||
Multiple calls to BeginPostFrames are possible.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.EndPostFrames
|
||
|
||
<FM>Declaration<FC>
|
||
procedure EndPostFrames(target: TImageEnView);
|
||
|
||
<FM>Description<FN>
|
||
Stops sending of the current image to a target <A TImageEnView> that has been commenced using <A TImageEnView.BeginPostFrames>.
|
||
|
||
<FM>Example<FC>
|
||
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
|
||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCropBackground
|
||
|
||
<FM>Declaration<FC>
|
||
procedure TImageEnView.LayersCropBackground(SelectedOnly: Boolean = False; FillAlpha: Integer = 255; AllowReduce: Boolean = True; AllowEnlarge : Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Resize the background (layer 0) to fit all layers (the image is sized, but its content is not stretched).
|
||
<TABLE>
|
||
<R> <H>Parameter</H> <H>Description</H> </R>
|
||
<R> <C><FC>SelectedOnly<FN></C> <C>The background will be cropped to fit selected layers only</C> </R>
|
||
<R> <C><FC>FillAlpha<FN></C> <C>Alpha value used to fill added regions (0: Fully Transparent - 255: Opaque)</C> </R>
|
||
<R> <C><FC>AllowReduce<FN></C> <C>Parts of the image can be cut so layers will align with image edges</C> </R>
|
||
<R> <C><FC>AllowEnlarge<FN></C> <C>Parts will be added to the image so layers are not beyond hte image area</C> </R>
|
||
</TABLE>
|
||
|
||
Note: The color of added background is specified by <A TImageEnView.Background>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCopyToAlpha
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersCopyToAlpha(DestLayer: Integer);
|
||
|
||
<FM>Description<FN>
|
||
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: <A TImageEnView.LayersCreateFromAlpha>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCreateFromAlpha
|
||
|
||
<FM>Declaration<FC>
|
||
function LayersCreateFromAlpha: Integer;
|
||
|
||
<FM>Description<FN>
|
||
Creates a new <L TIEImageLayer>image layer</L> 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: <A TImageEnView.LayersCopyToAlpha>
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
{!!
|
||
<FS>TImageEnView.LayersCancelEditor
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LayersCancelEditor(SaveChanges: Boolean = True);
|
||
|
||
<FM>Description<FN>
|
||
Terminates any active text editors.
|
||
Users can edit the text of a <A TIETextLayer> or <A TIELineLayer> by double-clicking or selecting F2. They can then cancel it clicking "Esc" (or "Enter" to enact the change). <FC>LayersCancelEditor<FN> is the programmatic equivalent of clicking "Esc".
|
||
If <FC>SaveChanges<FN> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SetSelectionMarkOuterStyle
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetSelectionMarkOuterStyle(Alpha: Integer; Color: TColor);
|
||
|
||
<FM>Description<FN>
|
||
When <A TImageEnView.SelectionOptions> is <FC>iesoMarkOuter<FN>, 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.
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.SaveState
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SaveState(const FileName: String);
|
||
procedure SaveState(Stream: TStream);
|
||
|
||
<FM>Description<FN>
|
||
Saves layers, selection and some other parameters such as Zoom and Scroll position.
|
||
|
||
See also: <A TImageEnView.LoadState> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.LoadState
|
||
|
||
<FM>Declaration<FC>
|
||
procedure LoadState(const FileName: String);
|
||
procedure LoadState(Stream: TStream);
|
||
|
||
<FM>Description<FN>
|
||
Loads layers, selection and some other parameters such as Zoom and Scroll position.
|
||
|
||
See also: <A TImageEnView.SaveState> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.ResetState
|
||
|
||
<FM>Declaration<FC>
|
||
procedure ResetState();
|
||
|
||
<FM>Description<FN>
|
||
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 <A TImageEnView.LegacyBitmap> 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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.HighlightedPixelColor
|
||
|
||
<FM>Declaration<FC>
|
||
property HighlightedPixelColor: TColor;
|
||
|
||
<FM>Description<FN>
|
||
Colored box color.
|
||
|
||
<FM>See Also<FN>
|
||
- <A TImageEnView.HighlightedPixel>
|
||
!!}
|
||
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}
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnRulerClick
|
||
|
||
<FM>Declaration<FC>
|
||
property OnRulerClick: <A TRulerClickEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when the user clicks on a <A TImageEnView.ShowRulers>ruler</L>.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnRulerGripClick
|
||
|
||
<FM>Declaration<FC>
|
||
property OnRulerGripClick: <A TRulerGripClickEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when the user clicks a grip on a <A TImageEnView.ShowRulers>ruler</L>.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnRulerGripDblClick
|
||
|
||
<FM>Declaration<FC>
|
||
property OnRulerGripDblClick: <A TRulerGripClickEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when the user double-clicks a grip on a <A TImageEnView.ShowRulers>ruler</L>.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TImageEnView.OnRulerGripPosChange
|
||
|
||
<FM>Declaration<FC>
|
||
property OnRulerGripPosChange: <A TRulerGripPosChangeEvent>;
|
||
|
||
<FM>Description<FN>
|
||
Occurs when a grip is moved on a <A TImageEnView.ShowRulers>ruler</L>.
|
||
|
||
<FM>Example<FC>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.SetBitmapPolygon
|
||
|
||
<FM>Declaration<FC>
|
||
procedure SetBitmapPolygon(Rect: TRect);
|
||
|
||
<FM>Description<FN>
|
||
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 <FC>TImageEnView.Invalidate<FN> if you change this property when the crop selection is visible
|
||
|
||
<FM>Example<FC>
|
||
// 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();
|
||
|
||
<FM>See Also<FC>
|
||
- <A TIECropToolInteraction.BitmapPolygon>
|
||
- <A TIECropToolInteraction.Rotation>
|
||
!!}
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Mode
|
||
|
||
<FM>Declaration<FC>
|
||
property Mode: <A TIECropToolInteractionMode>;
|
||
|
||
<FM>Description<FN>
|
||
Specifies the shape of cropping area.
|
||
<TABLE>
|
||
<R> <H>Value</H> <H>Description</H> </R>
|
||
<R> <C><FC>iectmRECTANGLE<FN></C> <C>The cropping area is rectangular (for standard cropping)</C> </R>
|
||
<R> <C><FC>iectmPERSPECTIVE<FN></C> <C>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.</C> </R>
|
||
</TABLE>
|
||
|
||
Note: You must call <FC>TImageEnView.Invalidate<FN> if you change this property when the crop selection is visible
|
||
|
||
Default: iectmRECTANGLE
|
||
|
||
<IMG help_images\Perspective.jpg>
|
||
|
||
<IMG help_images\Perspective2.jpg>
|
||
|
||
<FM>Example<FC>
|
||
// 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;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Selected
|
||
|
||
<FM>Declaration<FC>
|
||
property TIECropToolInteraction.Selected: Boolean;
|
||
|
||
<FM>Description<FN>
|
||
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;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Cancel
|
||
|
||
<FM>Declaration<FC>
|
||
procedure TIECropToolInteraction.Cancel();
|
||
|
||
<FM>Description<FN>
|
||
Clears the crop selection. This is the same as the user clicking the "Esc" key.
|
||
|
||
<FM>Example<FC>
|
||
// "Cancel Crop" button clicked
|
||
procedure TMainForm.btnCancelCropClick(Sender: TObject);
|
||
begin
|
||
ImageEnView1.CropToolInteraction.Cancel();
|
||
end;
|
||
|
||
<FM>See Also<FC>
|
||
- <A TIECropToolInteraction.Crop>
|
||
!!}
|
||
procedure TIECropToolInteraction.Cancel();
|
||
begin
|
||
fState := iectisUNSELECTED;
|
||
fRotation := 0;
|
||
Refresh();
|
||
RestoreCursor;
|
||
end;
|
||
|
||
|
||
{!!
|
||
<FS>TIECropToolInteraction.Crop
|
||
|
||
<FM>Declaration<FC>
|
||
procedure TIECropToolInteraction.Crop();
|
||
|
||
<FM>Description<FN>
|
||
Crop the image to the selection. This is the same as the user clicking the "Enter" key.
|
||
|
||
<FM>Example<FC>
|
||
// "Apply Crop" button clicked
|
||
procedure TMainForm.btnApplyCropClick(Sender: TObject);
|
||
begin
|
||
ImageEnView1.CropToolInteraction.Crop();
|
||
end;
|
||
|
||
<FM>See Also<FC>
|
||
- <A TIECropToolInteraction.Cancel>
|
||
!!}
|
||
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.
|
||
|
||
|
||
|
||
|
||
|