Come unire 2 jpeg senza perdita di dati senza decodifica usando un editor esadecimale?

StackOverflow https://stackoverflow.com/questions/609586

  •  03-07-2019
  •  | 
  •  

Domanda

Sto cercando di scrivere un programma (prob in java) per unire un numero di jpeg senza perdita di dati senza decodificarli prima.

Ho pensato di iniziare in modo semplice e provare ad aggiungere 2 jpeg della stessa dimensione compressi con le stesse impostazioni una sopra l'altra usando un editor esadecimale.

Per prima cosa estraggo i dati dell'immagine di jpeg B e li aggiungo a jpeg A. Modificando le dimensioni specificate nelle intestazioni ottengo una nuova immagine riconoscibile (jpeg A + jpeg B aggiunta nell'asse y) che può essere visualizzata. Tuttavia, sebbene i dati dell'immagine di jpeg B siano chiaramente riconoscibili, sembra che abbiano perso molte informazioni sul colore ed è chiaramente errato.

Quindi la mia domanda è: quali passi mi sto perdendo qui? Non credo che ci siano altri valori di intestazione specifici della dimensione che devo modificare, quindi forse ho bisogno di huffman per decodificare i dati dell'immagine da entrambi i jpeg, quindi aggiungerli insieme e ricodificare nuovamente il lotto?

Ho trascorso un po 'di tempo a leggere le specifiche e le intestazioni jpeg, ecc., ma a dire il vero sono fuori dalla mia profondità e potrei davvero fare con un puntatore o due!

Grazie mille per qualsiasi aiuto.


Grazie per tutti i suggerimenti. Sì, questo è sicuramente possibile, avrei dovuto menzionare jpegtran nella mia domanda originale. In pratica sto cercando di replicare questo aspetto della funzionalità jpegtran ma di usarlo nel mio programma. Immagino che dovrei guardare alla fonte jpegtran ma non so nulla della C e non molto della programmazione in generale, quindi il codice sorgente del reverse engineering è più facile a dirsi che a farsi!

È stato utile?

Soluzione 2

Ok, ho capito dove stavo sbagliando.

1) i dati di scansione dell'immagine vengono salvati in byte, ma le informazioni importanti effettive vengono codificate come stringhe di bit di lunghezza variabile. Ciò significa che la fine dei dati dell'immagine reale non rientra necessariamente in un limite di byte. Quando l'encoder jpeg deve completare il numero di bit per rendere il limite di byte, aggiunge semplicemente una serie di 1s.

2) il modo in cui sono memorizzate le informazioni sui pixel effettive è un po 'troppo complicato (almeno per me) da spiegare, ma fondamentalmente tutto è codificato in MCU, unità di codifica minime o qualcosa del genere. Le dimensioni variano in base al sottocampionamento cromatico, le dimensioni orizzontale e verticale sono di 8 o 16 pixel. Per ogni MCU, ci sono parti DC e AC che compongono un singolo componente di Luminance, Y o chrominance, Cb e Cr. Il problema era che i componenti CC venivano memorizzati come valori in relazione al valore CC rilevante dell'MCU precedente. Quindi, quando ho aggiunto i nuovi dati immagine dal jpg B, aveva memorizzato i suoi valori DC in relazione a 0 (perché non c'erano MCU precedenti), ma doveva tenere conto dei valori DC finali dell'ultimo MCU da jpg A. (spero che abbia un senso).

La soluzione:

È necessario eseguire una decodifica iniziale (Huffman + lunghezza di esecuzione) dei dati dell'immagine per scoprire esattamente dove finiscono i dati dell'immagine e quindi eliminare gli 1 finali. È inoltre necessario modificare i valori DC iniziali nel secondo jpg in modo appropriato. È quindi necessario ricodificare i bit appropriati, aggiungere 1s per adattarli a un limite di byte e voilà.

Se vuoi aggiungere nell'asse x, è un po 'più complicato. Devi riorganizzare gli MCU in modo che eseguano la scansione nel giusto ordine. I jpg eseguono la scansione da sinistra a destra, quindi dall'alto verso il basso e quindi regolano i valori DC in modo appropriato.

Finora l'ho provato solo su jpg MCU singoli, ma teoricamente dovrebbe funzionare anche con quelli più grandi.

A proposito, l'ho risolto solo grazie al proprietario di questo eccellente risorsa / blog relativa al jpg

Altri suggerimenti

Questo è molto fattibile. L'ho fatto su molte tessere di immagini di mappe di Google per unirle e formare un'immagine di dimensioni poster. Esiste un pacchetto per Unix chiamato JPEG Tools per fare esattamente questo. Il programma si chiama jpegjoin . Fonte C pura, con binari di Windows disponibili. Una volta compilato, crea un'applicazione da riga di comando che, quando eseguita, unisce due immagini jpeg senza sosta tra molte altre cose. NON decomprime alcuna immagine, unisce semplicemente i dati compressi e corregge l'intestazione di conseguenza. L'ho usato per unire 100 immagini per creare 50 strisce e quindi unirle nuovamente per creare un'immagine di grandi dimensioni.

Ulteriori informazioni sono disponibili all'indirizzo http://en.wikipedia.org/wiki/Lossy_compression #Lossless_editing

Codice sorgente

Il codice sorgente per la jpegtran sottostante qui . Uno script di esempio per imitare jpegjoin è qui .

jpeg è - come mp3 - generalmente stabile quando lo ricomprimi (usando lo stesso algoritmo).

quindi, quando unisci le immagini e le ricomprimi, assicurati che il nuovo tasso di compressione sia più alto o uguale alla più alta delle 2 immagini. in questo modo non perderai davvero la precisione.

Due approcci:

1) decodifica entrambe le immagini JPEG di origine, unisce le bitmap risultanti e codifica nuovamente come JPEG. Lo svantaggio qui è la ricompressione.

2) Assicurati che la larghezza e l'altezza dell'immagine sorgente siano multipli di 16, possibilmente ritagliando le immagini. Non decodificare le immagini ma assemblare invece il JPEG di destinazione dai blocchi MCU di origine (dimensioni 16 x 16 pixel, quindi il ritaglio).

Ti suggerisco di prendere in considerazione i marcatori DRI e RSTn, sebbene ciò richieda molti presupposti, ma funziona per me: aggiungere un PPM (un formato bitmap) a un jpeg codificato usando DRI e RSTn, entrambi sono in stessa larghezza ed entrambi sono in multipli di MCU.

Ho appena ritagliato i dati jpeg dopo l'ultimo marker RSTn (se presente), decodificato in PPM e unendo i due PPM a una singola linea MCU, codificandolo con le stesse opzioni con il jpeg originale, riorganizzando gli RST nel jpeg risultante in base al jpeg originale, quindi aggiungendo il risultato al jpeg originale. Usando questo metodo, mi impedisce di decodificare l'intero jpeg originale e di codificarlo di nuovo.

Come roba di decodifica e codifica, sto usando libjpeg.

Invece di aggiungere immagini orizzontalmente, è probabilmente più facile ruotare ciascuna immagine di 90 gradi, quindi unirle verticalmente, quindi ruotare l'immagine risultante di 90 gradi indietro.

Le operazioni JPEG senza perdita di dati sono praticamente un ossimoro. Puoi fare qualche trucco, come ruotare, ma è praticamente tutto.

Ti suggerirei di avere immagini sorgente senza perdita di dati (mi viene in mente TIFF o PNG) o di rivalutare i tuoi requisiti di qualità dell'immagine & # 8211; il ricampionamento di un JPEG ancora una volta, dati i file originali decenti, è indistinguibile per la stragrande maggioranza delle persone là fuori.

Quello che stai cercando di fare non è praticamente possibile.
La codifica del file JPEG è piuttosto complessa e se stai cambiando il contenuto dei pixel, la codifica verrà modificata. Potresti finire con un'immagine più piccola o più grande della somma delle due immagini che combini. Le uniche operazioni possibili senza perdita di dati sono quelle che mantengono una corrispondenza uno a uno con i pixel dell'immagine originale. questo sostanzialmente si riduce a rotazioni di 90 gradi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top