Make WordPress Core

Changeset 58456


Ignore:
Timestamp:
06/21/2024 07:49:19 PM (3 months ago)
Author:
joedolson
Message:

Media: Fix admin image cropping calculations.

The admin image editor crop function introduced rounding errors by using a scaled image to calculate values. Fix uses the image at 100% scale for calculations. Also avoid recalculating selection when the selection position is changed, and prevent incorrect values after scaling or restoration.

Props Jossnaz, johnillo, shailu25, rachelbaker, sudipatel007, joedolson.
Fixes #32282.

Location:
trunk/src
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/js/_enqueues/lib/image-edit.js

    r56653 r58456  
    144144     */
    145145    init : function(postid) {
    146         var t = this, old = $('#image-editor-' + t.postid),
    147             x = t.intval( $('#imgedit-x-' + postid).val() ),
    148             y = t.intval( $('#imgedit-y-' + postid).val() );
     146        var t = this, old = $('#image-editor-' + t.postid);
    149147
    150148        if ( t.postid !== postid && old.length ) {
     
    152150        }
    153151
    154         t.hold.w = t.hold.ow = x;
    155         t.hold.h = t.hold.oh = y;
    156         t.hold.xy_ratio = x / y;
    157152        t.hold.sizer = parseFloat( $('#imgedit-sizer-' + postid).val() );
    158153        t.postid = postid;
     
    187182
    188183        $( document ).on( 'image-editor-ui-ready', this.focusManager );
     184    },
     185
     186    /**
     187     * Calculate the image size and save it to memory.
     188     *
     189     * @since 6.6.0
     190     *
     191     * @memberof imageEdit
     192     *
     193     * @param {number} postid The post ID.
     194     *
     195     * @return {void}
     196     */
     197    calculateImgSize: function( postid ) {
     198        var t = this,
     199        x = t.intval( $( '#imgedit-x-' + postid ).val() ),
     200        y = t.intval( $( '#imgedit-y-' + postid ).val() );
     201
     202        t.hold.w = t.hold.ow = x;
     203        t.hold.h = t.hold.oh = y;
     204        t.hold.xy_ratio = x / y;
     205        t.hold.sizer = parseFloat( $( '#imgedit-sizer-' + postid ).val() );
     206        t.currentCropSelection = null;
    189207    },
    190208
     
    526544                i = history[n];
    527545                if ( i.hasOwnProperty('c') ) {
    528                     op[n] = { 'c': { 'x': i.c.x, 'y': i.c.y, 'w': i.c.w, 'h': i.c.h } };
     546                    op[n] = { 'c': { 'x': i.c.x, 'y': i.c.y, 'w': i.c.w, 'h': i.c.h, 'r': i.c.r } };
    529547                } else if ( i.hasOwnProperty('r') ) {
    530548                    op[n] = { 'r': i.r.r };
     
    861879            this.init( postid );
    862880        }
     881        this.calculateImgSize( postid );
    863882
    864883        this.initCrop(postid, img, parent);
     
    910929            selW = $('#imgedit-sel-width-' + postid),
    911930            selH = $('#imgedit-sel-height-' + postid),
    912             selX = $('#imgedit-start-x-' + postid),
    913             selY = $('#imgedit-start-y-' + postid),
    914931            $image = $( image ),
    915932            $img;
     
    946963                 * @return {void}
    947964                 */
    948                 parent.children().on( 'mousedown, touchstart', function(e){
    949                     var ratio = false, sel, defRatio;
    950 
    951                     if ( e.shiftKey ) {
    952                         sel = t.iasapi.getSelection();
    953                         defRatio = t.getSelRatio(postid);
    954                         ratio = ( sel && sel.width && sel.height ) ? sel.width + ':' + sel.height : defRatio;
     965                parent.children().on( 'mousedown touchstart', function(e) {
     966                    var ratio = false,
     967                        sel = t.iasapi.getSelection(),
     968                        cx = t.intval( $( '#imgedit-crop-width-' + postid ).val() ),
     969                        cy = t.intval( $( '#imgedit-crop-height-' + postid ).val() );
     970
     971                    if ( cx && cy ) {
     972                        ratio = t.getSelRatio( postid );
     973                    } else if ( e.shiftKey && sel && sel.width && sel.height ) {
     974                        ratio = sel.width + ':' + sel.height;
    955975                    }
    956976
     
    10011021             */
    10021022            onSelectChange: function(img, c) {
    1003                 var sizer = imageEdit.hold.sizer;
    1004                 selW.val( imageEdit.round(c.width / sizer) );
    1005                 selH.val( imageEdit.round(c.height / sizer) );
    1006                 selX.val( imageEdit.round(c.x1 / sizer) );
    1007                 selY.val( imageEdit.round(c.y1 / sizer) );
     1023                var sizer = imageEdit.hold.sizer,
     1024                    oldSel = imageEdit.currentCropSelection;
     1025
     1026                if ( oldSel != null && oldSel.width == c.width && oldSel.height == c.height ) {
     1027                    return;
     1028                }
     1029
     1030                selW.val( Math.min( imageEdit.hold.w, imageEdit.round( c.width / sizer ) ) );
     1031                selH.val( Math.min( imageEdit.hold.h, imageEdit.round( c.height / sizer ) ) );
     1032
     1033                t.currentCropSelection = c;
    10081034            }
    10091035        });
     
    10231049     */
    10241050    setCropSelection : function(postid, c) {
    1025         var sel;
     1051        var sel,
     1052            selW = $( '#imgedit-sel-width-' + postid ),
     1053            selH = $( '#imgedit-sel-height-' + postid ),
     1054            sizer = this.hold.sizer,
     1055            hold = this.hold;
    10261056
    10271057        c = c || 0;
     
    10381068        }
    10391069
    1040         sel = { 'x': c.x1, 'y': c.y1, 'w': c.width, 'h': c.height };
     1070        // adjust the selection within the bounds of the image on 100% scale
     1071        var excessW = hold.w - ( Math.round( c.x1 / sizer ) + parseInt( selW.val() ) );
     1072        var excessH = hold.h - ( Math.round( c.y1 / sizer ) + parseInt( selH.val() ) );
     1073        var x = Math.round( c.x1 / sizer ) + Math.min( 0, excessW );
     1074        var y = Math.round( c.y1 / sizer ) + Math.min( 0, excessH );
     1075
     1076        // use 100% scaling to prevent rounding errors
     1077        sel = { 'r': 1, 'x': x, 'y': y, 'w': selW.val(), 'h': selH.val() };
     1078
    10411079        this.setDisabled($('.imgedit-crop', '#imgedit-panel-' + postid), 1);
    10421080        $('#imgedit-selection-' + postid).val( JSON.stringify(sel) );
     
    11661204        this.closePopup(t);
    11671205        this.addStep({ 'r': { 'r': angle, 'fw': this.hold.h, 'fh': this.hold.w }}, postid, nonce);
     1206
     1207        // Clear the selection fields after rotating.
     1208        $( '#imgedit-sel-width-' + postid ).val( '' );
     1209        $( '#imgedit-sel-height-' + postid ).val( '' );
     1210        this.currentCropSelection = null;
    11681211    },
    11691212
     
    11881231        this.closePopup(t);
    11891232        this.addStep({ 'f': { 'f': axis, 'fw': this.hold.w, 'fh': this.hold.h }}, postid, nonce);
     1233
     1234        // Clear the selection fields after flipping.
     1235        $( '#imgedit-sel-width-' + postid ).val( '' );
     1236        $( '#imgedit-sel-height-' + postid ).val( '' );
     1237        this.currentCropSelection = null;
    11901238    },
    11911239
     
    12201268
    12211269        // Clear the selection fields after cropping.
    1222         $('#imgedit-sel-width-' + postid).val('');
    1223         $('#imgedit-sel-height-' + postid).val('');
    1224         $('#imgedit-start-x-' + postid).val('0');
    1225         $('#imgedit-start-y-' + postid).val('0');
     1270        $( '#imgedit-sel-width-' + postid ).val( '' );
     1271        $( '#imgedit-sel-height-' + postid ).val( '' );
     1272        $( '#imgedit-start-x-' + postid ).val( '0' );
     1273        $( '#imgedit-start-y-' + postid ).val( '0' );
     1274        this.currentCropSelection = null;
    12261275    },
    12271276
     
    13131362            sizer = this.hold.sizer, x1, y1, x2, y2, ias = this.iasapi;
    13141363
     1364        this.currentCropSelection = null;
     1365
    13151366        if ( false === this.validateNumeric( el ) ) {
    13161367            return;
     
    13361387                x1 = 0;
    13371388                x2 = imgw;
    1338                 elX.val( Math.round( x2 / sizer ) );
     1389                elX.val( Math.min( this.hold.w, Math.round( x2 / sizer ) ) );
    13391390            }
    13401391
     
    13421393                y1 = 0;
    13431394                y2 = imgh;
    1344                 elY.val( Math.round( y2 / sizer ) );
     1395                elY.val( Math.min( this.hold.h, Math.round( y2 / sizer ) ) );
    13451396            }
    13461397
     
    13481399            ias.update();
    13491400            this.setCropSelection(postid, ias.getSelection());
     1401            this.currentCropSelection = ias.getSelection();
    13501402        }
    13511403    },
  • trunk/src/wp-admin/includes/image-edit.php

    r58214 r58456  
    736736                    $h    = $size['height'];
    737737
    738                     $scale = 1 / _image_get_preview_ratio( $w, $h ); // Discard preview scaling.
     738                    $scale = isset( $sel->r ) ? $sel->r : 1 / _image_get_preview_ratio( $w, $h ); // Discard preview scaling.
    739739                    $image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
    740740                } else {
    741                     $scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // Discard preview scaling.
     741                    $scale = isset( $sel->r ) ? $sel->r : 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // Discard preview scaling.
    742742                    $image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
    743743                }
Note: See TracChangeset for help on using the changeset viewer.