| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- {
- Vampyre Imaging Library Demo
- Image Browser (class api, canvas, VCL/LCL interaction)
- This simple viewer application shows usage of high level class interface
- to Imaging library and also drawing images onto standard VCL/LCL TCanvas.
- TImagingCanvas class is also used here.
- In the left part of the window is shell tree view component. Here you can
- select files located in your computer. If the selected file is in one of the
- supported formats it is displayed in the viewer
- area and some information about the file is displayed in the info area.
- If image file contains subimages you can view them too. Select active subimage
- by clicking on buttons with arrows (Previous/Next).
- When supported file is selected in shell tree view it is loaded to
- TMultiImage and converted to ifA8R8G8B8
- data format. Active subimage is then drawn TPainBox component's
- client area using DisplayImage procedure (direct bit copy, no need to
- convert Imaging's data to TGraphic).
- Delphi: ShellCtrls unit with used TShellTreeView component is not installed in the IDE
- by default in most Delphi versions. It used to be a part of demos
- (in BDS 2006 you can find them in Demos\DelphiWin32\VCLWin32\ShellControls,
- in newer in c:\Users\Public\Documents\Embarcadero\Studio\21.0\Samples).
- Later the unit was incorporated in VCL sources
- (c:\Program Files (x86)\Embarcadero\RAD Studio\10.0\source\vcl\Vcl.Shell.ShellCtrls.pas)
- but the demo and package was removed in XE7 (https://stackoverflow.com/questions/578241)
- }
- unit Main;
- {$I ImagingOptions.inc}
- interface
- uses
- {$IFDEF MSWINDOWS}
- Windows,
- {$ENDIF}
- Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, ComCtrls, ShellCtrls, ExtCtrls, StdCtrls, Buttons, ExtDlgs,
- ImagingTypes,
- Imaging,
- ImagingClasses,
- ImagingComponents,
- ImagingColors,
- ImagingCanvases,
- ImagingFormats,
- ImagingUtility;
- type
- TMainForm = class(TForm)
- ImageList: TImageList;
- LeftPanel: TPanel;
- RightPanel: TPanel;
- InfoPanel: TPanel;
- LabDataFormat: TLabel;
- LabFileFormat: TLabel;
- LabDim: TLabel;
- LabFileName: TLabel;
- Label3: TLabel;
- Label2: TLabel;
- Label1: TLabel;
- Lab1: TLabel;
- ViewPanel: TPanel;
- PaintBox: TPaintBox;
- Tree: TShellTreeView;
- Splitter1: TSplitter;
- Label4: TLabel;
- LabActImage: TLabel;
- StatusBar: TStatusBar;
- BtnPrev: TSpeedButton;
- BtnNext: TSpeedButton;
- BtnFirst: TSpeedButton;
- BtnLast: TSpeedButton;
- BtnSave: TButton;
- SaveDialog: TSavePictureDialog;
- CheckFilter: TCheckBox;
- procedure PaintBoxPaint(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure TreeChange(Sender: TObject; Node: TTreeNode);
- procedure BtnPrevClick(Sender: TObject);
- procedure BtnNextClick(Sender: TObject);
- procedure TreeKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
- procedure BtnFirstClick(Sender: TObject);
- procedure BtnLastClick(Sender: TObject);
- procedure BtnSaveClick(Sender: TObject);
- procedure ViewPanelResize(Sender: TObject);
- procedure CheckFilterClick(Sender: TObject);
- private
- // Class that holds multiple images (loaded from MNG or DDS files for instance)
- FImage: ImagingClasses.TMultiImage;
- // Canvas for drawing on loaded images
- FImageCanvas: ImagingCanvases.TImagingCanvas;
- // Image background
- FBack: ImagingClasses.TSingleImage;
- // Canvas for background image
- FBackCanvas: ImagingCanvases.TImagingCanvas;
- FFileName: string;
- FLastTime: LongInt;
- FOriginalFormats: array of TImageFormat;
- FOriginalSizes: array of Integer;
- FSupported: Boolean;
- {$IFDEF FPC}
- procedure TreeGetImageIndex(Sender: TObject; Node: TTreeNode);
- procedure TreeGetSelectedIndex(Sender: TObject; Node: TTreeNode);
- {$ENDIF}
- public
- procedure SetSupported;
- procedure SetUnsupported;
- procedure LoadFile;
- procedure FillDefault;
- end;
- const
- FillColor = $FFE6F2FF;
- CheckersDensity = 32;
- SUnsupportedFormat = 'Selected item format not supported';
- var
- MainForm: TMainForm;
- implementation
- {$IFDEF FPC}
- {$R *.lfm}
- uses
- LCLType;
- {$ELSE}
- {$R *.dfm}
- {$ENDIF}
- procedure TMainForm.FormCreate(Sender: TObject);
- begin
- Caption := Caption + ' version ' + Imaging.GetVersionStr;
- FImage := TMultiImage.Create;
- FImageCanvas := TImagingCanvas.Create;
- FBack := TSingleImage.CreateFromParams(128, 128, ifA8R8G8B8);
- FBackCanvas := FindBestCanvasForImage(FBack).CreateForImage(FBack);
- SetUnsupported;
- {$IFDEF FPC}
- Tree.OnGetImageIndex := TreeGetImageIndex;
- Tree.OnGetSelectedIndex := TreeGetSelectedIndex;
- {$ENDIF}
- end;
- procedure TMainForm.FormDestroy(Sender: TObject);
- begin
- FImage.Free;
- FImageCanvas.Free;
- FBack.Free;
- FBackCanvas.Free;
- end;
- procedure TMainForm.LoadFile;
- var
- I: LongInt;
- T: Int64;
- begin
- try
- // DetermineFileFormat reads file header and returns image
- // file format identifier (like 'jpg', 'tga') if file is valid,
- // otherwise empty string is returned
- if Imaging.DetermineFileFormat(FFileName) <> '' then
- try
- // Load all subimages in file
- T := ImagingUtility.GetTimeMicroseconds;
- FImage.LoadMultiFromFile(FFileName);
- if not FImage.AllImagesValid then
- begin
- SetUnsupported;
- Exit;
- end;
- FLastTime := (ImagingUtility.GetTimeMicroseconds - T) div 1000;
- StatusBar.SimpleText := Format('Last image loaded in: %.0n ms', [FLastTime * 1.0]);
- // Store original data formats and sizes for later use
- SetLength(FOriginalFormats, FImage.ImageCount);
- SetLength(FOriginalSizes, FImage.ImageCount);
- for I := 0 to FImage.ImageCount - 1 do
- begin
- FImage.ActiveImage := I;
- FOriginalFormats[I] := FImage.Format;
- FOriginalSizes[I] := FImage.Size;
- // Convert image to 32bit ARGB format if current format is not supported
- // by canvas class
- if not (FImage.Format in TImagingCanvas.GetSupportedFormats) then
- FImage.Format := ifA8R8G8B8;
- end;
- // Activate first image and update UI
- FImage.ActiveImage := 0;
- SetSupported;
- PaintBox.Repaint;
- except
- SetUnsupported;
- raise;
- end
- else
- SetUnsupported;
- except
- SetUnsupported;
- end;
- end;
- procedure TMainForm.SetSupported;
- var
- XRes, YRes: Double;
- ImgSize: Integer;
- begin
- // Update image info and enable previous/next buttons
- ImgSize := FOriginalSizes[FImage.ActiveImage];
- if ImgSize > 8192 then
- ImgSize := ImgSize div 1024;
- LabDim.Caption := Format('%dx%d pixels', [FImage.Width, FImage.Height]);
- if GlobalMetadata.GetPhysicalPixelSize(ruDpi, XRes, YRes) then
- LabDim.Caption := LabDim.Caption + Format(' (DPI %.0nx%.0n)', [XRes, YRes]);
- LabFileFormat.Caption := Imaging.FindImageFileFormatByName(FFileName).Name;
- LabDataFormat.Caption := Imaging.GetFormatName(FOriginalFormats[FImage.ActiveImage]);
- LabDataFormat.Caption := LabDataFormat.Caption +
- Format(' (Size in memory: %s %s)', [IntToStrFmt(ImgSize), Iff(ImgSize = FOriginalSizes[FImage.ActiveImage], 'B', 'KiB')]);
- LabActImage.Caption := Format('%d/%d', [FImage.ActiveImage + 1, FImage.ImageCount]);
- BtnPrev.Enabled := True;
- BtnNext.Enabled := True;
- BtnFirst.Enabled := True;
- BtnLast.Enabled := True;
- BtnSave.Enabled := True;
- CheckFilter.Enabled := True;
- FSupported := True;
- end;
- procedure TMainForm.SetUnsupported;
- var
- X, Y, Step: LongInt;
- begin
- // Set info texts to 'unsupported' and create default image to show
- LabDim.Caption := SUnsupportedFormat;
- LabFileFormat.Caption := SUnsupportedFormat;
- LabDataFormat.Caption := SUnsupportedFormat;
- LabActImage.Caption := '0/0';
- StatusBar.SimpleText := 'No image loaded';
- BtnPrev.Enabled := False;
- BtnNext.Enabled := False;
- BtnFirst.Enabled := False;
- BtnLast.Enabled := False;
- BtnSave.Enabled := False;
- CheckFilter.Enabled := False;
- FSupported := False;
- if Assigned(FImage) then
- begin
- FImage.CreateFromParams(CheckersDensity, CheckersDensity, ifA8R8G8B8, 1);
- FImageCanvas.Free;
- FImageCanvas := FindBestCanvasForImage(FImage).CreateForImage(FImage);
- Step := FImage.Width div CheckersDensity;
- for Y := 0 to CheckersDensity - 1 do
- for X := 0 to CheckersDensity - 1 do
- begin
- FImageCanvas.FillColor32 := IffUnsigned((Odd(X) and not Odd(Y)) or (not Odd(X) and Odd(Y)),
- pcWhite, pcGray);
- FImageCanvas.FillRect(Rect(X * Step, Y * Step, (X + 1) * Step, (Y + 1) * Step));
- end;
- end;
- // Paint current image
- PaintBox.Repaint;
- end;
- procedure TMainForm.BtnPrevClick(Sender: TObject);
- begin
- FImage.ActiveImage := FImage.ActiveImage - 1;
- SetSupported;
- PaintBox.Repaint;
- end;
- procedure TMainForm.BtnSaveClick(Sender: TObject);
- var
- CopyPath: string;
- begin
- SaveDialog.Filter := Imaging.GetImageFileFormatsFilter(False);
- SaveDialog.FileName := ChangeFileExt(ExtractFileName(FFileName), '');
- SaveDialog.FilterIndex := Imaging.GetFileNameFilterIndex(FFileName, False);
- if SaveDialog.Execute then
- begin
- CopyPath := ChangeFileExt(SaveDialog.FileName, '.' +
- Imaging.GetFilterIndexExtension(SaveDialog.FilterIndex, False));
- FImage.SaveMultiToFile(CopyPath);
- end;
- end;
- procedure TMainForm.CheckFilterClick(Sender: TObject);
- begin
- PaintBox.Repaint;
- end;
- procedure TMainForm.BtnFirstClick(Sender: TObject);
- begin
- FImage.ActiveImage := 0;
- SetSupported;
- PaintBox.Repaint;
- end;
- procedure TMainForm.BtnLastClick(Sender: TObject);
- begin
- FImage.ActiveImage := FImage.ImageCount - 1;
- SetSupported;
- PaintBox.Repaint;
- end;
- procedure TMainForm.BtnNextClick(Sender: TObject);
- begin
- FImage.ActiveImage := FImage.ActiveImage + 1;
- SetSupported;
- PaintBox.Repaint;
- end;
- procedure TMainForm.TreeChange(Sender: TObject; Node: TTreeNode);
- begin
- // Selected item in the shell tree view has been changed
- // we check whether the selected item is valid file in one of the
- // supported formats
- FFileName := Tree.Path;
- LabFileName.Caption := ExtractFileName(FFileName);
- if FileExists(FFileName) and Assigned(Imaging.FindImageFileFormatByName(FFileName)) then
- LoadFile
- else
- SetUnsupported;
- end;
- {$IFDEF FPC}
- procedure TMainForm.TreeGetImageIndex(Sender: TObject; Node: TTreeNode);
- begin
- if Node.HasChildren then
- Node.ImageIndex := 1
- else if IsFileFormatSupported(Node.Text) then
- Node.ImageIndex := 0;
- end;
- procedure TMainForm.TreeGetSelectedIndex(Sender: TObject; Node: TTreeNode);
- begin
- Node.SelectedIndex := Node.ImageIndex;
- end;
- {$ENDIF}
- procedure TMainForm.TreeKeyDown(Sender: TObject; var Key: Word;
- Shift: TShiftState);
- begin
- if FImage.ImageCount > 1 then
- begin
- if Key = VK_SPACE then
- BtnNextClick(Self);
- end;
- end;
- procedure TMainForm.ViewPanelResize(Sender: TObject);
- begin
- // Resize background image to fit the paint box
- FBack.Resize(PaintBox.ClientWidth, PaintBox.ClientHeight, rfNearest);
- // Update back canvas state after resizing of associated image
- FBackCanvas.UpdateCanvasState;
- end;
- procedure TMainForm.PaintBoxPaint(Sender: TObject);
- var
- R: TRect;
- Filter: TResizeFilter;
- begin
- // Fill background with default color
- FillDefault;
- // Determine which stretching filter to use
- if FSupported and CheckFilter.Checked then
- Filter := rfBicubic
- else
- Filter := rfNearest;
- // Scale image to fit the paint box
- R := ImagingUtility.ScaleRectToRect(FImage.BoundsRect, PaintBox.ClientRect);
- // Create canvas for current image frame
- FImageCanvas.Free;
- FImageCanvas := FindBestCanvasForImage(FImage).CreateForImage(FImage);
- // Stretch image over background canvas
- FImageCanvas.StretchDrawAlpha(FImage.BoundsRect, FBackCanvas, R, Filter);
- // Draw image to canvas (without conversion) using OS drawing functions.
- // Note that DisplayImage only supports images in ifA8R8G8B8 format so
- // if you have image in different format you must convert it or
- // create standard TBitmap by calling ImagingComponents.ConvertImageToBitmap
- ImagingComponents.DisplayImage(PaintBox.Canvas, PaintBox.BoundsRect, FBack);
- end;
- procedure TMainForm.FillDefault;
- begin
- // Fill background canvas with default color
- FBackCanvas.FillColor32 := FillColor;
- FBackCanvas.FillRect(Rect(0, 0, FBack.Width, FBack.Height));
- end;
- {
- File Notes:
- -- 0.80 Changes/Bug Fixes ---------------------------------
- - Added Lazarus support so dropped "VCL" prefix.
- -- 0.77 Changes/Bug Fixes ---------------------------------
- - Displays size of image in memory.
- -- 0.26.5 Changes/Bug Fixes ---------------------------------
- - Displays image physical resolution if present.
- -- 0.26.3 Changes/Bug Fixes ---------------------------------
- - Creates best canvas class for given image for faster
- blending and scaling.
- -- 0.25.0 Changes/Bug Fixes ---------------------------------
- - Added alpha blended drawing with optional filtered stretching.
- -- 0.21 Changes/Bug Fixes -----------------------------------
- - Added Save Image Copy button and related stuff.
- - Added XP controls manifest (no TXPManifest since its not
- in older Delphis).
- - Wrong active image index was shown sometimes after several
- clicks on Prev/Next buttons.
- - Added First/Last subimage buttons.
- - Original data format of subimages at index >1 is displayed right now
- (was always A8R8G8B8)
- - Space key now shows next subimage if multi-images is loaded.
- -- 0.19 Changes/Bug Fixes -----------------------------------
- - added canvas usage too
- - added support for viewing multiimages (like MNG)
- - change drawing to use stuff from ImagingComponents unit instead of
- converting to TBitmap
- - changed demo to use high level interface instead of low level
- }
- end.
|