Problem/Motivation
In the current code, the determination of the effective cropping coordinates are spread between JS and PHP.
We should have a clean architecture that makes us error prone and flexible in presentation, also responsiveness.
Proposed resolution
IMHO, the only thing that is relevant for the server is the original image dimension.
Agree, we introduce a crop preview image that is downscaled already, but that's more a convenience for image delivery with smaller file size.
It's the client that then needs to determine based on the screen geometry at what scale the image is presented (1:1 or for instance 100% on any mobile screen).
Thus, the cropper is initialised at a specific size with cropping data.
At that display time, initialisation can determine a scaling in JS.
When extracting the effective cropping coordinates, the displaying scale can be inverted to determine the paremeters in context of the original image.
I propose to add data attributes to the cropper image output with original width and height to drive the cropper initialisation.
The form values to collect the effective cropping coordinates / width / height are also in original context.
Thus PHP doesn't care about image scaling at all. Just JS.
Most calculations from getThumbnailCalculatedProperties would move to JS. Also getAxisCoordinates would be more a client side determination.
I might be wrong, but i also don't get why we need thumb-w and thump-h at all, at least not as hidden input elements.
At the same time, an aspect-ratio data attribute can be added that is properly precalculated in PHP and doesn't need JS eval.
Additionally, the server should do some health checks to avoid crop parameters exceed the image max dimensions in validation.
Remaining tasks
Discuss if this approach is supported by all, decide.
Then reimplement calculations.
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | interdiff-2641970-29.txt | 2.22 KB | sanja_m |
| #29 | 2641970-29.patch | 15.92 KB | sanja_m |
| #17 | interdiff-2641970-17.txt | 5.03 KB | sanja_m |
| #17 | 2641970-17.patch | 14.75 KB | sanja_m |
Comments
Comment #2
slashrsm commentedI agree. Anything that has to do with display is something that should be handled by code that is responsible for display. Crop information itself doesn't and shouldn't care about this details.
Comment #3
luksakIMO JS should contain as few calculation logic as possible. All of the crop calculation happens on the PHP side already. So why should we have it in JS here?
Do we have that much calculation on the JS side? the only thing we do is rounding the values Cropper outputs:
Before the
cropendcallback is being executed, Cropper calculates the coordinates based on the downscaling of the image style.Is this solution that bad?
Another option would be to only calculate relative (percentages) of the cropping data in JS and then do the rest of the calculations in PHP. I guess this would be more accurate since we round only once.
Comment #4
miro_dietikerAs long as you think in image styles and static values, you think this is a good idea.
When you then consider that the effective cropper size (width, height) is a dynamic decision and can be any scale... a UI could offer full screen zoom any everything else, you realise that scale is a pure client decision. And the PHP domain should only operate in origin scale. Everything else adds complexity.
I guess, the current solution didn't yet end up at that problem because you're not yet dynamically supporting to scale cropper to the effective viewport size of mobile cases. Related tickets are open, is it?
Comment #5
sanja_m commentedAssigning to me.
Comment #6
sanja_m commentedI removed thumb-w and thumb-h input elements and eval() from JS and precalculated aspect ratio in PHP, currently I am working on scaling determination in JS during initialisation of the cropper, I am not sure if I understood that part of the issue properly, I will use getImageData() function from the cropper to determine width and height of the preview image that is used to initialize cropper and will send data attribute with original image width and height, and with those data I will calculate the delta, that is image scaling.
Comment #7
woprrr commentedI think we need at first to agree. I highly Lukas joined in the sense that we must not calculate dimenssions via JS because the whole system is based on images_style. Let me explain to correctly pass the user select area we need more data that is not available through JS interogeant but in drupal. To reflect the selected area on a ui style picture we need to know the dimmensions thumbnail image to determine the enlargement or reduction rate of the thumbnail image to affect the original image
The data manipulated by JS are primarily intended to pass on a crop area on the thumbnail precise manner.
@sanja_m : The ratio must not be it calculated automatically, this was one of the old functionality of the module and it has been proved that often the user or graphic uses ratios "as non-standard 95:35.
Comment #8
sanja_m commentedThis is my unfinished patch, what I started to change, now I am not sure should we continue with this issue, and if we should is this the right direction?
Comment #9
miro_dietikerwoprrr, i have proposed the approach and discussed with team. i updated the proposal and explained all reasons why this is important and simplifies the situation. Janez also agrees.
Please let sanja provide a patch that cleans up the situation with our review.
I'm pretty sure the patch will easily visualise that the complexity is reduced with this approach and that the responsibility between backend and UI is better separated and you will like it when you think about it again.
woprrr, if it's important for you to keep aspect ratio in the original definition domain, we can do this:
We add two data attributes ratio_x and ratio_y and do the devision in JS.
Why limit precision to only 2 digits? That's too short.
For sure, "NaN" is not to be translated. Remove t(). Also in case of NaN, the division is messing up. Let's add a proper if for the case an aspect ratio is defined.
I prefer a multiline notation so we can see the attributes easily.
Please delete, not comment.
Comment #10
miro_dietikerComment #11
slashrsm commentedYes, I agree. It totally makes sense to have all calculation logic in one place. All PHP should be interested in is original image and crop information in it's context. This also makes code useful for other usages where presentation might be different. We are already trying to bring IWC to file_entity edit page. True, presentation will be very similar, but anyway. I still think it is a valid point.
Comment #12
sanja_m commentedFixed all issues from comment #9 except the first one. @woprrr should I add two data attributes ratio_x and ratio_y and move the devision in JS like Miro suggested?
Also removed some unnecessary functions from PHP, because now coordinate calculations are moved to JS.
Comment #13
miro_dietikerYeah this looks much better and i can see that a significant part of complexity is going away in the diff. (I hope you didn't drop too much though.)
This needs more testing and in depth review. Happy if everyone involved can take a look at it!
Comment #14
woprrr commentedI test & review it today but seem very GOOD :) @sanja_m thanks you verry much & @miro too for your help :)
Comment #15
slashrsm commentedI found a bug that this patch introduces. I tested on 8.x-1.x I wasn't able to reproduce. Steps:
- Enable image_widget_crop_example module
- Navigate to node/add/crop_simple_example
- Upload image and apply crop
- Save node
- Expected result: cropped image appears on view page
- Actual result: image is not cropped
- Edit node
- Re-apply crop
- Save
- Image is cropped now
And few more other comments:
D8 requires 5.5. Let's remove this comment as it makes no sense.
Why do we need to pass attribute values as arrays?
Rounding is not needed since we removed division with delta.
This also makes this function just a wrapper that copies array values to another array. We may not need it any more.
.
Comment #16
sasanikolic commentedThe comments above make sense... I've also tested it and can confirm that the cropping is not saved correctly. Let's debug and fix it.
But the approach is good and nice to have a proper cleanup!
Comment #17
sanja_m commentedFixed all bugs from comment #15.
Comment #18
woprrr commentedI ve re-create patch with last version of repo, there was a problem to apply the patch on the most recent version of the module. (Line 209)
I am under review thank you for the work.
Comment #19
woprrr commentedGreat job !!!
Your patch fix another problem too (the image appears more completely in the thumbnail).
There is just one aspect that is not available is the respect of the ratio, the crop area is always free now since I applied the patch.
But this is good way !
Step to reproduce :
Enable image_widget_crop_example module
- Navigate to node/add/crop_simple_example
- Upload image and apply crop in 16:9 tabs
Your crop area is free and not fix to 16:9 ratio.
@see
Comment #20
slashrsm commentedI was able to reproduce this problem too.
Comment #21
woprrr commentedIs eval() deletion.... :( I try to find a way not to do that ...
I think cropper accept only an number value with this option. We sould calculate this 16 : 9 = 1.7777777777777777 and if we take this cropper work fine.
Comment #22
slashrsm commentedeval() is evil. We should find a different solution.
Comment #23
woprrr commentedYes this is evil but the solution is under our eye O-O, the ratio is formated in good format like (16/9) and we need to just added () in ratio variable to proced the division W/H = aspect ratio number.
All seems good now for me aspect ratio are applied now we can confirm if is good for you too ?
Comment #24
woprrr commentedComment #27
slashrsm commentedTrue. It is formatted correctly when module does it. But what if someone changes that somehow?
I'd feel much better if we'd actually make sure ratio is what we expect it to be. Maybe split string, make sure there are integers on both sides and do division.
Another strange thing. Above we assign values of cropperOptions to options. Then we add some stuff to options and pass cropperOptions to the cropper initialization.
Why do we need to create new variable (options) at all?
Comment #28
woprrr commentedOk i ve seen and add some test to ensure data ratio isNumeric to procced to division.
For me all it's all Ok fonctionaly.
@slashrsm : I think we add some stuff in option when user not have aready clic on vertical tab, when user open details element js trigger we need to get an options with data empty but with aspectRatio set.
Comment #29
sanja_m commentedJust removed ImageWidgetCropManager::getThumbnailCalculatedProperties() since we don't need it anymore.
Comment #30
slashrsm commentedLooks good.
Comment #32
woprrr commentedThank a lot all :) @sanja_m Great job !!
Comment #33
miro_dietikerMany thanks from my side also. Party time! :-)