AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Bilder [mit/ohne Transparenz] in universelles Format bringen

Bilder [mit/ohne Transparenz] in universelles Format bringen

Offene Frage von "Jens01"
Ein Thema von berens · begonnen am 16. Aug 2016 · letzter Beitrag vom 17. Aug 2016
Antwort Antwort
Seite 1 von 3  1 23   
berens

Registriert seit: 3. Sep 2004
421 Beiträge
 
Delphi 2010 Professional
 
#1

Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 13:32
Hallo,
das ist ein indirekter Cross-Post zu https://delphigl.com/forum/viewtopic.php?f=10&t=11526 , bei dem ich das Problem nun von mehr von der "Delphi"-Seite als von der OpenGL-Seite angehen will.

Zusammenfassung:
Die Benutzer verwenden viele verschiedene Dateiformate (teilweise mit Transparenz), und die Graphiken sind viel manchmal zu groß für die Graphikkarte und sprengen den Arbeitsspeicher. Die Graphiken werden letztendlich als TglBitmap2D im Arbeitsspeicher gehalten und mit OpenGL dargestellt, müssen jedoch vorher verkleinert werden.

Problem:
Neben den vielfältigen Dateiformaten (JPG, BMP, PNG, TIF, ...) gibt es innerhalb dieser Dateiformate noch Unterschiedliche Einstellungen wie "PixelFormat" etc. Für die Zuweisung an TglBitmap2D fehlt mir das Hintergrundwissen 1) welche Dateiformate es alles gibt 2) welche Pixelformate es für die jeweiligen Dateiformate gibt 3) welche Besonderheiten zu beachten sind etc.

Genaugenommen sollte das eigentlich auch nicht mein Problem sein. Über TImage/TPicture kann ich ja alle verschiedenen Bild-Dateiformate korrekt laden und in einer VCL-Form mit TImage korrekt darstellen lassen. D.h. irgendwo sind ja die Pixeldaten für diese Graphik schon vorhanden.

Leider kann ich die Pixel des Bildes, das irgendwo in dem TPicture-gebilde abgespeichert ist, nicht 1:1 übernehmen (z.B. via ScanLine), da je nach Dateiformat und -codierung die Byte-Werte für Rot-Grün-Blau und Alpha (% Transparent 0-255, sofern vorhanden) in den unterschiedlichsten Reihenfolgen (RGB, BGR, RGBA ARGB, ABGR, ...) und Bitbreiten vorkommen, und ich somit auch wieder eine "Zuordnungstabelle" bräuchte, um je nach Situation die Bytes anders zu drehen...

Anmerkungen: Dass Texturen PowerOf2 sein müssen ist mir klar; mein Programm regelt das generell; es sollte nicht Thema dieses Threads sein.

Was ich brauche:
Ich brauche eine TImage/TPicture Kopie des originalen TImage/TPicture (nur halt verkleinert). Diese muss dann als Format noch lesbar sein, damit TglBitmap2D damit noch was anfangen kann.

Das habe ich bereits probiert:
-Google/DP/DelphiGL Suche: War leider nicht so erfolgreich: Meistens werden bei Programmen ja die Graphiken mitgeliefert (also die Texturen) und liegen in einem einheitlichen Format vor den Ansprüchen von OpenGL angemessen ist.

-TBitmap erzeugen und mit Draw/StretchDraw/StretchBlt zeichnen: Generell gute Idee. Wichtig zu Wissen, dass TBitmap <> dem Dateiformat .bmp ist, und somit auch generell in der Lage ist, die TransparenzInformationen zu "halten". Das Problem ist, dass TglBitmap2D mit 32-Bit Bitmaps nichts anfangen kann und die Textur verwirft (Fehler beim Laden vom Stream; falscher Header für Bitmap Format). D.h. ich muss alle Graphiken auf 24Bit reduzieren, und das würde also bedeuten, dass ich alle TransparenzInformationen verliere? Keine Option! Ich habe es mit AssignFromBitmap und LoadFromStream probiert.

-Selber Weg wie oben, nur das Bild auf ein TPNGImage zeichnen: Scheitert schon daran, dass ich kein "leeres" TPNGImage.CreateBlank erzeugen kann. Sowohl mit COLOR_RGB wie COLOR_RGBAlpha und Bittiefe 32, notfalls 24, jedesmal gibt es einen Fehler mit "Ungültige Werte". Wie kann ich ein leeres PNG-Bild erzeugen, dass die maximale Farbtiefe und Alpha-Informationen hat? Weil dann könnte ich drauf zeichnen und das Bild dann mit TglBitmap2D.LoadFromStream laden (TglBitmap2D unterstützt PNG).

-Ich habe auch diverse andere Sachen probiert, wie die Bilder umzuwandeln und als temporäre Datei auf Festplatte zu speichern und neu zu laden. Aber das bringt auch keine Besserung, wenn das Dateiformat (.bmp) wieder Beschränkungen mit der Farbtiefe hat oder spätestens beim Laden (pf32Bit) wieder inkompatibel zu TglBitmap2D wird. Auch PNG kann ich nicht zwischenspeichern, weil ich ja kein neues PNG als Objekt erzeugen kann...

Wie gehe ich da weiter vor?

Danke im Vorraus!
  Mit Zitat antworten Zitat
Benutzerbild von Neutral General
Neutral General

Registriert seit: 16. Jan 2004
Ort: Bendorf
5.163 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#2

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 13:43
Also erstmal würde ich kein TImage benutzen. Das ist nämlich (wenn du das im DelphiGL-Forum schon ansprichst) unprofessionell
Wenn der Benutzer ein Bild auswählt erzeuge anhand der Dateiendung ein Objekt der entsprechenden TGraphic-Klasse (TPNGImage, TBitmap, ...).
Schau dann ob, die jeweilige TGraphic-Klasse eine Möglichkeit bietet das Bild in der Größe zu ändern und danach gehst du wie bei deinem Versuch mit TPNGImage vor und speicherst das verkleinerte Bild in einem Stream und übergibst diesen dann an OpenGL.
Michael
"Programmers talk about software development on weekends, vacations, and over meals not because they lack imagination,
but because their imagination reveals worlds that others cannot see."
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#3

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 13:51
Zitat:
D.h. ich muss alle Graphiken auf 24Bit reduzieren, und das würde also bedeuten, dass ich alle TransparenzInformationen verliere?
Davon kannst du ausgehen keine 32Bit beim *.bmp dann ist die Transparenz futsch.
Das Problem ist du hast zwar viel geschrieben aber dein Anliegen kann ich jetzt nicht direkt ersehen.

Was möchtest du also?
Unabhängig vom Format!
Lade ein Bild und erstelle dann ein neues direkt aus dem Speicher.
Transparent oder was auch immer.

Ich hab da mal was in C# gemacht vielleicht hilft es dir ja.

Code:
  ///<summary>
  ///Graphics related funcs
  ///</summary>
  [SuppressUnmanagedCodeSecurity]
  public sealed class PicFromMem
  {

    private static bool GetImageFromBytes(byte[] data, out Image image)
    {
      try
      {
        using (var ms = new MemoryStream(data))
        {
          image = Image.FromStream(ms);
        }
      }
      catch (ArgumentException)
      {
        image = null;

        return false;
      }

      return true;
    }

    private static Image RemoveMetadata(byte[] data)
    {
      Image image;

      if (GetImageFromBytes(data, out image))
      {
        Bitmap bitmap = new Bitmap(image);

        using (var graphics = Graphics.FromImage(bitmap))
        {
          graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
          graphics.CompositingMode = CompositingMode.SourceCopy;
          graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

          graphics.DrawImage(image, 0, 0);
        }
        return image;
      }

      return null;
    }
    ///<summary>
    /// Get Image from Memory Pointer
    ///</summary>
    ///<returns>
    ///Image from Byte Array without MetaData
    ///</returns>
    public static Image GetImageFromMemPtr(IntPtr DataPtr, long Size)
    {
      byte[] bArray = new byte[Size];

      Marshal.Copy(DataPtr, bArray, 0, (int)Size);

      // Remove MetaData from File
      return RemoveMetadata(bArray);

    }
  }

gruss

Geändert von EWeiss (16. Aug 2016 um 14:27 Uhr)
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
421 Beiträge
 
Delphi 2010 Professional
 
#4

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 14:42
> Was möchtest du also?

Ich möchte wissen, ob es ein universelles Objekt (ala TBitmap) gibt, von dem aus ich eine Graphik in TglBitmap2D verwandeln kann.


Spätestens wenn ich TBitmap voll ausreize und auf 32-Bit gehe, geht das ganze ja schon wieder nicht. Von PNG _kann_ TglBitmap2D aber 32-Bit (incl. Alpha) übernehmen. Was gibt es also besseres als TBitmap?

TPicture hatte halt den angenehmen vorteil, dass ich mich als solches nicht um das Dateiformat kümmern brauche. Wenn das (auch zukünftige) Betriebssystem die Bilder laden kann ist gut, Bibliotheken für JPG und PNG ergänzen den Rest. Wenn ich nun wirklich für _jeden_ Dateityp eine eigene Ableitung von TGraphic berücksichtigen muss (sofern es einen gibt!), muss ich erst mal wissen welche das sind (Wo steht das?) und welche es alles gibt (BMP, JPG, PNG, TIF, PCX, GIF, ...). Dafür, dass TPicture schon Alles "von Haus aus" (mithilfe der Bibliotheken) kann, steigert das separate verarbeiten nach TGraphic unterschieden -meines Erachtens(!)- das die Fehleranfälligkeit, erhöht unnötig die Redundanz aber leider nicht die Sicherheit, da ja TglBitmap2D leider je nach Pixelformat etc. trotzdem nicht mit allen Varianten von TGraphic zurechtkommt. Deshalb würde ich gerne 100% sicher sein, dass die von mir aufbereitete Graphik _vor_ der übergabe an OpenGL/TglBitmap2D garantiert in einem Datei-/Pixel-/Graphikformat ist (auch mit RGB<-->BGR Problematik), was später problemlos von TglBitmap2D verarbeitet werden kann.

Gerne speichere ich es als TPNGImage zwischen, aber da kommt ja die Fehlermeldung. Das genau werde ich jetzt nochmal detaillierter und hier im Forum suchen, das Oben nur mal als Zwischenbericht.

Danke nochmal; für weitere Tips habe ich die Ohren offen.

Edit: Da unten ging dein Beitrag ja noch weiter mit Code, den schaue ich mir an. Danke.
  Mit Zitat antworten Zitat
Benutzerbild von bytecook
bytecook

Registriert seit: 6. Aug 2010
Ort: Dornbirn
143 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 14:50
Würde Graphics32 (www.graphics32.org in Kombination mit (gr32_png) einsetzen.

Aktuelle GR32 Version: https://github.com/graphics32/graphics32 (Support inkl. 10.1 Berlin)
Aktuelles Png Lib: https://sourceforge.net/projects/gr32pnglibrary/

Damit hast du mal die Basis, GR32 arbeitet per se mit 24 Bit Farbtiefe + 8 Bit Alphachannel.
Du kannst auch jederzeit einem TBitmap32 ein "normales" Bitmap zuordnen.

Gruß,

Peter
Peter

Geändert von bytecook (16. Aug 2016 um 14:59 Uhr)
  Mit Zitat antworten Zitat
EWeiss
(Gast)

n/a Beiträge
 
#6

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 15:01
Mein Code erfüllt doch deinen zweck..
Das Format was dabei im Speicher liegt ist unwichtig.
Wichtig ist nur das mit meinem Code ein PNG zurückgegeben wird in höchster Qualität.

Dieses kannst du dann auf deine Größe zurecht stutzen.

Du benötigst nur den Pointer auf die im Speicher liegende Datei und die länge.
Ich habe das teil mal für einen Tag Editor (Coverart) geschrieben da weißt du auch nicht welches Bildformat im Tag abgelegt ist.

gruss

Geändert von EWeiss (16. Aug 2016 um 15:04 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.549 Beiträge
 
Delphi 10.3 Rio
 
#7

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 15:19
Unter Windows könntest Du TWICImage verwenden. Das kennt alle gängigen Formate und bietet Methoden zum Ändern der Größe unter Beibehaltung der Transparenz. Es ist jedoch (vermutlich weil es OS-Methoden nicht gut kapselt) nicht sonderlich schnell, wie hier gezeigt wurde. Ein Beispiel wie ein Image verkleinert wird ist hier zu finden.

Sherlock
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
berens

Registriert seit: 3. Sep 2004
421 Beiträge
 
Delphi 2010 Professional
 
#8

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 15:39
Danke für die Beiträge.

Zuerst nochmal "sorry" @EWeiss, beim schreiben meiner ersten Antwort hatte ich Deinen Post nur bis "Was möchtest du also?" gesehen/gelesen und dachte ursprünglich mein erster Post wäre unklar.

Deinen Code habe ich mir angeschaut, weiß allerdings nicht so Recht, wie ich das auf Delphi übertragen soll bzw. was der Code macht. Von den Prozedurnamen her scheinst Du eine Datei zu laden, die Metadaten zu entfernen und die Datei wieder zu speichern. Den eigentlichen Transfer machst du mit DrawImage, und scheinst direkt auf eine TGraphic zu zeichnen (geht in Delphi nicht?), bzw. auf ein Bitmap (wieder Problem mit 32Bit/Alpha bzw. dem Pixelformat ansich). Dafür bin ich leider nicht gut genug in C drin, damit ich das auch nur gedanklich übertragen könnte, vll. kannst du nochmal 1-2 Kommentare zu den Zeilen machen, bitte?

Mein aktueller Lösungsweg sieht dank @bytecook so aus, dass ich den Umweg über TBitmap32 und TPortableNetworkGraphic32 gehe. Abgesehen von vielen, vielen Units die nun zusätzlich in meinem Projekt für eine Quelltextzeile mitverwendet werden müssen (jammern auf hohem Nivea ) kann ich nicht direkt von TBitmap32 in einen MemoryStream speichern, da das Format (logischerweise) anders ist als TBitmap, und somit TglBitmap2D das nicht laden kann. Also Umweg über PNG-Komponente, das geht generell, ABER: Trotz eines wirklich schnellen Rechners dauert png32.Assign bald über 10 Sekunden. Wenn der Benutzer also 10-20 Bilder einfügt, dauert das Starten vom Programm dann bald 2-3 Minuten, das kann ja dann wohl auch nicht sein.

Wo habe ich den Fehler, wie geht es anders?

@Sherlock: Ich befürchte, TPortableNetworkGraphic32 benutzt vielleicht auch WIC und ist deshalb so langsam?

Primär die Frage: Wie erzeuge ich ein leeres TPNGImage mit 32 Bit Farbtiefe incl. Alphakanal?

   png := TPngImage.CreateBlank(COLOR_RGBALPHA, 32, 2048, 1024); erzeugt:
Zitat:
---------------------------
Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt bla.exe ist eine Exception der Klasse EPNGInvalidSpec mit der Meldung '"Portable Network Graphics" konnte nicht erstellt werden, weil ungültige Bildtypparameter angegeben wurden.' aufgetreten.

Delphi-Quellcode:
uses
  ..., GR32, gr32_png;

var
  bmp32: TBitmap32;
  png32: TPortableNetworkGraphic32;
begin
   bmp32 := TBitmap32.Create;
   bmp32.Width := 2048; // zum testen
   bmp32.Height := 1024;
   bmp32.Canvas.Draw(0, 0, tmpImage.Picture.Graphic); // zum Testen auch keine Skalierung etc.

   png32 := TPortableNetworkGraphic32.Create;
   png32.Assign(bmp32);

   ms := TMemoryStream.Create;
   ms.Position := 0;
   png32.SaveToStream(ms);
// bmp32.SaveToStream(ms); // geht nicht, TglBitmap2D kann das dann nicht wieder einlesen
   ms.Position := 0;
   LoadFromStream(ms);
   FreeAndNil(ms);

   GenTexture(True); // geladene Textur an OpenGL übergeben

   FreeAndNil(png32);
   FreeAndNil(bmp32);
Edit:
Ich habe es nun mit WIC versucht, und es geht einfach und schnell:

Delphi-Quellcode:
var
  wic: TWICImage;
begin
ms := TMemoryStream.Create;
ms.Position := 0;
wic := TWICImage.Create;
wic.LoadFromFile(_Filename);
wic.ImageFormat := wifPng;
wic.SaveToStream(ms);
ms.Position := 0;
   LoadFromStream(ms);
   FreeAndNil(ms);

   GenTexture(True); // geladene Textur an OpenGL übergeben
Aktuell kann ich nun sowohl meine .png wie auch .bmp-Datei korrekt laden. Es ist halt nur die Frage, wie ich das nun noch ohne AlphaVerlust skaliere. Der Link zum verkleinern von TWicImage erfordert das IWICBitmapScaler aus der windowscodec.dll. Gibt es bei Delphi 2010 standardmäßig nicht. Muss ich gleich mal schauen, wie ich das Bild klein bekomme...

Geändert von berens (16. Aug 2016 um 15:54 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von bytecook
bytecook

Registriert seit: 6. Aug 2010
Ort: Dornbirn
143 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#9

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 15:59
Danke für die Beiträge.

Delphi-Quellcode:
uses
  ..., GR32, gr32_png;

var
  bmp32: TBitmap32;
  png32: TPortableNetworkGraphic32;
begin
   bmp32 := TBitmap32.Create;
   bmp32.Width := 2048; // zum testen
   bmp32.Height := 1024;
   bmp32.Canvas.Draw(0, 0, tmpImage.Picture.Graphic); // zum Testen auch keine Skalierung etc.

   png32 := TPortableNetworkGraphic32.Create;
   png32.Assign(bmp32);

   ms := TMemoryStream.Create;
   ms.Position := 0;
   png32.SaveToStream(ms);
// bmp32.SaveToStream(ms); // geht nicht, TglBitmap2D kann das dann nicht wieder einlesen
   ms.Position := 0;
   LoadFromStream(ms);
   FreeAndNil(ms);

   GenTexture(True); // geladene Textur an OpenGL übergeben

   FreeAndNil(png32);
   FreeAndNil(bmp32);

Delphi-Quellcode:

uses
     ...
     Gr32,
     GR32_Png,
     GR32_PortableNetworkGraphic;

...

  (** PNG - Routinen **)
  function SaveAsPng (Const FileName : String; ABmp : TBitmap32) : Boolean;
  function LoadPng (Const FileName : String; ABmp : TBitmap32) : Boolean;


(******************************************************************************)

(** PNG - Routinen - QnD                                                     **)

(******************************************************************************)

function SaveAsPng (Const FileName : String; ABmp : TBitmap32) : Boolean;

  var APng : TPortableNetworkGraphic32;

  begin
    try
      APng := TPortableNetworkGraphic32.Create;
      APng.Assign(ABmp);
      APng.SaveToFile(FileName);
      Result := True;
    except
      Result := False;
    end;
    APng.Free;
  end;
(******************************************************************************)
function LoadPng (Const FileName : String; ABmp : TBitmap32) : Boolean;

  var APng : TPortableNetworkGraphic32;

  begin
    try
      APng := TPortableNetworkGraphic32.Create;
      APng.LoadFromFile(FileName);
      APng.AssignTo(ABmp);
      Result := True;
    except
      Result := False;
    end;
    APng.Free;
  end;
(******************************************************************************)


procedure TForm1.LadePng

  var ABmp : TBitmap32;

  begin
    ABmp := TBitmap.Create();
    LoadPng ('Bart.png', ABmp);

    ... tuwas ...

    FreeAndNil(ABmp);

  end;

So sollte es klappen. TPortableNetworkGraphic32 funktioniert nativ, ohne DirectX ...
Peter
  Mit Zitat antworten Zitat
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.549 Beiträge
 
Delphi 10.3 Rio
 
#10

AW: Bilder [mit/ohne Transparenz] in universelles Format bringen

  Alt 16. Aug 2016, 16:01
Also sooo langsam ist ein TWICImage dann doch nicht. Ein LoadFromFile dauert weniger als eine Sekunde...natürlich hängt es etwas von der Dateigröße und dem Speicherort ab.

Sherlock
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 +2. Es ist jetzt 04:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf