Search code examples
javascriptphpjquerycropimage-scaling

Zooming and moving a graphic at a reduced size using a cropper - is my method sound?


I am hoping this question is OK in stack overflow.

I am writing some code and only have the alogrithim worked out at this stage and was wondering if I am going about this the best way or not ?

Here is what I need to do :

Take an image of 2000x2000 pixels and use an existing JS/Jquery crop/scale library (not settled on any particular one yet - suggestions welcome) and allow the user to move this image around and zoom in and out so it fits in a 1000x1000 area. This "cropped/zoomed" 1000x1000 area will be the final output image for the user.

HOWEVER, in the actual UI, for reasons of fitting it in a particular space, I need the user to be working at half size. So, their 1000x1000 "final image" area is represented by a 500x500px area. Hope that makes sense.

Here is the algo I have come up :

Original 2000px x 2000px image is source.png

  1. Take source.png and using ImageMagick or similar resize it by 50% in PHP and feed this new "temporary" 1000x1000 image back to my code via Ajax.
  2. Use a cropper/scaler to show this temp image behind a 500x500 work area and allow user to crop/move.
  3. When user finished, send the crop/zoom co-ords from the scaler code to a PHP routine that crops the original source.png to a new 1000px x 1000px image via ImageMagick by multiplying the X,Y,H,W by 2 and dividing the Zoom(scale) by 2.

I think this would work and wondered if anyone thinks this is the best way of doing this or am I missing something totally obvious.

EDIT DUE TO VAGUENESS OF ABOVE:

Basically here is what I am creating : App outputs a 1000x1000px image with user selected text on it (didn't mention that so as not to overcomplicate). Where the 2000x2000 image comes in is that the user can select from several images, this is going to be the background image behind text. User can move and scale that background image so the bits they want show as the background in the final 1000x1000 output. But the work area is only 500x500.


Solution

  • Your approach is completely valid. In fact, I would opt for your approach over the alternative. I'll explain...

    Essentially you have two primary ways you could implement the solution that you have explained.

    Your proposed approach is considered a 'backend resize' implementation, in the sense that you let ImageMagick take some front-end inputs via AJAX (position of image, scale, whatever. Just some numbers really.) - but then do the resize/storage on the 'backend'

    You could do a 'frontend resize', in which you let a JavaScript operation take the image, scale it down, re-express that as binary, and then push it online. You would need the raw binary of the resized/cropped image because the resized version doesn't physically exist anywhere on the disk (so you can't do a typical 'POST' operation either) unless the user first saves the image and re-uploads it (which isn't ideal)

    But I would advocate for the backend resize... why? Security. It's far less prone to front-end injection. A malicious user could load the image for cropping/resize, then use JS injection to insert a new image of their choosing (of malcious intent. Think nudity etc) and then post that back on your server. Or worse, a very clever user could encode a malicious script inside your image, and then execute it once it's uploaded onto your server.

    Another consideration is consistency; you become less reliant on JS behaving consistently (or even at all, depending on some browsers) when you let a 'central point' handle the resizing, like a backend implementation.

    By only accepting a few numbers from the user via the AJAX script (and validate the numbers properly) the malcious user has far less scope to maliciously attack your site.

    Granted it's annoying to work through the math, rather than just scoop up the perfectly resized front-end content, but it's practically a necissity.

    What about using ImageMagick? Of course, there is no 'perfect' tool, or you would be using it. That said, you need to measure whether the tool is the best one for your project. Some considerations...

    • Scale: Let's be honest, we're not really using ImageMagick to it's fully extent here. It's a simple resize operation, so we can use a 'dumber' library to handle it. We are now employing a gigantic binary library to use 1% of it's functions, which I consider a waste of space on the server.
    • Deployment: So imagine one day you find yourself needing to migrate to a different hosting provider. If that provider 'does not support' ImageMagick, you will find yourself re-writing code in a way that will allow your site to continue functioning.
    • Availability: use ImageMagick if you know it will be available on the production servers. It's a great library and very easy to use, especially with the PHP implementations. The PHP GD libraries which are much more likely to be deployed on a default PHP server, and all it takes to get those going is some basic math (refer to my previous answer, except you'll need a PHP implementation)

    All that said, based on your likely considerations, I would opt for just using some simple GD PHP functionality (in conjunction with the 'backend resize' approach).

    Another alternative is to leverage a code library which is more focused on performing light changes on an image. One excellent library I found for this is TimThumb. It's just a hidden PHP file on your server - you give it a few GET parameters (source image url, destination size, resize mode, some filters, alignment... whatever you like) and the loaded result will be the requested image. It has support for caching requests so that it can easily return a previously called transform, if you find yourself performing the same resizes frequently.

    However, TimThumb appears to lack support for distinctly positioning an image, which puts it back in the realm of 'not a good solution' - so sticking with some handwritten GD PHP functions will work fine (except for the frustratingly longwinded programming nomenclature that is the GD function names, wink)

    Hope this helps! refer to my previous answer for help on the backend resize operations etc