686 lines
25 KiB
Plaintext
686 lines
25 KiB
Plaintext
(* ------------------------------------------------------------------------------
|
|
TImageEnView Image Processing in a TThread : 1.0
|
|
For A Programmers Introduction To Using ImageEn Library Suite
|
|
Copyright © 2013 : Copyright Adirondack Software & Graphics
|
|
Last Modification : 06-19-2013
|
|
Source File : Unit1.pas
|
|
Compiler : Delphi 2010
|
|
ImageEnVersion : 4.3.1
|
|
Operating System : Windows 7
|
|
Comment : This demo shows how to process images in a secondary thread
|
|
|
|
: Multi-Threading
|
|
: Multi-threading in Delphi lets you create applications that include
|
|
: several simultaneous paths of execution or processes. A "normal"
|
|
: Delphi application is single-threaded: all (VCL) objects access their
|
|
: properties and execute their methods within this single thread usually
|
|
: referred to as the main thread.
|
|
:
|
|
: Secondary Thread
|
|
: To speed up data processing in your application you can decide to
|
|
: include one or more "secondary" threads. When several threads are
|
|
: running in the application a question arises: how to update your GUI
|
|
: (user interface) as a result of a thread execution.
|
|
:
|
|
: GUI
|
|
: The answer to the question lies in the TThread class Synchronize method.
|
|
: To update your application's user interface run in the main thread
|
|
: from a secondary thread you need to call the TThread.Synchronize
|
|
: method - a thread-safe method that avoids multi-threading conflicts
|
|
: that can arise from accessing object properties or methods that are
|
|
: not thread-safe, or using resources not in the main thread of
|
|
: execution.
|
|
:
|
|
: An active GUI is maintained in this demo while doing processor
|
|
: intensive image processing in the background. The five image
|
|
: processing procedures run in this example in sequence are AutoImageEnhance,
|
|
: AdjustGainOffset, AutoSharp, HistAutoEqualize and (optionally) Negative.
|
|
: In a non-threaded Delphi application these procedures run in succession
|
|
: would take several seconds to complete depending on the size of the image
|
|
: file and the processor used. While the image processing procedures are
|
|
: running the application would act like the GUI is locked. It would be
|
|
: impossible to cancel the operation or resize the form because the GUI
|
|
: would be unresponsive to button clicks, key presses or mouse actions.
|
|
: The same procedures processed in a secondary thread allow the GUI to remain
|
|
: responsive and not interfere with the image processing.
|
|
:
|
|
: Synchronize
|
|
: In this demo all image processing is performed in a secondary thread
|
|
: and all GUI elements (TForm, TLabel, TButton, TProgressBar and
|
|
: TImageEnView are all updated in the main thread by using the TThread
|
|
: Synchronize method.
|
|
:
|
|
: Usage
|
|
: When processing an image in the secondary thread, the processing may
|
|
: be aborted at any time by pressing the Cancel button. If you resize
|
|
: the form or view the about dialog while the processing thread is
|
|
: running, the thread will not be interrupted because these things are
|
|
: executed in the main thread, and image processing is executed in a
|
|
: secondary thread.
|
|
:
|
|
: What You Should Not Do
|
|
: You should not directly access a VCL object or component directly in a
|
|
: secondary thread. All calls to a VCL object or component must be made in
|
|
: the main thread or by calling the procedure with TThread.Synchronize.
|
|
: What this means is if you call ImageEnView1.LayersMergeAll or
|
|
: ImageEnView1. LayersDrawTo or any other VCL component call with Syncronize,
|
|
: the call will be executed in the main thread and not in the secondary
|
|
: thread. In essence then, any call made in Syncronize will not be threaded
|
|
: and will act as though you made the call in the main thread.
|
|
:
|
|
: You should never call ImageEnView1.LayersMergeAll or
|
|
: ImageEnView1.LayersDrawTo in the secondary thread. This will lead to
|
|
: potential threading conflicts, exceptions and/or memory loss.
|
|
:
|
|
: In essence then, to create a truly threaded image processing operation
|
|
: ImageEnView1.Proc.Sharpen, ImageEnView1.Proc.AutoImageEnhance or any other
|
|
: ImageEnView1.Proc should never be called from within the secondary thread.
|
|
: Instead create a TimageEnProc component at run time within the thread and
|
|
: then update the ImageEnView1 on the main form by assigning the TIEBitmap
|
|
: that is modified by the procedure in the secondary thread to the
|
|
: Form1.ImageEnView by calling Synchronize.
|
|
|
|
This file is copyright (C) W W Miller, 1986-2013.
|
|
It may be used without restriction. This code distributed on an "AS IS"
|
|
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
|
|
------------------------------------------------------------------------------ *)
|
|
|
|
unit Unit1;
|
|
|
|
|
|
{$I ie.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
StdCtrls, ExtCtrls, ExtDlgs, ComCtrls,
|
|
imageenproc, ieview, imageenview, imageenio, hyiedefs, hyieutils, Menus, iexBitmaps, iesettings, iexLayers,
|
|
iexRulers;
|
|
|
|
type
|
|
|
|
{ A TThread descendent for Image Processing }
|
|
TProcessingThread = class(TThread)
|
|
private
|
|
{ Private declarations }
|
|
procedure ImageEnProcFinishWork(Sender: TObject);
|
|
procedure ImageEnProcProgress(Sender: TObject; per: Integer);
|
|
protected
|
|
{ Protected declarations }
|
|
procedure Execute; override;
|
|
public
|
|
{ Public declarations }
|
|
constructor Create(CreateSuspended: Boolean);
|
|
end;
|
|
|
|
TForm1 = class(TForm)
|
|
Panel1: TPanel;
|
|
Process1: TButton;
|
|
Cancel1: TButton;
|
|
Open1: TButton;
|
|
OpenPictureDialog1: TOpenPictureDialog;
|
|
Fit1: TCheckBox;
|
|
Panel3: TPanel;
|
|
Undo1: TButton;
|
|
Exit1: TButton;
|
|
ImageEnView1: TImageEnView;
|
|
StatusBar1: TStatusBar;
|
|
ProcessingPanel1: TPanel;
|
|
LabelThread1: TLabel;
|
|
LabelProcedure1: TLabel;
|
|
Panel4: TPanel;
|
|
ProgressBar1: TProgressBar;
|
|
Information1: TButton;
|
|
procedure Process1Click(Sender: TObject);
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure Cancel1Click(Sender: TObject);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure Open1Click(Sender: TObject);
|
|
procedure Fit1Click(Sender: TObject);
|
|
procedure Undo1Click(Sender: TObject);
|
|
procedure Exit1Click(Sender: TObject);
|
|
procedure ImageEnView1Resize(Sender: TObject);
|
|
procedure ImageEnView1FinishWork(Sender: TObject);
|
|
procedure ImageEnView1Progress(Sender: TObject; per: Integer);
|
|
procedure FormClose(Sender: TObject; var Action: TCloseAction);
|
|
procedure Information1Click(Sender: TObject);
|
|
private
|
|
{ Private declarations }
|
|
public
|
|
{ Public declarations }
|
|
AThread: TProcessingThread; { Image processing thread }
|
|
{ Image processing thread terminate event }
|
|
procedure ThreadTerminate(Sender: TObject);
|
|
end;
|
|
|
|
var
|
|
Form1: TForm1;
|
|
|
|
implementation
|
|
|
|
{$R *.dfm}
|
|
|
|
uses Unit2;
|
|
|
|
{ ------------------------------Global functions--------------------------------------------- }
|
|
|
|
function AddThousandSeparator(const AString: string; const AChar: Char): string;
|
|
{ Add a specified thousand separator in the correct location in a string. }
|
|
var
|
|
i: integer; { Loop through separator position }
|
|
begin
|
|
Result := AString;
|
|
i := Length(AString) - 2;
|
|
while i > 1 do
|
|
begin
|
|
Insert(AChar, Result, i);
|
|
i := i - 3;
|
|
end;
|
|
end;
|
|
|
|
function AddDefThousandSeparator(const AString: string): string;
|
|
{ Add the local default thousand separator in the correct location in a string. }
|
|
begin
|
|
// Note: FormatSettings.ThousandSeparator in XE8 or Newer
|
|
Result := AddThousandSeparator(AString, {$IFDEF DelphiXE8orNewer} FormatSettings.ThousandSeparator {$ELSE} SysUtils.ThousandSeparator {$ENDIF});
|
|
end;
|
|
|
|
function IntegerToStr(const i: Int64): string;
|
|
{ Add the local default thousand separator in the correct location in a number and returns a string. }
|
|
begin
|
|
Result := AddDefThousandSeparator(IntToStr(i));
|
|
end;
|
|
|
|
function EllipsifyText(const AsPath: Boolean; const AText: string;
|
|
const ACanvas: Graphics.TCanvas; const MaxWidth: Integer): string;
|
|
{ Ellipisfy AText and return the text as a ellipisfied text string. }
|
|
var
|
|
TempPChar: PChar; { temp buffer to hold text }
|
|
TempRect: TRect; { temp rectangle hold max width of text }
|
|
Params: UINT; { flags passed to DrawTextEx API function }
|
|
begin
|
|
{ Alocate mem for PChar }
|
|
GetMem(TempPChar, (Length(AText) + 1) * SizeOf(Char));
|
|
try
|
|
{ Copy Text into PChar }
|
|
TempPChar := SysUtils.StrPCopy(TempPChar, AText);
|
|
{ Create Rectangle to Store PChar }
|
|
TempRect := Classes.Rect(0, 0, MaxWidth, High(Integer));
|
|
{ Set Params depending wether it's a path or not }
|
|
if AsPath then
|
|
Params := Windows.DT_PATH_ELLIPSIS
|
|
else
|
|
Params := Windows.DT_END_ELLIPSIS;
|
|
{ Tell it to Modify the PChar, and do not draw to the canvas }
|
|
Params := Params + Windows.DT_MODIFYSTRING + Windows.DT_CALCRECT;
|
|
{ Ellipsify the string based on availble space to draw in }
|
|
Windows.DrawTextEx(ACanvas.Handle, TempPChar, -1, TempRect, Params, nil);
|
|
{ Copy the modified PChar into the result }
|
|
Result := SysUtils.StrPas(TempPChar);
|
|
finally
|
|
{ Free Memory from PChar }
|
|
FreeMem(TempPChar, (Length(AText) + 1) * SizeOf(Char));
|
|
end;
|
|
end;
|
|
|
|
{ TProcessingThread }
|
|
|
|
constructor TProcessingThread.Create(CreateSuspended: Boolean);
|
|
{ Create the thread. }
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
procedure TProcessingThread.ImageEnProcProgress(Sender: TObject; per: Integer);
|
|
{ Set the progressbar position. }
|
|
begin
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ProgressBar1.Position := per;
|
|
{ Ensure progress is painted when themes are enabled }
|
|
Form1.ProgressBar1.Position := per - 1;
|
|
end);
|
|
end;
|
|
|
|
procedure TProcessingThread.ImageEnProcFinishWork(Sender: TObject);
|
|
{ Reset the progressbar position. }
|
|
begin
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ProgressBar1.Position := 0;
|
|
end);
|
|
end;
|
|
|
|
procedure TProcessingThread.Execute;
|
|
{ Process the image in the thread.
|
|
Note: All references to GUI elements must occur inside a Synchronize method.
|
|
Synchronize suspends the current thread and has the main thread call the procedure. When
|
|
the procedure finishes, control returns to the current thread. The actual image processing
|
|
is done by an imageenproc (non GUI element) directly in the thread. All of the GUI elements
|
|
are accessed with Synchronize.}
|
|
var
|
|
iImageEnProc: TImageEnProc;
|
|
iIEBitmap: TIEBitmap;
|
|
begin
|
|
|
|
inherited;
|
|
{ Free the thread onTerminate }
|
|
FreeOnTerminate := True;
|
|
|
|
{ Set the LabelThread caption ------------------------------------------------------------------ }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.Cancel1.Enabled := True;
|
|
Form1.Cancel1.Update;
|
|
Form1.LabelThread1.Caption := 'Thread is running...';
|
|
Form1.LabelThread1.Update;
|
|
end);
|
|
{ Provide time to see the change }
|
|
Sleep(500);
|
|
end;
|
|
|
|
{ Get the IEBitmap from the main form----------------------------------------------------------- }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
iIEBitmap := TIEBitmap.Create(Form1.ImageEnView1.IEBitmap);
|
|
end);
|
|
try
|
|
|
|
{ Create a copy of ImageEnView bitmap }
|
|
iImageEnProc := TImageEnProc.CreateFromBitmap(iIEBitmap);
|
|
try
|
|
|
|
{ Turn off auto undo }
|
|
iImageEnProc.AutoUndo := False;
|
|
{ Permit up to 5 undos - 5 filters are applied here so if you add more filters increase
|
|
the undolimit to match. The filters or procedures run here are AutoImageEnhance,
|
|
AdjustGainOffset, AutoSharp, HistAutoEqualize, and (optionally) Negative }
|
|
iImageEnProc.UndoLimit := 5;
|
|
{ Set the OnProgress and OnFinishWork events }
|
|
iImageEnProc.OnProgress := ImageEnProcProgress;
|
|
iImageEnProc.OnFinishWork := ImageEnProcFinishWork;
|
|
|
|
{ AutoImageEnhance Filter --------------------------------------------------------Filter 1-- }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.LabelProcedure1.Caption := 'Applying Auto Image Enhance Filter...';
|
|
Form1.LabelProcedure1.Update;
|
|
Form1.Undo1.Hint := 'Auto Image Enhance Filter';
|
|
Form1.ImageEnView1.Proc.SaveUndoCaptioned('Auto Image Enhance Filter');
|
|
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
|
|
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
|
|
end);
|
|
|
|
{ Actual work done here in the secondary thread }
|
|
iImageEnProc.AutoImageEnhance3;
|
|
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap); { update image seen by the user }
|
|
Form1.ImageEnView1.Update;
|
|
Application.ProcessMessages();
|
|
end);
|
|
Sleep(500); { Provide time to see the change }
|
|
end;
|
|
|
|
{ Adjust Gain Offset Filter ------------------------------------------------------Filter 2-- }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.LabelProcedure1.Caption := 'Adjusting Gain Offset Filter...';
|
|
Form1.LabelProcedure1.Update;
|
|
Form1.Undo1.Hint := 'Agjust Gain Offset Filter…';
|
|
Form1.ImageEnView1.Proc.SaveUndoCaptioned('Adjust Gain Offset Filter');
|
|
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
|
|
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
|
|
end);
|
|
|
|
{ Actual work done here in the secondary thread }
|
|
iImageEnProc.AdjustGainOffset;
|
|
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap); { update image seen by the user }
|
|
Form1.ImageEnView1.Update;
|
|
Application.ProcessMessages();
|
|
end);
|
|
Sleep(500); { Provide time to see the change }
|
|
end;
|
|
|
|
{ AutoSharp ----------------------------------------------------------------------Filter 3-- }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.LabelProcedure1.Caption := 'Applying Auto Sharp Filter...';
|
|
Form1.LabelProcedure1.Update;
|
|
Form1.Undo1.Hint := 'Applying Auto Sharp Filter…';
|
|
Form1.ImageEnView1.Proc.SaveUndoCaptioned('Hist Sharp Filter');
|
|
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
|
|
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
|
|
end);
|
|
|
|
{ Actual work done here in the secondary thread }
|
|
iImageEnProc.AutoSharp;
|
|
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap); { update image seen by the user }
|
|
Form1.ImageEnView1.Update;
|
|
Application.ProcessMessages();
|
|
end);
|
|
Sleep(500); { Provide time to see the change }
|
|
end;
|
|
|
|
{ HistAutoEqualize ---------------------------------------------------------------Filter 4-- }
|
|
if not Terminated then
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.LabelProcedure1.Caption := 'Applying Hist Auto Equalize Filter...';
|
|
Form1.LabelProcedure1.Update;
|
|
Form1.Undo1.Hint := 'Applying Hist Auto Equalize Filter…';
|
|
Form1.ImageEnView1.Proc.SaveUndoCaptioned('Hist Auto Equalize Filter');
|
|
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
|
|
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
|
|
end);
|
|
|
|
{ Actual work done here in the secondary thread }
|
|
iImageEnProc.HistAutoEqualize;
|
|
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap); { update image seen by the user }
|
|
Form1.ImageEnView1.Update;
|
|
Application.ProcessMessages();
|
|
end);
|
|
Sleep(500); { Provide time to see the change }
|
|
end;
|
|
|
|
{ Negative -----------------------------------------------------------------------Filter 5-- }
|
|
if not Terminated then
|
|
begin
|
|
case MessageDlg('Do you want to apply a Negative Filter?', mtConfirmation, [mbYes, mbNo],
|
|
0) of
|
|
mrYes:
|
|
begin
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.LabelProcedure1.Caption := 'Applying Negative Filter...';
|
|
Form1.LabelProcedure1.Update;
|
|
Form1.Undo1.Hint := 'Applying Negative Filter…';
|
|
Form1.ImageEnView1.Proc.SaveUndoCaptioned('Hist Negative Filter');
|
|
Form1.StatusBar1.Panels[4].Text := 'Undo: ' +
|
|
IntToStr(Form1.ImageEnView1.Proc.UndoCount);
|
|
end);
|
|
|
|
{ Actual work done here in the secondary thread }
|
|
iImageEnProc.Negative;
|
|
|
|
{ Synchronize GUI elements }
|
|
Synchronize(
|
|
procedure
|
|
begin
|
|
Form1.ImageEnView1.IEBitmap.Assign(iIEBitmap); { update image seen by the user }
|
|
Form1.ImageEnView1.Update;
|
|
Application.ProcessMessages();
|
|
end);
|
|
Sleep(500); { Provide time to see the change }
|
|
end;
|
|
mrNo:
|
|
begin
|
|
end;
|
|
end; // case
|
|
end;
|
|
|
|
{ Free iIEBitmap }
|
|
finally
|
|
iImageEnProc.Free;
|
|
end;
|
|
{ Free iImageEnProc }
|
|
finally
|
|
iIEBitmap.Free;
|
|
end;
|
|
{ Terminate the thread }
|
|
Terminate;
|
|
end;
|
|
end;
|
|
|
|
{ ----------------------------------------TForm1-------------------------------------------- }
|
|
|
|
procedure TForm1.Open1Click(Sender: TObject);
|
|
{ Open an image. }
|
|
begin
|
|
if OpenPictureDialog1.Execute then
|
|
begin
|
|
if FileExists(OpenPictureDialog1.Filename) then
|
|
begin
|
|
ImageEnView1.Clear;
|
|
Caption := 'Processing An Image with ImageEn In A Thread The Delphi Way- ' +
|
|
OpenPictureDialog1.Filename;
|
|
ImageEnView1.IO.LoadFromFile(OpenPictureDialog1.Filename);
|
|
{ Display status information in the StatusBar }
|
|
StatusBar1.Panels[0].Text := EllipsifyText(True, ExtractFileDir(OpenPictureDialog1.Filename),
|
|
Canvas, StatusBar1.Panels[0].Width);
|
|
StatusBar1.Panels[1].Text := EllipsifyText(False,
|
|
ExtractFileName(OpenPictureDialog1.Filename), Canvas, StatusBar1.Panels[1].Width);
|
|
StatusBar1.Panels[2].Text := 'Width: ' + IntegerToStr(ImageEnView1.IO.Params.Width);
|
|
StatusBar1.Panels[3].Text := 'Height: ' + IntegerToStr(ImageEnView1.IO.Params.Height);
|
|
if Fit1.Checked then
|
|
ImageEnView1.Fit;
|
|
ImageEnView1.Update;
|
|
{ Initialize the buttons }
|
|
Cancel1.Enabled := False;
|
|
Process1.Enabled := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.Process1Click(Sender: TObject);
|
|
{ Start the thread to begin processing images. }
|
|
begin
|
|
ProcessingPanel1.Color := $0000D7FF;
|
|
LabelThread1.Color := clWhite;
|
|
LabelProcedure1.Color := clWhite;
|
|
{ Enable the cancel button }
|
|
Cancel1.Enabled := True;
|
|
Cancel1.Update;
|
|
{ Disable the Undo button }
|
|
Undo1.Enabled := False;
|
|
{ Create the thread suspended }
|
|
AThread := TProcessingThread.Create(True);
|
|
{ Set the threads OnTerminate event }
|
|
AThread.OnTerminate := ThreadTerminate;
|
|
{ Set the Cancel button as the focused control }
|
|
Cancel1.SetFocus;
|
|
{ Disable the Process button }
|
|
Process1.Enabled := False;
|
|
{ Start the thread }
|
|
AThread.Start;
|
|
{ Processing will occur in the TProcessingThread.Execute event }
|
|
end;
|
|
|
|
procedure TForm1.ThreadTerminate(Sender: TObject);
|
|
{ When the thread terminates set the label captions and button states. }
|
|
var
|
|
iObject: TObject;
|
|
begin
|
|
{ Show a message if exception takes place in the thread }
|
|
Assert(Sender is TThread);
|
|
iObject := TThread(Sender).FatalException;
|
|
if Assigned(iObject) then
|
|
begin
|
|
{ Thread terminated due to an exception }
|
|
if iObject is Exception then
|
|
Application.ShowException(Exception(iObject))
|
|
else
|
|
ShowMessage(iObject.ClassName);
|
|
end
|
|
else
|
|
begin
|
|
{ Thread terminated without an exception }
|
|
end;
|
|
ProcessingPanel1.Color := clMoneyGreen;
|
|
LabelThread1.Color := clBlack;
|
|
LabelProcedure1.Color := clBlack;
|
|
{ Set the label captions }
|
|
LabelThread1.Caption := 'Thread is not running...';
|
|
LabelProcedure1.Caption := 'Image Processing Complete...';
|
|
{ Enable the Undo button }
|
|
Undo1.Enabled := True;
|
|
{ Disable the Cancel button }
|
|
Cancel1.Enabled := False;
|
|
{ Enable the Process button }
|
|
Process1.Enabled := True;
|
|
ProgressBar1.Position := 0;
|
|
StatusBar1.Panels[4].Text := 'Undo: ' + IntToStr(ImageEnView1.Proc.UndoCount);
|
|
{ Free the AThread }
|
|
AThread := nil;
|
|
end;
|
|
|
|
procedure TForm1.Undo1Click(Sender: TObject);
|
|
{ Undo the last change. }
|
|
begin
|
|
Screen.Cursor := crHourglass;
|
|
try
|
|
LabelProcedure1.Caption := 'Undoing ' + Undo1.Hint;
|
|
LabelProcedure1.Update;
|
|
Sleep(250);
|
|
ImageEnView1.Proc.Undo();
|
|
ImageEnView1.Proc.ClearUndo;
|
|
Undo1.Hint := ImageEnView1.Proc.UndoCaptions[0];
|
|
Undo1.Enabled := ImageEnView1.Proc.CanUndo;
|
|
LabelProcedure1.Caption := '';
|
|
StatusBar1.Panels[4].Text := 'Undo: ' + IntToStr(ImageEnView1.Proc.UndoCount);
|
|
finally
|
|
Screen.Cursor := crDefault;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.Exit1Click(Sender: TObject);
|
|
{ Exit the application. }
|
|
begin
|
|
Close;
|
|
end;
|
|
|
|
procedure TForm1.Fit1Click(Sender: TObject);
|
|
{ Fit the image. }
|
|
begin
|
|
if Fit1.Checked then
|
|
ImageEnView1.Fit
|
|
else
|
|
ImageEnView1.Zoom := 100;
|
|
end;
|
|
|
|
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
|
|
{ If the thread is assigned, then terminate and free the thread. }
|
|
begin
|
|
if Assigned(AThread) then
|
|
begin
|
|
AThread.Terminate;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.FormCreate(Sender: TObject);
|
|
{ Initialize variables and create the Thread. }
|
|
begin
|
|
{ Register imageen supported file types with vcl }
|
|
IERegisterFormats;
|
|
{ Set the OpenPicture Filter }
|
|
OpenPictureDialog1.Filter := GraphicFilter(TGraphic);
|
|
|
|
Cancel1.Enabled := False;
|
|
Process1.Enabled := False;
|
|
|
|
ImageEnView1.Proc.AutoUndo := False;
|
|
ImageEnView1.Proc.UndoLimit := 99;
|
|
Undo1.Enabled := ImageEnView1.Proc.CanUndo;
|
|
|
|
LabelThread1.Caption := 'Thread is Not Running';
|
|
end;
|
|
|
|
procedure TForm1.FormDestroy(Sender: TObject);
|
|
{ Form Destroy. }
|
|
begin
|
|
IEUnregisterFormats;
|
|
end;
|
|
|
|
procedure TForm1.ImageEnView1FinishWork(Sender: TObject);
|
|
{ Reset the progressbar. }
|
|
begin
|
|
ProgressBar1.Position := 0;
|
|
end;
|
|
|
|
procedure TForm1.ImageEnView1Progress(Sender: TObject; per: Integer);
|
|
{ Set the progressbar. }
|
|
begin
|
|
ProgressBar1.Position := per;
|
|
ProgressBar1.Position := per - 1;
|
|
ProgressBar1.Position := per;
|
|
end;
|
|
|
|
procedure TForm1.ImageEnView1Resize(Sender: TObject);
|
|
{ If Fit1 is checked then fit. }
|
|
begin
|
|
if Fit1.Checked then
|
|
ImageEnView1.Fit;
|
|
end;
|
|
|
|
procedure TForm1.Information1Click(Sender: TObject);
|
|
{ Display the information form. }
|
|
begin
|
|
Form2 := TForm2.Create(self);
|
|
try
|
|
Form2.ShowModal;
|
|
finally
|
|
Form2.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.Cancel1Click(Sender: TObject);
|
|
{ Cancel the thread. }
|
|
begin
|
|
AThread.Terminate;
|
|
if AThread.Terminated then
|
|
begin
|
|
Cancel1.Enabled := False;
|
|
Process1.Enabled := True;
|
|
LabelThread1.Caption := 'Thread is Not Running...';
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|