How to convert PNG to pdf and center the image? - imagemagick

I'm using Magick's convert tool to convert and combine all my images into PDF.
magick convert *.png -page a4 out.pdf
The resolution of the images are 1079 x 1397
The images in the generated PDF file are off-centered. There's some white space on the top of each page.
Here's a screenshot : https://i.imgur.com/EpvxZNU.png
I don't want to "fill" the entire page with my image. I want to simply "fit" the image the way it has in the screenshot above, BUT be centered (have equal whitespace on the top and bottom)

I don't believe that you can center with -page in ImageMagick 7 unless you do inline computations using the actual desired A4 size in pixels (592x842) via distort and its viewport setting. See page sizes in pixels at https://imagemagick.org/script/command-line-options.php#page
In ImageMagick 7, you should use magick and not magick convert. The latter will emulate ImageMagick 6. However there is a bug currently in ImageMagick 7. The following command works fine with convert in ImageMagick 6, but fails with magick in ImageMagick 7. But it works fine with magick convert in ImageMagick 7.
magick convert *.jpg -virtual-pixel white -set option:distort:viewport "592x842-%[fx:(592-u[t].w)/2]-%[fx:(842-u[t].h)/2]" -distort SRT 0 +repage result.pdf
Here is a simple example:
Input Images:
magick convert lena.jpg barn.jpg -virtual-pixel white -set option:distort:viewport "592x842-%[fx:(592-u[t].w)/2]-%[fx:(842-u[t].h)/2]" -distort SRT 0 +repage result.pdf
Result:

Related

convert doesn't conserve size when scaling down and up

In order to make applying blur faster I'm first scaling my image down and then scale it back up:
convert - -scale 10% -blur 0x2.5 -resize 1000% RGB:-
This works most of the time but sometimes the output resolution is slightly different from the original input. Is there a way to force the pipeline to be size-preserving?
You should be able to access the original geometry of the image via %G, so you can do:
convert input.jpg -scale 10% -blur 0x2.5 -resize '%G!' RGB:-
If you are using Windows, you probably want "%G!" in double rather than single quotes.
If you are using v7 ImageMagick, replace convert with magick.
I think you are getting errors because if you take 10% of 72 pixels (say), you will get a whole number of pixels, i.e. 7 pixels and then when you scale back up by a factor of 10 you'll get 70 rather than your initial 72.
If you are using Imagemagick 7, you can do the following:
magick input.jpg -set option:wd "%w" -set option:ht "%h" -scale "%[fx:wd/10]x%[fx:ht/10]" -blur 0x2.5 -resize "%[fx:wd]x%[fx:ht]\!" RGB:-
This stores the input width and height. Then uses the stored values to scale by 1/10 of those dimensions, then does the blur, then resizes exactly back to the origin input size. Note the ! that forces the resize to the exact dimensions.
or simpler without storing the input width and height:
magick lena.jpg -scale "%[fx:w/10]x%[fx:h/10]" -blur 0x2.5 -resize "%[fx:w]x%[fx:h]\!" lena_x.jpg

Imagemagick: How to bulk convert images into square

I want the size of the square should be equal to the largest side of the original photo
E.g.
Original: 500 x 400 => Output:500 x 500
Original: 400 x 600 => Output: 600 x 600
You can do that as follows for any given image in Imagemagick 7. To do multiple image, you would need to write a "for" loop, whose syntax depends upon your OS.
magick image.suffix -gravity center -background black -extent "%wx%h^" result.suffix
or
magick image.suffix -gravity center -background black -extent "%[fx:max(w,h)]x%[fx:max(w,h)]" result.suffix
Here is a better way to convert all images in a folder with either Imagemagick 6 or 7. I use -distort SRT's viewport to do the padding with a no-op warping (i.e. no rotation, scale or translation) in mogrify to process all images in the folder.
First create a new folder to hold your output images, if desired and use the -path option to mogrify. Specify a background color (in this case I use red).
For Imagemagick 7:
magick mogrify -path path_to/new_folder -virtual-pixel background -background red -set option:distort:viewport "%[fx:max(w,h)]x%[fx:max(w,h)]-%[fx:0.5*(max(w,h)-w)]-%[fx:0.5*(max(w,h)-h)]" +distort srt 0 *
For Imagemagick 6, remove "magick" before mogrify.

crop image with imagemagick offset given in percentage

imagemagick's crop command supports cropping to a percentage of an image but the offset values must be specified in pixel values, e.g.:
convert image.png -crop 50%x+10+20
I want to crop with offset values x and y given in percentage of the image width, and height respectively. The pixel values can be calculated, for instance if the image size is 100x200 an offset of 10% would result in 10 and 20 respectively. Is it possible to do this calculation as part of the call to convert? Width and height are available as %w and %h at some places, but this does not work:
convert image.png -crop 50%x+(0.1*%w)+(0.1*%h)
If you're running IM v6 you can use FX expressions with "-set" to set image attributes. By setting the page geometry you can specify the offsets to a calculated percentage and do the crop like this...
convert image.png -set page -%[fx:w*0.1]-%[fx:h*0.1] -crop 50%x+0+0 result.png
That reads the image, sets the geometry for the upper left corner to a location outside the original canvas, and crops to the new top left corner specified by the geometry.
Note the offsets are negative numbers.
Also, if you're doing additional processing in the same command you'll probably want to "+repage" after the crop in order to reset the page geometry to the new WxH+0+0.
Edited to add: You can even include the width and height dimensions for the crop when using "-set page". This command would crop an output of 50% the input width and height, and starting at 10% in from the left and top...
convert image.png \
-set page %[fx:w*0.5]x%[fx:h*0.5]-%[fx:w*0.1]-%[fx:h*0.1] -crop +0+0 result.png
Notice how the crop operation is simply "-crop +0+0" since the dimensions and offsets are in the page geometry.
This method lets you use more complex calculations than just using a percent or number of pixels for the cropped output dimensions.
You cannot do that in ImageMagick 6. But you can do that in ImageMagick 7.
magick image.png -crop "50%x+%[fx:0.1*w]+%[fx:0.1*h]" +repage result.png
In ImageMagick 6, you need to do the computations ahead of the command, store them in a variable and use the variable in the crop command.
However, in ImageMagick 6, you can do the equivalent using -distort with viewport processing as follows:
convert image.png -set option:distort:viewport "%[fx:0.5*w]x%[fx:0.5*h]+%[fx:0.1*w]+%[fx:0.1*h]" -filter point -distort SRT 0 result.png
With v7 ImageMagick, make start image:
magick -size 200x100 gradient: a.jpg
Now crop using lots of calculated widths, heights, offsets:
magick a.jpg -crop "%[fx:w*0.9]x%[fx:h*0.8]+%[fx:w*0.1]+%[fx:h*0.05]" b.png
Check:
identify b.png
b.png PNG 180x80 200x100+20+5 8-bit Gray 256c 408B 0.000u 0:00.000
If you only have v6, use bash and integer arithmetic:
read w h < <(identify -format "%w %h" a.jpg)
convert a.jpg -crop $((w*80/100))x$((h*90/100))+$((w*10/100))+$((h*5/100)) result.png
Check:
identify result.png
result.png PNG 160x90 200x100+20+5 8-bit Gray 256c 412B 0.000u 0:00.000

Applying watermark on an image

I'm trying to apply watermark on an image using the following imagemagick command
convert input.png watermark.png.png -gravity northwest -composite output.png
The input png file size is 16KB and the watermark file size is 900bytes, but when I executed the above command to apply a watermark, the output png size is 61KB which is almost 4X the size of the original input png file. Is there any better way of applying a watermark to an image file with much better result in terms of output filesize
Test Image: https://res.cloudinary.com/deks86ilr/image/upload/v1533015495/1_rnpbye.png
Test watermark: https://res.cloudinary.com/deks86ilr/image/upload/v1533015494/2_usmonh.png
Here are my results of processing of your images with my PNG8 output using ImageMagick 6.9.10.8 Q16 with libpng 1.6.34.
I note that your input image was type palette, which means it is 8-bits of color per pixel and not 24-bit color. So it is already a low quality image.
Input (~16 KB):
Watermark Image (white on transparency -- so it is invisible here):
Convert to 24-bit PNG:
convert input.png watermark.png -gravity northwest -compose over -composite input_with_watermark.png
I see no significant visible quality loss but the output is now increase from 16 KB to 60 KB. But you can use tools such as pngcrush to compress it further.
Convert to 8-bit PNG:
convert input.png watermark.png -gravity northwest -compose over -composite PNG8:input_with_watermark2.png
The file size is now back to about 16 KB. But as you note the quality is a little poorer. This is likely because the input image (at 8-bits and has 217 colors) was first read back to 24-bits, then watermarked, which included new shades of white and then quantized back to 8-bits, but contains only 84 colors colors.
Another way is to add +dither -colors 256 to the command (the +dither turns off dithering):
convert 1_rnpbye.png 2_usmonh.png -gravity northwest -compose over -composite +dither -colors 256 PNG8:watermark3.png
This is a bit better, since it now uses 189 colors and still has a file size of 16 KB.
One final method is to save the colors from your input to a colortable image. Then use -remap to recolor the output using that colortable:
convert 1_rnpbye.png -unique-colors colortable.gif
convert 1_rnpbye.png 2_usmonh.png -gravity northwest -compose over -composite +dither -remap colortable.gif PNG8:watermark4.png
This results in 8-bit output with 227 colors and still a file size of about 16 KB. So it has a few more colors than your input and visually looks about the same quality as your input.
If you cannot reproduce these results, then perhaps you should upgrade either or both ImageMagick and libpng.

Converion of pdf page to fixed size images

I want to convert pdf pages to images of same size(aspect ratio maintained) irrespective of the pdf quality. Say A4 size. I am using convert from Imagemagick for this but struggling to get the fixed size of images for different pdfs of different quality.
Can anyone help me?
Something like:
convert -density 288 document.pdf -resize 2480x3508 result.png
The density must come before the PDF to ensure the rasterisation is done at sufficient quality/resolution.
If you want that centred on a piece of A4 and padded with white to fill the page:
convert -density 288 document.pdf -resize 2480x3508 -background white -gravity center -extent 2480x3508 result.png

Resources