Was kann man über ein JPEG aussagen, wenn keine Blocklänge und kein Start gefunden wird (das Bild aber existiert und funktioniert)?

  • Allgemein

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

    Was kann man über ein JPEG aussagen, wenn keine Blocklänge und kein Start gefunden wird (das Bild aber existiert und funktioniert)?

    Moin,

    ich poste dies bei "sprachübergreifende Themen", weil es zwar um ein Analyseprogramm geht, aber auch um Jpegs an sich.
    Ich habe von hier Code, der die Blocklänge und die Position des eigentlichen Motivs in der Jpeg-Datei findet.
    Es kommt bei einigen Bildern vor, dass nichts gefunden wird. Ich kann leider kein Muster erkennen. Ich kann nicht sagen
    • es kommt nur bei Screenshots vor,
    • oder bei Internetbildern,
    • oder Smartphonebildern,
    • oder Bildern, die von einem Bearbeitungsprogramm (GIMP) stammen.
    Die einzige Aussage, die ich treffen kann, ist, dass die while-Schleife verlassen wird, wenn das Bild relativ klein ist [kB].
    Also Zeile 31
    er erkennt kein 0xFF

    Was sagt das über die Datei aus? Bild corrupt?

    C-Quellcode

    1. [/font]//Gets the JPEG size from the array of
    2. data passed to the function, file reference:
    3. http://www.obrador.com/essentialjpeg/headerinfo.htm
    4. static char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short *width, unsigned short *height) {
    5. //Check for valid JPEG image
    6. int i=0; // Keeps track of the position within the file
    7. if(data[i] == 0xFF && data[i+1] == 0xD8 && data[i+2] == 0xFF && data[i+3] == 0xE0) {
    8. i += 4;
    9. // Check for valid JPEG header (null terminated JFIF)
    10. if(data[i+2] == 'J' && data[i+3] == 'F' &&
    11. data[i+4] == 'I' && data[i+5] == 'F' && data[i+6] ==
    12. 0x00) {
    13. //Retrieve the block length of the first block since the first block will not contain the size of file
    14. unsigned short block_length = data[i] * 256 + data[i+1];
    15. while(i<data_size) {
    16. i+=block_length; //Increase the file index to get to the next block
    17. if(i >= data_size) return false; //Check to protect against segmentation faults
    18. if(data[i] != 0xFF) return false; //Check that we are truly at the start of another block
    19. if(data[i+1] == 0xC0) { //0xFFC0 is the "Start of frame" marker which contains the file size
    20. //The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
    21. *height = data[i+5]*256 + data[i+6];
    22. *width = data[i+7]*256 + data[i+8];
    23. return true;
    24. }
    25. else
    26. {
    27. i+=2; //Skip the block marker
    28. block_length = data[i] * 256 + data[i+1]; //Go to the next block
    29. }
    30. }
    31. return false; //If this point is reached then no size was found
    32. }else{ return false; } //Not a valid JFIF string
    33. }else{ return false; } //Not a valid SOI header
    34. }[font='arial,helvetica,sans-serif']
    @Bartosz Kannst Du vielleicht ein passendes Bild dazu posten?
    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!
    @RodFromGermany Zum Beispiel dieses kleine Jpg, welches ich mit einem anderen Programm kreiert habe.

    Ich poste auch den übersetzen VB.net-Code (+ meine zusätzliche Arbeit darin)

    VB.NET-Quellcode

    1. Dim pos As Integer = 0 'Position in the file.
    2. pos += 4
    3. 'wenn JPEG, dann prüfen, ob Jpeg File Interchange Format (JFIF)
    4. If Convert.ToChar(buffer(6)) = "J"c AndAlso Convert.ToChar(buffer(7)) = "F"c AndAlso Convert.ToChar(buffer(8)) = "I"c AndAlso Convert.ToChar(buffer(9)) = "F"c AndAlso buffer(10) = 0 Then
    5. TextBox2.Text = "JFIF" & " (Pos. 6)"
    6. Application.DoEvents()
    7. 'Pixeldaten auslesen
    8. If buffer(4) = 0 AndAlso buffer(5) = 16 Then 'length of segment excl. APP0 marker
    9. 'Einheiten für die folgenden Pixeldichtefelder
    10. If buffer(13) = 0 Then 'keine Einheiten
    11. '??
    12. TextBox_hor_Aufl.Text = "?"
    13. TextBox_ver_Aufl.Text = "?"
    14. ElseIf buffer(13) = 1 Then 'pixel per inch (auch dots per inch)
    15. If buffer(14) = 1 Then
    16. TextBox_hor_Aufl.Text = (256 + buffer(15)).ToString & " dpi"
    17. ElseIf buffer(14) = 0 Then
    18. TextBox_hor_Aufl.Text = buffer(15).ToString & " dpi"
    19. End If
    20. If buffer(16) = 1 Then
    21. TextBox_ver_Aufl.Text = (256 + buffer(17)).ToString & " dpi"
    22. ElseIf buffer(16) = 0 Then
    23. TextBox_ver_Aufl.Text = buffer(17).ToString & " dpi"
    24. End If
    25. ElseIf buffer(13) = 2 Then 'pixel per cm
    26. If buffer(14) = 1 Then
    27. TextBox_hor_Aufl.Text = (256 + buffer(15)).ToString & " d p cm"
    28. ElseIf buffer(14) = 0 Then
    29. TextBox_hor_Aufl.Text = buffer(15).ToString & " d p cm"
    30. End If
    31. If buffer(16) = 1 Then
    32. TextBox_ver_Aufl.Text = (256 + buffer(17)).ToString & " d p cm"
    33. ElseIf buffer(16) = 0 Then
    34. TextBox_ver_Aufl.Text = buffer(17).ToString & " d p cm"
    35. End If
    36. End If
    37. End If
    38. 'Retrieve the block length of the first block since the first block will not contain the size of file.
    39. Dim block_length As UInt16 = CUShort(buffer(pos) * 256 + buffer(pos + 1)) 'pos = 4. Block_length is always 16 in the beginning.
    40. While pos < mySize
    41. pos += block_length 'Increase the index to get to the next block.
    42. If pos >= mySize Then
    43. TextBox_pos.Text = "mit normaler Formel nicht gefunden"
    44. TextBox_BlockSize.Text = "mit normaler Formel nicht gefunden"
    45. Exit While
    46. End If
    47. If buffer(pos) <> &HFF Then
    48. TextBox_pos.Text = "mit normaler Formel nicht gefunden"
    49. TextBox_BlockSize.Text = "mit normaler Formel nicht gefunden"
    50. Exit While 'The next block must begin with 0xFF. If the program doesn't see it, go out! (Are we at the beginning of a new block?)
    51. End If
    52. If buffer(pos + 1) = &HC0 Then '' after Start of Frame Marker (FF C0)
    53. TextBox_pos.Text = $"Position: {pos}"
    54. TextBox_BlockSize.Text = block_length.ToString
    55. myHeight = CUShort(buffer(pos + 5) * 256 + buffer(pos + 6))
    56. myWidth = CUShort(buffer(pos + 7) * 256 + buffer(pos + 8))
    57. Else
    58. pos += 2
    59. block_length = CUShort(buffer(pos) * 256 + buffer(pos + 1))
    60. End If
    61. End While
    62. Else
    63. TextBox2.Text = "kein JFIF"
    64. 'Retrieve the block length of the first block since the first block will not contain the size of file.
    65. Dim block_length As UInt16 = CUShort(buffer(pos) * 256 + buffer(pos + 1)) 'pos = 4. Block_length is always 16 in the beginning.
    66. While pos < mySize
    67. pos += block_length 'Increase the index to get to the next block.
    68. If pos >= mySize Then
    69. TextBox_pos.Text = "mit normaler Formel nicht gefunden"
    70. TextBox_BlockSize.Text = "mit normaler Formel nicht gefunden"
    71. Exit While
    72. End If
    73. If buffer(pos) <> &HFF Then
    74. TextBox_pos.Text = "mit normaler Formel nicht gefunden"
    75. TextBox_BlockSize.Text = "mit normaler Formel nicht gefunden"
    76. Exit While 'The next block must begin with 0xFF. If the program doesn't see it, go out!
    77. End If
    78. If buffer(pos + 1) = &HC0 Then '' after Start of Frame Marker.
    79. TextBox_pos.Text = $"Position: {pos}"
    80. TextBox_BlockSize.Text = block_length.ToString
    81. myHeight = CUShort(buffer(pos + 5) * 256 + buffer(pos + 6))
    82. myWidth = CUShort(buffer(pos + 7) * 256 + buffer(pos + 8))
    83. Else
    84. pos += 2
    85. block_length = CUShort(buffer(pos) * 256 + buffer(pos + 1))
    86. End If
    87. End While
    88. End If


    Es wurde JFIF gefunden, daher ist der Fehler bei dem IF in Zeile 49. Programm verlässt die while in Zeile 52
    Bilder
    • 32x24.jpg

      828 Byte, 32×24, 190 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.

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

    @Bartosz Mit Deinem Code (nach C# übertragen und aufgeräumt) und Deinem Bild kommt bei mir dies:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Windows.Forms;
    3. namespace WindowsFormsApplication1
    4. {
    5. public partial class Form1 : Form
    6. {
    7. public Form1()
    8. {
    9. this.InitializeComponent();
    10. }
    11. private void button1_Click(object sender, EventArgs e)
    12. {
    13. string file = @"C:\Temp\__Test JPG\32x24.jpg";
    14. byte[] data = System.IO.File.ReadAllBytes(file);
    15. int width;
    16. int height;
    17. if (get_jpeg_size(data, data.Length, out width, out height))
    18. {
    19. label1.Text = string.Format("Width = {0}", width);
    20. label2.Text = string.Format("Height = {0}", height);
    21. }
    22. else
    23. {
    24. label1.Text = "Error";
    25. }
    26. }
    27. static bool get_jpeg_size(byte[] data, int data_size, out int width, out int height)
    28. {
    29. width = 0;
    30. height = 0;
    31. //Check for valid JPEG image
    32. int i = 0; // Keeps track of the position within the file
    33. if (!(data[i] == 0xFF && data[i + 1] == 0xD8 && data[i + 2] == 0xFF && data[i + 3] == 0xE0))
    34. {
    35. //Not a valid JFIF string
    36. return false;
    37. }
    38. i += 4;
    39. // Check for valid JPEG header (null terminated JFIF)
    40. if (!(data[i + 2] == 'J' && data[i + 3] == 'F' && data[i + 4] == 'I' && data[i + 5] == 'F' && data[i + 6] == 0x00))
    41. {
    42. //Not a valid SOI header
    43. return false;
    44. }
    45. //Retrieve the block length of the first block since the first block will not contain the size of file
    46. int block_length = data[i] * 256 + data[i + 1];
    47. while (i < data_size)
    48. {
    49. //Increase the file index to get to the next block
    50. i += block_length;
    51. if (i >= data_size)
    52. {
    53. //Check to protect against segmentation faults
    54. return false;
    55. }
    56. if (data[i] != 0xFF)
    57. {
    58. //Check that we are truly at the start of another block
    59. return false;
    60. }
    61. if (data[i + 1] == 0xC0)
    62. {
    63. //0xFFC0 is the "Start of frame" marker which contains the file size
    64. //The structure of the 0xFFC0 block is quite simple [0xFFC0][ushort length][uchar precision][ushort x][ushort y]
    65. height = data[i + 5] * 256 + data[i + 6];
    66. width = data[i + 7] * 256 + data[i + 8];
    67. return true;
    68. }
    69. else
    70. {
    71. i += 2; //Skip the block marker
    72. block_length = data[i] * 256 + data[i + 1]; //Go to the next block
    73. }
    74. }
    75. //If this point is reached then no size was found
    76. return false;
    77. }
    78. }
    79. }

    Was läuft nicht so, wie Du erwartest?
    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!
    @RodFromGermany Als Erstes Danke für deine Mühe. Nur es klappt wieder nicht. Selber Fehler.

    Zur Kontrolle: Ich habe folgende Startwerte:

    i ist 4 zu Beginn.

    und Dim block_length As Integer = buffer(i) * 256 + buffer(i + 1) = 16

    ==============================
    Hat sich erledigt. Ich habe einen Fehler gemacht.

    Man sollte hierin

    VB.NET-Quellcode

    1. If buffer(i) <> &HFF Then
    2. 'Check that we are truly at the start of another block
    3. Exit While
    4. End If
    keine Textbox füllen mit "mit normaler Formel nicht gefunden", denn in Wirklichkeit wurde sie bereits befüllt. Nur die Schleife läuft weiter und es wird nochmals das If geprüft. Und mit Exit While – so hat sich der Autor des Codes gedacht – soll die Schleife regulär verlassen werden (statt wie üblich im Schleifenkopf oder unten :rolleyes: ).
    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 schrieb:

    i ist 4 zu Beginn.
    Da liegt möglicherweise der Fehler, denn i zeigt auf JFIF, ggf. musst Du i auf 8 setzen.
    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!
    Hallo an alle,
    nach langer Zeit konnte ich mich wieder hiermit beschäftigen.
    Da liegt möglicherweise der Fehler, denn i zeigt auf JFIF, ggf. musst Du i auf 8 setzen.
    Aber im Code wird das doch auch nicht gemacht? Warum sollte ich das tun?

    Was kann man nun aussagen, wenn die Größe rechnerisch nicht gefunden werden kann (was der Sinn des aus dem Netz kopierten Codes ist)?

    Einen schönen 3. Oktober
    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:

    Warum sollte ich das tun?
    Um zu probieren, ob der Fehler danach verschwindet.
    ====
    Wie lange brauchst Du, so einen kleinen Test zu machen?
    Wie lange brauchst Du, einen Post zu schreiben?
    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!

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

    Der Fehler verschwindet nicht.

    Ich hatte das Projekt lange Zeit verworfen, bis ich gestern am neuen PC weitergemacht habe.
    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.