![]() |
Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Weiß jemand, in welchem Format Delphi die Images in der Formulardatei speichert? In der Textfassung sieht das ja ungefähr so aus:
Code:
Ich würde nun gern die Image mit einem externen Programm laden, manipulieren und wieder zurückschreiben. Kennt jemand einen einfachen Weg?
object Image1: TImage
Left = 48 Top = 40 Width = 105 Height = 105 HelpType = htKeyword HelpKeyword = 'g' Picture.Data = { 07544269746D6170E6040000424DE60400000000000036000000280000001400 0000140000000100180000000000B00400000000000000000000000000000000 |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Die Daten sind Hex-Codiert.
In deinem Beispiel steht TBitmap + den Binärstream des Bitmaps drin. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Mit TReader einlesen, in TWriter kopieren und dabei das Gewünschte verändern.
(man muß nur mal nachsehn, ob bei dem Textformat etwas beachtet werden muß, da das Format grundsätzlich erstmal binär ist ... eventuell gibt es auch irgendwo ein paar Konvertierungsfunktionen) Man könnte auch ganz böse die DFM "laden", also eine Form-Insttanz erstellen (die Methodenzeiger müssen aber beachtet werden), ändert dann in der TImageInstanz das Bild und speichert die DFM danach wieder ab. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Mich würde interessieren, was der Hintergrund dieser Anforderung ist: Um an die Bitmap- bzw. Picture-Daten zu kommen, genügt doch einfach ein
Delphi-Quellcode:
... wozu benötigt man dann die DFM, um dort umständlich die Picture-Daten auszulesen und zu interpretieren?
Image1.Picture.SaveToFile(Dateiname);
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Wenn sowas austauschbar gestaltet werden soll gibt es 100 bessere und einfachere Lösungen als das im DFM zu machen. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Also wenn ich eine DFM ohne PAS-Datei hätte und wollte das Bild haben, würde ich einfach ein neues Formular mit allen Komponeten der DFM-Datei erstellen, speichern, DFM austauschen, wieder laden und dann das Bild kopieren. Alles über die IDE und alles ohne Programmcode. Sollte in 1 Minute erledigt sein.
Vermutlich reicht es, ein TImage auf eine Form zu klatschen, speichern, DFM austauschen, laden, Fehler wegklicken, fertig. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Ich habe mal versucht, ein Programm zu erzeugen, das zwei Images auf der Form hat. Nun wollte ich erst mal die Image2 laden und dann "kopieren" (wie Du schreibst) und in Image1 schreiben (die Image-Manipulation habe ich mir also erst einmal geschenkt). So sieht der Source-Code aus:
Code:
Bei der gekennzeichneten Zeile kommt der Fehler wie beschrieben.
procedure TForm43.FormCreate(Sender: TObject);
var writer: TWriter; reader : TReader; msr, msw: TMemorystream; begin msr:= TMemorystream.create; msw := TMemorystream.create; reader := TReader.Create (msr,0); // Liest Komponente "Image2" reader.ReadComponent (Image2); // Hier kommt stream-lesefehler Writer := TWriter.Create (msw, 0); msr.position := 0; msw.CopyFrom (msr, msw.size); writer.WriteComponent (Image1); end; Was mache ich falsch, bzw. muss ich anders machen? |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Hintergrund ist u.a., dass z.B. bei der Konvertierung mit dem MIDA-Converter die i.d.R. 24-Bit Bitmaps auch in 24-Bit konvertiert werden. Dann werden diese aber mit den hässlichen Hintergrundfarben (z.B. Pink) angezeigt. Insofern möchte ich vorher mit einem kleinen Programm alle 24-Bit Bitmaps in einem Rutsch in 32-Bit Bitmaps ändern, die "Hintergrundfarbe" durch Transparenz ersetzen, damit diese Bitmaps dann in der FMX-Form transparent angezeigt werden können. Wenn man z.B. 100 oder mehr TSpeedButtons in einer Form hat, mit entsprechenden Glpyhs, wäre es schon ein irrer Aufwand, hinterher manuell die Bitmaps bearbeiten zu müssen, das will ich mir halt ersparen (habe zwar den MIDA-Leuten vorgeschlagen, diese Option in deren Programm einzubauen, habe daher aber bislang noch keine Antwort erhalten [Sie wollten es prüfen]). |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Ich würde mir ein zentralen Icon/Image-Pool aufbauen und in jedem Formular sich bei diesen bedienen. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Leider weiß ja nur die Komponente selber, wie die binären Daten codiert sind. Es gibt da ja auch unterschiedliche Property-Namen, z.b. Picture, Bitmap, Image.Data, Glyph etc.
Ich würde das wie folgt lösen: Eine Designtime Komponente erstellen mit einem Editor, die keine Persistenz hat. Die beinhaltet dann einen Editor der über das Verb aufgerufen wird. In diesem Editor durchläufst Du alle Komponenten des Formulars und liest die Image-Objekte in eine Liste ein wobei Du Dir merkst welche Property welches Objekts das war. Die Listeneinträge kannst Du dann evtl. visualisieren, markieren und zur Konvertierung bestätigen. Daraufhin das Format entsprechend wandeln und die Komponenten-Eigenschaften aktualisieren. Für die Umstellung eines Formulars müsstest Du zunächst die BPL installiert haben. Dann nur die Komponente fallen lassen, draufklicken und die Konvertierung bestätigen. Dann die Komponente wieder löschen und nächstes Formular. Alternativ könnte man natürlich auch einen Experten schreiben. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Handelt es sich z.B. um ein TSpeedButton mit einem Glyph, dann beginnt in dem Datenstream ab Offset 5 das eigentliche Bitmap. Vorher sind 4 Bytes, die Delphi anscheinend intern für die Komponente verwendet (nennen wir das mal "Komponentenheader"). So kann ich also ohne Probleme die Bitmap ab Position 5 auslesen. Das Problem entsteht nun, wenn ich eine geänderte Bitmap zurückschreiben will. Denn die ersten 4 Bytes unterscheiden sich, je nach dem, welche Bit-Tiefe und welches Ausmaß die Bitmap hat. Eine echte Logik konnte ich da selber leider nicht erkennen. Ist jemanden eine Beschreibung bekannt, nach welcher Systematik die ersten 4 Bytes in dem Stream ("Komponentenheader") für "Glpyh.data" (Tspeedbutton), "Picture.data" (TImage) oder "Bitmap" (TImagelist) geschrieben werden müssen? |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Ich würde sagen das ist die Längenangabe:
In deinem Fall: E6040000 Intel (Little-Endian) Reihenfolge, also 000004E6 = 1254 Byte Datenlänge |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Nein, Größenangaben können das m.E. nicht sein.
Ein 16x16 großes 24-Bit-Bitmap hat z.B. diese 4 Bytes als "Komponentenheader":
Code:
Ein 16x16 großes 32-Bit-Bitmap hat z.B. diese 4 Bytes als Header:
Glyph.Data = {
36030000...
Code:
Ein 24x24 großes 24-Bit-Bitmap hat z.B. diese 4 Bytes als Header:
Glyph.Data = {
36040000...
Code:
Glyph.Data = {
F6060000... |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
16*16*24 Bit = 768 Byte <-> 0x0336 -> 822 Bildaten inkl. den 54 Byte BMP-Header 16*16*32 Bit = 1024 Byte <-> 0x0436 = 1078 Bildaten inkl. den 54 Byte BMP-Header 24*24*24 Bit = 1728 Byte <-> 0x06F6 = 1782 Bildaten inkl. den 54 Byte Bmp-Header |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Lässt erst mal ein wenig Hoffnung aufkommen:-D
Wobei ich festgestellt habe, dass bei einem 16x16 großen 32-Bit-Bitmap auch dies dort stehen kann:
Code:
(der Bitmap-Stream ist dann auch 2102 Byte groß)
Glyph.Data = {
36080000... also, statt dem
Code:
Anscheinend können 32-Bit-Bitmaps, 16x16 Size auch unterschiedlichen Speicherbedarf annehmen, dachte die wären bei gleichem Ausmaß und Bit-Tiefe immer gleich groß.
Glyph.Data = {
36040000... |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Hast Du noch einen Tipp, wie ich die Größe des Streams (Integerwert) in den HEX-Wert, Little Endian-Reihenfolge konvertiere? Gibt es dafür eine fertige Funktion?
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Ich habe hier mal ein Formular hochgeladen und die beiden verwendeten Bitmaps. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Die Idee einfach mal in TPicture.WriteData, TPicture.ReadData, TBitmap.WriteData und TBitmap.ReadData reinzuschauen hatte noch Keiner?
Auf die Idee dort reinzugucken, wäre man gekommen, wenn man in TPicture.DefineProperties und TGraphic.DefineProperties geschaut hätte. :angel: |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Danke, guter Hinweis.
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Liste der Anhänge anzeigen (Anzahl: 4)
Ich habe dafür eine Komponente erstellt. Die installiert sich unter Samples/TImageConverter. Die setzt man auf das Form mit den Controls, die Grafiken enthalten. Über das Kontextmenü der Komponente wählt man 'Images dieses Formulares bearbeiten' aus. Dann öffnet sich ein Dialog in dem die Komponenten angezeigt werden mit der Auflösung der Grafiken. Beim Klick auf "Speichern" werden alle Grafiken auf 32 bit Farbtiefe gesetzt. Danach ist die Komponente wieder zu entfernen und die evtl. eingefügte unit "ImageConvertEditor" aus den uses zu entfernen.
Die dpk:
Delphi-Quellcode:
Die Komponente, die nichts weiter macht als auf einen Doppelklick bzw, die Auswahl des Kontextmenüs zu reagieren:
package ImageConvertPackage;
{$R *.res} {$R 'ImageConvertEditor.dcr'} {$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO OFF} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS OFF} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} {$RANGECHECKS OFF} {$REFERENCEINFO OFF} {$SAFEDIVIDE OFF} {$STACKFRAMES OFF} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DEFINE RELEASE} {$ENDIF IMPLICITBUILDING} {$DESCRIPTION 'Image converter'} {$DESIGNONLY} {$IMPLICITBUILD ON} requires rtl, vcl, designide; contains ImageConvertEditor in 'ImageConvertEditor.pas', uImageConvertEditor in 'uImageConvertEditor.pas' {frmImageConvertEditor}; end.
Delphi-Quellcode:
Der Dialog und die Beasrbeitungslogik, die relevante Bearbeitung findet in SaveImages statt:
unit ImageConvertEditor;
interface uses System.Classes, DesignIntf, DesignEditors; type TImageConvertEditor = class(TComponentEditor) public procedure ExecuteVerb(Index: Integer); override; function GetVerb(Index: Integer): string; override; function GetVerbCount: Integer; override; procedure ShowImageConvertEditor; private TheDesigner: DesignIntf.IDesigner; end; TImageConverter = class(TComponent) end; procedure Register; implementation uses Dialogs, Forms, uImageConvertEditor; { TImageConvertEditor } procedure TImageConvertEditor.ExecuteVerb(Index: Integer); begin inherited; case Index of 0 : ShowImageConvertEditor; end; end; function TImageConvertEditor.GetVerb(Index: Integer): string; begin case Index of 0 : result := 'Images dieses Formulares bearbeiten'; end; end; function TImageConvertEditor.GetVerbCount: Integer; begin result := 1; end; procedure TImageConvertEditor.ShowImageConvertEditor; var frmConvertEditor: TFrmImageConvertEditor; begin TheDesigner := Self.Designer; frmConvertEditor := TFrmImageConvertEditor.Create(Application, TheDesigner.CurrentParent); frmConvertEditor.ShowModal; frmConvertEditor.Free; end; procedure Register; begin RegisterComponents('Samples', [TImageConverter]); RegisterComponentEditor(TImageConverter, TImageConvertEditor); end; end.
Delphi-Quellcode:
Das Formular dazu:
unit uImageConvertEditor;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.ExtCtrls; type TfrmImageConvertEditor = class(TForm) lvImages: TListView; lblTitle: TLabel; btnSave: TButton; btnCancel: TButton; ImagePreview: TImage; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure lvImagesSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); procedure btnSaveClick(Sender: TObject); private { Private-Deklarationen } ImageInfo : TStringList; ValidProperties : TStringList; FRootComponent: TComponent; procedure FillValidProperties; function GetBitmap(AData : TObject) : TBitmap; procedure SaveImages; function IsValidProperty(APropName : string) : boolean; procedure ProcessComponents(AParent : TComponent; var APath : string); procedure GetImageProperties(AComponent : TComponent; const APath : string); procedure ShowImages; public constructor Create(AOwner: TComponent; ARootComponent : TComponent); reintroduce; end; var frmImageConvertEditor: TfrmImageConvertEditor; implementation uses RTTI, TypInfo; {$R *.dfm} procedure TfrmImageConvertEditor.FormDestroy(Sender: TObject); begin ImageInfo.Free; ValidProperties.Free; end; function TfrmImageConvertEditor.GetBitmap(AData: TObject): TBitmap; begin if AData is TBitmap then result := TBitmap(AData) else if AData is TPicture then begin result := TPicture(AData).Bitmap; end else result := nil; end; procedure TfrmImageConvertEditor.GetImageProperties(AComponent: TComponent; const APath : string); var LRtCo : TRttiContext; LRtTyp : TRttiType; LRtProp : TRttiProperty; LPicture : TBitmap; begin LRtCo := TRttiContext.Create; LRtTyp := LRtCo.GetType(AComponent.ClassType); for LRtProp in LRtTyp.GetProperties do begin if LRtProp.IsReadable and LRtProp.IsWritable then begin if IsValidProperty(LRtProp.Parent.Name + '.' +LRtProp.Name) then begin LPicture := TBitmap(LRtProp.GetValue(AComponent).AsObject); ImageInfo.AddObject(APath + AComponent.Name + '.' + LRtProp.Name + ' : ' + AComponent.ClassName, LPicture); end; end; end; LRtCo.Free; end; function TfrmImageConvertEditor.IsValidProperty(APropName: string): boolean; begin result := ValidProperties.IndexOf(APropName) >= 0; end; procedure TfrmImageConvertEditor.lvImagesSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); var LBitmap : TBitmap; begin ImagePreview.Picture.Bitmap := nil; if Selected then begin LBitmap := GetBitmap(Item.Data); if Assigned(LBitmap) then ImagePreview.Picture.Bitmap.Assign(LBitmap); end; end; procedure TfrmImageConvertEditor.ProcessComponents(AParent : TComponent; var APath : string); procedure AddPath; begin APath := APath + AParent.Name + '.'; end; procedure RemovePath; begin APath := copy(APath, 1, length(APath) - length(AParent.Name)-1); end; var i : integer; begin if (AParent <> nil) and (AParent <> Self) then begin GetImageProperties(AParent, APath); AddPath; for i := 0 to AParent.ComponentCount-1 do begin ProcessComponents(AParent.Components[i], APath); end; RemovePath; end; end; procedure TfrmImageConvertEditor.SaveImages; var LBitmap : TBitmap; i : integer; begin for i := 0 to ImageInfo.Count -1 do begin LBitmap := GetBitmap(ImageInfo.Objects[i]); if Assigned(LBitmap) and (LBitmap.Width > 0) then begin LBitmap.PixelFormat := pf32bit; // Zur Demonstration "Durchstreichen". Hier kann man natürlich // beliebige Sauereien anstellen // LBitmap.Canvas.Pen.Width := 2; // LBitmap.Canvas.Pen.Color := clred; // LBitmap.Canvas.MoveTo(0, 0); // LBitmap.Canvas.LineTo(LBitmap.Width, LBitmap.Height); end; end; end; procedure TfrmImageConvertEditor.ShowImages; var i : integer; LItem : TListItem; DataBitmap : TBitmap; SmallBitmap : TBitmap; LargeBitmap : TBitmap; begin for i := 0 to ImageInfo.Count -1 do begin DataBitmap := GetBitmap(ImageInfo.Objects[i]); LItem := lvImages.Items.Add; LItem.Data := DataBitmap; LItem.Caption := ImageInfo[i]; if Assigned(DataBitmap) then begin try SmallBitmap := TBitmap.Create; SmallBitmap.Width := 16; SmallBitmap.Height := 16; SmallBitmap.Canvas.StretchDraw(Rect(0,0,16,16), DataBitmap); LargeBitmap := TBitmap.Create; LargeBitmap.Width := 64; LargeBitmap.Height := 64; LargeBitmap.Canvas.StretchDraw(Rect(0,0,64,64), DataBitmap); lvImages.SmallImages.AddMasked(SmallBitmap, clFuchsia); lvImages.LargeImages.AddMasked(LargeBitmap, clFuchsia); LItem.ImageIndex := lvImages.SmallImages.Count-1; LItem.SubItems.Add(Format('%d x %d', [DataBitmap.Width, DataBitmap.Height])); LItem.SubItems.Add(GetEnumName(TypeInfo(TPixelFormat), Integer(DataBitmap.PixelFormat))); except end; end; end; end; procedure TfrmImageConvertEditor.btnSaveClick(Sender: TObject); begin SaveImages; end; constructor TfrmImageConvertEditor.Create(AOwner, ARootComponent: TComponent); begin inherited Create(AOwner); FRootComponent := ARootComponent; end; procedure TfrmImageConvertEditor.FillValidProperties; begin ValidProperties.Add('TSpeedButton.Glyph'); ValidProperties.Add('TBitBtn.Glyph'); ValidProperties.Add('TImage.Picture'); end; procedure TfrmImageConvertEditor.FormCreate(Sender: TObject); var ARootPath : string; begin lvImages.SmallImages := TImageList.Create(nil); lvImages.LargeImages := TImageList.Create(nil); ImageInfo := TStringList.Create; ValidProperties := TStringList.Create; FillValidProperties; ARootPath := ''; ProcessComponents(FRootComponent, ARootPath); ShowImages; end; end.
Code:
RC (ImageConvertEditor.rc)für die Erstellung der dcr:
object frmImageConvertEditor: TfrmImageConvertEditor
Left = 0 Top = 0 Caption = 'Image Converter' ClientHeight = 277 ClientWidth = 559 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poOwnerFormCenter OnCreate = FormCreate OnDestroy = FormDestroy DesignSize = ( 559 277) PixelsPerInch = 96 TextHeight = 13 object lblTitle: TLabel Left = 8 Top = 8 Width = 82 Height = 13 Caption = 'Gefundene Bilder' end object ImagePreview: TImage Left = 407 Top = 148 Width = 144 Height = 121 Anchors = [akRight, akBottom] Stretch = True end object lvImages: TListView Left = 8 Top = 24 Width = 393 Height = 245 Anchors = [akLeft, akTop, akRight, akBottom] Columns = < item AutoSize = True Caption = 'Komponente' end item AutoSize = True Caption = 'Gr'#246#223'e' end item AutoSize = True Caption = 'Format' end> TabOrder = 0 ViewStyle = vsReport OnSelectItem = lvImagesSelectItem end object btnSave: TButton Left = 476 Top = 22 Width = 75 Height = 25 Anchors = [akTop, akRight] Caption = 'Speichern' ModalResult = 1 TabOrder = 1 OnClick = btnSaveClick end object btnCancel: TButton Left = 476 Top = 53 Width = 75 Height = 25 Anchors = [akTop, akRight] Caption = 'Abbruch' ModalResult = 2 TabOrder = 2 end end
Code:
Dafür ist in den Projektoptionen als Pre-Build-Ereignis folgendes einzutragen:
TIMAGECONVERTER16 BITMAP "Graphic design 16.bmp"
TIMAGECONVERTER BITMAP "Graphic design 24.bmp" TIMAGECONVERTER32 BITMAP "Graphic design 32.bmp"
Code:
brcc32 -fo"ImageConvertEditor.dcr" "ImageConvertEditor.rc"
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Liste der Anhänge anzeigen (Anzahl: 1)
Wow, Union, ich bin beeindruckt, was Du da an Arbeit reingesteckt hast. Ist ein interessanter Ansatz und demonstriert einige interessante Techniken im Rahmen der Komponentenentwicklung (wovon ich leider nur sehr wenig Ahnung habe).
Ich habe es nun so gelöst, dass ich die Informationen zu allen Grafiken, die in einer VCL-Form sind, in einen Dialog einlese und habe diesen Dialog aber in mein Bildbearbeitungsprogramm eingebunden (habe dafür nun einen extra zu aktivierenden "Entwicklermodus" integriert, denn ein normaler Mensch braucht so etwas ja nicht). So kann bei den Bildern nicht nur die Bit-Tiefe ändern, sondern eben alles das, was man mit einem Bildbearbeitungsprogramm machen kann. Änderungen kann ich dann einzeln oder für alle geänderten Bilder zurückschreiben. Habe mal einen Screenshot des aktuellen Zustands des Dialogs angehängt. Wenn ich das fertig habe, poste ich noch mal eine Info dazu. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Du kannst ja in der Komponente den Aufruf Deines Dialoges einbauen. Der darf dann natürlich keine Abhängigkeiten haben. Das wäre dann der Entwickler modus.
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
Vielleicht wird das alles ein wenig mehr verständlich, wenn man es in einem kurzen Video sieht. Obwohl die Funktion noch nicht fertig ist, habe ich diese als BETA gekennzeichnet in die aktuelle Version 6.19 von PixPower eingebunden und in meinem PixPower-Channel ein kurzes Video dazu hinterlegt. Das könnt Ihr Euch hier ansehen: ![]() |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Da das Einlesen der TImageList hier noch nicht 100% funktioniert (Delphi verwendet hier wohl eine Maskengrafik, um Transparenz darzustellen), habe ich noch mal eine weitere Möglichkeit gezeigt, um an die Bilder aus der TImageList zu gelangen und ALLE enthaltenen Grafiken in einem Rutsch zu exportieren und dann als einzelne Grafiken speichern zu können. So kann man mit 5 Minuten Aufwand seine bisherige ImageList unter FMX weiterverwenden oder die Grafiken sonst anderweitig verwenden.
Hier der Link zu diesem Video: ![]() |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Nicht nur teilweise: Die Imagelist kapselt ein CommonControl. Der interne Aufbau der Daten ist damit u.U. sogar abhängig von der installierten Version des IE :(
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Joar und obwohl die Bilder gleich bleiben, meint die Versionierung öfters mal, daß sich in der DFM (ImageList) etwas/massig geändert hat, nur weil man die Form/Datenmodul neu speichert.
|
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Wie sieht denn nun eigentlich der Lösungsansatz genau aus? Nach den hier vorliegenden Hinweisen würde ich einen Parser vermuten, der aus der DFM die Deklarationen einer Image/ImageList-Komponente extrahiert und isoliert um darauf den jeweiligen Componentreader loszulassen. Ich würde mir noch nicht einmal die Mühe machen, das Hexkauderwelsch zu verstehen.
Das sollte doch für alle Komponenten gleich funktionieren. Man müsste sie nur registrieren und die Bildextrahierlogik auf Basis der konkreten Properties individuell programmieren. Dafür bietet sich eine Factory an. Der Pseudocode sähe so aus:
Delphi-Quellcode:
Für jede Komponente, die Bildinformationen enthält, implementiert man einen 'ComponentImageExtractor', der die beiden recht banalen Methoden implementiert und registriert die Klasse zusammen mit der Komponente, für die der Extractor gedacht ist (also TImage, TImageList, TBitBtn usw.)
Procedure ExtractImages (aDFM : string; aImages : TList);
var index : Integer; imageComponentDFM : string; classType : TComponentClass; definition : string; extractor : IComponentImageExtractor; Begin repeat imageComponentDFM := ExtractNextPortion(aDFM, index); // get next component definition if imageComponentDFM='' then break; // no more components SplitDFMIntoClassAndDefinition(imageComponentDFM, classType, definition); extractor := TComponentImageExtractorFactory.Create(classType); if extractor = nil then continue; // the class is not registered extractor.ReadComponentData(definition); extractor.ExtractImages(aImages); until false; end; type IComponentImageExtractor : interface Procedure ReadComponentData (aDefinition : String); // Will initialize the component from the DFM definition Procedure ExtractImages (aImages : TList); // Will copy the images from the component to the list end; TComponentImageExtractorFactory : class class procedure Create (aComponentClass : TComponentClass); class procedure Register (aExtractor : IComponentImageExtractor; aComponentClass : TComponentClass); end; Die Methode 'ReadComponentData' ist vermutlich für alle Komponenten gleich. Sie erwartet einen String der Form (o.ä.)
Delphi-Quellcode:
und liest die Daten über
'object ImageList: TImageList #13#10 Bitmap = {494...} end'
Delphi-Quellcode:
ein.
TStream.ReadComponent
Über die Factory kann man das dann problemlos und beliebig erweitern. Unübersichtlich ist es auch nicht, das die Aufgaben schon komplett verteilt sind. |
AW: Wie Image aus VCL-Formular-Datei (.dfm) auslesen
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:02 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz