AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia EXIF auf anderes JPEG übertragen

EXIF auf anderes JPEG übertragen

Ein Thema von e-gon · begonnen am 28. Okt 2013 · letzter Beitrag vom 6. Nov 2013
Antwort Antwort
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#1

EXIF auf anderes JPEG übertragen

  Alt 28. Okt 2013, 11:43
Hallo!

Wie kann man den\die\das (oder wie auch immer) EXIF von einem JPEG auf ein anderes übertragen?

Hintergrund: Durch die Bildverarbeitung mit verschiedenen Grafikprogrammen gingen die EXIFs verloren. Bisher hat das niemand gestört, doch nun wären diese wichtig. Die orginalen JPEGs gibt's zum Glück noch, doch wäre es wohl bedeutend einfacher die EXIFs auf die bearbeiteten JPEGs zu übertragen als die Grafikbearbeitung nochmals zu wiederholen.

Weiß jemand wie man das am besten machen kann? Ich habe mich mal mit dEXIF beschäftigt. Leider bekomme ich das allerdings nicht so richtig hin.

Delphi-Quellcode:
procedure TForm1.CopyEXIF(const FileNameEXIFSource,FileNameEXIFTarget: string);
var ImgData: TImgData;
     Data: string; // EXIF-Daten
     JPEGImage: TJPEGImage;
begin
  ImgData:= TimgData.Create;
  try
    // Zielbild laden und EXIF-Daten zwischenspeichern
    ImgData.BuildList:= GenAll;
    ImgData.ProcessFile(FileNameEXIFSource);
    if ImgData.HasEXIF then begin
      Data:= ImgData.GetDataBuff;

      // Quellbild laden
      ImgData.BuildList:= GenAll;
      ImgData.ProcessFile(FileNameEXIFTarget);
      if not ImgData.HasEXIF or
         (MessageDLG('Die Datei '''+FileNameEXIFTarget+''' hat selbst ein EXIF! Soll dieser wirklich überschrieben werden?',
                     mtConfirmation,[mbYes,mbNo],0)=mrYes)then begin
        JPEGImage:= TJPEGImage.Create;
        try
          JPEGImage.LoadFromFile(FileNameEXIFTarget);
          // EXIF-Daten kopieren
          ImgData.SetDataBuff(Data);
          ImgData.WriteEXIFjpeg(JPEGImage,FileNameEXIFTarget);
        finally
          JPEGImage.Free;
        end;
      end;
    end
    else MessageDLG('Die Datei '''+FileNameEXIFSource+''' hat kein EXIF!',mtError,[mbOk],0);
  finally
    FreeAndNil(ImgData);
  end;
end;
Habe ich da einen Denkfehler drin? Oder geht das mit dEXIF gar nicht?

Gruß
e-gon
  Mit Zitat antworten Zitat
ASM

Registriert seit: 16. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#2

AW: EXIF auf anderes JPEG übertragen

  Alt 28. Okt 2013, 18:45
Wie kann man den\die\das (oder wie auch immer) EXIF von einem JPEG auf ein anderes übertragen?
So schwierig ist das doch nicht.

Zum Beispiel als Möglichkeit wie folgt:
  1. Lies aus Deiner originalen jpeg-Datei die Größe der EXIF-Struktur aus (steht in den Bytes unmittelbar nach dem EXIF-StartTag "FFE1" und reicht bis zur Kennung "786969660000" = "Exif").
  2. Lies die originale jpeg-Datei in einen MemoryStream. Setze die Größe des MemoryStreams zurück auf die Größe der EXIF-Struktur zuzüglich der 4 führenden Kennbytes der jpeg-Datei (FFD8 und FFE1).
  3. Übertrage den MemoryStream in den FileStream, der Deine neue jpeg-Datei anlegt, welche sowohl Dein verändertes jpeg-Bild als auch die ursprüngliche EXIF-Information aufnehmen soll.
  4. Lies dann Deine veränderte jpeg-Datei in den MemoryStream.
  5. Setze den Pointer des MemoryStreams auf die Position $02 (also ab dem 3.Byte, d.h. ohne die JPEG-Kennung "FFD8" der zweiten Datei) und übertrage den MemoryStream ab dieser Position in den zuvor begonnenen Filestream.

Die neu generierte jpeg-Datei enthält dann die originale EXIF-Information sowie das veränderte Bild.
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#3

AW: EXIF auf anderes JPEG übertragen

  Alt 29. Okt 2013, 13:42
Danke für die Antwort! Ich werde es gleich heute Abend ausprobieren...

Gruß
e-gon
  Mit Zitat antworten Zitat
Benutzerbild von roga
roga

Registriert seit: 15. Jun 2008
Ort: Sachsen-Anhalt
109 Beiträge
 
Delphi XE8 Professional
 
#4

AW: EXIF auf anderes JPEG übertragen

  Alt 29. Okt 2013, 17:38
RestoreEXIF

einfach entpacken und RestoreEXIF starten. Du wählst die Quelldatei und eine oder mehrere Zieldateien. Die Quelldatei muss die EXIF-Daten enthalten. Bei der Übernahme werden auch die enthaltenen Thumbnails automatisch aktualisiert.

Hab mir das kleine Programm mit CCR.Exif gebastelt, weil bei der Datenwiederherstellung sämtliche EXIF-Daten verloren gegangen sind. Warum das passierte weis ich leider nicht. Es kann an dem benutzten Programm gelegen haben. Jedenfalls waren die Fotos sonst ok.
Ronald
  Mit Zitat antworten Zitat
ASM

Registriert seit: 16. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#5

AW: EXIF auf anderes JPEG übertragen

  Alt 30. Okt 2013, 23:38
Dein Programm RestoreEXIF liest zur Anzeige des Aufnahmedatums fälschlicherweise das Tag "ModifyDate" (syn Image.DateTime, TagID $0132) aus.
Richtig aber wäre dafür vielmehr das Tag "DateTimeOriginal" (TagID $9003).
  Mit Zitat antworten Zitat
Benutzerbild von roga
roga

Registriert seit: 15. Jun 2008
Ort: Sachsen-Anhalt
109 Beiträge
 
Delphi XE8 Professional
 
#6

AW: EXIF auf anderes JPEG übertragen

  Alt 31. Okt 2013, 08:14
Danke für den Hinweis. Werde ich bei Gelegenheit mal korrigieren. Ich brauchte halt zu dem Zeitpunkt eine schnelle Lösung und so ist es dann entstanden. In einigen Foto-Foren war ich auch auf dieses Problem gestoßen, dass leider nicht alle Bildbearbeitungsprogramme die EXIF-Daten übernehmen. Und dann gibt es später bei der Bilderverwaltung oder HDR-Reihe Probleme...

Aber das ist ja hier kein Foto- sondern ein Delphi-Forum
Ronald
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#7

AW: EXIF auf anderes JPEG übertragen

  Alt 31. Okt 2013, 08:42
Hallo!

Vielen Dank für die Antworten! CCR.Exif hört sich sehr interessant an! Inzwischen überlege ich mir ernsthaft einen Wechsel von dEXIF.pas auf CCR.Exif. Wird zwar etwas Zeit kosten mich dort einzuarbeiten, aber CCR.Exif scheint einfach mehr Kameras zu unterstützen.

Mein Projekt mit der EXIF-Übertragung wird deshalb noch etwas warten müssen...

Aber vielen Dank für Eure Hilfen und Anregungen!

Gruß
e-gon
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#8

AW: EXIF auf anderes JPEG übertragen

  Alt 5. Nov 2013, 15:38
So, ich habe nun mal die Anleitung von ASM umgesetzt. Leider ist das JPEG nach der Übernahme von EXIF nicht mehr lesbar.

Delphi-Quellcode:
procedure TForm1.CopyEXIF(const FileNameEXIFSource, FileNameEXIFTarget: string);
var MSSource,MSTarget: TMemoryStream;
     FS: TFileStream;
     TargetStartPos, SourceEndPos: Longint;
     Buf: Array [0..3] of Byte;
begin
  MSTarget := TMemoryStream.Create;
  try
// 4. Lies dann Deine veränderte jpeg-Datei in den MemoryStream.
    MSTarget.LoadFromFile(FileNameEXIFTarget);
    MSTarget.Seek(2, soFromBeginning);
    if (MSTarget.Read(Buf, 4) = 4) then begin
      if (Buf[1] <> M_EXIF) or
         (MessageDLG('Die Datei '''+FileNameEXIFTarget+''' hat selbst ein EXIF! Soll dieser wirklich überschrieben werden?',
                     mtConfirmation, [mbYes, mbNo], 0) = mrYes) then begin
        if Buf[1] = M_EXIF then TargetStartPos := (Buf[2]*256)+Buf[3]+2
        else TargetStartPos := 2;

        MSSource := TMemoryStream.Create;
        try
// 1. Lies aus Deiner originalen jpeg-Datei die Größe der EXIF-Struktur aus (steht in den Bytes unmittelbar nach dem EXIF-StartTag "FFE1" und reicht bis zur Kennung "786969660000" = "Exif").
          SourceEndPos := 2;
          MSSource.LoadFromFile(FileNameEXIFSource);
          MSSource.Seek(SourceEndPos, soFromBeginning);
          MSSource.Read(Buf, 3);
          if Buf[1] = M_EXIF then SourceEndPos := SourceEndPos+(Buf[2]*256)+Buf[3]+2;
// 2. Lies die originale jpeg-Datei in einen MemoryStream. Setze die Größe des MemoryStreams zurück auf die Größe der EXIF-Struktur zuzüglich der 4 führenden Kennbytes der jpeg-Datei (FFD8 und FFE1).
          MSSource.SetSize(SourceEndPos);

// 3. Übertrage den MemoryStream in den FileStream, der Deine neue jpeg-Datei anlegt, welche sowohl Dein verändertes jpeg-Bild als auch die ursprüngliche EXIF-Information aufnehmen soll.
          FS:= TFileStream.Create(FileNameEXIFTarget, fmCreate or fmShareExclusive);
          try
            MSSource.SaveToStream(FS);

// 5. Setze den Pointer des MemoryStreams auf die Position $02 (also ab dem 3.Byte, d.h. ohne die JPEG-Kennung "FFD8" der zweiten Datei) und übertrage den MemoryStream ab dieser Position in den zuvor begonnenen Filestream.
            MSTarget.Seek(TargetStartPos, soFromBeginning);
            FS.CopyFrom(MSTarget, MSTarget.Size-TargetStartPos);
          finally
            FS.Free;
          end
        finally
          MSSource.Free;
        end
      end;
    end
    else MessageDLG('Fehler beim Lesen der Datei '''+FileNameEXIFTarget+'''!', mtError, [mbOk], 0);
  finally
    MSTarget.Free;
  end;
end;
Kann mir jemand sagen, was ich falsch gemacht habe? Ich finde einfach keinen Fehler. Oder geht das so gar nicht?

Gruß
e-gon
  Mit Zitat antworten Zitat
ASM

Registriert seit: 16. Aug 2004
165 Beiträge
 
Delphi 7 Enterprise
 
#9

AW: EXIF auf anderes JPEG übertragen

  Alt 5. Nov 2013, 17:27
Kann mir jemand sagen, was ich falsch gemacht habe? Ich finde einfach keinen Fehler. Oder geht das so gar nicht?
Doch natürlich, es geht. Aber Dein Fehlschlag ist durch einen unvorsichtigen Fehler bei meinen Angaben zum Vorgehen verursacht:
Auch wenn man den Pointer im Stream auf eine Position in einem Offset vom Anfang des Streams setzt, wird trotzdem beim SaveToStream der komplette Stream von Position 0 an gespeichert. Somit also auch die beiden ersten Bytes $FF$D8 aus dem Stream des Files ohne ExIf, von dem die eigentlichen Bilddaten übernommen werden und der an den Stream der ExIf-Daten angehängt wird. Diese beiden Bytes dürfen aber nicht mitkopiert werden. Wenn das jedoch der Fall ist, kommen diverse (allerdings nicht alle) Bildbearbeitungsprogramme bzw. Viewer aus dem Tritt.

Berichtigte Lösung: Überschreiben der ersten beiden Bytes (also $FF$D8) im Stream der Bilddaten durch $00$00 vor dem Anhängen dieses Streams an den Stream der ExIf-Struktur.

Folgendes Beispiel vermeidet den beschriebenen Fehler (ausgetestet!):
Delphi-Quellcode:
procedure CopyExIf2JPG(const SourceFileHasExIf, SourceFileWithOutExIf, TargetFile: String);
var
  fsTarget: TFileStream;
  ms: TMemoryStream;
  buffer: Array [1..2] of byte;
begin
  fsTarget := TFileStream.Create(TargetFile, fmCreate);
  try
    ms := TMemoryStream.Create;
    try
      ms.LoadFromFile(SourceFileHasExIf);
      ms.Seek(0, soFromBeginning);
      ms.Size := $03E6;
      ms.SaveToStream(fsTarget);
      ms.Clear;
      ms.LoadFromFile(SourceFileWithOutExIf);
      fillchar(buffer,sizeof(buffer),#0);
      ms.Seek(0, soFromBeginning);
      ms.Write(Buffer,2); // hic!
      ms.SaveToStream(fsTarget);
    finally
      ms.Free;
    end;
  finally
    fsTarget.Free;
  end;
end;
  Mit Zitat antworten Zitat
e-gon

Registriert seit: 7. Jul 2003
Ort: Stuttgart
154 Beiträge
 
Delphi 6 Enterprise
 
#10

AW: EXIF auf anderes JPEG übertragen

  Alt 6. Nov 2013, 10:08
Hallo ASM,

vielen Dank für Deine Unterstützung! Mit dem Problem der Positionierung im Stream hast Du grundsätzlich recht. Ich habe allerdings festgestellt, wenn man unmittelbar vor dem CopyFrom den Seek-Befehl ausführt, funktioniert das Kopieren ab der Seek-Position.

Mein Problem war übrigens ein Leichtsinnsfehler! Habe beim zweiten Read statt 4 nur 3 Zeichen gelesen! Das habe ich aber erst nach viel Debuggen und Hexen herausbekommen!
Immerhin, jetzt scheint es zu funktionieren!

Falls es mal jemand braucht, hier nochmals der finale Code:

Delphi-Quellcode:
procedure TForm1.CopyEXIF(const FileNameEXIFSource, FileNameEXIFTarget: string);
const
  M_JFIF = $E0;
  M_EXIF = $E1;
var
  MSSource, MSTarget: TMemoryStream;
  FS: TFileStream;
  TargetStartPos, SourceEndPos: Longint;
  Buf: Array [0..3] of Byte;
begin
  MSTarget := TMemoryStream.Create;
  try
// 4. Lies dann Deine veränderte jpeg-Datei in den MemoryStream.
    TargetStartPos := 2;
    MSTarget.LoadFromFile(FileNameEXIFTarget);
    MSTarget.Seek(TargetStartPos, soFromBeginning);
    MSTarget.Read(Buf, 4);
    if Buf[1] = M_JFIF then begin
      TargetStartPos := TargetStartPos+(Buf[2]*256)+Buf[3]+2;
      MSTarget.Seek(TargetStartPos, soFromBeginning);
      MSTarget.Read(Buf, 4);
    end;
    if (Buf[1] <> M_EXIF) or
       (MessageDLG('Die Datei '''+FileNameEXIFTarget+''' hat selbst ein EXIF! Soll dieser wirklich überschrieben werden?',
                   mtConfirmation, [mbYes,mbNo], 0) = mrYes) then begin
      if Buf[1] = M_EXIF then TargetStartPo s:= TargetStartPos+(Buf[2]*256)+Buf[3]+2;

      MSSource := TMemoryStream.Create;
      try
// 1. Lies aus Deiner originalen jpeg-Datei die Größe der EXIF-Struktur aus (steht in den Bytes unmittelbar nach dem EXIF-StartTag "FFE1" und reicht bis zur Kennung "786969660000" = "Exif").
        SourceEndPos := 2;
        MSSource.LoadFromFile(FileNameEXIFSource);
        MSSource.Seek(SourceEndPos, soFromBeginning);
        MSSource.Read(Buf, 4);
        if Buf[1] = M_EXIF then SourceEndPos := SourceEndPos+(Buf[2]*256)+Buf[3]+2;
// 2. Lies die originale jpeg-Datei in einen MemoryStream. Setze die Größe des MemoryStreams zurück auf die Größe der EXIF-Struktur zuzüglich der 4 führenden Kennbytes der jpeg-Datei (FFD8 und FFE1).
        MSSource.SetSize(SourceEndPos);

// 3. Übertrage den MemoryStream in den FileStream, der Deine neue jpeg-Datei anlegt, welche sowohl Dein verändertes jpeg-Bild als auch die ursprüngliche EXIF-Information aufnehmen soll.
        FS := TFileStream.Create(FileNameEXIFTarget, fmCreate or fmShareExclusive);
        try
          MSSource.SaveToStream(FS);

// 5. Setze den Pointer des MemoryStreams auf die Position $02 (also ab dem 3.Byte, d.h. ohne die JPEG-Kennung "FFD8" der zweiten Datei) und übertrage den MemoryStream ab dieser Position in den zuvor begonnenen Filestream.
          MSTarget.Seek(TargetStartPos, soFromBeginning);
          FS.CopyFrom(MSTarget, MSTarget.Size-TargetStartPos);
        finally
          FS.Free;
        end;
      finally
        MSSource.Free;
      end
    end;
  finally
    MSTarget.Free;
  end;
end;
  Mit Zitat antworten Zitat
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 +1. Es ist jetzt 11:58 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