2017-12-31 111 views
-2

Ich würde gerne wissen, wie groß eine JPEG-Datei ist, ohne die Meta, Header und Codec-Informationen von JPEG. Damit erhalten Sie am Ende nur die komprimierten Pixeldaten, die aus den DCT-Koeffizienten und der Quantisierungs- und Huffman-Tabelle bestehen.Wie groß ist eine JPEG-Datei ohne all ihre Codec-Informationen?

Aber wie extrahiert man die Größe dieser Arrays mit Python oder C/C++?

ich versuche libjpeg zu verwenden, aber nicht einen Weg finden, um die Größe der komprimierten Daten zu berechnen.

+0

ich ziemlich sicher, dass libjpeg bin [ich es durch die docs lesen gerade] wird Ihnen diese Information nicht geben (direkt, ohne Änderungen an der Quelle). Da Pythons JPEG-Code auf libjpeg basiert, bezweifle ich, dass es auch helfen wird. Sie können natürlich Code schreiben, um die Header und so zu lesen, und dann nur die Metadatengröße von der Gesamtgröße subtrahieren. –

+3

Warum möchten Sie wissen? Ohne die Metadaten ist der Rest ohnehin nutzlos. –

+0

Ich glaube, dass am Anfang einer JPEG-Datei etwa 9 Bytes reine Identifikationsdaten liegen. Alles andere ist für die Decodierung erforderlich. –

Antwort

0

Hier ist ein Stück Code, der, grob gesagt, um was gebeten wird. Ich glaube nicht, dass es dafür in jeder Bibliothek eine "fertige" Lösung gibt.

Es ist nicht sehr sauber, und nicht so einfach, wie ich es mir erhofft hatte. Ich habe mehrere hundert zufällige Bilder aus meinem "~/Pictures" -Ordner (und ein paar anderen an anderen Orten) laufen lassen, aber keine Garantie, dass es "irgendwelche" Bilder behandelt - ich denke, alle meine Bilder werden von zwei verschiedenen Anwendungen erstellt. Die "ein paar andere" mögen das nicht, aber wiederum kann ein anderer Produzent andere Felder verwenden oder die Daten in einer Form erzeugen, die dieser Code nicht verarbeiten kann. Wenn es bricht, erhältst du alle Stücke, aber keine Rückerstattung.

Ich überlasse es dem Leser zu bestimmen, was ist tatsächliche Bilddaten und was nicht. Beachten Sie, dass Blockgrößen nicht den Blockheader selbst enthalten, dh weitere 2 Bytes oben.

Oh, und ja, das ist eine Mischung aus C++ und C. Ich habe das nur mit Teilen von Code, die ich für einen anderen Zweck gelegt habe, gehackt und aufgeräumt, damit es kein KOMPLETTES Chaos ist, aber es ist durch keine meiner besten jede Codierung bedeutet ...

ich den Code hinzugefügt haben auch hier: https://github.com/Leporacanthicus/jpegrd

#include <fstream> 
#include <ios> 
#include <vector> 
#include <cstdint> 


#define die(str, ...) \ 
    do { printf(str, __VA_ARGS__); exit(1); } while(0) 

void read_bytes(std::ifstream &f, uint8_t *buffer, std::streamsize sz) 
{ 
    if(!f.read(reinterpret_cast<char*>(buffer), sz)) 
    { 
     die("Expected to read %zd bytes\n", sz); 
    } 
} 

uint32_t read_size(std::ifstream &f) 
{ 
    uint8_t buffer[2]; 
    read_bytes(f, buffer, 2); 
    uint32_t size = buffer[0] << 8 | buffer[1]; 
    return size; 
} 

void skip_size(std::ifstream &f, std::streamsize to_skip) 
{ 
    f.seekg(to_skip - 2, std::ios_base::cur); 
} 

void check_buffer(uint8_t *buffer, const std::vector<uint8_t> &val) 
{ 
    uint8_t *b = buffer; 
    for(auto v : val) 
    { 
     if (*b != v) 
     { 
      die("Mismatch! Expected %02x, got %02x\n", v, *b); 
     } 
     b++; 
    } 
} 

uint32_t find_next_header(std::ifstream &f) 
{ 
    uint8_t b; 
    bool found = false; 
    uint32_t count = 0; 
    do 
    { 
     read_bytes(f, &b, 1); 
     if (b == 0xFF) 
     { 
      if (f.peek() == 0x00) 
      { 
       read_bytes(f, &b, 1); 
       count+= 2; 
      } 
      else 
      { 
       f.unget(); 
       found = true; 
      } 
     } 
     else 
     { 
      count++; 
     } 
    } while(!found); 

    return count; 
} 

int main(int argc, char **argv) 
{ 
    if (argc != 2) 
    { 
     printf("Expected filename as argument\n"); 
     exit(1); 
    } 

    std::ifstream f(argv[1], std::ios_base::in|std::ios_base::binary); 
    if (!f) 
    { 
     die("Couldn't open the file %s\n", argv[1]); 
    } 

    uint8_t buffer[2]; 
    uint32_t total = 0; 

    read_bytes(f, buffer, 2); 
    check_buffer(buffer, {0xFF, 0xd8}); 
    total += 2; 

    bool eoi = false; 
    do 
    { 
     uint32_t size; 
     read_bytes(f, buffer, 2); 
     if (buffer[0] != 0xff) 
     { 
      die("Expected 0xFF byte, got %02x at offset %zu\n", 
       buffer[0], (size_t)f.tellg()); 
     } 
     total += 2; 
     switch(buffer[1]) 
     { 
     case 0xE0: 
     case 0xE1: 
     case 0xE2: 
     case 0xE3: 
     case 0xE4: 
     case 0xE5: 
     case 0xE6: 
     case 0xE7: 
     case 0xE8: 
     case 0xE9: 
     case 0xEA: 
     case 0xEB: 
     case 0xEC: 
     case 0xED: 
     case 0xEE: 
     case 0xEF: 
      size = read_size(f); 
      total += size; 
      printf("APP Data Type %02x: %u bytes of application data\n", 
        buffer[1], size); 
      skip_size(f, size); 
      break; 

     case 0xDB: 
      size = read_size(f); 
      total += size; 
      printf("DQT: %u bytes of quantization data\n", size); 
      skip_size(f, size); 
      break; 

     case 0xC0: 
     case 0xC2: 
      size = read_size(f); 
      total += size; 
      printf("SOF: %u bytes of frame data\n", size); 
      skip_size(f, size); 
      break; 

     case 0xC4: 
      size = read_size(f); 
      total += size; 
      printf("DHT: %u bytes of huffman tables\n", size); 
      skip_size(f, size); 
      break; 

     case 0xDA: 
      size = read_size(f); 
      skip_size(f, size); 
      size += find_next_header(f); 
      total += size; 
      printf("SOS: %u bytes of scan data\n", size); 
      break; 

     case 0xD9: 
      printf("EOI: end of image\n"); 
      eoi = true; 
      break; 

     case 0xFE: 
      size = read_size(f); 
      skip_size(f, size); 
      total += size; 
      printf("COM: comment %u bytes\n", size); 
      break; 

     default: 
      die("Expected known encoding byte, got %02x\n", buffer[1]); 
      break; 
     } 
    } while(!eoi); 
    printf("Total size = %u\n", total); 
} 
+0

Leider funktioniert es nur bei einigen Bildern. Einige dieser Fehler schlagen fehl: https://imgur.com/a/YvrOc. – baudcode

+0

Von "funktioniert nicht", was genau meinst du? Ich habe diese Bilder heruntergeladen, und sie alle durchlaufen das Programm mit etwas Ausgabe - ich habe keine Mühe darauf verwendet, was es sein sollte und was es ist, aber die Ausgabe sieht im Allgemeinen OK aus. Das kann natürlich sein, dass die Bilder nicht wirklich die gleichen sind wie das, was Sie hochgeladen haben (viele Seiten rekodieren ihre Bilder als Teil des Upload-Prozesses, meistens um die Größe zu reduzieren), also sollten Sie zuerst überprüfen, ob das Problem reproduzierbar ist mit dem Bild von Ihrem Link heruntergeladen. Beschreiben Sie dann genauer, was falsch läuft. –

+0

Sorry, es war ein Fehler in meinem Code :(Alles funktioniert einwandfrei. – baudcode

0

die Menge der Metadaten ist völlig abhängig von dem Encoder. Es ist nur noch in einem Strom JPEG erforderlich header ist der 2-Byte-SOI-Marker.Die einzige Fußzeile ist der 2-Byte-EOI-Marker

Alles andere ist was auch immer t Der Encoder puts in.

+0

In der Praxis fügt dieser Encoder eine angemessene Menge hinzu.Ich fing an, ein Programm zu schreiben, um aus den Header-Feldern zu lesen, was in einer JPEG-Datei ist, aber es ist ein bisschen komplexer als nur die Marker und Längen zu lesen. Allerdings enthält meine 4.1K-Datendatei ungefähr 3160 Bytes an Metadaten (soweit ich das jetzt sagen kann) - das ist von GIMP. Dieselbe Eingabedatei mit einer niedrigeren Komprimierungseinstellung (mehr Details im Bild) scheint die gleichen 3160 Bytes an Metadaten zu haben. –

+0

Es hängt vom Encoder ab. Mine fügt keine hinzu. – user3344003

+0

Welches ist das? Oder dein eigenes Haus? Ich nehme an, dass Baudcode wissen wollte, wie viel es ist, weil es keine bekannte Menge an Overhead von einem Encoder gibt, der nicht selbst gebraut wird. –

Verwandte Themen