follow-up of #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType
Problem/Motivation
While working on #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType, we realized that in the GD toolkit we are currently *always* loading fully an image into a GD resource. This is unnecessary overhead, as the actual GD resource is needed only if an image needs to be manipulated by applying operations to it. In most cases, $imageFactory->get()
will only be needed to determine MIME type, height and width to deliver an image to the client, which can be achieved by only calling getimagesize()
, and avoiding the current calls to image_type_to_extension()
, imagecreatefromxxx()
, and even overlaying if an image is not truecolor.
Proposed resolution
Split the logic:
ImageToolkitInterface::parseFile()
only rungetimagesize()
, and store its results in a 'preload' property that will be used by getMimeType, getHeight, getWidth if the GD resource has not been created yet- fully load the image in the GD resource only when an operation has to be applied on it, and getMimeType, getHeight, getWidth will then return their values dynamically from the resource
In doing so, move the image validity checking fully into the toolkit.
Remaining tasks
- review patch
User interface changes
Nope
API changes
One method added to ImageToolkitInterface
and implemented in GD and Test toolkits: isValid()
. ImageInterface::isValid()
just defers execution to the toolkit,
Comment | File | Size | Author |
---|---|---|---|
#16 | 2244359-16.patch | 13.14 KB | mondrake |
#16 | interdiff_14-16.txt | 3.36 KB | mondrake |
#14 | 2244359-14.patch | 11.59 KB | mondrake |
Comments
Comment #1
mondrakeBlockers are in, back to active
Comment #2
mondrakeTest only. We expect that when we get a fresh image from the factory, the load() method is not invoked, not even after calling getImage(), getWidth(), etc.
Comment #4
mondrakeHere's a patch. This introduces a new
setValid()
method onImageInterface
. This is becauseparseFile()
andload()
now are called in different times and may lead to independent errors so invalidating the image. This method will also be useful later when in #2063373: Cannot save image created from scratch we will need to validate a blank image after some processing (when we get an image via$image = \Drupal::service('image.factory')->get();
we are currently getting an image that has the $valid flag set to FALSE).Comment #6
mondrakeThe test failure in #4 is not related to load() method being called, but on the toolkit id returned by testGetToolkitId() being null instead of 'gd'. This is due to the way the stubs array was built in the test. This patch fixes the test in that respect + code standard and docs.
Comment #7
mondrakeComment #8
mondrakeComment #9
fietserwinPlease no, not another method on the interface that means nothing to the outside world. If Image needs info from the toolkit about the validity of the image source, add a method on toolkit that gets called by image.
This seems like too much activity and logic in a getter: this should end up as something like:
Where load has a quick return path or like:
When load() will always execute the loading.
In cases where we have 3 options, I would prefer using the same logic, thus either a nested ternary or an if/elseif/else, not an if followed by a ternary. (Same for getHeight)
be (instead of ba)
The first point will completely change the patch, so a new extensive review will be needed by then. However, I also doubt if this whole exercise is needed at all, as I prefer to reduce the functionality of the image system further according to the (now) related issue #2211227: Refactor image and imagetoolkit: isExisting, isSupported, supportedTypes, getMimeType. If we do that, there won't remain (m)any cases where an image object is created that will not undergo any processing. (Image field dimensions validation and then deciding that it is not needed to scale down is probably such a case.)
What do you think?
Comment #10
mondrakeThanks @fietserwin, all done. In fact point 1 is very valid, I moved the entire validity check at the toolkit level. Re. more generic point on #2257163: Restrict image system to image processing, I would only say that, no matter what, we need to be able to manage the image validity if we want to address #2063373: Cannot save image created from scratch: currently if we get() an image from the factory with no source file specified, it will be invalid, and there are no ways to make it valid through an operation.
Comment #14
mondrakeFix for the failing test + cleanup.
Comment #15
fietserwinGreat, this is much better. I would RTBC it in this state, but would even more appreciate it if the few nitpicks below are solved. These are not all are introduced by this patch here, but as this patch does touch the code, we might as well improve it here in this patch. So you may set it to NR (with a new patch) or RTBC if you think that these should not be part of this patch.
This is not properly documenting the return value but the desired side effect of the function.
@var resource|null (as we accept and explicitly handle null values for this property).
- @ var array|null (as we accept and explicitly handle null values for this property).
- We may consider more explicitly documenting what info from a file it contains, i.e. refer to @see imagegetsize().
The if is not necessary.
Comment #16
mondrakeThanks.
All done.
Re. #15.1 - I took a step further and just removed parseFile() from Image, I believe we no longer need a separate method here.
Adjusted issue summary.
Comment #17
fietserwinTop, even better so.
Comment #19
webchickHm. That $load_expected param kinda hurts my brain, but I guess as long as it's isolated to tests it's not a huge deal.
Committed and pushed to 8.x. Thanks!
Comment #20
fietserwinThanks, added a remark to issue #2109459: Review image test suite about that param.