webp-convert icon indicating copy to clipboard operation
webp-convert copied to clipboard

Feature Request: input/output - Imagick objects, binary blobs, GD objects?

Open Kadigan opened this issue 4 years ago • 7 comments

Would it be possible to have your converter handle these things? In order of importance to me, it'd be Imagick, then blobs (binary file contents), then GD objects.

The way I'd expect this feature to work would be that instead of providing a $src and $dst, I could simply provide one param - an object of either Imagick or GD, or a binary blob - and have the process return the result in kind?

Being able to handle Imagick objects is important to me - I need to perform colorspace conversions, and I want to do it using Imagick even if it doesn't support WebP.

Being able to handle binary blobs is important to me - I sometimes need to process images in environments where saving files to disk is impossible/prohibited, and I would much rather receive a binary blob in response. (Thankfully, this should be somewhat trivial - to fetch the blob, you can wrap GD with output buffering, or just Imagick::getImageBlob(); similarly, reading the blob is trivial in both w/ Imagick::readImageBlob() and imagecreatefromstring())

The inclusion of GD objects - simply for completeness' sake - not important to me personally, since the GD library doesn't do well w/ non-sRGB images, so I don't use it much.

I am aware that using any of these would probably make the process incompatible w/ some of the methods (notably anything exec-related).

Notably, this may also be useful for people that deal with environments where storing any sort of files is disallowed (some hosts even disallow access to folders like /tmp), and instead every resource is sourced from - and stored in - a database (as binary blobs). I know this isn't the most efficient solution, but these exist.

It might be helpful if your converter first brought images to sRGB. As far as I'm aware, PHP's GD library doesn't support colour profiling, so this is something that might trip you up if you're not aware of the issue.


I've been told that in order to have ImageMagick w/ WebP support that supports profiles, you need to build it specifically w/ lcms - but from what I can see, it should be built by default (in fact, you need to build it with --disable-lcms=yes in order to not have it), so I don't know how much truth there is to that statement, or how difficult it is to determine whether ICC profiles are working or not (I personally haven't had much luck yet).

This may be important, because there may be people like me - those that flocked to PHP::Imagick over GD2 because of its ICC support - that may get tripped up by this issue. I spent about 3 hours trying various approaches before I realised I was getting sRGB on output (and for me, this is important because I use these libraries to manipulate professionally-manipulated photographs).

Kadigan avatar Oct 11 '19 12:10 Kadigan

Hi Kadigan,

Thanks for your suggestions.

I'm not inclined to provide multiple signatures for the ::convert() method. But I could simply provide a new ::convertBlob() method for receiving and returning blobs. This goes better with doc comments. The strongly typing via doc comments are useful because they help track errors (by the help of PHPStan and Scrutinizer).

Similar, we could have a ::convertObject() method on the Imagick class, which receives and returns an Imagick object.

I'm wondering if there would be need for a an output that is different than the input. This could be implemented with a return-type option. However, this would require loosing up the return type in the doc-comments, so there is a price. I'm guessing there is no real need as converting a blob or an image to a file is trivial, as you say.

rosell-dk avatar Oct 23 '19 07:10 rosell-dk

Yes, it seems blobs would be a problem for the exec converters. We could of course save the blob as a file first, do the conversion and return the content of the file. But this will not work in environments where storing files is disallowed. So this apparently won't do, as this is exactly why we would want a ::convertBlob() method. But on the other hand, it will do if there is just a single place we can write - for example /tmp.

It is possible to pass a blob to ImageMagick via the command line 1 2. However, this will only work for small files. My system allows ~2MB on the command line.

So if files are out of the question and command line too, what is left? There is of course the possibility of executing a database query directly from the command line. But this is problematic for several reasons. It seems that to solve this, one would need some serious trickery. Perhaps executing php from the command line could be part of such solution. Or using some other command. Or creating our own binary. The main problem seems to be finding a place to store the blob that will be accessible from a shell command when neither a regular file nor the command line itself is an option.

rosell-dk avatar Oct 23 '19 08:10 rosell-dk

No issue from me on having different methods for these things, so long as they're nicely summed up somewhere in the main readme. All I ask is for the functionality to be there.

Being able to process images w/o having access to writeable disk space is an uncommon requirement - true... but when you find you have a problem like that, there aren't that many solutions for it.

As for processing blobs - thankfully, PHP has its own implementation of ImageMagick (the Imagick class), and it can both read and output binary blobs just fine (there are built-in methods for doing both). GD2 can also process blobs directly - it has imagecreatefromstring() if memory serves (makes you wonder why other format creators are exposed, if you can read every supported image type with a combo like imagecreatefromstring(file_get_contents( ... )) without even needing to know what you're opening), and you can catch output w/ output buffering.

Kadigan avatar Oct 23 '19 11:10 Kadigan

Hm. Looking more closely in the source, I realize that such change will be api breaking. The AbstractConverter class, which the rest of the converter classes are based upon takes $source and $destination in the constructor. Or, alternatively, I must do as you suggest and fake multiple signatures for that constructor.

rosell-dk avatar Oct 23 '19 12:10 rosell-dk

Forget that last post. I can simply set an (internal) option for ignoring/overriding those arguments. Ie input-type (default: "file") and output-type (default: "file")

rosell-dk avatar Oct 23 '19 12:10 rosell-dk

I dropped this ball. Is it still relevant?

rosell-dk avatar Nov 10 '20 11:11 rosell-dk

To be honest I haven't done a lot of work with this - I entirely dropped the work due to having colour profile issues, and to a lesser extent because the produced .webp files weren't offering great savings. The functionality I asked for was more of a quality-of-life thing, and I'd still like to see it included at some point... but like I said, due to various issues, I dropped WebP support entirely -- I couldn't get the colours right, and when I eventually did, the savings were marginal (to the tune of maybe 10% difference, if that much).

If I ever get back to this, I'd love to see the ability to manipulate these blobs/objects in a more direct manner. My primary issue was that I had to save an image (meaning: find a place to store it temporarily), then open it in your converter to work on it further, and finally save it somewhere with persistence - without the ability to output it directly to the browser. I was considering your converter more in a "transparent filter" application, where neither the end-user nor the employed CMS would have to be aware of there being any conversion actually done (original files would remain, the outputs would not be stored, and I would trade processing time for having less clutter to deal with overall).

Kadigan avatar Nov 12 '20 04:11 Kadigan