Seguí adelante y repetí el experimento para ver si podía descubrir qué estaba pasando.
Procedimiento
Generé una imagen RGB aleatoria de 256 por 256 píxeles usando el filtro "Ruido sólido" en GIMP (Filtros> Renderizar> Nubes> Ruido sólido ...) usando la configuración predeterminada (que se muestra a continuación):
Y el resultado:
Luego guardé la imagen como JPEG usando la configuración predeterminada:
Luego transfirí la imagen a Windows y abrí la imagen con Windows Photo Viewer haciendo clic derecho en la imagen en el Explorador de archivos y seleccionando Vista previa en el menú. Luego giré la imagen usando los botones en la parte inferior, y guardé la imagen navegando a la siguiente imagen usando las teclas de flecha.
Para cada una de las pruebas a continuación, comencé con una copia de la imagen original y giré (hice clic en el botón de girar) el número correspondiente de veces antes de guardar. Aquí están los tamaños reslting ( 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
Observaciones inmediatas
- Windows Photo Viewer (WPV) aumenta el tamaño dramáticamente; ¡La cantidad de aumento es alrededor de cuatro veces en esta prueba!
- Todas las imágenes nuevas aumentan aproximadamente al mismo tamaño, pero no son idénticas.
- WPV no vuelve a codificar ni a volver a guardar la imagen cuando la gira un múltiplo de 360 grados. (La marca de tiempo, 11:27, es cuando los archivos se copiaron por primera vez).
El uso cmp -l
en archivos que deben tener contenido idéntico nos permite ver en qué difieren los archivos.
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
Estos archivos difieren en solo cuatro bytes (en realidad en una marca de tiempo), lo que significa que WPV está haciendo lo mismo cada vez; ahora solo necesitamos descubrir qué es eso.
Observaciones detalladas
Para esto utilicé JPEGsnoop para ver exactamente qué había en las imágenes.
Como los resultados son bastante largos, los he vinculado como una esencia . Aquí hay un resumen de las diferencias:
GIMP usa solo un segmento APP0
(JFIF) y COM
(comentario) para los metadatos. WPV deja el APP0
segmento intacto, pero curiosamente agrega un byte nulo al comentario (de modo que está terminado en nulo).
WPV agrega dos APP1
segmentos, que son metadatos Exif y XMP. Estos segmentos son 4286 y 12726 bytes, respectivamente. Juntos representan casi todo el aumento en el tamaño del archivo.
GIMP produce un JPEG progresivo, mientras que WPV produce un JPEG de referencia (no progresivo). Por esta razón, la imagen de GIMP tiene múltiples segmentos de escaneo, mientras que la imagen de WPV tiene solo uno. En mi experiencia, la imagen progresiva es a veces ligeramente más pequeña.
GIMP usó submuestreo de croma 1 × 1, mientras que WPV usó submuestreo 2 × 2. Esto me lleva a creer que WPV no está usando la rotación sin pérdidas "verdadera", a menos que de alguna manera pueda detectar que se trata de una imagen en blanco y negro.
Para resolver estos problemas, realicé una segunda prueba.
Procedimiento
Seguí pasos similares a la primera prueba. Creé una imagen aleatoria de 256 × 256 RGB usando el filtro de ruido RGB (Filtros> Nariz> Nariz RGB ...) con la siguiente configuración:
Aquí está el resultado:
Exporté el archivo como JPEG usando la siguiente configuración:
Progressive se ha desactivado, pero Submuestreo todavía está configurado en 4: 4: 4 (que es otro nombre para submuestreo 1 × 1). La calidad se incrementa a 98.
Copié la imagen y giré la copia en sentido horario; luego copié la versión girada y giró esa copia en sentido antihorario, para que podamos comparar directamente la calidad entre el original y la copia procesada por 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
Aunque el aumento este tiempo es menor en términos relativos (alrededor del 40%), el aumento absoluto es aún mayor: alrededor de 62 kB. Esto sugiere que WMV está utilizando una codificación menos eficiente.
Voy a usar ImageMagick para comparar las dos imágenes:
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
Hay cero píxeles diferentes entre el original y la copia girada. Por lo tanto, incluso si WPV no está usando una rotación sin pérdidas "verdadera", está haciendo un trabajo lo suficientemente bueno. Sospecho que sé lo que está sucediendo, y para explicarlo me desviaré un poco en las matemáticas detrás de la compresión JPEG.
El algoritmo de compresión JPEG divide una imagen en bloques de 8 × 8 píxeles. Cada uno de estos bloques se somete a una Transformación discreta de coseno (DCT) . Los coeficientes DCT resultantes describen el bloque como una suma de ondas de frecuencia diferente. El algoritmo luego "arroja" cierta información en las ondas de alta frecuencia que corresponden al ruido y a los detalles muy pequeños. El proceso de decodificación invierte el DCT, sumando las ondas almacenadas para recuperar el bloque.
Es posible rotar las "ondas" de DCT sin deshacer y rehacer la transformación (básicamente, convierte todas las ondas horizontales en ondas verticales y viceversa). Lo que creo que sucede en WPV es que la imagen se decodifica, gira y luego se vuelve a codificar. Durante el proceso de recodificación, dado que el tamaño de nuestra imagen es un múltiplo de 8 en ambas dimensiones, cada uno de los nuevos bloques corresponde a uno de los bloques originales. Es importante destacar que, dado que cada bloque no tiene componentes de alta frecuencia, el algoritmo no arroja ninguna información, y encuentra exactamente los componentes DCT correctos que tendría una rotación "verdadera" sin pérdidas.
Por último, volveré a ver los componentes de los archivos JPEG. Los resultados están nuevamente vinculados como lo esencial . Comparando los dos:
La imagen WPV contiene 4286 + 2 bytes adicionales de metadatos Exif, 1 byte adicional en el comentario y 12,726 + 2 bytes de metadatos XMP. Esto es un total de 17,017 bytes de metadatos adicionales. ¿Para qué se utilizan todos esos datos? Me asomé al archivo con mi confiable editor hexadecimal y una copia de los estándares relevantes:
Los metadatos Exif están estructurados como una imagen TIFF, que contiene una serie de etiquetas (hay mucha más complejidad, pero pasaré por alto). La mayoría de los bytes en el segmento Exif están contenidos en dos etiquetas idénticas con un número de etiqueta EA1C
(59,932 decimal). Ese número de etiqueta no está documentado en ningún lugar que pueda encontrar. Ambas etiquetas contienen 2060 bytes de tipo "indefinido", que son todos bytes nulos, excepto los primeros seis ( 1C EA 00 00 00 08
). No tengo idea de cuáles son estas etiquetas, por qué hay dos y por qué deben ser de 2 kB cada una.
Los metadatos XMP son en realidad un documento XML incrustado completo con espacios de nombres y UUID largos, que solo contiene la cadena de versión de WPV (que ya estaba en los metadatos Exif). Sin embargo, eso solo representa alrededor de 400 bytes. El resto del segmento son 122 repeticiones de 100 espacios seguidos de una nueva línea . Eso es más de 12,000 bytes de espacio totalmente desperdiciado.
Al igual que la prueba anterior, tanto GIMP como WPV usan las mismas tablas de cuantificación DCT. Esto significa que deberían estar calculando exactamente los mismos coeficientes DCT, razón por la cual las imágenes son exactamente iguales. No estoy seguro de si WPV utiliza las mismas tablas de cuantificación o si copia las tablas de la entrada.
A diferencia de la prueba anterior, esta vez WPV utiliza submuestreo 1 × 1, por lo que en realidad puede detectar que se trata de una imagen en color (o al menos que se necesitan muestras más altas para volver a codificar la imagen sin pérdidas).
GIMP y WPV usan diferentes tablas de Huffman (parte del paso de codificación de entropía). Las tablas para WPV son más grandes por un total de 279 bytes, y en un caso contienen 7 veces más códigos.
Mirando las estadísticas de JPEGsnoop, podemos ver que algunos de estos códigos rara vez se usan. Por ejemplo, en la ID: 1, Class: AC
tabla, de los 119 códigos de 16 bits definidos, solo 23 se utilizan realmente. En general, el segmento de escaneo real es 28.5% más grande en la versión WPV.
Resumen
WPV puede no estar haciendo rotaciones "verdaderas" sin pérdidas, pero las rotaciones parecen ser prácticamente sin pérdidas.
El tamaño adicional se debe en parte a una cantidad fija de metadatos agregados, y en parte a una codificación de entropía menos eficiente.
Información de versión:
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 (del paquete gimp
, versión 2.8.14-1+deb8u1
)
Window Photo Viewer (según los metadatos de la imagen):
Microsoft Windows Photo Viewer 10.0.10586.0