Was bedeutet es, wenn ein JPEG nicht mit {&HFF, &HD9} endet?

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    Was bedeutet es, wenn ein JPEG nicht mit {&HFF, &HD9} endet?

    Hallo zusammen,

    ich habe eine kurze Frage: ich schreibe gerade ein kleines Programm, das JPEGs analysieren soll. Laut Wikipedias JPEG-Seite muss ein JPEG mit FF und D9 enden.
    • die JPEGs, die durch Screenshots zustande gekommen sind, enden auch so. Die Screenshots wurden durch den PC erstellt.
    • die JPGEGs, die durch mein Smartphone erstellt wurden, enden jedoch mit 70d und 84d. Ich finde dafür keine Erklärung. Hat das etwas mit Metadaten zu tun?
    • • hier wird auch keine Kombination von {&HFF, &HD9} gefunden. ?( Zeile28

    VB.NET-Quellcode

    1. Private Sub Button_Start_Click(sender As Object, e As EventArgs) Handles Button_Start.Click
    2. If System.String.IsNullOrEmpty(file_path) Then Return
    3. Dim mySize As Long = My.Computer.FileSystem.GetFileInfo(file_path).Length
    4. Label1.Text = CType(Math.Round(mySize / 1024.0, 0), String) & " kB"
    5. If mySize > Int32.MaxValue Then Return 'Overflow vermeiden
    6. Dim buffer(CInt(mySize - 1)) As Byte
    7. Dim Anzahl_gelesene_Bytes As Integer
    8. Using FS As New System.IO.FileStream(file_path, IO.FileMode.Open, IO.FileAccess.Read)
    9. Anzahl_gelesene_Bytes = FS.Read(buffer, 0, buffer.Length)
    10. End Using
    11. If buffer(0) = 255 AndAlso buffer(1) = 216 Then
    12. Label2.Text = "JPEG"
    13. Else
    14. Label2.Text = "Kein JPEG"
    15. Return
    16. End If
    17. If buffer(buffer.Length - 2) = 255 AndAlso buffer(buffer.Length - 1) = 217 Then 'EOI
    18. Label3.Text = "endet gewöhnlich"
    19. Else
    20. Label3.Text = "endet nicht gewöhnlich" 'ist "endet nicht gewöhnlich" überhaupt die richtige Formulierung?
    21. If buffer.SequenceEqual({&HFF, &HD9}) Then
    22. Debug.WriteLine("")
    23. End If
    24. End If
    25. End Sub
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Wenn die letzten Bytes nicht diese sind, sind dort noch irgendwelche nachfolgende Daten.
    Also sowas gibt es, gut gut.... Was sind das für Daten?
    Warum finde ich die EOI zwischendrin nicht?
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Warum du kein EOI findest kann ich nicht sagen, vielleicht ist ein Bit beim download oder kopieren gekippt. Die Bytes nach EOI können alles mögliche darstellen.

    Ich hab einen kleinen Test gemacht, habe einfach mal hinter EOI was angehängt, Windows, Gimp und Paint.Net ignorieren das scheinbar. Auch die Preview in Windows funktioniert.

    Schaut euch die Datei mal an.


    Kannst du die Datei ohne EOI mal hochladen?
    Bilder
    • wbbLogo_vbp.jpg

      11,24 kB, 320×80, 106 mal angesehen
    Alle Dateien, die durch Screenshots entstanden sind, haben EOI. Alle Fotos aus einer Digitalkamera gehen auch. Fotos, runtergladen aus dem INet gehen auch. Alle vom Smartphone nicht. Deswegen muss das an meinem Code liegen, vermute ich.

    Schaut euch die Datei mal an.
    So etwas möchte ich mit dem Programm erreichen :)
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Ich hab noch weitere Informationen gefunden. Hab einfach mal aus 0xFF 0xD9, 0xEE 0xD9 gemacht, damit kein EOI mehr in der Datei ist. Kein Programm meldet einen Fehler. Ich habe nicht viel Wissen über JPEG, wusste aber das die Grösse nicht in der Datei steht, ich fragte mich daher warum das Bild trotzdem korrekt dargestellt werden kann, auch dafür fand ich eine Antwort.

    web.archive.org/web/2013101621…nes.com/jpeg-width-height
    @Takafusa ich habe mir den im LInk gezeigten Code mal in Einzelschritten debuggt.

    Man muss anscheinend mit

    VB.NET-Quellcode

    1. ' FF D8 FF E0
    2. If buffer(0) = 255 AndAlso buffer(1) = 216 AndAlso buffer(2) = 255 AndAlso buffer(3) = 224 Then
    3. Label2.Text = "JPEG"
    4. Else
    5. Label2.Text = "Kein JPEG"
    6. Return
    7. End If
    prüfen (also nur

    VB.NET-Quellcode

    1. buffer(0) = 255 AndAlso buffer(1) = 216
    reichen nicht)!

    Daher ist das Smartphone-Bild kein richtiges JPEG. Danke soweit.

    Eine Frage hätte ich aber noch, und zwar zu dieser ganzen Struktur...
    Ich habe mir wie gesagt den Code zu vb.net übersetzt und habe ihn getestet. Offensichtlich ist ein JPEG in Blöcken aufgebaut. Bei einem kleinen Bild (1280 x 720) läuft er nur einmal ins Else (Zeile 28 unten), bei einem großen (4032 x 2268) sehr oft. Ins Else gehen muss er ja, um zu iterieren. Solange, bis er &HC0 sieht. Dann kann man die Größe bestimmen. Laut der Wikipedia-Tabelle sind wir selbst dann noch ganz oben. Das heißt, alles weitere ist nur Nebenwerk?

    hier nochmal der ganze Code aus dem Link (in VB)

    VB.NET-Quellcode

    1. 'Check for correct JPEG format.
    2. ' FF D8 FF E0
    3. If buffer(0) = 255 AndAlso buffer(1) = 216 AndAlso buffer(2) = 255 AndAlso buffer(3) = 224 Then
    4. Label2.Text = "JPEG"
    5. Else
    6. Label2.Text = "Kein JPEG"
    7. Return
    8. End If
    9. pos += 4
    10. 'Check for correct JPEG header (JFIF'\0').
    11. If Convert.ToChar(buffer(pos + 2)) = "J"c AndAlso Convert.ToChar(buffer(pos + 3)) = "F"c _
    12. AndAlso Convert.ToChar(buffer(pos + 4)) = "I"c AndAlso Convert.ToChar(buffer(pos + 5)) = "F"c _
    13. AndAlso buffer(pos + 6) = 0 Then
    14. Label4.Text = "JFIF"
    15. Application.DoEvents()
    16. 'Retrieve the block length of the first block since the first block will not contain the size of file.
    17. Dim block_length As UInt16 = CUShort(buffer(pos) * 256 + buffer(pos + 1)) 'pos = 4. Block_length immer zuerst 16
    18. While pos < mySize
    19. pos += block_length 'Increase the index to get to the next block.
    20. If pos >= mySize Then Exit While
    21. If buffer(pos) <> &HFF Then Exit While 'mit 0xFF muss der nächste Block beginnen. Wenn er das nicht sieht, dann raus!
    22. If buffer(pos + 1) = &HC0 Then '' nach Start of Frame Marker.
    23. myHeight = CUShort(buffer(pos + 5) * 256 + buffer(pos + 6))
    24. myWidth = CUShort(buffer(pos + 7) * 256 + buffer(pos + 8))
    25. Debug.WriteLine("")
    26. Else
    27. pos += 2
    28. block_length = CUShort(buffer(pos) * 256 + buffer(pos + 1))
    29. End If
    30. End While
    31. Else
    32. Label4.Text = "Kein JFIF"
    33. End If

    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Bartosz schrieb:

    kein richtiges JPEG
    Wenn Du von dem Bild eine Bitmap-Instanz erzeugen kannst, ist es ein richtiges JPEG.
    Und wenn Du nicht mit Byte und Char arbeitest, hole Dir die betreffenden 4 Byte in ein Integer und teste das mit einem Befehl, das lässt sich dann auch leichter lesen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Bartosz schrieb:

    Laut der Wikipedia-Tabelle sind wir selbst dann noch ganz oben. Das heißt, alles weitere ist nur Nebenwerk?


    Wie weit man damit in der Datei liest, müsste ich selbst mal testen. Lass dir einfach mal die aktuelle Position im While pos < mySize loop ausgeben. Um sicher zu sein ob es ein korrekt darstellbares JPEG handelt, müsste man es komplett parsen und versuchen darzustellen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    Wie weit man damit in der Datei liest, müsste ich selbst mal testen.
    Ich habe gerade herausgefunden, wie weit man lesen muss. Gemäß diesem Dokument liest man immer bis FF D9, um die Größe der Datei zu ermitteln, egal, ob dahinter noch etwas steht oder nicht.
    • bei den "normalen" JPEGs war FF D9 ja auch wirklich das Ende. Daher stimmen sowohl

      VB.NET-Quellcode

      1. Dim mySize As Long = My.Computer.FileSystem.GetFileInfo(file_path).Length
      und

      VB.NET-Quellcode

      1. For i As Integer = 0 To buffer.Length - 2 Step 1
      2. If buffer(i) = 255 AndAlso buffer(i + 1) = 217 Then
      3. JPEG_Size = i + 1
      4. Label5.Text = CType(Math.Round(JPEG_Size / 1024.0, 0), String) & " kB selbst ermittelt"
      5. End If
      6. Next
      exakt überein.
    • Bei den Smartphone-JPEGs ist ein (1) kB mehr zu sehen bei My.Computer.FileSystem.GetFileInfo(file_path).Length, weil ich glaube, dass es an "weiteren Daten", wie z.B. die vielen Metadaten, liegt. Stimmt das?
    • By the way: wie ihr seht, wird nun auch FF D9 im Smartphone-Bild gefunden. buffer.SequenceEqual wollte nicht so..

    Letzten Endes kann man sagen, dass es ein FF D9 gibt – des Öfteren mittendrin statt am Ende, weswegen buffer(buffer.Length - 2) = 255 nichts aussagen muss.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Bartosz“ ()

    Bartosz schrieb:

    weil ich glaube, dass es an "weiteren Daten", wie z.B. die vielen Metadaten, liegt. Stimmt das?


    Ohne zu sehen was da angehängt ist kann man nur raten. Mach mal in Foto(ein Schuss ins schwarze) und lade es hoch, ich kann dann mal probieren herauszufinden was das für Daten sind. Kann zwar nicht garantieren, das ich herausfinde was es für Daten sind, aber versuch macht klug.
    anbei das Originalfoto
    Bilder
    • 20200727_214345.jpg

      1,62 MB, 4.032×3.024, 82 mal angesehen
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.
    Viele Informationen sind nicht enthalten es handelt sich nur um 98 Bytes. Auf dem ersten Blick ist ein Timestamp zu finden, allerding ist der timestamp 3 Bytes zu lang, ich vermutze Samsung hängt einfach millisekunden an, denn lasse ich diese 3 weg, passt der Timestamp zur Aufnahmezeit des Fotos. Morgen schau ich mal nach weiteren Informationen.

    Ich habe bereits eine kleine Recherche zu den Daten gemacht, dieses fand ich dazu. Aber da es schon spät ist, gugge ich morgen weiter.
    superuser.com/questions/109920…d-of-jpg-files-on-sd-card





    Aufgrund der Informationen vermute ich das es von der Samsung Gallery-App angehängt wird. Es wurden scheinbar bei machen nach Tagen diese Daten verändert, was mit Events der App zusammenhängen kann.

    Ein Zitat aus dem xda-dev-forum.
    I forgot to mention that it turned out it is because of the Samsung Gallery app functionality. By default it creates automatic events trying to group similar photos. To turn it off it is required to open up the Gallery app, go to Events, then click Settings and disable Automatic events.



    Addition:
    @Bartosz Die eigendlich Metadaten des Bilder sollten im EXIF-Tag stehen.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Takafusa“ ()

    Wow, danke. Dann kann ich diese Frage mogen abschließen.

    EDIT: ich habe mir gerade sagen lassen, eine JPG endet immer mit FF D9, es sei denn, sie wurde "manipuliert" (wenn auch hier im Guten).
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    @Bartosz Die RaspiCam kann ein 16BPP-Format, da ist die Low-Byte-Hälfte des Bildes hinten an die "normale" 100%-JPG (unkomprimiert) angehängt.
    Mit jedem Standard-Viewer kommt die High-Byte-Hälfte, mit der entsprechenden Software kann man beide Hälften zusammensetzen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Yo, wegen zu wenig Zeit konnte ich nicht viel herausbekommen.

    In High-End Modellen speichert Samsung sogar die IMEI
    Die IMEI einiger (high-end) Samsung Galaxy Smartphones wird in den SEFT "trailing data" von JPEG-Dateien gespeichert, abhängig von den Einstellungen des Geräts, und wird jetzt, falls vorhanden, im Detail-Modus der SEFT-Datei angezeigt. Die SEFT-Datei wird von "Eingebettete Daten in diversen Dateitypen suchen" erzeugt.

    Quelle:
    x-ways.net/winhex/mailings/2018-d.html

    Auch ist der MCC(MobileCoutryCode) zu sehen, erste byte(32) 2(ASCII interpretation) für Europa, die folgenden beiden(36, 32) 62(ASCII interpretation) für Deutschland. Ich kann mir vorstellen, das auch der MNC(MobileNetworkCode) in diesem Feld ist, etvl. sogar bis hin zur Cell-Id.

    Sobald sich die Gelegenheit bietet und ein Kollege mit einem Samsung Telefon mir seine IMEI und Provider nennt, wie auch ein Foto zur verfügung stellt, kann ich das mal abgleichen.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Takafusa“ ()

    @Takafusa Vielen Dank! Ich habe gerade nachgeschaut, was eine IMEI ist. Das ist ja krass, dass die im Bild ist.

    Ich habe übrigens heute auch etwas geschafft. Ich habe ein Programm geschrieben, mit dem ich alles nach FF D9 auslesen lann, bis zum wirklichen Ende. Daher erhalte ich auch die Daten wie du in deinem Bild. Also wenn du mehr weißt, können wir uns gerne unterhalten.
    An die Neulinge: Nutzt Option Strict On und Option Infer Off. Dadurch kommt ihr mit Datentypumwandlungen nicht durcheinander und der Code verbessert sich um Einiges! Solche Fehler à la Dim Beispiel As Integer = "123" können nicht mehr passieren.