1
votes

The story

An overview of what I want to accomplish: I have photos that need to be cropped and resized, once for a thumbnail view (around 295x195), and once for a "header-image" style view (around 1400x560). The original photos vary in size, the biggest are around 2440x1600. This would not be a problem to solve.

However, the image should not be cropped with a "North" or "Center" gravity but should have a defined center position from where the image should be cropped. For this, an image has x and y values that represent the center point in percentage; x=50,y=50 would mean that the focus point of the image is actually in the middle.

I searched here and on the imagemagick forums but could not find anything suitable, except for "cutting off a certain part of an image and then resize it". I'm not sure if this can be done in one imagemagick command or if I need to calculate everything on my own and basically create an empty canvas, put the image on it, move and resize the image, and then shave off everything else to achieve this.

What I want to achieve

I need one imagemagick command to

  • take one image as input
  • resize and crop it to a given size (e.g. 295x195) respecting the focus point I have (either in percentage or pixels)
  • output the image in the given size with the focus point in the middle

I will be using one command per image and per size needed.

Here's a short visualization I made in sketch with a demo picture in hope to make it more understandable what I am trying to do:

Problem representation

The image on the left is the base image on which I put on a focus point at 282,282. The one on the right is the desired crop that I want in 295x195px dimensions (without the lines on it, they're just for the problem demonstration). As you can see, the crop has its center point where the focus point on the original image is.

What I tried

My first attempt was to play around with the offset values for -crop to set the focus point of the image:

convert photo.jpg -resize 1440x560^ -crop "1440x560+25%+25%" result.jpg

But I learned quickly that this is not the way it works as it results in images being too small (when the coordinates are e. g. in the bottom left of an image) and in general cuts off parts of the image that would be visible with the focus point, which makes sense after reading about it in the docs.

Then I saw the -region option and tried to play around with it having an image size of 2400x1600 and getting various cuts out of my image:

convert photo.jpg -region 610x400 -resize 1440x560^ -crop 1440x560+0+0 result.jpg

The only effect of the region option is that I get the same cut of the image regardless of what values I put into, and it always puts distorted white horizontal stripes on the image.

Any hints towards the right direction (with or without code examples) would be helpful so I know where to dig deeper.

The environment

  • macOS Catalina for development
  • app containing the code will run on debian buster
  • local imagemagick version is 7.0.8-66
  • server imagemagick version is 6.9.10-23 (I can update this with a manual build, though, it would be okay to have a solution that only works in IM7)
1
When you use "-crop" you can specify the dimensions and the center point of the cropped piece by setting the gravity. Try something like ... -gravity center -crop 1440x560+480+140 .... You can't mix dimensions with percentages like you tried. Also, "-region" requires offsets, but won't do what you're trying to do anyway.GeeMack
Also, you can easily modify an image multiple ways and create more than just one output image within a single ImageMagick command. Maybe clarify your description of what you're trying to do there so we can offer examples.GeeMack
Added a short and hopefully clear "What I want to achieve" section. It's basically one command for one image and one image sizepdu
-region needs offsets to specify its top left corner. No point in using -region, just compute the correct top left corner for the crop command. How do you define where you want the center of the crop to occur? -crop does not use % for the offsets. But you can compute the pixel location from the %. It would be easy in IM 7. For IM 6, you need to compute them ahead of time. What is your platform -- Unix or Windows? Why not crop first and then resize as many ways as you want?fmw42
Thanks for the explanation. I edited my question and added a visualization in hope it is helpful. I also added environment information at the bottom of the question. In the end, the command is used in a rails app which will build and cache the cropped image, thus I either need a simple command that gets passed through to imagemagick, or in case it is more complex, I'd have to build something on my own to make it happen inside the rails framework. However, if I can make it work in the terminal, I can make it work in rails, so...pdu

1 Answers

2
votes

The "-distort SRT" operator in ImageMagick can scale an image, resize the canvas, and move a point from one set of coordinates to another all in one move.

This command would read your input image and set an output viewport of 295x195. Then it uses "-distort SRT" to scale the input image to 50%, move that starting center point of +282+282 to the new output center point of +147.5+97.5, and change the viewport size to 295x195.

convert input.png -set option:distort:viewport 295x195 \
   -distort SRT "282,282 0.5 0 147.5,97.5" result.png

The distort arguments start with the point you want to be the center of the operation, "+282+282". Then the scale "0.5" reduces the size to 50%. The "0" argument is for how many degrees of rotation, but you're not rotating the image, so "0". And the last argument is the landing spot, "+147.5+97.5", for what was the starting point, so it becomes the new center of your 295x195 output canvas.

Of course you'll have to manually insert and adjust your arguments if you're using various sized inputs.

EDITED TO ADD...

ImageMagick can calculate the amount to scale the image using an FX expression. Here is the same command where the FX expression divides the X offset, or the center of the output viewport, by the X offset used from the input image.

convert input.png -set option:distort:viewport 295x195 \
   -distort SRT "282,282 %[fx:147.5/282] 0 147.5,97.5" result.png

That puts the original 282 X coordinate point at 147.5, and scales the image to that ratio.