Here is a little script that does what you want, and can do it to multiple .jpg files at the same time, converting each into its own one-page .pdf file.
Save the script as imgs_to_pdfs.sh
and call it with one or multiple filename arguments, like this:
./imgs_to_pdfs.sh myimg1.jpg myimg2.jpg img-*.jpg
Output filenames will correspond to input filenames with .jpg replaced with .pdf. So make sure the script will not accidentally overwrite existing files!
How it works
- For the page to mount the image on, the script uses A4 format. It calculates the A4 dimensions itself, since the A4 keyword is seemingly not supported in recent ImageMagick versions anymore.
- The image is not resampled ("scaled") by the script, just shown centered with a certain resolution on the A4 PDF page canvas. So, no image information is lost by scaling down, and no useless file size added by scaling up.
- Instead of a 30 pixel minimum margin all around, the script leaves a space between image and PDF page borders. The advantage of this over adding a white border to the image is that it does not add to the file size, and that you can extract the unmodified image later from the PDF if desired, using a command like
pdfimages -j file.pdf img
.
- By default, the border around the image will be set to ≥5% of each page dimension. The image is scaled proportionally to achieve this, so x dimension borders will be 5% and y dimension borders will be lager, or the other way round, depending on image proportions. You can adapt the size of the borders by adapting the resolution factor in the script. Currently it is
1.1
, leading to 110% of the resolution for an A4 page fit. So the image covers only 90% of the A4 page dimensions, leaving two 5% borders. If you set the factor to 1.2
, you get two 10% borders and so on.
Other details
- Here's the proof how the formulas in the script lead to 5% borders:
- Page size in pixels is calculated as
page_size_x = density * 8.27
- Density is calculated as
density = img_size_x / 8.27 * 1.1
. (This assumes the case where the x dimension needs the higher density to leave a 5% border empty.)
- Line 2 in line 1 yields:
page_size_x = (img_size_x/8.27*1.1) * 8.27 = img_size_x * 1.1
. So indeed, the page is 110% the pixel width of the image, giving two 5% borders.
- Some people seem to need a
-repage
operation (like here) to prevent page size from being slightly "off". Did not need it, but if you do, try -repage ${page_size_x}x${page_size_y}
or -repage A4
as last operation in the convert
call.
Script source code
#!/bin/bash
# Converts input images to one-page PDF files each, without changing image data.
# The image is centered on a A4 page with a 5% border.
# bc function to calculate maximum of two floats
bc_functions="
define max(a,b) {
if (a>b) {
return(a)
} else {
return(b)
}
} ";
for file in "$@"; do \
# Determine image dimensions in pixels.
img_size_x=$(identify -format "%w" "$file");
img_size_y=$(identify -format "%h" "$file");
# Calculate image density (in dpi) needed to fit the image and a 5%
# border all around on an A4 page (8.27x11.69"). Factor 1.1 creates
# 2*5% borders, see https://unix.stackexchange.com/a/220114 for details.
min_density_x=$(echo "$img_size_x/8.27*1.1" | bc -l);
min_density_y=$(echo "$img_size_y/11.69*1.1" | bc -l);
# Use the higher density to prevent any dimension exceeding the required fit.
density=$(echo "$bc_functions max($min_density_x,$min_density_y)" | bc -l);
# Calculate canvas dimensions in pixels.
# (Canvas is an A4 page (8.27x11.69") with the calculated density.)
page_size_x=$(echo "8.27*$density" | bc -l);
page_size_y=$(echo "11.69*$density" | bc -l);
# Center image on a larger canvas (with a size given by "-extent").
convert "$file" \
-gravity center -extent ${page_size_x}x${page_size_y} \
-units PixelsPerInch -density $density \
-format pdf -compress jpeg \
"${file/.jpg/.pdf}";
done;
References