简体   繁体   English

如何在网络工作者中获取图像的宽度和高度?

[英]How to get image width and height in a web-worker?

Here's my code: 这是我的代码:

// process-image.js (web-worker)
self.addEventListener('message', ev => {
    const {id,file} = ev.data;

    const reader = new FileReader();
    reader.onload = ev => {
        const imageFile = new Image(); // <-- error is here
        imageFile.src = ev.target.result;

        imageFile.onload = () => {
            const fit = makeFit(imageFile);

            self.postMessage({
                id,
                file: {
                    src: ev.target.result,
                    width: fit.width,
                    height: fit.height,
                }
            })
        }
    };

    reader.readAsDataURL(file);
});

This was working fine in the main UI thread, but apparently I don't have access to Image inside of a web-worker. 这在主UI线程中工作正常,但显然我无法在网络工作者中访问Image The specific error is: 具体错误是:

Uncaught ReferenceError: Image is not defined at FileReader.reader.onload (process-image.js:12) 未捕获的ReferenceError:未在FileReader.reader.onload中定义图像(process-image.js:12)

Is there another way get the width and height of an image? 有没有其他方法可以获取图像的宽度和高度?

I'd like to support as many file types as possible, but just JPG is good enough for now if there's some sort of library that can do this and will run in a web-worker. 我希望支持尽可能多的文件类型,但是如果有某种可以执行此操作并且可以在网络工作者中运行的库,那么JPG就足够了。


Here's the relevant bit from the UI thread: 这是UI线程的相关内容:

// some-react-component.js
    componentDidMount() {
        this.worker = new ImageWorker();
        this.worker.addEventListener('message', ev => {
            const {id, file} = ev.data;

            this.setState(({files}) => {
                files = files.update(id, img => ({
                    ...img,
                    ...file,
                }))

                const withWidths = files.filter(f => f.width);
                const avgImgWidth = withWidths.reduce((acc, img) => acc + img.width, 0) / withWidths.size;

                return {files, avgImgWidth};
            });
        });
    }


    onDrop = ev => {
        ev.preventDefault();


        Array.prototype.forEach.call(ev.dataTransfer.files, file => {

            const id = shortid();
            this.worker.postMessage({id, file});

            const img = {
                id,
                width: null,
                height: null,
                src: null,
                name: file.name,
            }
            this.setState(({files}) => ({files: files.set(id, img)}));
        });
    }

Only thing worth noting here is that id is just a random UUID, and file is a File . 这里唯一值得注意的是id只是一个随机的UUID,而file是一个File I'm passing the whole thing to the web-worker so that I can do all the processing there. 我将整个事情传递给网络工作者,以便在那里进行所有处理。

I think there might be a simpler solution: 我认为可能有一个更简单的解决方案:

https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/createImageBitmap

I managed to get the size without using FileReader at all: 我设法完全不使用FileReader来获得大小:

http://jsfiddle.net/hL1Ljkmv/2/ http://jsfiddle.net/hL1Ljkmv/2/

var response = `self.addEventListener('message', async ev => {
    const {id,file} = ev.data;
    console.log('received data');
    let image = await self.createImageBitmap(file);
    console.log(image);
});`;

const blob = new Blob([response], {type: 'application/javascript'});
const worker = new Worker(URL.createObjectURL(blob));

const input = document.querySelector('#file-input');
input.addEventListener('change', (e) => {
  worker.postMessage({file: input.files[0], id: 1})
});

I managed to get the width and height of most JPEGs by following this spec . 通过遵循此规范,我设法获得了大多数JPEG的宽度和高度。

self.addEventListener('message', ev => {
    const {id, file} = ev.data;

    const reader = new FileReader();
    reader.onload = ev => {
        const view = new DataView(reader.result);

        let offset = 0;
        let header = view.getUint16(offset, false);

        if(header !== 0xFFD8) {
            throw new Error(`Not a JPEG`);
        }
        offset += 2;

        for(; ;) {

            header = view.getUint16(offset, false);
            offset += 2;
            let length = view.getUint16(offset, false);

            if(header === 0xFFC0) break;
            offset += length;
        }

        const height = view.getUint16(offset + 3);
        const width = view.getUint16(offset + 5);

        const fit = makeFit({width, height});

        self.postMessage({
            id,
            file: {
                src: URL.createObjectURL(file),
                width: fit.width,
                height: fit.height,
            }
        })
    };

    reader.readAsArrayBuffer(file);
});

This code is flakey as heck, but surprisingly it works. 这段代码简直是千篇一律,但令人惊讶的是它可以工作。 I'm still looking for a more robust solution. 我仍在寻找更强大的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM