AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben
Thema durchsuchen
Ansicht
Themen-Optionen

Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

Ein Thema von Benmik · begonnen am 4. Jan 2016 · letzter Beitrag vom 11. Jan 2016
Antwort Antwort
Benutzerbild von uligerhardt
uligerhardt

Registriert seit: 19. Aug 2004
Ort: Hof/Saale
1.735 Beiträge
 
Delphi 2007 Professional
 
#1

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 08:36
Delphi-Quellcode:
      lBitmap := TBitmap.Create;
      try
        // ...
        lBitmap := nil;
      finally
        lBitmap.Free;
      end;
Das gibt ein Memory leak, wenn ich mich nicht sehr irre.
Nur, wenn die ObjectList, der direkt vor der nil-Zuweisung die Bitmap-Instanz zugefügt wird, diese nicht frei gibt.
Dann halt so: lBitmap := nil gefolgt von lBitmap.Free ist sinnfrei.

Edit: Ah, jetzt hab ich's kapiert. Im Falle einer Exception greift das Free ja noch.
Uli Gerhardt
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#2

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 09:25
Irgendwie entzieht sich mir der Sinn des Ganzen. Wenn ich doch bereits eine generische TObjectList habe, wieso verwendet man dann nicht einfach die Methoden, die das Objekt bereitstellt oder ergänzt das Objekt um eben diese Methoden? Wenn ich z.B. ein Objekt erstelle, das sagen wir mal ein TImage und ein TLabel enthält, dann sieht das z.B. so aus:
Delphi-Quellcode:
UNIT Bilder;
INTERFACE
USES
  Classes, ExtCtrls, StdCtrls, Graphics, Controls;

TYPE
  TBild = CLASS

    PRIVATE { Private-Deklarationen }
      Var
        fBild : TImage;
        fTitel : TLabel;
      Function GetfBild : TImage;
      Procedure SetfBild(Const Value : TImage);
      Function GetfTitel : TLabel;
      Procedure SetfTitel(Const Value : TLabel);

    PUBLIC { Public-Deklarationen  }
      Constructor Create();
      Destructor Destroy; override;
      Property Bild : TImage read GetfBild write SetfBild;
      Property Titel : TLabel read GetfTitel write SetfTitel;
  END;

IMPLEMENTATION
{ TBild }

Function TBild.GetfBild: TImage;
begin
  Result := fBild;
end;

Procedure TBild.SetfBild(Const Value: TImage);
begin
  fBild.Assign(Value);
end;

Function TBild.GetfTitel: TLabel;
begin
  Result := fTitel;
end;

Procedure TBild.SetfTitel(Const Value: TLabel);
begin
  fTitel.Assign(Value);
end;

Constructor TBild.Create;
begin
  inherited;

  fBild := TImage.Create(nil);
  fBild.Visible := False;
  fBild.AutoSize := False;
  fBild.Stretch := True;
  fBild.Proportional := True;
  fBild.Center := True;

  fBild.Picture.Bitmap.Canvas.Brush.Style := bsClear;
  fBild.Picture.Bitmap.Canvas.Pen.Color := clRed;
  fBild.Picture.Bitmap.Canvas.Pen.Style := psSolid;
  fBild.Picture.Bitmap.Canvas.Pen.Width := 5;

  fTitel := TLabel.Create(nil);
  fTitel.AutoSize := False;
  fTitel.Alignment := taCenter;
  fTitel.Layout := tlCenter;
  fTitel.WordWrap := False;
  fTitel.Visible := False;
end;

Destructor TBild.Destroy;
begin
  If Assigned(fBild) Then
     fBild.Free;
  If Assigned(fTitel) Then
     fTitel.Free;

  inherited;
end;
end.
So, jetzt brauche ich eine Methode, die das Bild speichert. Also ergänze ich das Objekt um die benötigte Methode. Wäre in diesem Fall, da ich bereits ein TImage verwende, nicht notwendig, da TImage (z.B. in TBitmap oder TPicture) bereits mehrere Methoden zum Speichern bereitstellt.

Wieso muß ich da umständlich ermitteln, wo das Bild im Speicher liegt, wo es beginnt und wo es aufhört, wenn ich das Ganze doch sowieso in einer TObjectList verwalte?
Delphi-Quellcode:
...
USES
  Windows, Messages, ..., Bilder, Generics.Collections, ...;
...

  PRIVATE { Private-Deklarationen }
    Var
      BList : Generics.Collections.TObjectList<TBild>;
Wozu dann überhaupt die TObjectList? Die TObjectList weiß doch genau, wo ihre Objekte liegen, darum muß mich doch gar nicht mehr kümmern. Ich greife einfach über den Index auf das jeweilige Objekt zu:
Delphi-Quellcode:
Procedure TFormMain.SaveBitmapFromList(Const Id : Integer; Const Datei : String);
begin
  BList[Id].Bild.Picture.Bitmap.SaveToFile(Datei);
end;
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
961 Beiträge
 
Delphi 6 Professional
 
#3

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 13:27
Hmm..

Anscheinend wird bei dem Bitmap, welches per ExtractThumbnail geholt wird etwas bei SaveToStream anders gemacht, wie bei Draw..

Wenn Du zunächst das Thumbnail mit einem 2. Bitmap holts und es dann auf dein eigentliches Bitmap malst (.Draw) dann gehts..

Delphi-Quellcode:
  
// Thumbnail aus JPG-Datei
  Bmp := TBitmap.Create;
  Bmp2:= TBitmap.Create;
  try
    ExtractThumbnail(Bmp2,Verz + JPGDatei,400,0);
    // Auf Form zeichnen
    Self.Canvas.Draw(450,10,Bmp2);

    Bmp.Assign(bmp2);
    Bmp.Canvas.Draw(0,0,bmp);

  ..

  finally
    Bmp2.Free;
    Bmp.Free;
  end;
So ist dann das Bitmap in bmp mit der korrekten Orientierung.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.051 Beiträge
 
Delphi 12 Athens
 
#4

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 14:47
Hmm..

Anscheinend wird bei dem Bitmap, welches per ExtractThumbnail geholt wird etwas bei SaveToStream anders gemacht, wie bei Draw..
Wie schon erwähnt, hat das nichts mit dem SaveToStream zu tun. Ein simples bmp.Dormant , was lediglich ein neues GDI-Objekt forciert, zeigt schon den Fehler. Vielleicht hat man den verlinkten Bug in der Implementation des IExtractImage Interfaces nicht mit gefixt.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
HolgerX

Registriert seit: 10. Apr 2006
Ort: Leverkusen
961 Beiträge
 
Delphi 6 Professional
 
#5

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 18:51
Hmm..

Anscheinend wird bei dem Bitmap, welches per ExtractThumbnail geholt wird etwas bei SaveToStream anders gemacht, wie bei Draw..
Wie schon erwähnt, hat das nichts mit dem SaveToStream zu tun. Ein simples bmp.Dormant , was lediglich ein neues GDI-Objekt forciert, zeigt schon den Fehler. Vielleicht hat man den verlinkten Bug in der Implementation des IExtractImage Interfaces nicht mit gefixt.
Schon klar, mir ging es nur um einen Workarround, damit der TE seine Bitmaps speichern kann, ohne dass Sie gedreht werden..
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
547 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 7. Jan 2016, 20:25
Danke an euch alle. Ich bin natürlich froh, dass ich jetzt nicht als Depp dastehe.

Die Lösung von HolgerX ist ziemlich schräg, funktioniert aber (und warum?).
Das doppelte Zeichnen ist unter Umständen verschmerzbar, weil ja nur die sichtbaren Vorschaubilder gezeichnet werden, das ist überschaubar.

Übrigens war es bei mir so, dass nicht immer alle Bilder auf dem Kopf standen, sondern nur die Hochkantbilder, während die querkantigen richtig herum waren. Ich werde mal sehen, ob HolgerX' Lösung auch hier wirkt.

@Perlsau: Danke für deine Mühe. Ich möchte natürlich alle Bilder in einer einzigen Datei speichern. Das könnte ich natürlich auch in die Klasse der Objectlist integrieren. Der direkte Speicherzugriff war ja doch nur wegen der Rotationsproblematik.

Geändert von Benmik ( 7. Jan 2016 um 20:31 Uhr)
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
547 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Objekte einer TObjectList direkt aus dem Speicher lesen / in ihn schreiben

  Alt 8. Jan 2016, 20:51
Die Implementierung von HolgerX' Idee hat nicht funktioniert und sie war mir ohnehin nicht so geheuer, weil ich nicht nachvollziehen konnte, warum sie überhaupt manchmal funktioniert.

Ich bin jetzt den Weg gegangen, einfach biHeight manuell negativ zu setzen, denn die Bitmap muss doch gar nicht gedreht, sondern es müssen nur die Scanlines in anderer Richtung ausgelesen werden. Das funktioniert prima. Dabei bin auch auch gleich Perlsaus Rat gefolgt, die Funktion in die Klasse zu verlegen.
Wird hier noch Verbesserungspotenzial gesehen (bis auf die Sünde, Umlaute zu verwenden)? Dieses doppelte "Free" zum Beispiel stört mich immer.

Zur Erläuterung der PosBiHeight: Die Größe des FileHeaders ist immer fix bei 14 Bytes. Beim nachfolgenden DIB header gibt es 7 Größen, aber alle fangen mit 3 x 4 Byte an. Die hartkodierte numerische Angabe erscheint mir sicherer als so etwas wie SizeOf(BitmapFileHeader) + SizeOf(InfoHeader.biSize) + SizeOf(InfoHeader.biWidth).
Delphi-Quellcode:
function TBilderListe.LeseVSBAusDatei(Dateiname: string): Boolean;
var BildNr,AnzDS:integer; Stream,VSBStream:TMemoryStream; VSBBmp:TBitMap; VSBHöhe:integer;
const PosBiHeight = 14 + 4 + 4;
begin
  Result := False;
  If not FileExists(Dateiname)
    then exit;
  Stream := TMemoryStream.Create;
  Try
    Stream.LoadFromFile(Dateiname);
  Except
    Stream.Free;
    exit;
  End;
  Stream.Position := 0;
  Stream.ReadData(AnzDS);
  If AnzDS <> BilderListe.Count
    then exit;
  VSBStream := TMemoryStream.Create;
  Try
    For BildNr := 0 to AnzDS - 1 do begin
      VSBBmp := TBitMap.Create;
      VSBBmp.LoadFromStream(Stream);
      VSBStream.Clear;
      VSBBmp.SaveToStream(VSBStream);
      VSBStream.Position := PosBiHeight;
      VSBStream.ReadData(VSBHöhe,SizeOf(VSBHöhe));
      VSBStream.Position := PosBiHeight;
      VSBStream.WriteData(-Abs(VSBHöhe));
      VSBStream.Position := 0;
      VSBBmp.LoadFromStream(VSBStream);
      Self[BildNr].VSB := VSBBmp;
    end;
    Stream.Free;
    VSBStream.Free;
  Except
    Stream.Free;
    VSBStream.Free;
    exit;
  End;
  Result := True;
end;
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:54 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz