Si una imagen se gira sin pérdidas, ¿por qué cambia el tamaño del archivo?

Estaba buscando métodos de rotación de imágenes sin pérdidas y encontré esta pregunta que lo explica bastante bien:

¿Son las rotaciones de "Windows Photo Viewer" sin pérdidas?

Así que creé un JPEG de 256 × 256 con píxeles aleatorios (filtro de nube de Photoshop) y luego lo giré usando Windows Picture Viewer. Después de la rotación, el tamaño del archivo aumentó, pero solo en la primera rotación. Cada rotación posterior a partir de entonces, el tamaño del archivo se mantuvo estático. Sé que está girando sin pérdidas porque lo he girado varias veces sin pérdida de calidad notable, mientras que una imagen de 257 × 257 rotada 20 veces se volvió muy con pérdidas.

¿Cuánto aumentó el tamaño del archivo en sus pruebas?
@JamesSnell Sabía que debería haber incluido eso. El que acabo de hacer usando el filtro de clounds de diferencia de GIMP tenía originalmente 14,583 bytes, pero cambió a 23,638 bytes después de la rotación. Esa es una diferencia de más de 9000 bytes que parece una gran cantidad de datos adicionales si hablamos solo de metadatos.
@JamesSnell Repetí la misma prueba con una imagen de 512x512 y la diferencia de archivos es de 9612 bytes (fue de 9055 con la primera). Dado que el aumento del tamaño del archivo no fue proporcional al aumento de las dimensiones, creo que es seguro decir que, de hecho, son metadatos.
Eso parece una gran cantidad de metadatos adicionales. No me apresuraría a asumir que todos esos datos adicionales son metadatos. Me parece que la diferencia de tamaño debido a los metadatos debería ser casi una constante (dentro de unos pocos bytes para tener en cuenta la representación de cadena de algunos números).
Cuando proporcione información adicional relacionada con la pregunta, edite en la pregunta en lugar de en los comentarios. Los comentarios son efímeros y pueden limpiarse de vez en cuando.
¿Qué sucede si rota usando alguna otra (mejor) herramienta de manipulación de imágenes? Diablos, no me sorprendería si WPV guardara los píxeles originales :-(
Sería útil cargar la versión original de su imagen de prueba.
@CodesInChaos: un conjunto de archivos 'antes y después' nos permitiría responder la pregunta por completo. Pero tendrían que suministrarse de una manera que no los altere, por lo que no es la ruta habitual de imgur, etc.
¿No podría ser simplemente que Windows Picture Viewer volvió a guardar la imagen con una relación de compresión menor?
El punto es que WPV vuelve a comprimir la imagen en la primera rotación, pero la comprime de tal manera que si el tamaño es múltiplo de 8 rotaciones posteriores se pueden realizar simplemente aplicando transformaciones de bytes al flujo de bytes comprimido, mi respuesta aborda correctamente eso, incluso si es negativo, tiene la explicación completa (y en realidad es la única respuesta correcta)
Como @DarioOO, pero tratando de dejarlo claro. Sin pérdida no significa igual ni idempotente. Al volver a codificar un jpg, uno podría tener una mejor compresión (computadora con mejor algoritmo/memoria versus cámara), y esto es cierto con o sin rotación. Sin pérdidas solo significa que la imagen sin comprimir será la misma, nada sobre la imagen original (comprimida).
@GiacomoCatenazzi En teoría, tiene razón, pero en la práctica, la compresión JPEG hace que esto sea casi imposible. La rotación JPEG de 90 grados sin pérdida se realiza exactamente sin compresión, mediante la transposición de datos comprimidos. Según entiendo su comentario, usted dice que siempre hay una recompresión, simplemente indistinguible, mientras que DarioOO dice que solo hay una recompresión inicial en formato transponible y se transpone a partir de ahí. Creo que el JPEG alineado con MCU es transponible de fábrica. betterjpeg.com/lossless-rotación.htm
Las bibliotecas de compresión de MS son deficientes y, a menudo, producen menos compresión que otros motores que utilizan el "mismo" algoritmo.

Respuestas (8)

Lo más probable es que esto se deba a la codificación de entropía , que es la etapa final sin pérdidas de la compresión JPEG, después de que los datos de la imagen se han cuantificado para reducir su tamaño.

Cuando una imagen JPEG se gira sin pérdidas, esta capa final de codificación sin pérdidas se debe deshacer, los coeficientes DCT desempaquetados se mezclan y luego los coeficientes mezclados deben codificarse en entropía nuevamente. Dado que la eficiencia de la capa de codificación de entropía depende del orden de los coeficientes DCT dentro de cada bloque, que cambiará al rotar la imagen, no debería sorprender que el archivo de imagen rotado pueda ser un poco más pequeño o más grande que el original.

También hay varias formas diferentes en las que se puede realizar el paso de codificación de entropía, por lo que es muy posible que el tamaño del archivo de exactamente la misma imagen JPEG varíe según el software que realiza la codificación. Algunas de las posibles diferencias entre los codificadores incluyen:

  • elección de codificación aritmética (rara pero potencialmente más eficiente, solía estar patentada) versus codificación Huffman (más simple, estándar);
  • elección de orden de codificación secuencial (cada bloque de 8x8 píxeles se codifica uno a la vez) frente a progresivo (los componentes de baja frecuencia de todos los bloques se codifican antes que los componentes de mayor frecuencia, generalmente un poco más compactos);
  • opción de usar las tablas de símbolos estándar de Huffman (más rápidas, más simples, pueden ser más eficientes para imágenes muy pequeñas) frente a tablas personalizadas optimizadas para cada imagen (generalmente más eficientes para imágenes grandes, más lentas y más complejas de codificar);
  • si se utilizan tablas de Huffman personalizadas, diferentes codificadores pueden generar tablas diferentes para los mismos datos de imagen;
  • varios detalles de bajo nivel del proceso de codificación en sí, como si incluir marcadores de reinicio en el flujo de datos y cuándo, también pueden variar entre codificadores.

Además, los "archivos JPEG" con los que la gente trabaja normalmente contienen datos de imagen comprimidos en JPEG envueltos en un contenedor JFIF o Exif , que combina los datos de imagen con uno o más bloques de metadatos e introduce su propio conjunto de complicaciones. Incluso si el software que gira la imagen en realidad no realiza ningún cambio sustancial en los metadatos JFIF/Exif, simplemente reorganizar los datos podría afectar el tamaño del archivo en unos pocos bytes.

En particular, los metadatos JFIF/Exif pueden contener una o más miniaturas de la imagen de tamaño completo, y el software que rota las imágenes realmente debería regenerar (¡o también rotar sin pérdidas!) las miniaturas para que coincidan con la nueva orientación de la imagen completa. imagen de tamaño Esto solo podría explicar fácilmente la diferencia de tamaño observada.

Para una diferencia de 9 KB (60 %), supongo que serían las miniaturas.
JPEG puede ser demasiado simple para que valga la pena que lo hagan los codificadores, pero los codificadores de video como x264 en realidad pueden considerar la capacidad del codificador de entrada para codificar lo que están a punto de generar a continuación, al tomar decisiones de equilibrio entre tasa y distorsión. (es decir, decidir cuántos bits podría costar cada alternativa y compararlo con el error con pérdida). Esto se llama cuantización trellis. Consulte las Notas sobre la implementación de la cuantificación trellis en H.264 del autor de x264 (Loren Merritt); comienza con una explicación bastante básica del propósito.
De todos modos, el codificador JPEG puede haber elegido coeficientes DCT de modo que se comprimieran bien con el codificador de entropía, por lo que incluso un compresor óptimo no podría hacer una versión girada tan pequeña. (Porque ponerlos en un orden diferente probablemente haría que se comprimieran menos). Es casi seguro que esto sería un pequeño efecto para JPEG, ya que cada bloque de 8x8 se codifica por separado (restableciendo el estado del codificador de entropía, AFAIK). (Los I-frames en h.264 usan predicción interna, prediciendo a partir de otros bloques en el mismo cuadro, haciéndolos más pequeños que un JPEG con la misma calidad visual).

Seguí adelante y repetí el experimento para ver si podía averiguar 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):

ingrese la descripción de la imagen aquí

Y el resultado:

ingrese la descripción de la imagen aquí

Luego guardé la imagen como JPEG usando la configuración predeterminada:

ingrese la descripción de la imagen aquí

Luego transfirí la imagen a Windows y la abrí con Windows Photo Viewer haciendo clic con el botón derecho en la imagen en el Explorador de archivos y eligiendo 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 siguientes pruebas, comencé con una copia de la imagen original y giré (haciendo clic en el botón de rotación) la cantidad correspondiente de veces antes de guardar. Aquí están los tamaños restantes ( 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 de forma espectacular; ¡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 vuelve a guardar la imagen cuando se 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 -lde archivos que deberían tener contenido idéntico nos permite ver dónde 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 hace lo mismo cada vez; ahora solo tenemos que averiguar qué es eso.

Observaciones detalladas

Para esto usé JPEGsnoop para ver qué había exactamente en las imágenes.

Dado que los resultados son bastante largos, los he vinculado como esencia . He aquí un resumen de las diferencias:

  • GIMP usa solo un segmento APP0(JFIF) y COM(comentario) para los metadatos. WPV deja el APP0segmento intacto, pero curiosamente agrega un byte nulo al comentario (para que termine en nulo).

  • WPV agrega dos APP1segmentos, 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 básico (no progresivo). Por esta razón, la imagen de GIMP tiene varios segmentos de escaneo, mientras que la imagen de WPV solo tiene uno. En mi experiencia, la imagen progresiva a veces es un poco 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á utilizando una 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 RGB aleatoria de 256 × 256 usando el filtro de ruido RGB (Filtros > Nariz > Nariz RGB...) con la siguiente configuración:

ingrese la descripción de la imagen aquí

Aquí está el resultado:

ingrese la descripción de la imagen aquí

Exporté el archivo como JPEG usando la siguiente configuración:

ingrese la descripción de la imagen aquí

El progresivo se ha desactivado, pero el submuestreo aún está configurado en 4:4:4 (que es otro nombre para el submuestreo 1×1). La calidad se incrementa a 98.

Copié la imagen y giré la copia en el sentido de las agujas del reloj; luego copió la versión rotada y giró esa copia en sentido contrario a las agujas del reloj, de modo 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 esta vez 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.

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 usa una rotación sin pérdidas "verdadera", está haciendo un trabajo suficientemente bueno. Sospecho que sé lo que está pasando, y para explicarlo, me desviaré un poco hacia 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. A continuación, cada uno de estos bloques se somete a una transformada de coseno discreta (DCT) . Los coeficientes DCT resultantes describen el bloque como una suma de ondas de diferentes frecuencias. Luego, el algoritmo "descarta" cierta información en las ondas de alta frecuencia que corresponden al ruido y al detalle muy pequeño. El proceso de decodificación invierte la DCT, sumando las ondas almacenadas para recuperar el bloque.

Es posible rotar las "ondas" DCT sin deshacer y rehacer realmente 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 en realidad se decodifica, gira y luego se vuelve a codificar. Durante el proceso de recodificación, dado que el tamaño de nuestra imagen es 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 descarta ninguna información y encuentra exactamente los componentes DCT correctos que tendría una rotación "verdadera" sin pérdidas.

Por último, volveré a examinar los componentes de los archivos JPEG. Los resultados están nuevamente vinculados como esencias . 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? Miré el 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 lo pasaré por alto). La mayoría de los bytes en el segmento Exif están contenidos en dos etiquetas idénticas con 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 qué son estas etiquetas, por qué hay dos y por qué deben tener 2 kB cada una.

    • Los metadatos XMP son en realidad un documento XML incrustado completo con espacio de nombres y UUID largos, que solo contiene la cadena de versión 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 utilizan 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 está usando las mismas tablas de cuantificación o si copia las tablas de la entrada.

  • A diferencia de la prueba anterior, esta vez WPV usa submuestreo 1×1, por lo que en realidad puede estar detectando 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 en 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: ACtabla, de los 119 códigos de 16 bits definidos, solo se utilizan 23. En general, el segmento de escaneo real es un 28,5 % más grande en la versión WPV.

Resumen

  • Es posible que WPV no esté 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:

  • Sistema operativo (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):

    ingrese la descripción de la imagen aquí

  • GIMP (Linux): 2.8.14 (del paquete gimp, versión 2.8.14-1+deb8u1)

    ingrese la descripción de la imagen aquí

  • Window Photo Viewer (según los metadatos de la imagen):

    Microsoft Windows Photo Viewer 10.0.10586.0
    

EDITAR : esta respuesta se publicó antes de que supiera que los archivos habían aumentado de tamaño en alrededor de 9 KiB (9055 bytes para la imagen de 256 × 256, 9612 KiB para la imagen de 512 × 512).

Con toda probabilidad, cuando giró la imagen por primera vez, Windows Picture Viewer hizo una (o ambas) de las siguientes cosas:

  1. Se agregó una etiqueta EXIF ​​que no estaba en la imagen JPEG original (quizás la etiqueta de Orientación);
  2. Información modificada/agregada a una etiqueta que ya existía (quizás etiquetas de Software de procesamiento o Software de imágenes).

Esto aumentó el tamaño del archivo debido a la etiqueta EXIF ​​adicional (y/o datos adicionales a las etiquetas existentes).

Las rotaciones posteriores no aumentaron el tamaño del archivo porque todas las etiquetas y/o datos de etiquetas que WPV habría agregado/modificado ya estaban allí. Solo cambió el valor de la etiqueta de orientación (y quizás también los valores de la etiqueta de fecha/hora).


EDITAR : es casi seguro que esta explicación no puede dar cuenta de aproximadamente 9 KiB de datos adicionales en el archivo. Además, en ausencia de otras razones para el aumento de tamaño, esta explicación esperaría que el aumento de tamaño fuera más o menos constante (módulo algunas diferencias de longitud entre representaciones de cadena de datos numéricos, probablemente unos pocos bytes). Obviamente, eso no es lo que está sucediendo aquí, al menos no la explicación completa.

¿Y una etiqueta EXIF ​​ocupará 9kB? Bueno, al menos esto es fácil de probar: haga que el OP elimine EXIF ​​u otras etiquetas de la imagen girada y vea cómo cambia el tamaño del archivo.
@CarlWitthoft los 9kB son información nueva. Edito para mencionar eso.

Sin ingeniería inversa, el jpeg en/decodificador es imposible decirlo con seguridad. En realidad, hay una serie de estándares jpeg y, contrariamente a la creencia popular, no todos pueden modificarse sin volver a codificarlos.

Es posible que el primer guardado sea una reescritura con pérdidas en su versión jpeg favorita y las rotaciones posteriores sean un simple ajuste de metadatos o una operación directamente en la tabla DCT (lo cual es posible para algunos esquemas de codificación).

El aumento en el tamaño del archivo también puede incluir algunos metadatos adicionales, aunque 9k parece mucho, es posible. El aumento también puede explicarse por la adición de una miniatura que puede no haber estado presente en la salida de GIMP. Es posible que podamos obtener más información de los archivos directamente (antes de WPV y después).

En cualquier caso, tratar de trabajar sin pérdidas con jpeg es realmente una tontería, ya que solo es útil con ciertos tamaños de imagen, no todos los decodificadores y codificadores son idénticos y requiere que esos editores trabajen directamente con el contenido jpeg en el que no puede confiar para ser el caso... El hecho de que lo haga ahora no significa que lo seguirá haciendo en el futuro.

Su mejor apuesta es trabajar con un formato sin pérdidas y evitar el dolor por completo.

No estoy del todo convencido de que la rotación de datos jpeg deba causar una recodificación en primer lugar.
Depende de si eres programador o no... Supongo que no lo eres. Tendría que estar buscando específicamente esa optimización para hacer ese cambio mínimo; de lo contrario, una operación de guardado comenzaría desde el mapa de bits sin comprimir.
De la pregunta vinculada, está claro que Windows Photo Viewer rota los archivos JPEG sin pérdidas.
Pero bajo qué circunstancias... Esa es la parte que no sabemos.
@James No soy un programador de bajo nivel, aunque juego en la televisión :-). El OP proporcionó un enlace a una descripción precisa de cuándo habría una recodificación y cuándo no. Había inferido de esa discusión que solo había estado rotando por $\frac{\pi}{2}$ . Estoy de acuerdo en que la rotación de ángulo arbitrario provoca la recodificación y, en realidad, provocará la pérdida de información a menos que la imagen X-by-Y esté incrustada en una región al menos tan grande como la hipotenusa.
El punto no es lo que es matemáticamente factible. Sin embargo, se trata de lo que realmente hace el código. Lo que ve el OP es que la iteración 1 provoca un cambio en el tamaño del archivo, pero las iteraciones posteriores no. Hay causas para eso y haré una edición en un momento para explicar lo que puede estar sucediendo.
La causa de la rotación sin pérdidas (que es un término pobre; mejor sería reversible ) es cuando las dimensiones de la imagen son múltiplos de 8 o 16, que es la Unidad Mínima Compresible . Si un JPEG no contiene MCU parciales, se puede rotar/voltear sin ningún cambio en los bloques de datos DCT. No hay recodificación en absoluto en ese caso, simplemente cambiando una matriz de índices a esos bloques.
@scottbb: eso solo se aplica a ciertos métodos de codificación dentro de la especificación jpeg. y se apoya en el software buscando esa optimización. Todo lo que sabemos es (a) sí, es posible bajo ciertas circunstancias y (b) que no sabemos exactamente qué está haciendo esta aplicación...
Estamos bastante seguros de que sabemos que WPV gira de forma reversible para imágenes con dimensiones múltiplos de 8/16. Vea el comentario de @Tristan a la respuesta de Matt Grum a la pregunta vinculada en el OP. Tristan trabajó en el equipo de WPV en Microsoft y básicamente lo confirma.
@scottbb: solo para el segundo y posteriores. NO sabemos qué está pasando con el primero y eso es lo que estamos tratando de averiguar aquí.

La rotación de JPEG sin pérdidas solo es posible sin la introducción de artefactos de contorno si las dimensiones de la imagen son múltiplos del tamaño del bloque (normalmente [/siempre?] 8). Consulte la página de manual de jpegtran (lo siento, no tengo un buen enlace canónico para él; si lo encuentra, siéntase libre de editarlo) para obtener detalles sobre lo que implica:

La transformación de transposición no tiene restricciones con respecto a las
dimensiones de la imagen. Las otras transformaciones funcionan de manera bastante extraña si las dimensiones de la imagen no son un múltiplo del tamaño de la iMCU (generalmente 8 o 16 píxeles), porque solo pueden transformar bloques completos de datos de coeficiente DCT de la manera deseada.

El comportamiento predeterminado de jpegtran al transformar una imagen de tamaño extraño
está diseñado para preservar la reversibilidad exacta y la
consistencia matemática del conjunto de transformación. Como se indicó, la transposición
puede voltear toda el área de la imagen. La duplicación horizontal deja intacta cualquier columna iMCU parcial en el borde derecho, pero puede voltear todas las filas de la imagen. De manera similar, la duplicación vertical deja intacta cualquier fila parcial de iMCU en el borde inferior, pero puede voltear todas las columnas. Las otras transformaciones se pueden construir como secuencias de operaciones de transposición y volteo; para mantener la coherencia, sus acciones en los píxeles de borde se definen como el mismo resultado final de la correspondiente secuencia de transposición y giro.

Para un uso práctico, es posible que prefiera descartar cualquier
píxel de borde no transformable en lugar de tener una tira de aspecto extraño a lo largo de los
bordes derecho y/o inferior de una imagen transformada. Para hacer esto, agregue el interruptor -trim:

Sospecho que Windows Photo Viewer está evitando este problema al realizar una descompresión y una recompresión de alta calidad extrema para simular un comportamiento sin pérdidas cuando las dimensiones de la imagen no son múltiplos de 8, en lugar de realizar una rotación sin pérdidas. Una buena utilidad simplemente haría sin pérdidas, artefactos y todo, o dejaría caer algunos píxeles, en lugar de arruinar la calidad de toda la imagen (y aumentar el tamaño del archivo).

irrelevante para una imagen de 256x256.
Leí mal y pensé que el problema era para la versión 257x257.

No tengo una respuesta definitiva, pero algunas posibles teorías de por qué sucedió eso. Algunos tipos de archivos funcionan de tal manera que dos códigos diferentes para una imagen de ese tipo de archivo no necesariamente producen imágenes diferentes. Por ejemplo, el tipo de archivo PNG funciona de esa manera porque permite un fondo transparente, pero una imagen con un fondo transparente y otra que es igual excepto que el mismo fondo es blanco aparecen exactamente de la misma manera. Se dice que un archivo de imagen está comprimido si ocupa menos de 3 bytes de memoria por píxel. Creo que, a excepción de los que tienen un fondo transparente, no hay dos archivos PNG que generen exactamente la misma imagen. Cada vez que guarda una imagen como PNG, la convierte en un código que genera la imagen original y, a excepción de imágenes muy inusuales como una en la que cada píxel es un color aleatorio de los 2^24 colores, el código ocupará menos memoria que 3 bytes por píxel, por lo que se dice que guardar como PNG es una compresión sin pérdidas. Por otro lado, para ahorrar memoria, solo ciertas imágenes pueden ser generadas por el código de un archivo de imagen JPEG. Probablemente haya más de un tipo de archivo JPEG y no sé si alguno de ellos tiene la propiedad de que dos imágenes diferentes de ese tipo de archivo puedan generar exactamente la misma imagen. Supongo que un montón de veces simplemente rotaste una imagen y luego la guardaste como JPEG y darás una explicación de lo que sucedió bajo el supuesto de que eso es lo que hiciste, lo cual no sé si es cierto. Una rotación que hizo no tiene pérdidas si hay una manera de recuperar exactamente el mismo código de archivo de imagen que tenía antes de rotarlo y guardarlo. Puede que no estés en lo cierto en cuanto a que realmente hiciste una rotación sin pérdidas. Si realmente no tuviera pérdidas,

Las razones detrás de esto son algunas

la forma en que se codifican y comprimen las imágenes cambiará el tamaño simplemente debido al algoritmo de compresión. puede probar esto guardándolo como un mapa de bits y luego girándolo. En ese formato o en cualquier formato sin procesar, el tamaño debe permanecer igual. Si no es así, el programa que guarda la imagen está agregando nuevos datos, posiblemente algunos metadatos o algo así.

Pero, ¿por qué rotas un jpeg 20 veces?

Si lee el enlace en la pregunta original, al menos para Windows Picture Viewer , si las dimensiones de un JPEG son un múltiplo de 8, entonces las rotaciones de JPEGS en WPV son transformaciones sin pérdidas. Una forma sencilla de probarlo es rotar 4 veces (lo que da como resultado la misma orientación que el original) y realizar una simple sustracción de imagen píxel por píxel.
@scottbb Esto no es necesariamente solo un problema con el visor de imágenes de Windows. Cualquier cosa que gire un formato con pérdida tiene que volver a calcular la compresión. rotar una imagen en múltiplos de 8 significa que todo cabe en palabras de 8 bits y es posible que no se comprima de una manera que agregue artefactos. Esto se basa en cómo funciona el algoritmo y se implementa en el programa utilizado.

Por cómo funciona la compresión de imágenes . Cualquier formato como PNG o JPG en general no conserva el tamaño del archivo después de la rotación.

Para el compresor, la imagen rotada es solo una imagen diferente, debido a cómo funciona la heurística de compresión, no hay garantía de que comprima una imagen rotada de la misma manera .

Por supuesto, si la compresión es sin pérdidas, si gira la imagen 4 veces la cuarta vez, la imagen vuelve a ser la misma (girada hasta que se inclina como original): en ese caso, debería volver a tener el mismo tamaño comprimido, si no, entonces es por una de las siguientes razones :

  • Metadatos agregados : el programa agregó una parte del texto por alguna razón
  • Compresor cambiado: el programa puede optar por volver a guardar la imagen como el original si no hay cambios, pero si aplica algún cambio (incluso 4 rotaciones de 90 grados) puede decidir volver a comprimir la imagen usando su propio compresor (el programa ya no sabe que sigue siendo la misma imagen).
  • En general, el mismo compresor (libPNG o libJPG) produce resultados muy diferentes en diferentes implementaciones, diferentes versiones de la misma biblioteca y con diferentes parámetros de compresión (también el sistema operativo y el compilador marcan la diferencia aquí a veces).

La compresión de imágenes funciona comprimiendo imágenes en trozos de 4x4 u otros tamaños. En general, un compresor ve una imagen rotada como una imagen diferente, sin embargo, dado que un fragmento de píxel comprimido es solo una descomposición lineal, si los fragmentos de la imagen son los mismos, es posible transponer/duplicar las matrices de descomposición lineal de manera efectiva manteniendo lo mismo. calidad:

Tenga en cuenta que esto debe implementarse por función , y eso también explica el aumento inicial de tamaño => en la primera rotación, solo intenta comprimir la imagen en fragmentos que son rotables:

  • Si no lo hace: la calidad de la imagen se degrada
  • Si tiene éxito, aumenta el tamaño solo una vez, luego cada rotación mantiene la misma calidad.

  • Esa operación es exitosa solo si la imagen está hecha por partes iguales. (el tamaño de la imagen es múltiplo del tamaño del trozo).

La respuesta de scottbb es incorrecta y puedes hacer una prueba simple:

  • Abra la imagen original: Captura de pantalla
  • Girar la imagen 4 veces con WPV: captura de pantalla
  • Compara las 2 capturas de pantalla

Verá que la imagen ha cambiado (se vuelve a comprimir en la primera rotación). Sin embargo, ese cambio está limitado en el tiempo, ahora puede girarlo nuevamente sin pérdida de calidad (si la imagen tiene un tamaño que es un múltiplo de 8)

Para responder directamente OP:

Sé que está girando sin pérdidas

No, no está girando sin pérdidas, pierde calidad al menos una vez (en la primera rotación: porque primero debe comprimirse de manera que pueda girar), luego mantiene su calidad.

La pregunta es sobre la rotación sin pérdidas, por lo que se evita la recompresión.
Programo un editor gráfico para saber lo que digo, cuando se guarda el archivo => se comprime. Al menos lo que se agrega al archivo es información de "rotación".
Sé lo que digo e incluso implementé un compresor de imágenes. Es posible si implementa eso solo para la rotación (lo que significa que sabe que la rotación es el único cambio en la imagen), en general, esto no es posible. Parece que los desarrolladores del editor de fotos de Windows hicieron ese truco
OP preguntó no sobre el caso general, sino exactamente sobre esa pieza de software específica y ese caso específico que lo hace. Su respuesta no es incorrecta, solo responde una pregunta diferente a la que preguntó OP.
No responde. Leelo de nuevo. Lo edité hace un tiempo.
Las primeras 3 oraciones siguen siendo una pregunta diferente: "cómo funciona la compresión de imágenes": no hay compresión en la rotación sin pérdidas. "Al compresor la imagen rotada" - nuevamente, el compresor no se invoca. "si la compresión no tiene pérdidas": la compresión tiene pérdidas. La rotación es sin pérdidas. Ahora, esto es lo lejos que estoy dispuesto a llevar este argumento. Puedo ver tu punto, estoy de acuerdo con él, pero está completamente fuera de lugar aquí. Por cierto, yo también soy programador e hice mi parte de lectura y escritura de archivos sin formato.
Parece que te lo tomas demasiado personal. NO ES UNA ROTACIÓN SIN PÉRDIDAS: simplemente lea el pequeño experimento y hágalo usted mismo. Básicamente muestra que tu último comentario está mal. Uu Puede que también seas programador, pero no creo que hayas codificado nunca un compresor de imágenes (incluso uno más simple)
Lo siento entonces, ¿qué experimento puedo hacer para demostrarlo? Porque se realizó un experimento en la pregunta vinculada. ¿Estoy interpretando mal los resultados?
Creé una imagen en Paint, la giré 4 veces y es idéntica, pero el tamaño saltó de 1,6 a 8,1 KB. La diferencia binaria muestra que los datos de la imagen no se tocaron, es solo una gran parte de los metadatos en las <?xpacketetiquetas.
Pintar la imagen no es un buen candidato uu Acabo de hacer el experimento con una foto real. ¿Utilizaste una imagen diferente? Lo siento, pero ¿qué versión de Windows tienes?
Tomé una captura de pantalla, la pegué en pintura y la recorté a 128x128. Parece que se repite la misma parte de los datos centrales, pero la versión rotada tiene una gran parte casi vacía <?xpacketagregada. No tengo una diferencia binaria adecuada aquí, así que no puedo decirlo. Después subí ambos a verexif.com y volvieron idénticos entre sí pero no al original. Pero como dije, los comparo a mano i hexeditor, así que probablemente me perdí mucho. Windows 8.1
Si las dimensiones de un JPEG son divisibles por 8 (o 16 con submuestreo), se puede rotar en incrementos de 90 grados sin pérdida . La clave es no decodificarlo hasta RGB, sino trabajar directamente con los coeficientes DCT. Es una función especializada que a menudo no se incluye en un editor de imágenes general. Consulte, por ejemplo , en.wikipedia.org/wiki/Libjpeg#jpegtran . Si realizó su experimento con Windows Photo Viewer como se especifica en la pregunta, verá que, de hecho, no tiene pérdidas.