weserv / images

Source code of wsrv.nl (formerly images.weserv.nl), to be used on your own server(s).
https://wsrv.nl/
BSD 3-Clause "New" or "Revised" License
1.97k stars 193 forks source link

Question: Cropping to a relative portion of the image (in percents) #384

Closed Sewdn closed 6 months ago

Sewdn commented 1 year ago

Say you want to crop an image to its upper left quadrant. The image should not be resized, only the top-left half of the image (1/4) should be retained. What is the best way to do this?

I understand it is an easy task if the image's dimensions are known beforehand. But what if you would like to skip the extra processing to assess the image's dimensions before cropping (and leave it up to wsrv)?

Is it possible to crop an image to a relative portion of the image, based on a percentage of the original size? Something like cx=0&cy=0&cw=0.5&ch=0.5? In the documentation it looks like you can only give absolute cropping values (in pixels) and would need to know the image dimensions beforehand.

Alignment does support percentage values (or top-left portions), but this is only used when resizing the image and using fit or cover and thus would always resize the image. If you would like to retain the image's ratio, this would always result in a resize without any cropping.

Thanks for your help or suggestions.

andrieslouw commented 1 year ago

Good question, it would be like https://wsrv.nl/docs/crop.html#rectangle-crop but with percentages indeed. @kleisauke: Any ideas on this? Does libvips provide any easy way to cut an image in equal sizes? I guess it would be handy to split up large images.

Sewdn commented 1 year ago

Thanks for your response!

It does not necessarily mean to have equal parts, or that libvips needs to cut all all the parts in one go.

The idea is just to request one part at a time, but instead of providing the absolute coordinates of the desired part, providing the relative part in percentages.

When cw equals ch an image of the same ratio of the original image is requested (and indeed this would end up in all equal sizes, if they all would be request):

But there are also use cases for none equal divisions / layouts for an image:

It doesnt seem to me this feature would have a big impact, because the existing cx, cy, cw, ch parameters can be reused (because it would never make sense to request images with smaller dimensions then 1px) and the absolute dimensions of the provided image are known for the image server, so the relative dimensions can easily be converted to absolute dimensions.

If you point me to the right spot in the source, I'm willing to provide you with a PR and we can discuss this further in this PR.

Kind regards, Pieter

Sewdn commented 1 year ago

The only possible conflict with the current API spec would arise for cx,cy,cw,ch = 1. This would break the possibility of requesting crops of 1px dimensions, but I don't think this is a real use case

Sewdn commented 1 year ago

@kleisauke do you see value in adding this feature request?

kleisauke commented 1 year ago

Sorry for the delay. I think this would be an interesting feature to add, but using a floating point API (i.e. values between 0.0 and 1.0, inclusive) would probably break backward compatibility when using c{x,y,w,h} == 1, as you said.

Perhaps we should use the percent sign (%) to indicate relative crops? Using the above example, that would result in:

(And of course, we need to ensure that percentages with decimal places are also supported, such as 50.5%).

I think this is relatively easy to add code-wise and could possibly be extended to the &w= and &h= parameters as well.

Let's mark this as an enhancement, I'll try to implement this sometime this week.

Sewdn commented 1 year ago

Alright, great!

Another possibility would be to use fraction notation. This would result in a higher precision then using floating points percentages (eg. 1/3 instead of 33.333%). This would also be closer to the actual use cases, where you are looking to divide the image in fractions.

100% would need to be expressed as ‘1/1’ to distinguish from an absolute dimension of 1px

The same examples would be like:

kleisauke commented 1 year ago

Fraction notation is slightly more difficult to implement because the parser must guard against division by zero and NaN values.

Commit e5489aad17dee1dcc95629f0351cd04388ccf93c allows percentage-based values (denoted by a value ending with %) for the &c[x,y,w,h]= and &[w,h]= parameters. This has just been rolled out to production, thanks for the suggestion!

Documentation will be updated later to reflect this.

Sewdn commented 1 year ago

Hi @kleisauke

I have been using the relative cropping with success. Thanks a lot. I am now using wsrv cropping urls with external services for other kind of image processing (after the image was cropped), and it seems like these services are url_encoding the % sign, because it is a value of one of the query parameters and it seems like weserv is not url_decoding the parameter values.

As i understand correctly from https://github.com/weserv/images/issues/334 weserv is url_decoding the url parameter to allow for other query parameters inside this url of the raw image.

My question to you: should weserv now also url_decode the c[w,h,x,y] parameters, since it now can contain special chars like % that are possible being url_encoded? Or is this up to the client, to make sure the parameters are not being url_encoded? What is your opinion?

kleisauke commented 12 months ago

@Sewdn Looks like a small oversight, fixed with commit fd7a184ef6d2f650cb3d1f99c10fadc4eacfef69.

kleisauke commented 6 months ago

Documentation has been updated. https://wsrv.nl/docs/crop.html#rectangle-crop