7.
FireMonkey–Funktionen
von einer VCL-Anwendung per DLL nutzen
Der Umbau einer bestehenden VCL-Anwendung zur FireMonkey-Anwendung kann in
einer "radikalen" Vorgehensweise erfolgen. Also alles in einem Rutsch
konvertieren. Nachteil dabei ist, dass dies bei einem größeren
VCL-Projekt sehr lange dauern kann und man an der aktuellen
Anwendung dann sinnvoller Weise nicht mehr viel verändert.
Die Alternative
zu dieser Vorgehensweise könnte ein sanfter Übergang sein. Indem man
z.B. Schritt für Schritt Dialoge und zugehörige Funktionen in eine
FireMonkey-DLL auslagert und somit den Übergang sukzessive bewirkt.
Dabei kann man auch gleich die neuen erweiterten Möglichkeiten (Grafik,
Ortungsfunktionen, etc.) einbauen, so dass die aktuelle Anwendung direkt
davon profitieren kann.
Möglicherweise wollen Sie aber auch (noch) nicht von VCL auf das
FireMonkey-Framework umsteigen, würden aber gerne bestimmte
Funktionalitäten von FireMonkey nutzen. In beiden Varianten bietet es
sich an, diese Funktionalitäten über eine FireMonkey-DLL zur Verfügung
zu stellen. Das ist gar nicht so schwer, es funktioniert so ähnlich wie
unter der VCL.
Hier zeige ich an einem Beispiel, wie ich meinem
VCL-Bildbearbeitungsprogramm „PixPower Photo & Draw“ einen neuen
Filtereffekt über eine FireMonkey-DLL hinzugefügt habe. Die erzeugte DLL
hat dabei eine Größe von ca. 4 MB, wirkt sich auf mein komprimiertes
Installationspaket aber nur mit einem Umfang von 1,3 MB aus. In den
kommenden Wochen werde ich hier noch weitere Filter hinzufügen.
Kurze Erläuterung der gewünschten Funktionalität: In der
VCL-Anwendung habe ich also eine Bitmap, die ich als Bitmap-Stream
speichere und an die FMX-DLL übergebe. Die Bitmap kann ich leider nicht
direkt als „TBitmap“ an die DLL übergeben, da VCL- und FireMonkey-Bitmap
untereinander nicht kompatibel sind. In der DLL wird die Bitmap in einem
Dialog in der Imageviewer-Komponente angezeigt, der ich einen
Papersketch-Effekt hinzugefügt habe. Die Intensität wird über eine Trackbar eingestellt.
Wenn der Anwender das dann mit „OK“ bestätigt, wird der PaperSketch
Effekt auf die Bitmap tatsächlich angewandt und und die Bitmap
wieder in den Stream geschrieben. Hier muss allerdings noch ein kleiner
Trick benutzt werden, denn standardmäßig schreibt FireMonkey einen
Bitmapstream als PNG-Stream. Daher wird eine eigene Klasse „TMyBitmap“
von TBitmap abgeleitet und die SaveStream-Prozedur überschrieben und so
angepasst, dass der Stream als Bitmap-Stream ("BMP"-Format bzw. RGB)
gespeichert werden kann.
Hier nun der konkrete Ablauf zur Erzeugung der FMX-DLL: Legen Sie
über Menü „Datei“, Befehl „Neu“ eine Dynamische Link-Bibliothek an:
library
FMXFilters;
uses
FMX.Forms,
System.SysUtils,
System.Classes,
FrmFilter in 'FrmFilter.pas' {F_Filters};
{R *.res}
exports
ShowBitmapFromStream;
begin
end.
Wenn Sie die Bibliothek angelegt haben, sind die hier in Fettschrift
gekennzeichneten Elemente noch nicht vorhanden.
Die Unit FMX.Forms müssen Sie manuell hinzufügen, damit klar ist, dass
es sich um eine FireMonkey-DLL handeln soll. Je nachdem, ob Sie die
Library bei einem bereits geöffneten VCL-Projekt anlegen oder separat,
kann es sein, dass Delphi darauf hinweist, dass für die DLL hier ein
FireMonkey-Projekt angenommen wird und daher eine entsprechende
Kennzeichnung vorgenommen werden müsste. Diese Abfrage können Sie dann
positiv bestätigen.
Die Unit FrmFilter ist eine Formularunit, die ich über den Befehl
„Datei“, „Neu“, „FireMonkey-Formular“ angelegt habe.
Achtung: Dieser Befehl wird nur angezeigt, wenn Sie das
DLL-Projekt im Projekt-Explorer angezeigt haben:
Das Formular sieht dabei so aus:
Im Struktur-Explorer so:
Im Source-Code habe ich vor dem „Implementation“ die folgende Funktion
definiert:
Function
ShowBitmapFromStream (ms: TMemoryStream):
Boolean; export;
Das ist die Funktion, die über die „exports“ Anweisung in der
Library-Datei als extern aufrufbare Funktion zur Verfügung gestellt
wird.
Hinweis 1: Wenn Sie statt einer Bitmap einen String an die DLL
übergeben möchten, sollten Sie entweder ShortString, PChar oder
WideString dafür verwenden. Das erspart Ihnen, die ShareMem-Unit
aufnehmen zu müssen und die BORLNDMM.DLL noch mit Ihrer Anwendung
weitergeben zu müssen.
Hinweis 2: Wenn Sie erreichen wollen, dass die erzeugte DLL nicht
nur von Delphiprogrammen, sondern auch von Programmen, die mit anderen
Entwicklungsumgebungen erzeugt wurden, aufgerufen werden können, sollten
Sie einen „IStream“, statt einen TMemoryStream verwenden.
Hier die Implementation dieser Funktion in der Formdatei (unter Uses
werden noch die Units FMX.Filter, FMX.Effects, FMX.Filter.Effects und
FMX.Surfaces benötigt):
function ShowBitmapFromStream (ms: TMemoryStream):
Boolean;
var
Filter: FMX.Filter.TFilter;
begin
Filter := TFilterManager.FilterByName('PaperSketch');
try
F_Filters := TF_Filters.Create(Application);
F_Filters.ImageViewer1.bitmap.LoadFromStream(ms);
if F_Filters.ShowModal = mrOK then begin
Filter.ValuesAsBitmap['Input'] :=
F_Filters.ImageViewer1.bitmap;
Filter.ValuesAsFloat ['BrushSize'] :=
F_Filters.TrackBar1.Value;
F_Filters.ImageViewer1.bitmap := TBitmap (Filter.ValuesAsBitmap['Output']);
TMyBitmap (F_Filters.ImageViewer1.bitmap).SaveToStream
(ms);
Result := True;
end else begin
Result := false;
end;
finally
F_Filters.Free;
end;
end;
Hier noch
die benötigte Anpassung zur Speicherung des Bitmap-Streams im
BMP-Format:
Type
TMyBitmap = class (TBitmap)
procedure SaveToStream(Stream: TStream);
end;
Implementation
procedure TMyBitmap.SaveToStream(Stream: TStream);
var
Surf: TBitmapSurface;
begin
Surf := TBitmapSurface.Create;
try
Surf.Assign(Self);
TBitmapCodecManager.SaveToStream(Stream, Surf, '.bmp');
finally
Surf.Free;
end;
end;
Erläuterung: Über den FilterManager wird also zunächst über den
Namen des Filters bzw. Effektes „PaperSketch“ die Filterfunktion
vorbelegt. Dann wird der FMX-Dialog erzeugt, der Bitmap-Stream wird in
die Bitmap des Imageviewers geladen.
Wenn der Anwender über die Trackbar die gewünschte Intensität des
Effektes eingestellt hat und die Aktion mit „OK“ bestätigt, wird die
Einstellung der Trackbar mit Hilfe der Filterfunktionen auf die Bitmap
im Imageviewer tatsächlich angewendet (der PaperSketch-Effekt in der
Form verändert ja das Bitmap des Imageviewers nicht, geändert wird nur
die Anzeige in der Form).
Dann wird
die geänderte Bitmap mit der abgeleiteten Klasse als „BMP"-Bitmap-
Stream gespeichert (also eine Bitmap im RGB-Format).
In der
VCL-Anwendung ist nun folgende Unit hinzuzufügen:
unit
uFMXLink;
interface
uses
Windows, Dialogs, Classes;
type
TShowBitmapFromStream = function(ms: TMemoryStream): Boolean;
var
ShowBitmapFromStream : TShowBitmapFromStream = nil;
DllHandle : THandle;
implementation
initialization
if DllHandle = 0 then begin
DllHandle := LoadLibrary('FMXFilters.dll');
if DllHandle > 0 then begin
@ShowBitmapFromStream := GetProcAddress(DllHandle,
'ShowBitmapFromStream');
End else begin
MessageDlg('ShowBitmapFromStream steht nicht zur
Verfügung',
mtInformation, [mbOK], 0);
end;
end;
finalization
if DLLHandle <> 0 then
FreeLibrary(DLLHandle);
end.
Erläuterung: Unter Type wird eine Funktion definiert, die der
exportieren Funktion aus der DLL entspricht. Unter Var wird wird
ShowBitmapFromStream dann als Procedur-Variable eingeführt.
Im Initialization-Abschnitt wird die DLL geladen und bei Erfolg dann die
Speicheradresse ermittelt und unserer zuvor deklarierten Prozedur
zugewiesen. Wenn Sie dann diese VCL-Unit in Ihre VCL-Anwendung
einbinden, können Sie dann von Ihrem Hauptformular aus die Funktion „ShowBitmapFromStream“
aufrufen.
Also z.B.
So:
Var
MemStream: TMemorySteam;
Begin
ABitmap.saveToStream (MemStream); // Bitmap als MemoryStream
MemStream.position := 0;
If ShowBitmapFromStream (MemStream) then begin
MemStream.Position := 0;
ABitmap.LoadFromStream (ms) //Datei wieder in Bitmap
laden
End;
ACHTUNG: Damit das funktioniert, muss in die Hauptform Ihrer
VCL-Anwendung die Windows-Unit „Winapi.GDIPOBJ“ eingebunden werden und
zwar direkt im USES-Abschnitt des Inteface-Abschnitts (also nicht in
einer Uses-Klausel im Implementations-Abschnitt, das wäre nicht
ausreichend).
Diese Unit wird benötigt, damit die GDI-Funktionalität auch für die
VCL-Anwendung initialisiert werden kann. Das kann nur über das
Hauptprogramm gemacht werden, in die FireMonkey-Unit gehört das also
nicht rein.
Wenn Sie Interesse haben, können Sie sich die Funktionalität in dem
Programm einmal ansehen (www.Pixpower.info)
oder ganz einfach in einem YouTube-Video in meinem PixPower-Kanal,
wo ich diesen Filter präsentiere:
http://youtu.be/W21uxyPsJvc.
Den
Source-Code für diese Demo können Sie
hier
laden. Voraussetzung ist Delphi XE4 oder XE5. Sie müssen sowohl
DLL und EXE kompilieren und die DLL muss im gleichen Verzeichnis wie die
EXE-Datei liegen.
Nachtrag:
Habe noch ein kleines Video erstellt, das zeigt, wie man die FMX-Form
auch gleichzeitig in einer FireMonkey-Anwendung verwenden kann.
Hier ist der Link.
Im
FireMonkey-Buch können Sie übrigens in Kapitel 4 "Grafikbearbeitung in
FireMonkey" unter Nummer 5 "Grafik drehen, spiegeln, invertieren oder
grau färben" mehr zur Verwendung der Filter- bzw. Effekt-Funktionen
erfahren.
|