2016-08-03 9 views
2

Sobald Sie laden und in eine Komponente Bild, kann ich sehen, dass Delphi die Bilddaten auf DFM speichern,. Beispiel:Wie konvertiert man Textdaten in ein Bild?

object img1: TImage 
    Left = 71 
    Top = 2 
    Width = 18 
    Height = 18 
    Picture.Data = { 
    0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000 
    001008060000001FF3FF610000000473424954080808087C0864880000000970 
    485973000000750000007501E3C207650000001974455874536F667477617265 
    007777772E696E6B73636170652E6F72679BEE3C1A000000EF4944415478DAAD 
    923B0AC2401086B3D7100F6110B415FBD8AB60E323E62262632DF15158A8BDB6 
    22D682E821C41B58C76F7003EB8A9A10073E36ECFCFB6766765514458E842258 
    3A5083A2F38C136C6016C5422B94EC7336C7F7122A7081A3CE97A0000768A2BD 
    BD1968F6E0428068FD2250AACE32863354ED4AE4701726D0B00F5B262BE8A199 
    DA065BC893709D2F8189547045E7D906D2D79684FFC32064F1D0E5FE6E90B985 
    CC434C738DF2F7BB7995691E521F163A1FC4262AE15396AA7650D6FBD2862F26 
    EAC313B767A0741BE64DCD657E890C0C93500F3D8E616203C344CA6FEBAD5B2A 
    03C364002D183D00658D8FCCCDEDEA100000000049454E44AE426082} 
end 

Wie Sie sehen können, ist es ein kleines Bild. Wie ist es möglich, diese Informationen ohne DFM zu bekommen und es ein Bild, zum Beispiel machen:

procedure TForm12.btn2Click(Sender: TObject); 
var 
    img2: TImage; 
    Loutput: TStream; 
begin 
    ObjectTextToBinary(TStringStream.Create(
    '0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000' 
    + '001008060000001FF3FF610000000473424954080808087C0864880000000970' 
    + '485973000000750000007501E3C207650000001974455874536F667477617265' 
    + '007777772E696E6B73636170652E6F72679BEE3C1A000000EF4944415478DAAD' 
    + '923B0AC2401086B3D7100F6110B415FBD8AB60E323E62262632DF15158A8BDB6' 
    + '22D682E821C41B58C76F7003EB8A9A10073E36ECFCFB6766765514458E842258' 
    + '3A5083A2F38C136C6016C5422B94EC7336C7F7122A7081A3CE97A0000768A2BD' 
    + 'BD1968F6E0428068FD2250AACE32863354ED4AE4701726D0B00F5B262BE8A199' 
    + 'DA065BC893709D2F8189547045E7D906D2D79684FFC32064F1D0E5FE6E90B985' 
    + 'CC434C738DF2F7BB7995691E521F163A1FC4262AE15396AA7650D6FBD2862F26' 
    + 'EAC313B767A0741BE64DCD657E890C0C93500F3D8E616203C344CA6FEBAD5B2A' 
    + '03C364002D183D00658D8FCCCDEDEA100000000049454E44AE426082'), Loutput); 
    img2 := TImage.Create(self); 
    img2.Name := 'image2'; 
    img2.Left := 71; 
    img2.Top := 30; 
    img2.Width := 18; 
    img2.Height := 18; 
    img2.Picture.Graphic.LoadFromStream(Loutput); 

    img1.Parent := Self; 
end; 
+0

Es ist Base16 codiert, auch bekannt als hex. Es wird auch einige Metadaten auf der Vorderseite geben. Lesen Sie den Quellcode für TPicture, um herauszufinden, was diese Metadaten sind. Der Rest ist einfach genug. –

+0

'ObjectTextToBinary()' wird in dieser Situation nicht funktionieren, weil 1) es nach einem tatsächlichen DFM sucht und in diesem Beispiel fehlschlägt, da es nur ein Teil eines größeren DFM ist, und 2) selbst wenn es nicht fehlgeschlagen ist, Es schreibt eine DFM-Signatur in den Ausgabestream, wodurch das Laden des Images beschädigt wird, wenn Sie es nicht überspringen. –

Antwort

7

Sie können nicht auf die TPicture.Graphic Eigenschaft, bis ein Bild in die TPicture zuerst geladen wurde.

TPicture unterstützt nicht das Laden von Daten von einem TStream (siehe QC#12434: Add LoadFromStream() method to TPicture), so dass Sie die Bilddaten manuell streamen müssen.

Die Picture.Data Eigenschaftendaten beginnen mit einem UTF-8 codierten ShortString, der den Namen der TGraphic-abgeleiteten Klasse enthält, die die Bilddaten erzeugte. In Ihrem Beispiel wird, dass Klassennamen codiert als:

0954506E67496D616765 

Das erste Byte (hex 09) ist die Anzahl von Bytes in dem Klassennamen (9), das folgende 9 Bytes (hex 54 50 6E 67 49 6D 61 67 65) ist die UTF- 8 Oktette des Klassennamens (TPngImage) und die verbleibenden Stream-Bytes sind die tatsächlichen PNG-Bilddaten.

Also, müssen Sie:

  1. Extrakt der Klassenname aus dem Stream.

  2. Instanziieren Sie die angegebene TGraphic-abgeleitete Klassentyp.

  3. laden Sie den verbleibenden Stream in das Objekt.

  4. Weisen Sie das Objekt TPicture zu.

Zum Beispiel:

uses 
    System.Classes, 
    System.SysUtils, 
    Vcl.Graphics, 
    Vcl.Imaging.Jpeg, 
    Vcl.Imaging.GIFImg, 
    Vcl.Imaging.PngImage; 

type 
    TGraphicAccess = class(TGraphic) 
    end; 

procedure TForm12.btn2Click(Sender: TObject); 
var 
    Linput: String; 
    Loutput: TMemoryStream; 
    LclsName: ShortString; 
    Lgraphic: TGraphic; 
    img2: TImage; 
begin 
    Linput := '0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000' 
      + '001008060000001FF3FF610000000473424954080808087C0864880000000970' 
      + '485973000000750000007501E3C207650000001974455874536F667477617265' 
      + '007777772E696E6B73636170652E6F72679BEE3C1A000000EF4944415478DAAD' 
      + '923B0AC2401086B3D7100F6110B415FBD8AB60E323E62262632DF15158A8BDB6' 
      + '22D682E821C41B58C76F7003EB8A9A10073E36ECFCFB6766765514458E842258' 
      + '3A5083A2F38C136C6016C5422B94EC7336C7F7122A7081A3CE97A0000768A2BD' 
      + 'BD1968F6E0428068FD2250AACE32863354ED4AE4701726D0B00F5B262BE8A199' 
      + 'DA065BC893709D2F8189547045E7D906D2D79684FFC32064F1D0E5FE6E90B985' 
      + 'CC434C738DF2F7BB7995691E521F163A1FC4262AE15396AA7650D6FBD2862F26' 
      + 'EAC313B767A0741BE64DCD657E890C0C93500F3D8E616203C344CA6FEBAD5B2A' 
      + '03C364002D183D00658D8FCCCDEDEA100000000049454E44AE426082'; 

    Loutput := TMemoryStream.Create; 
    try 
    Loutput.Size := Length(Linput) div 2; 
    HexToBin(PChar(Linput), Loutput.Memory^, Loutput.Size); 

    LclsName := PShortString(Loutput.Memory)^; 

    Lgraphic := TGraphicClass(FindClass(UTF8Decode(LclsName))).Create; 
    try 
     Loutput.Position := 1 + Length(LclsName); 
     TGraphicAccess(Lgraphic).ReadData(Loutput); 

     img2 := TImage.Create(self); 
     img2.Parent := Self; 
     img2.Name := 'image2'; 
     img2.Left := 71; 
     img2.Top := 30; 
     img2.Width := 18; 
     img2.Height := 18; 
     img2.Picture.Assign(Lgraphic); 
    finally 
     Lgraphic.Free; 
    end; 
    finally 
    Loutput.Free; 
    end; 
end; 

initialization 
    // this is not necessary for TPicture's own DFM streaming, 
    // but it is necessary for manual streaming, unless you 
    // implement your own classname lookups... 
    // 
    RegisterClass(TMetafile); 
    RegisterClass(TIcon); 
    RegisterClass(TBitmap); 
    RegisterClass(TWICImage); 
    RegisterClass(TJpegImage); 
    RegisterClass(TGifImage); 
    RegisterClass(TPngImage); 
    // and so on... 
end. 
+0

+ !, Ich habe ein TImage mit einem Bitmap-Bild versehen, anschließend Picture.Data aus der DFM-Datei kopiert und es LInput als statische Zeichenfolge zugewiesen, aber es wurde ein Fehler angezeigt: "Das Bitmap-Bild ist nicht gültig". der String-Wert ist genau Picture.Data-Wert in DFM –

+1

@ G3ntle_Man: Mein schlechtes. Nach dem Erstellen des 'TGraphic'-Objekts muss der Code' TGraphic.ReadData() 'anstelle von' TGraphic.LoadFromStream() 'aufrufen. Für 'TBitmap' gibt es einen zusätzlichen Wert in den Stream-Daten (die BMP-Byte-Größe) nach dem Klassennamen und vor den eigentlichen BMP-Daten. TBitmap muss diesen Wert lesen, oder Sie erhalten den Fehler "nicht gültig". 'TPnngImage' hat keine zusätzlichen Daten, die Stream-Daten nach dem Klassennamen sind nur PNG-Daten, weshalb mein ursprünglicher Code vorher gut funktionierte. Ich habe den Code dafür jetzt behoben. –

1
procedure TForm1.FormCreate(Sender: TObject); 
const 
    CONST_SIGN = '0954506E67496D616765'; 
var 
    LString: String; 
    LStart: Integer; 
    LStringStream: TStringStream; 
    LMem: TMemoryStream; 
    R: TBytes; 
begin 
    LString := 
    '0954506E67496D61676589504E470D0A1A0A0000000D49484452000000100000' 
    + '001008060000001FF3FF610000000473424954080808087C0864880000000970' 
    + '485973000000750000007501E3C207650000001974455874536F667477617265' 
    + '007777772E696E6B73636170652E6F72679BEE3C1A000000EF4944415478DAAD' 
    + '923B0AC2401086B3D7100F6110B415FBD8AB60E323E62262632DF15158A8BDB6' 
    + '22D682E821C41B58C76F7003EB8A9A10073E36ECFCFB6766765514458E842258' 
    + '3A5083A2F38C136C6016C5422B94EC7336C7F7122A7081A3CE97A0000768A2BD' 
    + 'BD1968F6E0428068FD2250AACE32863354ED4AE4701726D0B00F5B262BE8A199' 
    + 'DA065BC893709D2F8189547045E7D906D2D79684FFC32064F1D0E5FE6E90B985' 
    + 'CC434C738DF2F7BB7995691E521F163A1FC4262AE15396AA7650D6FBD2862F26' 
    + 'EAC313B767A0741BE64DCD657E890C0C93500F3D8E616203C344CA6FEBAD5B2A' 
    + '03C364002D183D00658D8FCCCDEDEA100000000049454E44AE426082'; 

    { Find and rid signature } 

    LStart := Pos(CONST_SIGN, LString); 

    if LStart = 0 then 
    Exit; 

    Delete(LString, LStart, Length(CONST_SIGN)); 

    { Main } 

    LStringStream := TStringStream.Create(LString); 
    LMem := TMemoryStream.Create; 
    try 
    { Prepare out array } 
    SetLength(R, Length(LString) div SizeOf(Char)); 

    { Convert } 
    HexToBin(PWideChar(LString), R, Length(LString) div SizeOf(Char)); 

    { Copy array to stream } 
    LMem.WriteBuffer(R[0], Length(R)); 

    { Save stream with image as file } 
    LMem.SaveToFile('xxx.png'); 

    { Load image from file } 
    Image1.Picture.LoadFromFile('xxx.png'); 
    finally 
    LStringStream.Free; 
    LMem.Free; 
    end; 
end; 
+0

Das Problem mit dieser Antwort besteht darin, dass es spezifisch für die vom OP geposteten Daten ist und nicht für alle Bildkomponenten, die im DFM gespeichert sind. Sie haben ein bestimmtes Bild fest codiert. –

+0

@KenWhite ja, ich habe nur mehr richtigen Code für sein Beispiel zur Verfügung gestellt, die zeigen, dass es möglich ist, zu tun. über 'generic für alle im DFM gespeicherten Bildkomponenten' - das klingt nach anderer/nächster Frage. – Zam

+0

Die Frage stellt sich die Frage, wie * Textdaten in ein Bild * umgewandelt werden können, und sagt auch * zum Beispiel, diesen Text * (was bedeutet, dass es nur ein Beispiel für den * Typ von Text * ist). Deine Antwort sagt * für diesen genauen Text *. –