重用 FileReader 时宽度和高度错误

Wrong width and height when reusing FileReader

我目前正在开发一个简单的界面,允许用户上传图片、预览图片,然后将其裁剪成正方形。

我正在使用 FileReader 获取图像预览,并使用 jCrop 对其进行裁剪。

这是我正在使用的代码(其中的一部分):

    var jcrop = null;
    var reader = new FileReader();

    reader.onload = function (e) {

            $('#upload-picture-sample').attr('src', e.target.result).load(function(){
                var img = this;

                var imageWidth = img.width;
                var imageHeight = img.height;

                console.log(img.width+'-- WIDTH --'+$(this).width());
                console.log(img.height+'-- HEIGHT --'+$(this).height());

                if(imageWidth != imageHeight){

                    var selectArray = [];

                    if(imageWidth > imageHeight){
                        selectArray = [(imageWidth-imageHeight)/2, 0, (imageWidth-imageHeight)/2 + imageHeight, imageHeight];
                    }else{
                        selectArray = [0, (imageHeight - imageWidth)/2, imageWidth, (imageHeight - imageWidth)/2 + imageWidth];
                    }
                    if(!jcrop){
                        $('#upload-picture-sample').Jcrop({
                            aspectRatio: 1,
                            keySupport: false,
                            addClass: 'jcrop-centered',
                            setSelect: selectArray
                        }, function(){
                            jcrop = this;
                        });
                    }else{
                        jcrop.setImage(e.target.result);
                        jcrop.setSelect(selectArray);

                    }
                }
                $(this).unbind('load');
            });   
        }

    $('#upload-picture-file').change(function(){
        $('#upload-picture-send').removeClass('disabled');
        $('#upload-picture-error').hide();

        console.log('changed!');

        reader.readAsDataURL(this.files[0]);
    })

我认为唯一真正重要的部分是计算宽度和高度的部分。

为了说明问题,我上传:

1/ 图片 1 (600x450)

2/ 图片 2 (94x125)

3/ Picture1 再次 (600x450)

第一次上传正常,第二次上传也正常,但我想这比其他事情更幸运,因为高度被错误地计算为 0。 第三次上传失败(大小设置不正确)。

表示cropzone显示不正确

关于css,我有这个:

#upload-picture-sample{
  display:block;
  margin-left: auto;
  margin-right: auto;
  margin-bottom: 30px;
  max-height:125px;
  height:auto;
  width:auto;
  max-width:300px;
}

您知道如何解决我的问题吗?

更新:按照@initialxy 的建议添加 setTimeout 之后

所以好多了,但是,第一张图片的尺寸与最后一张的尺寸不同(应该是,因为它是完全相同的图片) 谢谢。

你所有的数字看起来都不一致。在第一张图片中,img.width 的宽度最终为 167,而 jQuery 的宽度最终为 167。需要注意的一件事是 jQuery 得到 computed styleimg.widthimg.height 是设置所需宽度和高度的 DOM 属性。 (仅供参考,还有 naturalWidthnaturalHeight,它们是只读 DOM 属性,可让您获得 img 的原始尺寸。)

it's more luck than something else

如果您的代码取决于运气,那么我们遇到了问题。

看起来浏览器发出加载事件有点过早,以至于布局引擎尚未完成 DOM 的更新。 load 只是表示数据加载完毕,并不一定意味着布局引擎必须完成。因此,请稍后在任务队列中将您的代码块放入您的加载函数中。我的意思是将所有内容包装在 setTimeout(..., 0); 中,注意 this,因为它已更改。

例如

$('#upload-picture-sample').attr('src', e.target.result).load(function(){
    var img = this;

    setTimeout(function() {
        var imageWidth = img.width;
        var imageHeight = img.height;

        console.log(img.width+'-- WIDTH --'+$(img).width());
        console.log(img.height+'-- HEIGHT --'+$(img).height());

        // TODO: Crop
        ...
    }, 0);

    $(this).unbind('load');
});

编辑: 回应@Vico 的更新。看起来布局引擎这次已经解决了。让我们对这些数字进行一些观察。第一张图片的尺寸最初是 600x450,但最终变成了 167x125。这是有道理的,因为它是由 max-height: 125px; CSS 属性 调整大小的。第二张图片的两个尺寸均小于 max-widthmax-height,因此未调整大小。第三张图片的尺寸为 600x450,它最终具有这些尺寸,因此此时 max-widthmax-height 不再生效。这是为什么?也许 jcrop 搞砸了风格并覆盖了你的风格。启动你的 Chrome 调试器,检查你的 img 元素并使用它的 JavaScript 控制台来玩弄它。 (给你一个简短的回答,是的,jcrop 确实搞砸了样式并将内联样式应用于元素,这会覆盖你的样式。但是嘿,使用调试器更有趣。)另外,我不确定你为什么右边的尺寸都以 1440x514 结尾。你可以通过调试调试器找到答案。

想要了解更多信息,我建议所有潜在的读者看看这个问题: https://github.com/tapmodo/Jcrop/issues/46

变通办法工作正常。