[wp-trac] [WordPress Trac] #42663: Imagick support for stream wrappers

WordPress Trac noreply at wordpress.org
Wed Sep 30 07:46:46 UTC 2020


#42663: Imagick support for stream wrappers
-------------------------------------------------+-------------------------
 Reporter:  calin                                |       Owner:
                                                 |  mikeschroder
     Type:  enhancement                          |      Status:  assigned
 Priority:  normal                               |   Milestone:  5.6
Component:  Media                                |     Version:
 Severity:  normal                               |  Resolution:
 Keywords:  has-patch 2nd-opinion has-unit-      |     Focuses:
  tests                                          |
-------------------------------------------------+-------------------------

Comment (by p00ya):

 Sorry for the delay in replying (replies below required a bit of fact-
 checking).

 Replying to [comment:21 mikeschroder]:
 > > 1. should I add support for very old versions of the imagick extension
 as @calin's patch did?  Pros: works with old PHP; Cons: adds some code
 bloat.
 >
 > I did a bit of research here (both on @calin and your proposed Imagick
 functions to use).
 > After that, I’m not clear which versions of the Imagick extension we’d
 be dropping if we go with the approach in the PR, as the new function,
 `readImageBlob`, seems to be available from 2.0.0.
 >
 > A couple of datapoints to help the discussion:
 > - Right now, [https://github.com/WordPress/wordpress-
 develop/blob/master/src/wp-includes/class-wp-image-editor-imagick.php#L35
 2.2.0 is required].
 >
 > - This might not be representative, but as a spot check, looks like the
 majority of [https://make.wordpress.org/hosting/test-results/ recent test
 reporters] that support Imagick have 3.4.4.
 >
 > I'm guessing I'm missing something here -- Could you please explain what
 you've found so far?

 I agree with your analysis.  readimageblob has been around since imagick
 2.0.0
 [https://github.com/Imagick/imagick/blob/d0f8197c32b2075adb2806d2c413efb091ef63de/imagick.c
 this commit].  When I asked if I should add compatibility I was only
 looking at differences with calin's patch, without comparing the imagick
 history and the min version already enforced by WordPress.  Nothing to be
 done here.

 >
 >
 > > 2. should I try and call `make_image` from `_save` like @calin's patch
 did.  Pros: ??; Cons: convoluted code.
 >
 > `make_image()` was added to the class specifically to separate file
 stream concerns, so that's the reason I gave the earlier feedback.
 >
 > As an example, [https://github.com/WordPress/wordpress-
 develop/blob/master/src/wp-includes/class-wp-image-editor-gd.php#L508 this
 is how GD handles it].
 >
 > Would you mind going into a little detail on why you think it's a better
 not to use it in this case?

 Sure (apologies if this comes across as blunt - it's just my opinion).

 `WP_Image_Editor::make_image($filename, $function, $arguments)`'s contract
 is something like:
  If $filename is a stream URL, call $function($arguments...).  $function
 should output an image, and `make_image` will take care of capturing it in
 a buffer and then writing it to $filename.

 This is an unfortunate API design: make_image is doing two things:
 abstracting files vs streams, and also doing the output buffering stuff.
 In the imagick case, the output buffering is unnecessary because we can
 get the bytes directly with `getImageBlob` and then naturally write them
 with PHP's `file_put_contents`.

 Comparing the code complexity:
 * calling `file_put_contents` is simpler than the `fopen`/`fwrite` logic
 in `make_image` for writing to a file/stream
 * setting up a callback for `make_image` is a bunch of boilerplate
 * calling `getImageBlob` is simpler than writing an image to output just
 so that it can be `ob_get_contents()` and put back in a string.
 * all this so that the image editor can move (not even eliminate, as
 `WP_Image_Editor_GD` demonstrates!) a single branch depending on whether
 the output is a stream URL.

 I am also suspicious about extra copies using `make_image` but I haven't
 done any profiling to demonstrate this.  While the extra copies are
 perhaps fanciful, memory usage being a concern is not: image operations
 are the only time I hit container limits (memory) on a cloud WordPress
 install.  Ideally we'd actually push the stream write into the imagick
 extension (where it only needs to buffer a block at a time), but as noted
 it's a bit buggy in this regard (eventually this might get fixed in
 imagick or ImageMagick proper).  In that case, we'd definitely want to
 skip `make_image`.

 If `make_image` had hooks then maybe there would be more of a case for
 unifying on it (maybe a plugin could use the hook to set ACLs or such, and
 we would want that to work regardless of image editor and is_streamness).
 But there are no hooks, so to me it looks like `make_image` is an awkward
 solution looking for a problem, and PHP/imagick provide a superior
 solution OOTB in this case.

 >
 > > 3. should I add a dummy stream wrapper for testing like @calin's patch
 did instead of testing with `file://` URLs?  Pros: more likely to pick up
 future bugs if the code relies on features like seekable streams; Cons:
 bunch of extra code in the tests for the fake stream.
 >
 > I think that the more tests the better if it will improve coverage,
 since this is a less commonly used feature that has had a series of bugs.
 But of course, any tests you have the time to include are appreciated.

 I'll add the better tests this weekend (though I won't object to the
 existing PR being merged in the meantime!).

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/42663#comment:22>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list