使用媒体上传器选择特定大小的图像,执行裁剪

时间:2017-10-03 作者:Vivek Athalye

我跟踪了this article 在我的代码中使用媒体上载程序。当我单击表单上的浏览按钮时,媒体上载程序会打开,选择图像后,我会在我的表单字段中添加该图像的URL。目前没有问题。

但我想强制图像具有特定的大小。如果大小不同,用户必须裁剪它以匹配所需的大小(或纵横比)before 他可以选择图像(和我的mediaUploader.on(\'select\', function() { 已执行)。

请注意,我不想使用add_image_size 因为这将为上传的每个图像创建一个给定大小的缩略图(好吧,如果我错了,请纠正我)。相反,仅在特定场景中,我希望用户在上载时手动裁剪图像。

基本上,我的要求在一个问题中得到了很好的描述,因此:wordpress-media-library-crop-image-on-insert-like-header-image-cropper

但那里没有发布解决方案。所以我把它放在这里,让WP专家来指导我。

我试着搜索“wordpress media uploader(强制图像大小|图像裁剪器|选择特定大小的图像)”之类的东西。但不知何故,没有任何链接来描述实施给定图像大小的步骤。我也找不到wp.media 它描述了可以传递的所有选项。

我已经看到了以下问题,但这似乎不符合我的要求:

Edit

我可以找到WP_Customize_Cropped_Image_Control @ https://www.sitepoint.com/using-the-wordpress-customizer-media-controls/但它是在Customizer的上下文中。是否有任何类似的控件可以在标准插件中使用?

还有这个wp.media.controller.Cropper 在wp中定义包括/js/media视图。但是我该如何使用它呢?

3 个回复
最合适的回答,由SO网友:Vivek Athalye 整理而成

首先在任何页面上使用@Darren给出的代码。为了简单起见,我将PHP和JS代码组合在一个块中:

  <?php $heading_picture = esc_attr(get_option( \'heading_picture\' )); ?>
  <input type="hidden" name="heading_picture" id="heading_picture" value="<?php echo $heading_picture; ?>" />
  <img id="heading_picture_preview" class="heading-picture" src="<?php echo $heading_picture; ?>" />
  <button id="btn_heading_picture" name="btn_heading_picture" class="button default">Choose Picture</button>
<script>
jQuery(function($) {

function myTheme_calculateImageSelectOptions(attachment, controller) {

    var control = controller.get( \'control\' );

    var flexWidth = !! parseInt( control.params.flex_width, 10 );
    var flexHeight = !! parseInt( control.params.flex_height, 10 );

    var realWidth = attachment.get( \'width\' );
    var realHeight = attachment.get( \'height\' );

    var xInit = parseInt(control.params.width, 10);
    var yInit = parseInt(control.params.height, 10);

    var ratio = xInit / yInit;

    controller.set( \'canSkipCrop\', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );

    var xImg = xInit;
    var yImg = yInit;

    if ( realWidth / realHeight > ratio ) {
        yInit = realHeight;
        xInit = yInit * ratio;
    } else {
        xInit = realWidth;
        yInit = xInit / ratio;
    }        

    var x1 = ( realWidth - xInit ) / 2;
    var y1 = ( realHeight - yInit ) / 2;        

    var imgSelectOptions = {
        handles: true,
        keys: true,
        instance: true,
        persistent: true,
        imageWidth: realWidth,
        imageHeight: realHeight,
        minWidth: xImg > xInit ? xInit : xImg,
        minHeight: yImg > yInit ? yInit : yImg,            
        x1: x1,
        y1: y1,
        x2: xInit + x1,
        y2: yInit + y1
    };

    return imgSelectOptions;
}  

function myTheme_setImageFromURL(url, attachmentId, width, height) {
    var choice, data = {};

    data.url = url;
    data.thumbnail_url = url;
    data.timestamp = _.now();

    if (attachmentId) {
        data.attachment_id = attachmentId;
    }

    if (width) {
        data.width = width;
    }

    if (height) {
        data.height = height;
    }

    $("#heading_picture").val( url );
    $("#heading_picture_preview").prop("src", url);        

}

function myTheme_setImageFromAttachment(attachment) {

    $("#heading_picture").val( attachment.url );
    $("#heading_picture_preview").prop("src", attachment.url);             

}

var mediaUploader;

$("#btn_heading_picture").on("click", function(e) {

    e.preventDefault(); 

    /* We need to setup a Crop control that contains a few parameters
       and a method to indicate if the CropController can skip cropping the image.
       In this example I am just creating a control on the fly with the expected properties.
       However, the controls used by WordPress Admin are api.CroppedImageControl and api.SiteIconControl
    */

   var cropControl = {
       id: "control-id",
       params : {
         flex_width : false,  // set to true if the width of the cropped image can be different to the width defined here
         flex_height : true, // set to true if the height of the cropped image can be different to the height defined here
         width : 300,  // set the desired width of the destination image here
         height : 200, // set the desired height of the destination image here
       }
   };

   cropControl.mustBeCropped = function(flexW, flexH, dstW, dstH, imgW, imgH) {

    // If the width and height are both flexible
    // then the user does not need to crop the image.

    if ( true === flexW && true === flexH ) {
        return false;
    }

    // If the width is flexible and the cropped image height matches the current image height, 
    // then the user does not need to crop the image.
    if ( true === flexW && dstH === imgH ) {
        return false;
    }

    // If the height is flexible and the cropped image width matches the current image width, 
    // then the user does not need to crop the image.        
    if ( true === flexH && dstW === imgW ) {
        return false;
    }

    // If the cropped image width matches the current image width, 
    // and the cropped image height matches the current image height
    // then the user does not need to crop the image.               
    if ( dstW === imgW && dstH === imgH ) {
        return false;
    }

    // If the destination width is equal to or greater than the cropped image width
    // then the user does not need to crop the image...
    if ( imgW <= dstW ) {
        return false;
    }

    return true;        

   };      

    /* NOTE: Need to set this up every time instead of reusing if already there
             as the toolbar button does not get reset when doing the following:

            mediaUploader.setState(\'library\');
            mediaUploader.open();

    */       

    mediaUploader = wp.media({
        button: {
            text: \'Select and Crop\', // l10n.selectAndCrop,
            close: false
        },
        states: [
            new wp.media.controller.Library({
                title:     \'Select and Crop\', // l10n.chooseImage,
                library:   wp.media.query({ type: \'image\' }),
                multiple:  false,
                date:      false,
                priority:  20,
                suggestedWidth: 300,
                suggestedHeight: 200
            }),
            new wp.media.controller.CustomizeImageCropper({ 
                imgSelectOptions: myTheme_calculateImageSelectOptions,
                control: cropControl
            })
        ]
    });

    mediaUploader.on(\'cropped\', function(croppedImage) {

        var url = croppedImage.url,
            attachmentId = croppedImage.attachment_id,
            w = croppedImage.width,
            h = croppedImage.height;

            myTheme_setImageFromURL(url, attachmentId, w, h);            

    });

    mediaUploader.on(\'skippedcrop\', function(selection) {

        var url = selection.get(\'url\'),
            w = selection.get(\'width\'),
            h = selection.get(\'height\');

            myTheme_setImageFromURL(url, selection.id, w, h);            

    });        

    mediaUploader.on("select", function() {

        var attachment = mediaUploader.state().get( \'selection\' ).first().toJSON();

        if (     cropControl.params.width  === attachment.width 
            &&   cropControl.params.height === attachment.height 
            && ! cropControl.params.flex_width 
            && ! cropControl.params.flex_height ) {
                myTheme_setImageFromAttachment( attachment );
            mediaUploader.close();
        } else {
            mediaUploader.setState( \'cropper\' );
        }

    });

    mediaUploader.open();

});
});
</script>
然后在一些plugin 使用以下代码:

add_action( \'wp_enqueue_scripts\', \'vna_wp_enqueue_scripts\' );
function vna_wp_enqueue_scripts() {
    wp_enqueue_media();
    wp_enqueue_script( \'imgareaselect\', get_bloginfo(\'url\') . \'/wp-includes/js/imgareaselect/jquery.imgareaselect.js\', array( \'jquery\' ), \'1\', true );
    wp_enqueue_style( \'imgareaselect\', get_bloginfo(\'url\') . \'/wp-includes/js/imgareaselect/imgareaselect.css\', array(), \'0.9.8\' );
}
add_action( \'setup_theme\',\'vna_wp_ajax_crop_image\', 1 );
function vna_wp_ajax_crop_image() {
    global $wp_customize;
    if(isset($_REQUEST[\'action\']) && $_REQUEST[\'action\'] == \'crop-image\') {
        $post = new WP_Post(new stdClass());
        $post->ID = $_REQUEST[\'id\'];
        $post->post_type = \'customize_changeset\';
        $post->filter = \'raw\';

        wp_cache_set($wp_customize->changeset_uuid(), $post, \'customize_changeset_post\');
    }
}

Notes:

<有很多依赖于管理JS文件。早些时候,我试图根据测试期间遇到的JS错误,一个接一个地添加这些文件。然后我发现wp_enqueue_media() 它完成了大部分工作。它仍然无法加载imgareaselect JS和CSS,所以我们必须显式地加载它们plugin. 我在一个主题中尝试代码,但它不起作用,因为setup_theme 在预期事件之后调用主题中的操作(解释如下)。为了避免它,我不得不把它放在插件中edit_post 对图像的权限。如果没有,您将0 作为来自admin-ajax.php 当操作是crop-image.黑客之路:在setup_theme 优先级设置为的操作1. 这是因为class WP_Customize_Manager 有一个setup_theme 方法,并检查是否存在类型为的post id/postcustomize_changeset. 此外,后过滤器需要raw 否则,它会尝试从DB为给定的post ID加载post(在本例中,我们将图像ID设置为post ID),这会导致post type设置为attachment. 如果检查失败(找不到给定ID类型的postcustomize_changeset) 然后你得到-1 作为来自admin-ajax.php 当操作是crop-image. 我没有在DB中创建有效的变更集post,而是创建了一个伪post对象并将其添加到缓存中代码看起来不多,但正如我前面提到的my comment 发现这些情况真的很痛苦。我很高兴我终于成功了。

SO网友:Darren

看起来选择和裁剪功能目前仅在WordPress自定义程序中使用。

然而,在查看了WordPress管理文件夹中的代码后,我在我的主题选项页面上找到了它。

下面是我对标题图片的设置:

function setting_heading_picture() { 
  $heading_picture = esc_attr(get_option( \'heading_picture\' )); ?>
  <input type="hidden" name="heading_picture" id="heading_picture" value="<?php echo $heading_picture; ?>" />
  <img id="heading_picture_preview" class="heading-picture" src="<?php echo $heading_picture; ?>" />
  <button id="btn_heading_picture" name="btn_heading_picture" class="button default">Choose Picture</button>
}
下面是所需的管理javascript:

$(function() {

function myTheme_calculateImageSelectOptions(attachment, controller) {

    var control = controller.get( \'control\' );

    var flexWidth = !! parseInt( control.params.flex_width, 10 );
    var flexHeight = !! parseInt( control.params.flex_height, 10 );

    var realWidth = attachment.get( \'width\' );
    var realHeight = attachment.get( \'height\' );

    var xInit = parseInt(control.params.width, 10);
    var yInit = parseInt(control.params.height, 10);

    var ratio = xInit / yInit;

    controller.set( \'canSkipCrop\', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) );

    var xImg = xInit;
    var yImg = yInit;

    if ( realWidth / realHeight > ratio ) {
        yInit = realHeight;
        xInit = yInit * ratio;
    } else {
        xInit = realWidth;
        yInit = xInit / ratio;
    }        

    var x1 = ( realWidth - xInit ) / 2;
    var y1 = ( realHeight - yInit ) / 2;        

    var imgSelectOptions = {
        handles: true,
        keys: true,
        instance: true,
        persistent: true,
        imageWidth: realWidth,
        imageHeight: realHeight,
        minWidth: xImg > xInit ? xInit : xImg,
        minHeight: yImg > yInit ? yInit : yImg,            
        x1: x1,
        y1: y1,
        x2: xInit + x1,
        y2: yInit + y1
    };

    return imgSelectOptions;
}  

function myTheme_setImageFromURL(url, attachmentId, width, height) {
    var choice, data = {};

    data.url = url;
    data.thumbnail_url = url;
    data.timestamp = _.now();

    if (attachmentId) {
        data.attachment_id = attachmentId;
    }

    if (width) {
        data.width = width;
    }

    if (height) {
        data.height = height;
    }

    $("#heading_picture").val( url );
    $("#heading_picture_preview").prop("src", url);        

}

function myTheme_setImageFromAttachment(attachment) {

    $("#heading_picture").val( attachment.url );
    $("#heading_picture_preview").prop("src", attachment.url);             

}

var mediaUploader;

$("#btn_heading_picture").on("click", function(e) {

    e.preventDefault(); 

    /* We need to setup a Crop control that contains a few parameters
       and a method to indicate if the CropController can skip cropping the image.
       In this example I am just creating a control on the fly with the expected properties.
       However, the controls used by WordPress Admin are api.CroppedImageControl and api.SiteIconControl
    */

   var cropControl = {
       id: "control-id",
       params : {
         flex_width : false,  // set to true if the width of the cropped image can be different to the width defined here
         flex_height : true, // set to true if the height of the cropped image can be different to the height defined here
         width : 300,  // set the desired width of the destination image here
         height : 200, // set the desired height of the destination image here
       }
   };

   cropControl.mustBeCropped = function(flexW, flexH, dstW, dstH, imgW, imgH) {

    // If the width and height are both flexible
    // then the user does not need to crop the image.

    if ( true === flexW && true === flexH ) {
        return false;
    }

    // If the width is flexible and the cropped image height matches the current image height, 
    // then the user does not need to crop the image.
    if ( true === flexW && dstH === imgH ) {
        return false;
    }

    // If the height is flexible and the cropped image width matches the current image width, 
    // then the user does not need to crop the image.        
    if ( true === flexH && dstW === imgW ) {
        return false;
    }

    // If the cropped image width matches the current image width, 
    // and the cropped image height matches the current image height
    // then the user does not need to crop the image.               
    if ( dstW === imgW && dstH === imgH ) {
        return false;
    }

    // If the destination width is equal to or greater than the cropped image width
    // then the user does not need to crop the image...
    if ( imgW <= dstW ) {
        return false;
    }

    return true;        

   };      

    /* NOTE: Need to set this up every time instead of reusing if already there
             as the toolbar button does not get reset when doing the following:

            mediaUploader.setState(\'library\');
            mediaUploader.open();

    */       

    mediaUploader = wp.media({
        button: {
            text: \'Select and Crop\', // l10n.selectAndCrop,
            close: false
        },
        states: [
            new wp.media.controller.Library({
                title:     \'Select and Crop\', // l10n.chooseImage,
                library:   wp.media.query({ type: \'image\' }),
                multiple:  false,
                date:      false,
                priority:  20,
                suggestedWidth: 300,
                suggestedHeight: 200
            }),
            new wp.media.controller.CustomizeImageCropper({ 
                imgSelectOptions: myTheme_calculateImageSelectOptions,
                control: cropControl
            })
        ]
    });

    mediaUploader.on(\'cropped\', function(croppedImage) {

        var url = croppedImage.url,
            attachmentId = croppedImage.attachment_id,
            w = croppedImage.width,
            h = croppedImage.height;

            myTheme_setImageFromURL(url, attachmentId, w, h);            

    });

    mediaUploader.on(\'skippedcrop\', function(selection) {

        var url = selection.get(\'url\'),
            w = selection.get(\'width\'),
            h = selection.get(\'height\');

            myTheme_setImageFromURL(url, selection.id, w, h);            

    });        

    mediaUploader.on("select", function() {

        var attachment = mediaUploader.state().get( \'selection\' ).first().toJSON();

        if (     cropControl.params.width  === attachment.width 
            &&   cropControl.params.height === attachment.height 
            && ! cropControl.params.flex_width 
            && ! cropControl.params.flex_height ) {
                myTheme_setImageFromAttachment( attachment );
            mediaUploader.close();
        } else {
            mediaUploader.setState( \'cropper\' );
        }

    });

    mediaUploader.open();

});
});
不要忘记在上面的代码中调整所需的宽度/高度。

省略了将裁剪图像保存为附件的代码。裁剪后的图像仍将在wp内容/上载中的通常位置,但您不会在媒体库中看到裁剪后的图像。

我不知道如何在裁剪器中强制执行精确的尺寸。希望其他人能来帮忙回答这个问题。

SO网友:Алексей Дзяба

我不知道如何在裁剪器中强制执行精确的尺寸。希望其他人能来帮忙回答这个问题。

imgSelectOptions.aspectRatio = xInit + \':\' + yInit;
在此之前添加:return imgSelectOptions;

结束

相关推荐

Media Library Categories

我使用以下内容将类别分配给我的WordPress媒体库(在functions.php):function wptp_add_categories_to_attachments() { register_taxonomy_for_object_type( \'category\', \'attachment\' ); } add_action( \'init\' , \'wptp_add_categories_to_attachments\' ); 每个媒体库项目都