| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- {
- Vampyre Imaging Library Demo
- FireMonkey Demo (class api, fmx interaction)
- This demo is a simple image viewer. On the left of the window is a list box with
- information and thumbnail of images loaded from file. Selecting item in
- list box displays the image in image viewer component that fills the rest of
- the app window. Loaded image can be saved back to disk in one the supported
- file formats.
- Demo uses ImagingFmx extension to convert between Imaging's and FireMonkey's
- image classes.
- Image is loaded from the file in a background thread while the UI shows
- progress animation.
- Note: tested only in Delphi 10.3 now
- }
- unit MainForm;
- interface
- uses
- System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
- FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Filter.Effects, FMX.Graphics,
- FMX.Layouts, FMX.ListBox, FMX.ExtCtrls, FMX.Objects, FMX.StdCtrls, FMX.Effects,
- FMX.Controls.Presentation,
- ImagingTypes,
- Imaging,
- ImagingClasses,
- ImagingUtility,
- ImagingFmx;
- type
- TFormMain = class(TForm)
- Splitter: TSplitter;
- ToolBar: TToolBar;
- ListImages: TListBox;
- BtnOpenImage: TSpeedButton;
- ImageViewer: TImageViewer;
- StyleBook: TStyleBook;
- PanelBack: TPanel;
- AniIndicator: TAniIndicator;
- OpenDialog: TOpenDialog;
- BtnSaveImage: TSpeedButton;
- BtnAbout: TSpeedButton;
- EmbossEffect: TEmbossEffect;
- SaveDialog: TSaveDialog;
- procedure BtnOpenImageClick(Sender: TObject);
- procedure BtnAboutClick(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure BtnSaveImageClick(Sender: TObject);
- procedure ListImagesChange(Sender: TObject);
- private
- FImage: TMultiImage;
- FFileName: string;
- FLoaderThread: TThread;
- procedure LoadingFinished(Success: Boolean; const ErrorMsg: string);
- procedure FillListBox(Image: TMultiImage);
- procedure SelectImage(Index: Integer);
- end;
- var
- FormMain: TFormMain;
- implementation
- uses
- AboutForm;
- {$R *.fmx}
- const
- ThumbMaxX = 106;
- ThumbMaxY = 92;
- type
- TImgLoaderThread = class(TThread)
- private
- type
- TFinishedHandler = reference to procedure(Success: Boolean; const ErrorMsg: string);
- private
- FFileName: string;
- FImageRef: TMultiImage;
- FFinishedHandler: TFinishedHandler;
- protected
- procedure Execute; override;
- public
- constructor Create(const FileName: string; ImageRef: TMultiImage;
- FinishedHandler: TFinishedHandler);
- end;
- procedure ClearImagesAndThumbs(Img: TMultiImage);
- var
- I: Integer;
- begin
- for I := 0 to Img.ImageCount - 1 do
- begin
- if Img.DataArray[I].Tag <> nil then
- TObject(Img.DataArray[I].Tag).Free;
- end;
- Img.ClearAll;
- end;
- { TImgLoaderThread }
- constructor TImgLoaderThread.Create(const FileName: string;
- ImageRef: TMultiImage; FinishedHandler: TFinishedHandler);
- begin
- FFileName := FileName;
- FImageRef := ImageRef;
- FFinishedHandler := FinishedHandler;
- FreeOnTerminate := True;
- inherited Create(False);
- end;
- procedure TImgLoaderThread.Execute;
- var
- I: Integer;
- Success: Boolean;
- ErrorMsg: string;
- Thumb: TSingleImage;
- begin
- TThread.NameThreadForDebugging('ImageLoaderThread');
- ErrorMsg := '';
- // Delete old images and thumbmails
- ClearImagesAndThumbs(FImageRef);
- try
- // Load image from file
- FImageRef.LoadMultiFromFile(FFileName);
- Success := FImageRef.AllImagesValid;
- // Generate thumbnails for subimages
- for I := 0 to FImageRef.ImageCount - 1 do
- begin
- Thumb := TSingleImage.Create;
- FImageRef.ActiveImage := I;
- FImageRef.ResizeToFit(ThumbMaxX, ThumbMaxY, rfBilinear, Thumb);
- FImageRef.DataArray[I].Tag := Thumb;
- end;
- except
- on E: Exception do
- begin
- Success := False;
- ErrorMsg := E.Message;
- end;
- end;
- Synchronize(
- procedure
- begin
- FFinishedHandler(Success, ErrorMsg);
- end);
- end;
- { TFormMain }
- procedure TFormMain.FillListBox(Image: TMultiImage);
- var
- Item: TListBoxItem;
- I, ImgSize: Integer;
- Data: TImageData;
- Bmp: TBitmap;
- begin
- ListImages.Clear;
- Bmp := TBitmap.Create(0, 0);
- try
- for I := 0 to FImage.ImageCount - 1 do
- begin
- Data := FImage.DataArray[I];
- Item := TListBoxItem.Create(ListImages);
- Item.Parent := ListImages;
- Item.StyleLookup := 'ListBoxItem';
- ImgSize := Data.Size;
- if ImgSize > 8192 then
- ImgSize := ImgSize div 1024;
- ImagingFmx.ConvertImageToFmxBitmap(TSingleImage(Data.Tag), Bmp);
- Item.StylesData['ImgThumb'] := Bmp;
- Item.StylesData['TextTitle'] := Format('Image %d/%d', [I + 1, FImage.ImageCount]);
- Item.StylesData['TextInfo'] :=
- Format('Resolution: %dx%d', [Data.Width, Data.Height]) + sLineBreak +
- Format('Format: %s', [GetFormatName(Data.Format)]) + sLineBreak +
- Format('Size: %.0n %s', [ImgSize + 0.0, Iff(ImgSize = Data.Size, 'B', 'KiB')]);
- end;
- finally
- Bmp.Free;
- end;
- end;
- procedure TFormMain.FormCreate(Sender: TObject);
- begin
- Caption := Caption + ' - ' + Imaging.SImagingLibTitle + ' ' + Imaging.GetVersionStr;
- FImage := TMultiImage.Create;
- end;
- procedure TFormMain.FormDestroy(Sender: TObject);
- begin
- ClearImagesAndThumbs(FImage);
- FImage.Free;
- end;
- procedure TFormMain.ListImagesChange(Sender: TObject);
- begin
- if ListImages.ItemIndex >= 0 then
- SelectImage(ListImages.ItemIndex);
- end;
- procedure TFormMain.LoadingFinished(Success: Boolean; const ErrorMsg: string);
- begin
- if Success then
- begin
- FillListBox(FImage);
- ListImages.ItemIndex := 0;
- end
- else
- begin
- MessageDlg('Error loading image: ' + ErrorMsg, TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
- FImage.ClearAll;
- end;
- AniIndicator.Visible := False;
- EmbossEffect.Enabled := False;
- ToolBar.Enabled := True;
- end;
- procedure TFormMain.SelectImage(Index: Integer);
- begin
- FImage.ActiveImage := Index;
- ImageViewer.BeginUpdate;
- try
- ImagingFmx.ConvertImageToFmxBitmap(FImage, ImageViewer.Bitmap);
- ImageViewer.BestFit;
- finally
- ImageViewer.EndUpdate;
- end;
- end;
- procedure TFormMain.BtnSaveImageClick(Sender: TObject);
- begin
- if not FImage.AllImagesValid then
- begin
- MessageDlg('No image is loaded.', TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
- Exit;
- end;
- SaveDialog.Filter := GetImageFileFormatsFilter(False);
- SaveDialog.FileName := ChangeFileExt(ExtractFileName(FFileName), '');
- SaveDialog.FilterIndex := GetFileNameFilterIndex(FFileName, False);
- if SaveDialog.Execute then
- begin
- FFileName := ChangeFileExt(SaveDialog.FileName, '.' + GetFilterIndexExtension(SaveDialog.FilterIndex, False));
- FImage.SaveMultiToFile(FFileName);
- end;
- end;
- procedure TFormMain.BtnAboutClick(Sender: TObject);
- var
- X, Y: Integer;
- begin
- // Place it manually - poMainFormCenter etc. doesn't really work
- // when main form has poScreenCenter
- X := Left + (Width - FormAbout.Width) div 2;
- Y := Top + (Height - FormAbout.Height) div 2;
- FormAbout.SetBounds(X, Y, FormAbout.Width, FormAbout.Height);
- FormAbout.ShowModal;
- end;
- procedure TFormMain.BtnOpenImageClick(Sender: TObject);
- begin
- OpenDialog.Filter := Imaging.GetImageFileFormatsFilter(True);
- if OpenDialog.Execute then
- begin
- FFileName := OpenDialog.FileName;
- ListImages.Clear;
- ImageViewer.Bitmap.SetSize(0, 0);
- ToolBar.Enabled := False;
- AniIndicator.Visible := True;
- EmbossEffect.Enabled := True;
- FLoaderThread := TImgLoaderThread.Create(FFileName, FImage, LoadingFinished);
- end;
- end;
- end.
|