Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   httpCLI: Download PNG funktioniert nicht, JPG geht (https://www.delphipraxis.net/200295-httpcli-download-png-funktioniert-nicht-jpg-geht.html)

Siggi 6. Apr 2019 21:12

httpCLI: Download PNG funktioniert nicht, JPG geht
 
Hallo zusammen,

ich nutze schon länger einen einfache Code, der mir ein JPG holt und in eine TJPegImage mit LoadFromStream einfügt.
Jetzt gibt es aber auch PNG-Bilder und das Einfügen in ein TPNGObject geht nicht. Die heruntergeladene Grafik ist definitiv eine PNG. Ich habe das gleiche mal mit Indy (IdHttp) getestet, da geht es. Ich muss im dieser Applikation aber die httpCLI-Komponente von Overbyte verwenden, daher ist die einfachste Lösung (verwende Indy) leider nicht möglich :(.

Zusammenfassend:
- mit Indy kann ich JPG und PNG herunterladen und den geladenen MemoryStream mit LoadFromStream in einem TJPEGImage bzw. einem TPNGObject einfügen :-D.
- mit httpCLI kann ich das nur mit einem JPG, beim selben PNG das mit Indy funktioniert, wird mir im Code mit httpCLI ein ungültiger Header gemeldet :?.

Hier der Code mit httpCLI: (einige unnötige Zeilen (Protokollierung) rausgeworfen, so ist es übersichtlicher.)

Delphi-Quellcode:
Procedure GetPicture(ImageURL:String; var image:TJPEGImage);
Var
  Data:       TMemoryStream;
  png:        TPNGObject;
  tbmp:       TBitMap;
  SslHttpCli1: TSslHttpCli;
  SslContext1: TSslContext;
begin
  if (ImageURL>'') then
  begin
    Data := TMemoryStream.Create;
    try
      SslHttpCli1                     := TSslHttpCli.Create(nil);
      SslContext1                     := TSslContext.Create(nil);
      SslContext1.SslCipherList      := 'ALL:!ADH:RC4+RSA:+SSLv2:@STRENGTH';
      SslContext1.SslECDHMethod      := sslECDHNone;
      SslContext1.SslVerifyPeerModes := [SslVerifyMode_PEER];
      SslContext1.SslVersionMethod   := sslBestVer;
      SslHttpCli1.SslContext         := SslContext1;
      SslHttpCli1.URL                := ImageURL;
      SslHttpCli1.RcvdStream         := Data;
      try
        SslHttpCli1.Get;
        Data.Position := 0; //stream-position auf 0 setzen
        if TypeToStr(GetImageType(Data)) ='Image/JPEG' then
          Image.LoadFromStream(Data) // <--- das funktioniert !!!
        else if TypeToStr(GetImageType(Data)) ='Image/PNG' then
        begin
          png := TPNGObject.Create;
          tbmp:=TBitMap.Create;
          try
            png.LoadFromStream(Data); // <--- das funktioniert nicht, Fehlermeldung wegen ungültigem Header, selbe URL mit idHTTP (Indy) funktioniert.
            tbmp.Assign(png);
            image.Assign(tbmp);
          finally
            tbmp.Free;
            png.Free;
          end;
        end
        else
          showMessage('unbekannter Grafiktyp');
      except
        on E: Exception do
        begin
          MessageDlg(E.Message, mtWarning, [mbOK], 0);
        end;
      end;
    finally
      Data.Free;
      SslHttpCli1.Free;
      SslContext1.Free;
    end;
  end;
end;
Zum Vergleich der Code mit Indy, da geht's:
Delphi-Quellcode:
Procedure GetPicture(ImageURL:String; var image:TJPEGImage);
var
  MS: TMemoryStream;
  idHttp1:TIdHttp;
  sslIOHandler : TIdSSLIOHandlerSocketOpenSSL;
  png: TPNGObject;
  tbmp: TBitMap;
begin
  // Bild laden
  if ImageURL <> '' then
  begin
    MS := TMemoryStream.Create;
    IdHttp1 := TIdHTTP.Create(nil);
    if (AnsiUpperCase(copy(ImageURL, 1, 5)) = 'HTTPS') then
    begin
      sslIOHandler := frmInternetLookup.IdSSLIOHandlerSocketOpenSSL1; //TIdSSLIOHandlerSocketOpenSSL.Create(nil);
      sslIOHandler.PassThrough:=true;
      sslIOHandler.OnStatusInfo := frmInternetLookup.IdSSLIOHandlerSocketOpenSSL1.OnStatusInfo;
      IdHttp1.IOHandler := sslIOHandler;
    end;
    SetProxyData(IdHttp1);

    try
      IdHttp1.Get(ImageURL, MS);
      MS.Position := 0;
      if IdHTTP1.Response.ContentType = 'image/jpeg' then
        Image.LoadFromStream(MS) // <--- hier funktioniert sowohl das...
      else if IdHTTP1.Response.ContentType = 'image/png' then
      begin
        png := TPNGObject.Create;
        tbmp := TBitmap.Create;
        try
          png.LoadFromStream(MS);  // <--- und das geht hier auch, nur bei httpCLI nicht...
          tbmp.Assign(png);
          image.Assign(tbmp);
        finally
          tbmp.Free;
          png.Free;
        end;
      end;
    except
      // entfernt
    end;
    MS.Free;
  end;
end;
Hat jemand einen Tipp für mich, wo ich ansetzen kann, um die Ursache zu finden?

.. Ergänzung: das Image liegt unter http://books.google.com/books/conten...source=gbs_api

Danke und Gruß,
Siggi

Delphi.Narium 6. Apr 2019 21:29

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
Was macht GetImageType? Wird dadrin eventuell die Position im Stream verändert?

Dann eventuell
Delphi-Quellcode:
         try
            ///////////////
            Data.Position := 0; // <-- an den Anfang des Streams gehen.
            ///////////////
            png.LoadFromStream(Data); // <--- das funktioniert nicht, Fehlermeldung wegen ungültigem Header, selbe URL mit idHTTP (Indy) funktioniert.
Ansonsten testweise:
Delphi-Quellcode:
Data.SaveToFile('xxx.png');
png.LoadFromFile('xxx.png');
Geht das?
Wenn nein, mit 'nem anderen Programm prüfen, ob der Stream eine vernünftige PNG-Datei enthält.

Siggi 6. Apr 2019 22:14

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
hmmm, saveToFile / LoadFromFile geht. Dann sollte der selbe Stream ohne "Zwischenspeichern" aber doch auch gleich funktionieren :?: :? :roll:.
Rätselhaft, aber so habe ich zumindest einen Workaround.
Delphi-Quellcode:
          Data.SaveToFile(getTempDir+'\Image.png');
          png.LoadFromFile(getTempDir+'\Image.png');
erst mal danke, mal sehen ob ich noch rausfinde, warum das nicht auch ohne Umweg über die Datei geht.

Gruß,
Siggi

Delphi.Narium 6. Apr 2019 22:40

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
Setz' bitte mal 'nen Breakpoint vor
Delphi-Quellcode:
png.LoadFromStream(Data)
und debugge Dich da rein. Die ersten acht Byte des Streams müssten
Delphi-Quellcode:
#137 #80 #78 #71 #13 #10 #26 #10
bzw.
Delphi-Quellcode:
$89 $50 $E4 $47 $0D $0A $1A $0A
sein oder die ersten vier als ASCII
Delphi-Quellcode:
‰PNG
und Position von Data muss 0 sein.

Siggi 7. Apr 2019 12:00

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
sowohl der MemoryStream aus IdHTTP (Indy) als auch aus httpCLI (Overbyte) fangen so an:

Zitat:

89504E470D0A1A0A0000000D4948445200000080000000C208 020000000ECC5DFB0000000373424954080808DBE14FE00000
Auch ein kompletter Vergleich der Byte-weise in Hex-Strings umgewandelten Streams aus IDHTTP und httpCLI in Notepad++ ergab keine Unterschiede.

Ich suche nicht weiter und mache das jetzt unschön aber funktionierend so:
Delphi-Quellcode:
          try
            png.LoadFromStream(Data);
          except  // wenn es nicht geht -> Umweg über Datei
            Data.SaveToFile(getTempDir+'\Image.png');
            png.LoadFromFile(getTempDir+'\Image.png');
          end;
und das steckt nochmals in einem try..except..end für den Fall, dass auch das schief geht und zumindest eine verständliche Fehlermeldung und ein Logeintrag erfolgen.

Viele Grüße,
Siggi

TurboMagic 7. Apr 2019 21:17

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
Es gibt im englischen Teil der DP jetzt auch ein ICS Forum!
Vielleicht mal da nachfragen?

Michael II 8. Apr 2019 19:24

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
So lädst du ein PNG in einen Stream und von dort direkt in ein TPngImage.

TImage, THttpCli, TButton auf Form ziehen, uses mit pngimage ergänzen.

Delphi-Quellcode:

uses &#8230;. pngimage;

function TForm80.getpngimage( quelle : string; png : TPngImage ):boolean;
var tm : TMemoryStream;
begin
  tm := TMemoryStream.Create;
 try
  httpcli1.RcvdStream := tm;
  httpcli1.URL := quelle;
  httpCli1.Get;
  tm.Position := 0;
  png.LoadFromStream( tm );
 finally
  tm.free;
 end;
end;

Aufruf:

Delphi-Quellcode:
 

procedure TForm80.Button1Click(Sender: TObject);
var quelle : string;
    hpng : TPngImage;
begin
  quelle := 'http://pngimg.com/uploads/olives/olives_PNG14287.png';
  hpng := TPngImage.Create;
 try
  getpngimage( quelle, hpng );
  image1.Picture.Assign( hpng );
 finally
  hpng.Free;
 end;
end;
Ich habe gerade gemerkt, dass den Funktionen noch kein Result zugewiesen wird ;-). Sollte man noch tun.

Natürlich solltest du den Code erweitern - ist nur eine kurze Demo, welche funktioniert.
[Wenn du eine Anwendung schreibst, welche immer wieder die gleichen URLs auf neue Version abfragt, dann lohnt es sich die Bilder (etc.) zu "cachen". Beim Abrufen der Daten vom Server kannst du dann via HeaderData prüfen, ob die Datei bereits lokal vorhanden ist und falls Ja, den Download abbrechen.


Und wenn du Datei speichern willst:

Delphi-Quellcode:
function TForm80.geturl( quelle, ziel : string ):boolean;
var tf : TFileStream;
begin
  tf := TFileStream.Create( ziel, fmCreate or fmOpenWrite );
 try
  httpcli1.RcvdStream := tf;
  httpcli1.URL := quelle;
  httpCli1.Get;
 finally
  tf.free;
 end;
end;

Rolf Frei 9. Apr 2019 11:47

AW: httpCLI: Download PNG funktioniert nicht, JPG geht
 
Ich habe auch die Vermutung, dass GetImageType etwas am Position des Streams verändert. Daher mache anstatt den 2 GetImageType Aufrufen nur einen wie folgt:

Code:
       
s := TypeToStr(GetImageType(Data));      
if s = 'Image/JPEG' then
  Image.LoadFromStream(Data) // <--- das funktioniert !!!
else if s = 'Image/PNG' then
...


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:00 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