Fui em frente e repeti o experimento para ver se conseguia descobrir o que estava acontecendo.
Procedimento
Gerei uma imagem RGB aleatória de 256 por 256 pixels usando o filtro "Ruído sólido" no GIMP (Filtros> Renderização> Nuvens> Ruído sólido ...) usando as configurações padrão (mostradas abaixo):
E o resultado:
Em seguida, salvei a imagem como JPEG usando as configurações padrão:
Depois, transferi a imagem para o Windows e abri a imagem com o Windows Photo Viewer clicando com o botão direito do mouse na imagem no Explorador de Arquivos e escolhendo Visualizar no menu. Em seguida, girei a imagem usando os botões na parte inferior e salvei a imagem navegando para a próxima imagem usando as teclas de seta.
Para cada um dos testes abaixo, comecei com uma cópia da imagem original e girei (cliquei no botão girar) o número correspondente de vezes antes de salvar. Aqui estão os tamanhos de resltagem ( ls -l -r
):
size in bytes last-modified date
VVVVV VVVVV
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:24 original.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:30 cw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:30 cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:31 cw-cw-cw-cw-cw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:29 ccw.jpg
-rwxrwx--- 1 root vboxsf 23636 Nov 8 11:29 ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23645 Nov 8 11:29 ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 6258 Nov 8 11:27 ccw-ccw-ccw-ccw.jpg
-rwxrwx--- 1 root vboxsf 23649 Nov 8 11:30 ccw-ccw-ccw-ccw-ccw.jpg
Observações imediatas
- O Windows Photo Viewer (WPV) aumenta drasticamente o tamanho; a quantidade de aumento é de cerca de quatro vezes neste teste!
- Todas as novas imagens aumentam para o mesmo tamanho, mas não são idênticas.
- O WPV não recodifica nem salva novamente a imagem quando é girada em um múltiplo de 360 graus. (O registro de data e hora, 11:27, é quando os arquivos foram copiados pela primeira vez.)
Usar cmp -l
arquivos com conteúdo idêntico nos permite ver onde os arquivos diferem.
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg ccw-ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 60 66
robert@unity ../jpeg-rotate-test % cmp -l cw-cw.jpg ccw-ccw.jpg
2223 63 62
2224 60 71
2226 60 64
2227 62 64
robert@unity ..jpeg-rotate-test % cmp -l ccw.jpg cw-cw-cw.jpg
2223 62 63
2224 71 60
2226 64 60
2227 61 64
robert@unity ../jpeg-rotate-test % cmp -l cw.jpg cw-cw-cw-cw-cw.jpg
2221 60 61
2223 63 61
2224 60 66
2226 60 61
2227 60 61
robert@unity ../jpeg-rotate-test % cmp -l ccw.jpg ccw-ccw-ccw-ccw-ccw.jpg
2223 62 63
2224 71 60
2226 64 65
2227 61 64
Esses arquivos diferem em apenas quatro bytes (na verdade, em um carimbo de data / hora), significando que o WPV está fazendo a mesma coisa todas as vezes; agora só precisamos descobrir o que é isso.
Observações detalhadas
Para isso, usei o JPEGsnoop para ver exatamente o que havia nas imagens.
Como as saídas são razoavelmente longas, eu as vinculei como uma essência . Aqui está um resumo das diferenças:
O GIMP usa apenas um segmento APP0
(JFIF) e COM
(comentário) para metadados. O WPV deixa o APP0
segmento intocado, mas, curiosamente, adiciona um byte nulo ao comentário (para que seja terminado por nulo).
O WPV adiciona dois APP1
segmentos, que são os metadados Exif e XMP. Esses segmentos são 4286 e 12726 bytes, respectivamente. Juntos, eles respondem por quase todo o aumento no tamanho do arquivo.
O GIMP produz um JPEG progressivo, enquanto o WPV produz um JPEG de linha de base (não progressivo). Por esse motivo, a imagem do GIMP possui vários segmentos de digitalização, enquanto a imagem WPV possui apenas um. Na minha experiência, a imagem progressiva às vezes é um pouco menor.
O GIMP usou subamostragem cromatográfica 1 × 1, enquanto o WPV usou subamostragem 2 × 2. Isso me leva a acreditar que o WPV não está usando a rotação sem perdas "verdadeira", a menos que seja capaz de detectar de alguma maneira que se trata de uma imagem em preto e branco.
Para resolver esses problemas, executei um segundo teste.
Procedimento
Eu segui etapas semelhantes ao primeiro teste. Criei uma imagem aleatória de 256 × 256 RGB usando o filtro de ruído RGB (Filtros> Nariz> Nariz RGB ...) com as seguintes configurações:
Aqui está o resultado:
Eu exportei o arquivo como JPEG usando as seguintes configurações:
A progressiva foi desativada, mas a subamostragem ainda está definida como 4: 4: 4 (que é outro nome para a subamostragem 1 × 1). A qualidade é aumentada para 98.
Copiei a imagem e girei a cópia no sentido horário; depois copiou a versão girada e girou essa cópia no sentido anti-horário, para que possamos comparar diretamente a qualidade entre a cópia processada original e a WPV.
Resultados
-rwxrwx--- 1 root vboxsf 159774 Nov 8 16:21 original-random.jpg
-rwxrwx--- 1 root vboxsf 222404 Nov 8 16:24 cw-random.jpg
-rwxrwx--- 1 root vboxsf 222467 Nov 8 16:24 cw-ccw-random.jpg
Embora o aumento desse tempo seja menor em termos relativos (em torno de 40%), o aumento absoluto é ainda maior - em torno de 62 kB. Isso sugere que o WMV está usando uma codificação menos eficiente.
Vou usar o ImageMagick para comparar as duas imagens:
robert@unity ../jpeg-rotate-test % compare -verbose -metric AE original-random.jpg cw-ccw-random.jpg null:
original-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 160KB 0.000u 0:00.009
cw-ccw-random.jpg JPEG 256x256 256x256+0+0 8-bit sRGB 222KB 0.010u 0:00.010
Image: original-random.jpg
Channel distortion: AE
red: 0
green: 0
blue: 0
all: 0
original-random.jpg=> JPEG 256x256 256x256+0+0 8-bit sRGB 0.050u 0:00.020
Existem zero pixels diferentes entre a cópia original e a girada. Portanto, mesmo que o WPV não esteja usando a rotação sem perdas "verdadeira", ele está fazendo um trabalho suficientemente bom. Suspeito que sei o que está acontecendo e, para explicar, vou desviar um pouco da matemática por trás da compressão JPEG.
O algoritmo de compactação JPEG divide uma imagem em blocos de 8 × 8 pixels. Cada um desses blocos é então submetido a uma transformação discreta de cosseno (DCT) . Os coeficientes DCT resultantes descrevem o bloco como uma soma de ondas de frequências diferentes. O algoritmo "joga fora" algumas informações nas ondas de alta frequência que correspondem a ruído e detalhes muito pequenos. O processo de decodificação reverte o DCT, adicionando as ondas armazenadas para recuperar o bloco.
É possível girar as "ondas" do DCT sem desfazer e refazer a transformação (basicamente, você transforma todas as ondas horizontais em ondas verticais e vice-versa). O que eu acho que acontece no WPV é que a imagem é decodificada, girada e recodificada. Durante o processo de recodificação, como o tamanho da imagem é um múltiplo de 8 em ambas as dimensões, cada um dos novos blocos corresponde a um dos blocos originais. Importante, como cada bloco não possui componentes de alta frequência, o algoritmo não descarta nenhuma informação e encontra exatamente os componentes DCT corretos que uma rotação sem perdas "verdadeira" teria.
Por fim, examinarei os componentes dos arquivos JPEG novamente. Os resultados são novamente vinculados como sugestões . Comparando os dois:
A imagem WPV contém 4286 + 2 bytes extras de metadados Exif, 1 byte extra no comentário e 12.726 + 2 bytes de metadados XMP. Este é um total de 17.017 bytes de metadados adicionais. Para que servem todos esses dados? Examinei o arquivo com meu confiável editor hexadecimal e uma cópia dos padrões relevantes:
Os metadados Exif são estruturados como uma imagem TIFF, que contém várias tags (há muito mais complexidade, mas eu vou pular direto). A maioria dos bytes no segmento Exif está contida em duas tags idênticas com número de tag EA1C
(59.932 decimal). Esse número de etiqueta não está documentado em nenhum lugar que eu pudesse encontrar. Ambas as tags contêm 2060 bytes do tipo "indefinido", que são todos bytes nulos, exceto os seis primeiros ( 1C EA 00 00 00 08
). Não faço ideia do que são essas tags, por que existem duas e por que precisam ter 2 kB cada.
Os metadados XMP são, na verdade, um documento XML inteiro incorporado com namespacing e UUIDs longos, que contêm apenas a sequência de versões do WPV (que já estava nos metadados Exif). No entanto, isso representa apenas cerca de 400 bytes. O restante do segmento é de 122 repetições de 100 espaços seguidos por uma nova linha . São mais de 12.000 bytes de espaço totalmente desperdiçado.
Como no teste anterior, o GIMP e o WPV usam as mesmas tabelas de quantização do DCT. Isso significa que eles devem calcular exatamente os mesmos coeficientes de DCT, e é por isso que as imagens são exatamente as mesmas. Não tenho certeza se o WPV está usando as mesmas tabelas de quantização ou se ele copia as tabelas da entrada.
Diferentemente do teste anterior, desta vez o WPV usa subamostragem 1 × 1, portanto, na verdade, é possível detectar que essa é uma imagem colorida (ou pelo menos que amostras mais altas são necessárias para recodificar a imagem sem perdas).
O GIMP e o WPV usam tabelas diferentes de Huffman (parte da etapa de codificação da entropia). As tabelas para WPV são maiores em um total de 279 bytes e, em um caso, contêm 7 vezes mais códigos.
Observando as estatísticas do JPEGsnoop, podemos ver que alguns desses códigos raramente são usados. Por exemplo, na ID: 1, Class: AC
tabela, dos 119 códigos de 16 bits definidos, apenas 23 são realmente usados. No geral, o segmento de digitalização real é 28,5% maior na versão WPV.
Sumário
O WPV pode não estar fazendo rotações sem perda "verdadeiras", mas as rotações parecem praticamente sem perda.
O tamanho extra é parcialmente devido a uma quantidade fixa de metadados adicionados e parcialmente devido à codificação de entropia menos eficiente.
Versão informação:
SO (Linux) ( uname -a
):
Linux unity 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u1 (2016-09-03) x86_64 GNU/Linux
SO (Windows):
GIMP (Linux): 2.8.14 (do pacote gimp
, versão 2.8.14-1+deb8u1
)
Visualizador de fotos da janela (de acordo com os metadados da imagem):
Microsoft Windows Photo Viewer 10.0.10586.0