重用 FileReader 时宽度和高度错误

Posted

技术标签:

【中文标题】重用 FileReader 时宽度和高度错误【英文标题】:Wrong width and height when reusing FileReader 【发布时间】:2015-09-22 01:44:52 【问题描述】:

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

我正在使用 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/ 再次图片 1 (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

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

【问题讨论】:

【参考方案1】:

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

运气比什么都好

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

看起来浏览器发出的加载事件有点太早了,这样布局引擎还没有完成更新 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 结束。你可以通过调试器来找出答案。

【讨论】:

非常感谢您的回答@initialxy,我已更新我的帖子以显示新结果。尽管如此,我上次上传的结果仍然很奇怪。有什么线索吗? 感谢您的更新@initialxy。奇怪的是图像大小正确。 jcrop 一个和原始一个(上传图片样本)。当我与检查员核对时,一切似乎都很好。所以否则宽度和高度值是错误的,否则我会在应用 css 之前得到它们的大小。 @Vico 您正在使用相同的元素来测量图像大小以及让 jcrop 使用它。 jscrop 对它应用了一堆内联样式。打开您的调试器并在检查器中选择您的 original img。 (现在在 JavaScript 控制台中,您可以顺便使用$0 方便地引用它。)您看到了什么? <img id="upload-picture-sample" src="..." style="display: none; visibility: hidden; width: 1440px; height: 514px;"> 之类的东西不是吗?注意到style 属性有一堆不需要的值吗? 是的,我见过。但其实值是正确的:“display: none; visibility: hidden; width: 167px; height: 125px;” 这些值是由 jcrop 添加的,它们会覆盖 CSS 的行为。他们正在搞砸你的宽度和高度。【参考方案2】:

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

解决方法工作正常。

【讨论】:

以上是关于重用 FileReader 时宽度和高度错误的主要内容,如果未能解决你的问题,请参考以下文章

抓取 iPhone 的屏幕宽度和高度以实现可重用性

上传前获取文件大小、图片宽度和高度

显示 SVG 图标的 Angular 可重用组件的宽度/高度未在任何地方设置并位于图标正下方,stackblitz 内部

重用 tableviewcell 中的约束和高度未更新

在反应引导模式上指定/设置宽度和高度

创建位图时,宽度和高度必须 > 0