Jpeg losseless rotation isn't lossless

*** Please report new bugs here! ***

Moderators: helmut, XnTriq, xnview, Dreamer

Post Reply
Plotino
Posts: 19
Joined: Mon Oct 10, 2011 11:16 am

Jpeg losseless rotation isn't lossless

Post by Plotino »

Hi, Greetings to all forum members

I lossless rotate left and than right a picture and I checked md5 of the file before and after lossless rotation.
I expected that the md5 was identical, but it's changed.
Is this a bug?
bitz4
Posts: 37
Joined: Sun Apr 18, 2010 5:03 am

Re: Jpeg losseless rotation isn't lossless

Post by bitz4 »

Actually it's not how file signatures work. MD5/SHA's etc are made up from exact bits... in this case, if you perform a lossless rotation, it'll have to modify something (see below what) so the bits will change.

As to the inner working of JPEG... when it's rotated, there are multiple scenarios on this. If the JPEG matrix has an odd number of entries, it will cut some to make the rotation possible, but negligible, actually not even visible to people. If not, then the tiles that make up the image get rearranged.

When initially compressed this matrix gets close-to-the-original values, making JPEG lossy. When edited it gets computed and recompressed, there by making it lossy again over the already lossy values. But since the intended action is meant only to rearrange bits of information, it performs linear algebra on the matrices making up the image (highschool math, in place matrix transposition it's called). This way, the close-to-the-original values never get recompressed, just moved around. This is called lossless transformations... and it works as it should be, not bugs here.
MP 0.90 x64, Win 7 64-bit
Plotino
Posts: 19
Joined: Mon Oct 10, 2011 11:16 am

Re: Jpeg losseless rotation isn't lossless

Post by Plotino »

Hi bitz4,

I don't understand very well your explanation, english isn't my language. If you can, please, be more easy.
However with other programs md5 is not changed in jpeg losssless rotation
bitz4
Posts: 37
Joined: Sun Apr 18, 2010 5:03 am

Re: Jpeg losseless rotation isn't lossless

Post by bitz4 »

I should have though so... alright, lossless doesn't mean the actual file doesn't change. Lossless means the information inside the image doesn't change, that is gets decompressed from already lossy source, transformed, and applied a lossy compression again.

Test it... rotate an image losslessly several times, then to a copy of that image rotate it and save it each time, the same number of times. Compare and the result should tell you how decompression-transform-recompression would affect the image opposed to lossless rotation.

Also, something in the file would have to change for the image to remain rotated, thus the MD5 will change. Or better yet, what programs did you try which gave the same MD5 after rotation?
MP 0.90 x64, Win 7 64-bit
Plotino
Posts: 19
Joined: Mon Oct 10, 2011 11:16 am

Re: Jpeg losseless rotation isn't lossless

Post by Plotino »

The programs are Jpegview and Zoner Photo Studio 15
Md5 is the same after 2 rotations: a left and a right rotation of the same picture
User avatar
oops66
XnThusiast
Posts: 2005
Joined: Tue Jul 17, 2007 1:17 am
Location: France

Re: Jpeg losseless rotation isn't lossless

Post by oops66 »

Hello,
... Probably the soft counts the number of rotations/degrés (one left and one right = +90° -90° =0° so no change) probably if you do 4 times a left rotation (or 4 right rotations) a multiple of 360°=0° too ...then "Save" ... so same md5 too ???
... XnViewMP should do this too...
XnViewMP Linux X64 - Debian - X64
User avatar
XnTriq
Moderator & Librarian
Posts: 6512
Joined: Sun Sep 25, 2005 3:00 am
Location: Ref Desk

Re: Jpeg losseless rotation isn't lossless

Post by XnTriq »

I rotated FujiFilm FinePixS1Pro (1).jpg 4 consecutive times with XnView v2.03 (cmd_JPEGRotation90 = lossless 90° right).
  • Dimensions: 600×400 pixels
  • MCU: 16×16 pixels
  • Embedded thumbnail: 128×85 pixels
  • Metadata: Exif + IPTC + XMP + GPS
  • ICC profile: sRGB IEC61966-2.1
The dimensions of the resulting image are 592×400 pixels. The missing 8 pixels were cut off during the second rotation.

In cases like this (MCU = 16²), XnView's message is misleading:
JPEG lossless operation will modify original file(s), and may remove some unused pixels (width and height must be multiple of 8 pixels)!
FYI: The MCU size was determined with the help of JPEGsnoop and Stuffware Photo Studio.

User avatar
oops66
XnThusiast
Posts: 2005
Joined: Tue Jul 17, 2007 1:17 am
Location: France

Re: Jpeg losseless rotation isn't lossless

Post by oops66 »

XnTriq wrote:... In cases like this (MCU = 16²), XnView's message is misleading:
JPEG lossless operation will modify original file(s), and may remove some unused pixels (width and height must be multiple of 8 pixels)!
... Hello Xntriq ... Right, ... even if width and height (600x400) are multiples of 8 pixels ... the resulting for this image is: 592×400 pixels.
XnViewMP Linux X64 - Debian - X64
User avatar
XnTriq
Moderator & Librarian
Posts: 6512
Joined: Sun Sep 25, 2005 3:00 am
Location: Ref Desk

Re: Jpeg losseless rotation isn't lossless

Post by XnTriq »

oops66 wrote:... Hello Xntriq ... Right, ... even if width and height (600x400) are multiples of 8 pixels ... the resulting for this image is: 592×400 pixels.
Thanks for checking/confirming, JPEGsnoops66 ;-)

When I perform 4×90° lossless rotations on bananas_new.jpg (640×480 = 16*40×16*30 pixels), the warning message doesn't show up and the image isn't clipped.
However, the filesize of the resulting JPEG is smaller than that of the original. Metadata and color profile are left intact. Perhaps XnView optimizes the Huffman coding in the process?

<!--// Edit #1 //
  • According to JPEGsnoop, the lenght of the DQT (Define Quantization Table) and DHT (Define Huffman Table) markers has been decreased :mrgreen:
// Edit #1 //-->

<!--// Edit #2 //
  • Dick Sites ([url=http://www.dpreview.com/forums/post/4164488]Re: Rotating - lossless description[/url]) wrote:Don't confuse a change in file size with a change in your pixels. I assume you are talking about JPEGs here. A number of programs, including Photoshop Album, do lossless JPEG rotate.

    Oversimplifying slightly, JPEG compression has two important steps -- a quantized cosine transform (DCT) that is lossy, and a Huffman encoding of the resulting frequency coefficients, which is lossless.

    A lossy JPEG rotate does this, where the deDCT and DCT steps are (slightly) lossy:
    deHuffman -> deDCT -> rotate pixels -> DCT -> Huffman

    A lossless JPEG rotate does this:
    deHuffman -> rotate coefficients -> Huffman

    Since the coefficients being re-Huffman encoded are in a different order than the originals, there will be slight variations in the size of the the resulting Huffman bit stream, and hence in the file size.

    What you should see is that if you rotate 4 times in the same direction, the resulting image is pixel-for-pixel identical to the original.

    Note that lossless JPEG rotate can in general only be applied if your image dimensions are multiples of 8 or 16 (depending on color downsampling). Images out of digital cameras are almost always multiples of 16. Rotate before you crop. dick
    Lossless JPEG rotation only lossless at 360 degrees?
// Edit #2 //-->
bitz4
Posts: 37
Joined: Sun Apr 18, 2010 5:03 am

Re: Jpeg losseless rotation isn't lossless

Post by bitz4 »

Plotino wrote:The programs are Jpegview and Zoner Photo Studio 15
Md5 is the same after 2 rotations: a left and a right rotation of the same picture
Just did a quick test with Jpegview and then with MP.
Took one image, rotated it with MP at first to normalize then in both apps for the reults.
90+ then 90- back to its original state and got this:

Jpegview
Original = 18E443B4B180BCF48190D8307CF81A87 as left by MP after normalization
Rot 90+ = 202F4F19BDB06AE78426545977E3AD65
Rot 90- = 468CF47324E20A59394FD223BD967160
Rot 90+ = 202F4F19BDB06AE78426545977E3AD65 2nd time
Rot 90- = 468CF47324E20A59394FD223BD967160 2nd time

XnView MP
Original = 468CF47324E20A59394FD223BD967160 as left by Jpegview previously
Rot 90+ = 4F3DA5CFE48E4294BCE09613A82E67B7
Rot 90- = 18E443B4B180BCF48190D8307CF81A87 2nd time as Original
Rot 90+ = 4F3DA5CFE48E4294BCE09613A82E67B7 2nd time same as does Jpegview
Rot 90- = 18E443B4B180BCF48190D8307CF81A87 3rd time as Original

Like the other commenters posted above, the jpeg FILE is not composed of just the image data and nothing else... so if you rotate an image something else could be changed internally as the result of an optimization. But this is only the first time, when the image is tagged, exifed and build using who knows what library developed out of the the original jpeg specifications. The pic I used at first was PHP GD'ed... then I've prepared it for the test with MP.

As you've seen, once normalized, both apps pushed the same behaviour, after returning the image to its original position the hashes matched.
MP 0.90 x64, Win 7 64-bit
User avatar
oops66
XnThusiast
Posts: 2005
Joined: Tue Jul 17, 2007 1:17 am
Location: France

Re: Jpeg losseless rotation isn't lossless

Post by oops66 »

XnTriq wrote:...Thanks for checking/confirming, JPEGsnoops66 ;-) ...
...You're welcome ;-)
bitz4 wrote:...As you've seen, once normalized, both apps pushed the same behaviour, after returning the image to its original position the hashes matched.
Interesting .
Last edited by oops66 on Tue Jul 09, 2013 9:01 pm, edited 1 time in total.
XnViewMP Linux X64 - Debian - X64
User avatar
XnTriq
Moderator & Librarian
Posts: 6512
Joined: Sun Sep 25, 2005 3:00 am
Location: Ref Desk

Re: Jpeg losseless rotation isn't lossless

Post by XnTriq »

bitz4 wrote:As you've seen, once normalized, both apps pushed the same behaviour, after returning the image to its original position the hashes matched.
Good job, bitz4! Hopefully we can sort out these continued uncertainties regarding lossless transformations once and for all.

Stripping the samples for these kinds of experiments and tests of all extras via Tools » Metadata » Clean... might be helpful too in some cases.

BTW: It seems that JPEGView uses the same library as XnViewMP.
xnview ([url=http://newsgroup.xnview.com/viewtopic.php?p=89618#p89618]libjpeg-turbo[/url]) wrote:
xnview wrote:
jgutierrez wrote:I see both XnView and XnView MP use LibFormat 5.76, does this means that libjpeg-turbo is used in both?
No, only XnViewMP
johnnyboy
Posts: 5
Joined: Sun Oct 15, 2023 8:33 am

Re: Jpeg losseless rotation isn't lossless

Post by johnnyboy »

Hello, I'm really confused about this issue unfortunately.

I have an image 2592x1944 pixels. Both width and height are multiples of 8, right?

Yet if I try to "lossless rotate" it, I get the message that it will cut pixels.

However if I do a lossless rotate on a picture before this (in the same batch of photos, so it's taken by the same camera) and that image is 960x720, I don't get that message and it rotates immediately.

What's going on?
User avatar
XnTriq
Moderator & Librarian
Posts: 6512
Joined: Sun Sep 25, 2005 3:00 am
Location: Ref Desk

Re: Jpeg losseless rotation isn't lossless

Post by XnTriq »

Hi johnnyboy

It seems as if your 2592×1944 image has an MCU block size of 16×16 or 16×8 or 8×16.
Because 1944 isn't a multiple of 16, some pixels are truncated during “lossless” rotation.
XnTriq wrote: Sun Jul 07, 2013 10:45 amIn cases like this (MCU = 16²), XnView's message is misleading:
JPEG lossless operation will modify original file(s), and may remove some unused pixels (width and height must be multiple of 8 pixels)!
XnTriq wrote: Tue Oct 12, 2021 3:00 amChroma sub-sampling of seamless-colorful-floral-pattern-seamless-background-vector-1815061.jpg is 2x2,1x1,1x1, which means that the MCU size is 16×16 pixels. Because its dimensions (1000×1000 pixels) are not a multiple of 16, partial MCUs (i.e. non-transformable edge blocks) are discarded/trimmed/dropped by XnView when a lossless flip/mirror or rotate operation/transformation is executed (62×16=992):
https://web.archive.org/web/20211015232241/https://www.impulseadventure.com/photo/jpeg-minimum-coded-unit.html wrote:Every JPEG image is actually stored as a series of compressed image tiles that are usually only 8x8 pixels in size. The proper name for one of these tiles is the MCU or Minimum Coded Unit. When one refers to image blocking artifacts, they are really talking about visual discontinuities observed between one or more of these tiles. You can see the edges or boundaries of these tiles in JPEG images that have been compressed at a very low quality.

[…]

The Minimum Coded Unit size for JPEG images is usually 8x8, 16x8 or 16x16 pixels in size. The variations here (more specifically 16x8 and 16x16) are due to an optimization called chroma subsampling.

For JPEG compression and decompression algorithms to work, an image must be represented by an integer number of complete MCUs. In other words, the X and Y dimensions typically need to be a multiple of 8 pixels. Therefore, an image that is sized 501 x 375 must be first changed into an image sized 504 x 376 before it can be compressed. In this example, 501 = 62 horizontal MCUs + 3 extra pixels and 375 is 46 vertical MCUs + 1 extra pixel.

[…]

In the case where there are not enough pixels in a row or column to complete a full tile, a partial MCU is used. A partial MCU is automatically extended to be the size of a full MCU but then the overall image dimensions are used to indicate where to cut off the extra later. This extension is generally done by repeating the last pixel of the row or column as necessary.
Post Reply