30
\$\begingroup\$

I have a photo in JPEG format with resolution 4680x3120. I want to add a white border around this photo, turning it into a 5200x3467 photo (for printing reasons).

Clearly, I am not altering or removing anything from the photo, I am simply adding something. Therefore, in principle this procedure can be lossless. However, if I were to use Paint to add this border, the Saving process of Paint will compress the photo again into the JPEG format, thereby losing information and quality.

Is there a way (some more professional program) to add something to a JPEG photo, like a border, without affecting the original part of the photo, without reducing its quality?

\$\endgroup\$

8 Answers 8

37
\$\begingroup\$

Although Philip's answer is the best way to go, it is possible to do what you want entirely within the sphere of JPEG.

JPEG works by breaking your image up into blocks called Minimum Coding Units (MCUs), typically 16×16 each, and compressing them separately. You can see this in images when you crank the compression level up very high. At more reasonable compression levels, the blocks blend together so smoothly that you never see the borders.

We can take advantage of this fact to losslessly add a simple white border to an image. We simply have to create a hollow array of white blocks equal to the output image size, then drop the original JPEG MCU blocks into the middle.¹

There is a downside to that technique: it only works when the input and output image sizes are both an even multiple of the MCU size. When that is not the case, we need to recompress some of the blocks at the margin between the white border and the original image's edges. You won't see this difference in the output if you stay away from the excessively high JPEG compression levels, so it's still effectively lossless.

I am not aware of any program that does only this. The closest thing I'm aware of is something that does the inverse operation: jpegtran has a crop function that losslessly cuts away parts of the image edges.² It does so by discarding the cropped-away MCUs along the image edges, leaving those in the middle untouched.

The simplest ready-made solution I'm aware of is the Better JPEG Lossless Resave plugin for Photoshop. It uses techniques based on the ideas given above to copy MCUs from the original image wherever it can, in order to avoid re-creating them from the uncompressed version, as Photoshop normally does.³


Digressions:

  1. You might think that the resulting border will be not quite white, since the lossiness of JPEG will create some kind of color difference in the output. I did some testing, and in Photoshop at least, a purely white image saved via Save For Web's JPEG level 10 (i.e. "low" quality) results in a decoded image that is still purely white.

    I determined this with two tests:

    First, I loaded the JPEG as a layer on top of the original, set the top layer's blend mode to Difference, then added a Levels adjustment layer above it to try and magnify the differences. The resulting image stayed black, indicating "no difference."

    Second, when I failed to see the expected differences, I dropped the adjustment layer and returned the JPEG layer to Normal blend mode, picked up the eyedropper tool, and looked all over the image for a pixel that didn't show as RGB (255,255,255) in the Info panel. I never found one. I expected to see the numbers flicker a little bit as I scrubbed over the image, but they stayed rock-steady.

    I can only conclude that this is a degenerate case of the encoding algorithm: pure white blocks stay white through the discrete cosine transform.

    Interestingly, this does not happen with pure black blocks. At least with Photoshop's implementation, they turn into RGB (1,1,1) when decoded, not RGB (0,0,0).

    Bottom line, you don't need to worry about sputtered dots in this border area when printing an image produced using the above technique.

  2. jpegtran is a command line program, but there is also a GUI Windows program based on the same code called jpegcrop.

  3. Alas, this plugin is Windows-only.

\$\endgroup\$
8
  • 1
    \$\begingroup\$ I've used a program called JPEG Wizard which provided such functionality. It also had a very nice ability to apply different compression ratios to different parts of a JPEG. One might thus use a high quality setting for a person's head and hands, medium quality for their clothing, and lower quality for the background, and thus end up with a smaller file but better overall quality than if one had used medium quality for everything. \$\endgroup\$
    – supercat
    Commented Mar 16, 2015 at 16:41
  • 1
    \$\begingroup\$ I didn't get a chance to try it, but this blog post suggests that jpegtran's crop function can actually also be used to extend. (Not sure what color the extended borders end up being, though.) \$\endgroup\$
    – mattdm
    Commented Mar 16, 2015 at 16:42
  • 4
    \$\begingroup\$ @mattdm: Yes, jpegtran can also extend the image, but it always pads with a hard-coded middle gray, RGB(128,128,128). It does that simply because it's the only easy option, since in DCT coefficient space, you can do it with a simple bzero() call. I tried a wild hack at changing this, which doesn't work, but should give you a sense of the ugliness involved. throws hands up in frustration \$\endgroup\$ Commented Mar 16, 2015 at 17:43
  • \$\begingroup\$ @WarrenYoung: To change the color of the padding blocks, you'd presumably need to change just the first (DC) coefficient, and leave the others at zero. Of course, the coefficients are compressed, so... anyway, it should be doable, but I agree that it's not as trivial as it might seem. \$\endgroup\$ Commented Mar 16, 2015 at 19:19
  • 2
    \$\begingroup\$ As to your last point — the largest amount of savings comes from throwing away high-frequency information. The gain from throwing away precision on the color of a solid block of pixels couldn't be more than a byte or two, so it's never or almost never done. If there's any information loss it's in the YUV<->RGB colorspace conversion. \$\endgroup\$
    – hobbs
    Commented Mar 17, 2015 at 3:29
22
\$\begingroup\$

The point to remember here is that you lose quality when saving the photo into a lossy compression format. So long as you save the photo in a lossless format (PSD, TIFF, etc) after adding the border, you won't lose any more data than you've already lost by saving the photo as a JPEG in the first place.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Thanks. And this is true even when using a 'crappy' programme like Paint, when saving it into e.g. TIFF? \$\endgroup\$
    – LBogaardt
    Commented Mar 16, 2015 at 14:21
  • 4
    \$\begingroup\$ At least according to my quick test, Paint uses the lossless LZW compression algorithm when saving TIFFs so it looks OK. \$\endgroup\$
    – Philip Kendall
    Commented Mar 16, 2015 at 14:29
  • 6
    \$\begingroup\$ Keep in mind that this is likely to significantly increase the size of the image... \$\endgroup\$ Commented Mar 16, 2015 at 19:29
  • 2
    \$\begingroup\$ paint also supports PNG, which is also a lossless format \$\endgroup\$
    – phuclv
    Commented Mar 17, 2015 at 8:16
  • \$\begingroup\$ +1 for this as the answers which discuss saving back to jpeg are not compatible with all jpeg encoding options. \$\endgroup\$ Commented Mar 17, 2015 at 13:36
6
\$\begingroup\$

It's not quite lossless, but you can get pretty close using GIMP (or some other editor with a similar feature) and the following two tricks:

  1. First, make sure that the border you're adding is a multiple of 8 pixels wide (and preferably a multiple of 16 pixels).

    This is important because the JPEG compression algorithm breaks the image into 8×8 pixel blocks*, starting from the top left corner, and applies the lossy compression algorithm independently to each block. Thus, at least in principle, you can losslessly pad a JPEG image by adding full 8×8 pixel blocks around the existing ones. If, however, you tried to add a border that was not a whole number of blocks wide, the blocks in the padded image would not line up with those in the original, and some compression loss would be inevitable.

    *) Actually, most JPEG images use chroma subsampling, which means that only the grayscale part of the image is actually compressed in 8×8 blocks, whereas the chroma channels are scaled down by 50% before compression, making their effective block size 16×16 pixels. Thus, for best results, your border width should really be a multiple of 16 pixels. However, you can usually get away with a 8 (or 24 or 40 etc.) pixel border, since a bit of compression loss in the chroma is not very noticeable.

  2. The second part of the trick is, when saving the final image, to select the "Use quality settings from original image" checkbox in the Export Image as JPEG dialog (under Advanced settings). Do this even if it seems like it would result in a lower quality than you'd normally use!

    This setting makes GIMP reuse the exact same compression settings as were used for the original image, which usually eliminates around 99% of the compression losses, provided that you haven't edited the image too heavily, and in particular, that the blocks in the new image still line up with those in the original. (There will occasionally still be some losses due to roundoff errors, but much less than there would be otherwise.)


As a quick demonstration, I took this JPEG test image from Wikimedia Commons, originally saved with a fairly low quality setting of 50, and added a fancy (sort of) 8px black-and-white border to it using the method described above:

Test image with 8px border, mostly lossless

Here's the difference between the original (15.1 kB) and the edited image (16.7 kB), shown using GIMP's "Grain extract" layer mode:

Difference between padded image and original

You can see some very slight chroma errors, caused by the border width not being a multiple of 16, and (if you look closely) a few blocks where there were also minor losses in the luma channel due to roundoff. Still, visually, the original and the padded image are all but indistinguishable, even at 2x magnification and flipping alternately between them.

In particular, contrast this with the result of bumping the JPEG quality up from 50 to 60 before saving the padded image, which yields the following 17.6 kB image:

Test image with 8px border, quality raised from 50 to 60

At high magnification, you can definitely see that the edited image is noticeably blurrier in some places than the original, and taking the difference with Grain extract confirms this:

Difference between padded image (at q60) and original

\$\endgroup\$
17
  • \$\begingroup\$ "selecting this checkbox does not seem to affect the "Progressive" setting." Not a bug, as progressive encoding is an encoding setting, not a quality setting. Jpegtran can convert images to and from progressive losslessly. \$\endgroup\$ Commented Mar 17, 2015 at 17:51
  • \$\begingroup\$ @tepples: You're right; I've removed that paragraph. For some reason, I was under the impression that toggling progressive mode would cause the quality settings not to match, but a quick test seems to confirm that I was wrong about that. \$\endgroup\$ Commented Mar 17, 2015 at 20:05
  • 1
    \$\begingroup\$ @thomasrutter: I can't downvote a comment, so I'll just point you to the original forum post describing the feature, and in particular, this quote: "If you have only made a few changes to the image, then re-using the same quantization tables will give you almost the same quality and file size are the original image. This will minimize the losses caused by the quantization step, compared to what would happen if you used different quantization tables." \$\endgroup\$ Commented Mar 19, 2015 at 1:10
  • 1
    \$\begingroup\$ Just for comparison, here's another example in an answer to a different question. My understanding in theory agrees with Ilmari but at least in my example the practice seems to be much more with what Thomas says — at least when starting with a highly-degraded image. (I think the gravestone makes a poor example for this purpose, because the loss of detail on the stone are less obvious than they are on human skin.) \$\endgroup\$
    – mattdm
    Commented Mar 19, 2015 at 15:09
  • 1
    \$\begingroup\$ @mattdm: It seems to be quite software-dependent; I tried reproducing your results from that answer in GIMP, and it seems GIMP (v2.8.10, at least) is quite a bit better at preserving JPEG quality than ImageMagick (whatever version you tested). Your first image, saved once at q75, has a PSNR of 34.0298, while the one saved twice at q75 has one of just 32.8169 (and the one resaved 8 times has a PSNR of 32.6459). In comparison, saving the same source image once in GIMP at q75 gives a PSNR of 36.4560; opening and resaving it at the same quality drops it only slightly, to 36.3295. \$\endgroup\$ Commented Mar 19, 2015 at 16:30
3
\$\begingroup\$

Sorry if this is not exactly what you wanted but...

It sounds like your adding a white border as an aid for positioning your image when printing. Why not focus on learning the printing interfaces properly and avoid dodgy hacks like this? The other issue this brings up is are you allowing the printing program to resize your 4680x3120 image to fit the correct DPI/resolution. This might have a more severe effect than re-saving a jpeg.

\$\endgroup\$
1
  • \$\begingroup\$ Both valid points, thank you. However, I uploaded my photo to one of those online-print-shops, so I don't have control over the actual printer. \$\endgroup\$
    – LBogaardt
    Commented Mar 23, 2015 at 11:16
1
\$\begingroup\$

The previous answers are very good.

I will just add some "psychological aspects" of the jpg format.

If a jpg is well prepared, it loses only about 0.5% information. That is in the vast majority of cases something that the human eye can not see. You need a program to do some analysis and see the differences (like the analysis Ilmari just did).

"Good Quality" is a process, not only the way a file format saves the image. Yes, you recompressed the file with jpg once more because you really needed it. If it is on a controlled situation it is ok to do that.

You really needed it implies that you can not use another lossless format, you have very specific storage or software needs, or a very tight workflow.

If you are really concerned about the quality, probably you wouldn't be using Paint. The JPG format has some configurations that you can't control in Paint at all.

Here is my list of free programs where you really can control the jpg compression, and the option you need to select. (All of them in the jpg save dialog)

Irfanview - Turn on Disable chroma color subsampling.

FastStone Image Viewer - Color subsampling: None.

Gimp - Subsampling 4:4:4

Conclusion. Don't use Paint.

One thing I have not checked yet. If all these programs maintain the embedded color profile. I'll edit my post later.

\$\endgroup\$
5
  • \$\begingroup\$ Someone voted -1 on this answer. Normally I don't care becouse I know I can say something dumb. In this specific case, What part of the answer is wrong? \$\endgroup\$
    – Rafael
    Commented Mar 19, 2015 at 17:41
  • \$\begingroup\$ I didn't vote (up or down), but you might want to work on your spelling and grammar to give a better first impression (and also, honestly, to make your answer easier to read). Also, this question already has several answers (and mine, especially, turned out quite long); at some point, some people may start downvoting (or at least not upvoting) answers that don't clearly add something new to the existing ones. Also, try to structure your answer so that the important bits stand out at a glance; in this case, the only part you've highlighted in bold is an unimportant footnote. \$\endgroup\$ Commented Mar 21, 2015 at 15:16
  • \$\begingroup\$ Thank you for your comment Ilmari. I'm strugling to think in english, as it is not my native language. I will look for a spelling tool. I am not sure if there is a grammar one. - For the second part of the comment, I understand that the logic behind StackExchange is to answer the question independently, becouse the flow of the answers is not fixed, becouse they can change order or being edited. I will take a look on that. (I removed the bold text) Thanks again. :o) \$\endgroup\$
    – Rafael
    Commented Mar 23, 2015 at 3:27
  • 1
    \$\begingroup\$ "it loses only about 0.5% information" [citation needed] :) \$\endgroup\$ Commented Oct 10, 2015 at 6:53
  • \$\begingroup\$ Hey Warren, here it is: otake.com.mx/Apuntes/PruebasDeCompresion2/… It is in spanish, please use google translate for now, and I need to update it. In fact it is less than 0.392% :) \$\endgroup\$
    – Rafael
    Commented Oct 10, 2015 at 18:52
1
\$\begingroup\$

If PDF is an option, you can avoid the bloat of converting it a lossless format. img2pdf will embed JPEG, JPEG2000 and PNG files into a PDF file without re-encoding them (unlike all mainstream PDF creation software).

You can't use pixels as units, but you could make a PDF with a border of the same ratio by using pts instead (a pt is 1/72 of an inch, img2pdf's default unit). For a 4680x3120 image centred on a 5200x3467 page with a white border, you would enter:

img2pdf --output out.pdf --pagesize 5200x3467 --imgsize 4680x3120 image.jpg

If you want to set a physical size, you can also add mm, cm, or in after the numbers, e.g. --pagesize 520mmx346.7mm. For the imgsize, if you only set one unit, it will resize the image keeping the same aspect ratio, e.g. --imgsize 468mmx or x312mm.

It can do all kinds of other things that the online documentation doesn't cover. Run img2pdf -h to see the options.

\$\endgroup\$
0
\$\begingroup\$

IrfanView works well for me for sets of images. Here are some how-to notes

Here is my stored procedure for border insertion - Infran Procedure to add a border

  1. Right-Click image, 'Open with'->'InfranView'
  2. Press 'b'
  3. Check 'Use advanced options' in upper left, press 'Advanced'
  4. Check 'Canvas Size', press 'Settings'
  5. Enter each border width(Left side, Right side, Top side, Bottom side)
  6. Press 'OK'
  7. Select 'Overwrite existing files'
  8. Press 'OK'
  9. Enter the output directory 'Output directory for result files:'
  10. Navigate to and double click the image to add border to in upper list. This adds it to the 'input files:' listing at bottom list
  11. Press 'Start Batch'
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Could you explain what is special about those method so that it meets the poster's requirements of not lowering the quality of the image? On first reading, this would seem to send the JPEG through the whole decompress-recompress cycle that the poster is trying to avoid. \$\endgroup\$
    – Philip Kendall
    Commented Sep 14, 2016 at 17:36
  • \$\begingroup\$ hmmm, you bring an interesting point with respect to the image lifecycle through the process I list here, I did not think towards that. You may be right, if you would like me to remove or ammend my posting then please let me know :)! \$\endgroup\$
    – J-Dizzle
    Commented Sep 16, 2016 at 13:04
-2
\$\begingroup\$

You can do this for free using Adobe Acrobat! Right click your photo, then click Open with Adobe Acrobat. In Adobe, click Edit PDF. Select the entire image (Ctrl A) then make it a little smaller so that there is a white border around it. Then click Export as and select your desired format (JPEG, PNG, etc).

\$\endgroup\$
1
  • 4
    \$\begingroup\$ Could you explain how this avoids the quality loss from the JPEG decompression/recompression cycle? \$\endgroup\$
    – Philip Kendall
    Commented Oct 14, 2021 at 14:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.