AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language GetJPGSize Funktion (wollen wir sie verbessern?)
Thema durchsuchen
Ansicht
Themen-Optionen

GetJPGSize Funktion (wollen wir sie verbessern?)

Ein Thema von MicMic · begonnen am 7. Feb 2020 · letzter Beitrag vom 10. Mär 2020
Antwort Antwort
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#1

AW: GetJPGSize Funktion (wollen wir sie verbessern?)

  Alt 15. Feb 2020, 23:00
Ich bekomme noch die Kriese.
Dieser Wert "Abtastfaktor" hat gar nichts mit dem Format zu tun.
Ich las "vertikal/horizontal" und dachte...

Ich habe jedenfalls ein Bild im Hochformat aufgenommen, dass hier leider Breite/Höhe vertauscht. ExifTool gibt an (beim Orientation-Flag): Rotate 270 CW. Jetzt muss man wohl noch EXIF-Daten auslesen. Wobei es nicht immer EXIF-Daten gibt aber hier (ohne EXIF Daten bei Hochformat) vertauscht Windows selbst die Werte.
  Mit Zitat antworten Zitat
HolgerX

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

AW: GetJPGSize Funktion (wollen wir sie verbessern?)

  Alt 16. Feb 2020, 05:36
Hm..

Das ist halt die Krux, wenn Kamera Hersteller meinen es 'besser' machen zu wollen...
Die Höhle und Breite werden dann getauscht, wenn mit der Kamera um 90/270 Grad gedrehtes Bild gemacht wird.
Diese Drehung steht dann nur in den EXIF informationen, diese könnten jedoch mal entfernt werden, womit diese Angaben weg sind.

Nur mit Programmen, welche auch die EXIF (Segment $FFE1 = APP1) auslesen und interpretieren, können das erkennen.
Diese EXIF Daten können Binär oder XML sein.. Viel Spaß wenn Du diese selber auslesen willst ohne entsprechende Komponenten.

Ein Thumbnail kann entweder im $FFE0 = APP0 sein, wenn dies den Identifier "JFIF" hat.
Alternativ auch in den zusätzlichen JFIF extension APP0 mit einem anderen APP0 Identifier "JFXX".
Oder ich glaube auch in den EXIF Daten..
Ach ja, jeweils in anderem Bild-Format..


Wenn Du all diese Information haben möchtest (Größe/Drehung/Thumb..) dann kannst Du deine Funktion vergessen und musst, wie in meinem Beispiel, Segmentbasierend arbeiten. Bei meinem Source brauche ich nur im Case die weiteren Kinds hinzufügen und dann mit Casten die Daten per vorher definierten Records sauber auslesen. Nur so behältst Du die Übersicht in deinem Source.
(Ja ich Verwende Delphi 6 Pro und will NICHT wechseln!)
  Mit Zitat antworten Zitat
MicMic

Registriert seit: 26. Mai 2018
296 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#3

AW: GetJPGSize Funktion (wollen wir sie verbessern?)

  Alt 19. Feb 2020, 17:57
Ne, auf EXIF habe ich erst mal keine Lust
Der Fokus lag jetzt auf die Bildgröße und das verstehen des JPG-Headers. Zwar ein wenig blöd, wenn evtl. bei manchen Dateien die Breite/Höhe vertauscht ist aber das schieb ich mal nach hinten und kümmere mich um andere Codezeilen.
Also mal Danke an alle. Ich habe ein wenig dazugelernt.

Mike
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.691 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: GetJPGSize Funktion (wollen wir sie verbessern?)

  Alt 10. Mär 2020, 06:51
Lang hat's gedauert, da ich pers. Jpeg absolut nicht mag.
Hier ist mein Versuch was schnelles draus zu basteln, keine Benchmarks durchgeführt, selbst ist der Mann/die Frau

Hier meine herangehensweise, in der Hoffnung das es tatsächlich hilft:
Ps: Übergeben werden muss ein gültiger kompletter Pfad.
(MyGetFiles holt aus dem Verzeichniss nur die Dateinamen ab)
Delphi-Quellcode:
procedure TfrmMain.ComputeData(const input: String);
type
  TJpgInfo = record
    IsJpeg: Boolean;
    Version : String;
    Dimension : String;
    Mode: String;
  end;
  function BytesToWord(HiByte, LoByte: Byte): Word;
    type
      TWord = record
        case integer of
          0 : (Both : Word);
          1 : (Lo, Hi : Byte);
      end;
    var
      Long : TWord;
  begin
    with Long do
      begin
        Hi := HiByte;
        Lo := LoByte;
        Result := Both;
      end;
  end; // BytesToWord
  function GetJpgInfo(const FS: TFileStream): TJpgInfo;
    var
      Buf: TBytes;
      i: Integer;
      checker: Boolean;
      LastPos: Integer;
      S: String;
      MaxCache: Int64;
  begin
    MaxCache := (20 * 1024); // ggf anpassen für noch dickere header...
    checker := True;
    Result.IsJpeg := False;
    LastPos := 0;
    FS.Position := LastPos;
    if (FS.Size >= MaxCache) then
      SetLength(Buf, MaxCache)
    else
      SetLength(Buf, FS.Size);
    FS.Read(Pointer(Buf)^, Length(Buf)); // daten puffern um es flott im RAM dynamisch auswerten zu können
                                         // dyn = wenn signaturen nicht direkt bei position 0 anfangen
                                         // Jpeg's mit exif header zBsp
    if checker then // Signatur Check
      begin
        checker := False;
        for I := Low(Buf) to High(Buf) do
          begin
            if i + 3 < High(Buf) then
              if ((Buf[I] = $ff) and (Buf[I+1] = $d8) and (Buf[I+2] = $ff) and (Buf[I+3] = $e0)) then
                begin
                  checker := True;
                  LastPos := i + 3;
                  Break;
                end;
          end;
      end;
    if checker then // prüfe ob JFIF vorhanden ist, erst ab hier akzeptiere ich es als Jpeg Datei
      begin
        checker := False;
        for I := LastPos to High(Buf) do
          begin
              if i + 3 < High(Buf) then
              if ((Buf[I] = $4a) and (Buf[I+1] = $46) and (Buf[I+2] = $49) and (Buf[I+3] = $46)) then
                begin
                  checker := True;
                  Result.IsJpeg := True;
                  // Application.MessageBox(PChar('gefunden'), PChar('gefunden'), MB_OK);
                  LastPos := i + 3;
                  Break;
                end;
          end;
      end;
    if Result.IsJpeg then // hole Version
      begin
        if LastPos + 3 < High(Buf) then
          begin
            if Buf[LastPos+3] < 10 then
              Result.Version := IntToStr(Buf[LastPos+2]) + '.' + '0' + IntToStr(Buf[LastPos+3])
            else
              Result.Version := IntToStr(Buf[LastPos+2]) + '.' + IntToStr(Buf[LastPos+3]);
            LastPos := LastPos + 3;
          end;
      end;
    if Result.IsJpeg then // hole Dimension und Farbmodus vom letzten C0 segment was sich hoffentlich im MaxCache bereich befindet...
                          // da diese operation den kompletten puffer betrifft
                          // kann man hier bestimmt noch mehr speed rausholen
      begin
        checker := False;
        for I := LastPos to High(Buf) do
          begin
            if i + 1 < High(Buf) then
              if ((Buf[I] = $ff) and (Buf[I+1] = $c0)) then
                begin
                  checker := True;
                  LastPos := i;
                end;
          end;
        if checker then
          if LastPos + 10 < High(Buf) then
            begin
              Result.Dimension := IntToStr(BytesToWord(Buf[LastPos + 7], Buf[LastPos + 8])) + ' x ' + IntToStr(BytesToWord(Buf[LastPos + 5], Buf[LastPos + 6]));
              case Buf[LastPos + 9] of
                $1: Result.Mode := 'Grey';
                $3: Result.Mode := 'YCbCr';
                $4: Result.Mode := 'CMYK';
              end;
            end;
      end;
  end; // GetJpgInfo
var
  FileList: TStringDynArray;
  lvItem: TListItem;
  i: Integer;
  fs: TFileStream;
  JpgInfo: TJpgInfo;
begin
  lvFolder.Clear;
  if Length(input) <= 3 then Exit;
  edtFolder.Text := input;
  FileList := MyGetFiles(input, '*.jpg;*.jpeg;*.jpe;*.jfif', False);
  if Length(FileList) > 0 then
    begin
      for I := Low(FileList) to High(FileList) do
        begin
          lvItem := lvFolder.Items.Add;
          lvItem.Caption := ExtractFileName(FileList[I]);
          fs := TFile.OpenRead(FileList[I]);
          lvItem.SubItems.Add(IntToStr(fs.Size));
          JpgInfo := GetJpgInfo(fs);
          if JpgInfo.IsJpeg then
            begin
              lvItem.SubItems.Add(JpgInfo.Version);
              lvItem.SubItems.Add(JpgInfo.Dimension);
              lvItem.SubItems.Add(JpgInfo.Mode);
            end;
        end;
      fs.Free;
    end;
end; // ComputeData
Ein kleines Testprogramm dem dieser Code entspringt ist angepappt.
Viel Spass


/edit
Mir ist gerade noch 'ne Speed optimierung eingefallen betreffend diesem Abschnitt:
Code:
    if Result.IsJpeg then // hole Dimension und Farbmodus vom letzten C0 segment was sich hoffentlich im MaxCache bereich befindet...
                          // da diese operation den kompletten puffer betrifft
                          // kann man hier bestimmt noch mehr speed rausholen
      begin
        checker := False;
        for I := LastPos to High(Buf) do
genau andersrum machen, rückwärts abarbeiten lassen und einen break beim ersten fund...
Angehängte Dateien
Dateityp: 7z JpegLister.7z (608,4 KB, 6x aufgerufen)
Gruß vom KodeZwerg

Geändert von KodeZwerg (10. Mär 2020 um 11:49 Uhr)
  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 13:57 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