JPEGhack
Once upon a time, I was thinking about lossless jpeg editing. The sort that jpegtran can do.
jpegtran (1) - lossless transformation of JPEG files
Specifically, jpegtran can (within limits) rotate/flip/mirror losslessly, and also crop - for values of "lossless" that only apply to the cropped image data.
And I wondered if the reverse could be true. If jpeg image data can be cropped losslessly, then it cannot rely on surrounding data. Thus surely paste is equally possible.
I researched, and found... http://www.imagemagick.org/Usage/formats/#jpg_lossless. Scroll down to the 'Mixed JPEG Quality' section where it's suggested
* use jpegtran to merge the q60 on top of the q100
So, jpegtran can do that, huh?
nope.
But an experimental version can. http://jpegclub.org/jpegtran/
That reads to me that the 'drop' option has been experimental since 2000 at least... but, let's take a look. There are helpful binaries and a sample script provided, but I had something a bit more fun in mind.
One download later, and some fiddling around... and here is this!
Counting from the bottom where it's most evident, the rows of 80 pixels high each are of quality 1, 4, 5, 6, 7, 8, 9, 10, 15, 20, 50, and hte final 144 pixels at the top are original (ie, camera sourced jpeg with text composited in and saved at quality 100).
The resulting image is 153k in size. A direct conversion of the source (captioned) image to a constant quality at quality of 72 results in an image of equivalent size.
We can also see that the q100 stripe, being 14% of the pixels, is over 60% of the final image size! (percentage can be fuzzy since the total of the cropped stripes is 148KiB, but the final image is 156KiB
$ du -c --apparent-size --block-size=1 *crop*jpg | sort -g 3158 q1crop.jpg 3238 q10crop.jpg 3292 q9crop.jpg 3478 q6crop.jpg 3509 q4crop.jpg 3553 q5crop.jpg 4011 q7crop.jpg 4120 q8crop.jpg 6245 q15crop.jpg 6552 q20crop.jpg 8155 q50crop.jpg 98768 q100crop.jpg 148079 total $ ls -rot kwalitee.JPG -rw-r--r-- 1 nemo 156137 Jun 27 00:43 kwalitee.JPG
The simple script I wrote to create this final image is available in the discussion tab.
Another example image, in which I discovered that you cannot drop a colour segment onto a greyscale image (but you CAN drop a greyscale segment onto a colour image, and then subsequently drop a colour segment within the greyscale! :)
Additional notes
In creating this, I found a few things had to be kept in mind...
- Make sure the crops and drops are aligned on the jpeg iMCU boundaries, or headaches ensue since the crop size will be silently altered in position (as, I think, is the drop). I made all my changes on the boundary of 16x16 blocks, though 8x8 is also possible (depends on the jpeg)
- The caption text is a light grey - I found that pure white would cause jpeg errors when dropping (DCT coefficient out of range). I don't know if this is a bug, or just a limitation in what's possible due to jpeg encoding.
- dropping colour jpeg onto a greyscale jpeg result in greyscale. Specifically:
- crop 'cropped.jpg' from colour source.jpg
- create greyscale.jpg from source.jpg
- drop 'cropped.jpg' back onto the original location within greyscale.jpg to create merged.jpg
- merged.jpg and greyscale.jpg are binary identical!
- note: tested just once :)
- I blogged notes about this here
- http://blog.thorx.net/2011/07/multi-quality-jpeg-hack/