I did something like
convert -page A4 -compress A4 *.png CH00.pdf
But the 1st page is much larger than the subsequent pages. This happens even though the image dimensions are similar. These images are scanned & cropped thus may have slight differences in dimensions
I thought -page A4
should fix the size of the pages?
9 Answers 9
Last time I used convert
for such a task I explicitly specified the size of the destination via resizing:
$ i=150; convert a.png b.png -compress jpeg -quality 70 \
-density ${i}x${i} -units PixelsPerInch \
-resize $((i*827/100))x$((i*1169/100)) \
-repage $((i*827/100))x$((i*1169/100)) multipage.pdf
The convert
command doesn't always use DPI as default density/page format unit, thus we explicitly specify DPI with the -units
option (otherwise you may get different results with different versions/input format combinations). The new size (specified via -resize
) is the dimension of a DIN A4 page in pixels. The resize argument specifies the maximal page size. What resolution and quality to pick exactly depends on the use case - I selected 150 DPI and average quality to save some space while it doesn't look too bad when printed on paper.
Note that convert
by default does not change the aspect ratio with the resize operation:
Resize will fit the image into the requested size. It does NOT fill, the requested box size.
Depending on the ImageMagick version and the involved input formats it might be ok to omit the -repage
option. But sometimes it is required and without that option the PDF header might contain too small dimensions. In any case, the -repage
shouldn't hurt.
The computations use integer arithmetic since bash
only supports that. With zsh
the expressions can be simplified - i.e. replaced with $((i*8.27))x$((i*11.69))
.
Lineart Images
If the PNG files are bi-level (black & white a.k.a lineart) images then the img2pdf
tool yields superior results over ImageMagick convert
. That means img2pdf
is faster and yields smaller PDFs.
Example:
$ img2pdf -o multipage.pdf a.png b.png
or:
$ img2pdf --pagesize A4 -o multipage.pdf a.png b.png
-
2when using
-repage a4
I get ainvalid argument for option '-repage': a4
Scolytus– Scolytus2014年03月07日 11:36:55 +00:00Commented Mar 7, 2014 at 11:36 -
1@Scolytus, on a Fedora 19 system I've observed a similar issue - it seems that
-repage
does not support the a4 name anymore. I've worked around this via shell arithmetic:-repage $((150*8.27))x$((150*11.69))
maxschlepzig– maxschlepzig2014年03月07日 15:17:11 +00:00Commented Mar 7, 2014 at 15:17 -
I assume those magic numbers are 150dpi, and A4 expressed in legacy units?Michael Scheper– Michael Scheper2015年03月19日 03:07:50 +00:00Commented Mar 19, 2015 at 3:07
-
@MichaelScheper, yes, dpi and inches.maxschlepzig– maxschlepzig2015年03月19日 09:26:57 +00:00Commented Mar 19, 2015 at 9:26
-
Thanks, help me. Actually
-density 150
argument was important to add .dma_k– dma_k2015年04月21日 15:54:40 +00:00Commented Apr 21, 2015 at 15:54
What you really want to use is:
$ convert a.png b.png -compress jpeg -resize 1240x1753 \
-extent 1240x1753 -gravity center \
-units PixelsPerInch -density 150x150 multipage.pdf
-extent
actually extends the image to be 1240x1753, while -resize
keeps the image's ratio, fitting it into either 1240x...
or ...x1753
.
The -gravity
parameter is optional but can be used to center the image when extending.
-
1Thank you!
-extent
is really what I want to use :) -- please, add missed left quote in front of -extent, thanks!brownian– brownian2013年05月17日 12:18:14 +00:00Commented May 17, 2013 at 12:18 -
Thank you, I have eventually added the missing tick! ;-)caugner– caugner2013年05月28日 11:22:46 +00:00Commented May 28, 2013 at 11:22
Addition to caugner's answer:
having installed IM v6.6.9-7 i found out the -gravity
parameter needs to be placed in between -resize
and -extent
to have an effect.
additionally (altough not part of the o.p. question) i found setting a different background-color appealing which would result in the total command of
convert in.jpg -resize 1240x1750 -background black -compose Copy\
-gravity center -extent 1240x1750\
-units PixelsPerInch -density 150 out.pdf
another useful variation i often use when i don't want to re-scale an image that already comes in the correct aspect-ratio but keep its individual resolution is
convert in.jpg -units PixelsPerInch -set density '%[fx:w/8.27]'\
-repage a4 out.pdf
where the target density is dynamically determined by calculating the width divided by 8.27 (which is the width in inch of an A4 page). the -repage a4
parameter can be omitted most of the time but i've had a few cases where the resulting .pdf would have a different format sligtly off the A4 dimensions of 210x297mm (8.27x11.6")
I highly recommend the Python CLI program img2pdf
for lossless conversion:
https://gitlab.mister-muffin.de/josch/img2pdf
Example usage:
img2pdf img1.png img2.png -o out.pdf --pagesize A4
-
--pagesize
and--imgsize
options are why this answers the OP's question (for future reference about fixed page sizes). Note that maxschlepzig's 2011 answer / 2018 edit only mentions Lineart and img2pdf claims lossless pass-though of jpeg and png.Alan– Alan2023年08月07日 11:18:52 +00:00Commented Aug 7, 2023 at 11:18
I found Mikher's code very useful, however it lays out the PDF entirely as either Portrait or Landscape, so I have modified it to check the layout of each input file and match it in the output.
I didn't include Yotam's edit as it works without it on my Ubuntu 15.04 box.
$#!/bin/bash
# Resizes files to A4 (or other size - change PaperWdthMetr and PaperHghtMetr below) and merges into a PDF
export LOCALE=C
[[ "${2}x" == "x" ]] && \
{ echo "Usage: $( basename 0ドル ) output.pdf extension"
echo " merges all files (*.extension) into a single PDF"
echo "If files z_merged.pdf, z_temp.pdf or 1ドル exist, they will be overwritten"
exit 1
} || \
OutName="1ドル"
ext="2ドル"
# Set basic variables
unset Debug #; Debug="yes" # print extra messages
IMBackground="white" # what colour for paper
IMQuality="91" # JPEG compression level
PaperHghtMetr="297" # milimeters, 297 for ISO A4
PaperWdthMetr="210" # milimeters, 210 for ISO A4
PaperDens="200" # maximum (wanted) dpi for a page
PaperHInch=$( echo scale=5\; $PaperHghtMetr / 2.54 / 10 | bc -l ) # Inch
PaperWInch=$( echo scale=5\; $PaperWdthMetr / 2.54 / 10 | bc -l ) # Inch
PaperRtio=$( echo scale=5\; $PaperWdthMetr / $PaperHghtMetr | bc -l )
# Remove temporary files from prior run
rm -rf z_merged.pdf z_temp.pdf 2>/dev/null
# Process any $ext file in the current directory
find . -maxdepth 1 -name "*.${ext}" -print0 | sort -z | while read -d '' -r FName
do
echo "Converting $FName"
ImgIdentify=$( identify -format "%w %h" "$FName" )
ImgWdthOrig=$( echo $ImgIdentify | cut -d" " -f1 )
ImgHghtOrig=$( echo $ImgIdentify | cut -d" " -f2 )
ImgRtio=$( echo "scale=5; $ImgWdthOrig / $ImgHghtOrig" | bc -l )
# Match output page layout - Landscape or Portrait - to input file
if (( $(echo "$ImgRtio > 1 && $PaperRtio > 1 || $ImgRtio < 1 && $PaperRtio < 1" |bc -l) )); then
echo "Portrait"
PaperHghtInch=$PaperHInch
PaperWdthInch=$PaperWInch
else
echo "Landscape"
PaperHghtInch=$PaperWInch
PaperWdthInch=$PaperHInch
fi
[[ $( echo $ImgRtio'>'$PaperRtio | bc -l ) == 1 ]] \
&& ImgDens=$( echo scale=0\; $ImgWdthOrig / $PaperWdthInch | bc -l ) \
|| ImgDens=$( echo scale=0\; $ImgHghtOrig / $PaperHghtInch | bc -l )
[[ $Debug ]] && echo "ImgDens1: $ImgDens"
[[ $( echo $ImgDens'>'$PaperDens | bc -l ) == 1 ]] \
&& ImgDens=$PaperDens
[[ $Debug ]] && echo "ImgDens2: $ImgDens"
ImgWdth=$( echo $PaperWdthInch \* $ImgDens | bc -l ) # pixels
ImgHght=$( echo $PaperHghtInch \* $ImgDens | bc -l ) # pixels
[[ $Debug ]] && echo "ImgWdth: $ImgWdth".
[[ $Debug ]] && echo "ImgHght: $ImgHght".
convert "${FName}" \
-resize ${ImgWdth}x${ImgHght} \
-background $IMBackground -gravity center \
-extent ${ImgWdth}x${ImgHght} \
-units PixelsPerInch -set density $ImgDens \
-repage ${ImgWdth}x${ImgHght}+0+0 \
-compress JPEG \
-quality $IMQuality \
"${FName%.$ext}.pdf"
# Merge new PDF page with prior pages
[[ -f z_merged.pdf ]] && \
{ pdftk z_merged.pdf "${FName%.$ext}.pdf" cat output z_temp.pdf
mv z_temp.pdf z_merged.pdf
} || \
cp "${FName%.$ext}.pdf" z_merged.pdf
[[ $Debug ]] || rm -rf "${FName%.$ext}.pdf"
done
[[ -f z_merged.pdf ]] && mv z_merged.pdf "$OutName"
echo "Done."
I just used something similar to maxschlepzigs answer under Ubuntu 16.04 / ImageMagick
This also centers the result
i=300; convert a.png b.png -compress jpeg -quality 100 \
-density ${i}x${i} -units PixelsPerInch \
-resize $((i*827/100))x$((i*1169/100)) \
-gravity center \
-extent $((i*827/100))x$((i*1169/100)) multipage.pdf
I find the following script convenient which combines the answers listed here as well as some problems I had with the floating point calculation:
endInputArgs=$(($#-1))
quoted_args="$(printf " %q" "${@:1:$endInputArgs}")"
output_arg="$(printf " %q" "${@:$#:1}")"
ratiox=$(echo "150*8.27" | bc -l)
ratioy=$(echo "150*11.69" | bc -l)
bash -c "convert $quoted_args -compress jpeg -resize 1240x1753 \
-units PixelsPerInch -density 150x150 -repage ${ratiox}x${ratioy} $output_arg"
The script is called (saved as a file images2pdf)
images2pdf file\ 1.jpg file\ 2.jpg file\ 3.jpg output.pdf
/edit: Added "-l" flag according to comment by tanius for better precision.
-
1General hint:
$(echo "150*8.27" | bc)
is still not great for floating point. Works here because it's a multiplication. For$(echo "150/8.27" | bc)
though, the result is18
(truncated to integer). Instead, callbc
with higherscale
:$(echo "150/8.27" | bc -l)
, the results is18.137847...
.tanius– tanius2015年08月04日 10:37:47 +00:00Commented Aug 4, 2015 at 10:37
I was struggling with that stuff, too. Based on the above info, I wrote a script which adds alphabetically sorted image files into a single PDF.
Some variables are settable inside the script. It depends on ImageMagick and pdftk.
NB: If the input image has a higher resolution (dpi) than the wanted resolution of output.pdf, the image is resampled to the lower resolution. Otherwise, the image is not resampled and it is only extended to fit the page canvas.
#!/bin/bash
export LOCALE=C
[[ "${2}x" == "x" ]] && \
{ echo "Usage: $( basename 0ドル ) output.pdf extension"
echo " merges all files (*.extension) into a single PDF"
echo "If files z_merged.pdf, z_temp.pdf or 1ドル exist, they will be overwritten"
exit 1
} || \
OutName="1ドル"
ext="2ドル"
# Set basic variables
unset Debug #; Debug="yes" # print extra messages
IMBackground="white" # what colour for paper
IMQuality="91" # JPEG compression level
PaperWdthMetr="210" # milimeters, 210 for ISO A4
PaperHghtMetr="297" # milimeters, 297 for ISO A4
PaperDens="200" # maximum (wanted) dpi for a page
PaperWdthInch=$( echo scale=5\; $PaperWdthMetr / 2.54 / 10 | bc -l ) # Inch
PaperHghtInch=$( echo scale=5\; $PaperHghtMetr / 2.54 / 10 | bc -l ) # Inch
PaperRtio=$( echo scale=5\; $PaperWdthMetr / $PaperHghtMetr | bc -l )
# Remove temporary files from prior run
rm -rf z_merged.pdf z_temp.pdf 2>/dev/null
# Process any $ext file in the current directory
find . -maxdepth 1 -name "*.${ext}" -print0 | sort -z | while read -d '' -r FName
do
echo "Converting $FName"
ImgIdentify=$( identify -format "%w %h" "$FName" )
ImgWdthOrig=$( echo $ImgIdentify | cut -d" " -f1 )
ImgHghtOrig=$( echo $ImgIdentify | cut -d" " -f2 )
ImgRtio=$( echo "scale=5; $ImgWdthOrig / $ImgHghtOrig" | bc -l )
[[ $( echo $ImgRtio'>'$PaperRtio | bc -l ) == 1 ]] \
&& ImgDens=$( echo scale=0\; $ImgWdthOrig / $PaperWdthInch | bc -l ) \
|| ImgDens=$( echo scale=0\; $ImgHghtOrig / $PaperHghtInch | bc -l )
[[ $Debug ]] && echo "ImgDens1: $ImgDens"
[[ $( echo $ImgDens'>'$PaperDens | bc -l ) == 1 ]] \
&& ImgDens=$PaperDens
[[ $Debug ]] && echo "ImgDens2: $ImgDens"
ImgWdth=$( echo $PaperWdthInch \* $ImgDens | bc -l ) # pixels
ImgHght=$( echo $PaperHghtInch \* $ImgDens | bc -l ) # pixels
[[ $Debug ]] && echo "ImgWdth: $ImgWdth".
[[ $Debug ]] && echo "ImgHght: $ImgHght".
convert "${FName}" \
-resize ${ImgWdth}x${ImgHght} \
-background $IMBackground -gravity center \
-extent ${ImgWdth}x${ImgHght} \
-units PixelsPerInch -set density $ImgDens \
-repage ${ImgWdth}x${ImgHght}+0+0 \
-compress JPEG \
-quality $IMQuality \
"${FName%.$ext}.pdf"
# Merge new PDF page with prior pages
[[ -f z_merged.pdf ]] && \
{ pdftk z_merged.pdf "${FName%.$ext}.pdf" cat output z_temp.pdf
mv z_temp.pdf z_merged.pdf
} || \
cp "${FName%.$ext}.pdf" z_merged.pdf
[[ $Debug ]] || rm -rf "${FName%.$ext}.pdf"
done
[[ -f z_merged.pdf ]] && mv z_merged.pdf "$OutName"
echo "Done."
-
In the above, I had to change
-set density $ImgDens
into-density $ImgDens
Yotam– Yotam2015年08月15日 06:22:37 +00:00Commented Aug 15, 2015 at 6:22
I wanted to convert an image to page size of 5.00 x 8.00 in (viewed from adobe reader) Here's what I did on ubuntu 18.04 OS. First, figure out the page size I am after like so:
$ pdfinfo my-input.pdf
And the return is: Page size: 360 x 576 pts
Then the image is converted to a PDF of same size like so:
$ img2pdf --pagesize 360x576 -o outpage.pdf input_pic.jpg
Note: to install img2pdf
$ sudo apt install img2pdf