2017-09-26 122 views
2

这里是我的代码:如何获得网络工作者的图像宽度和高度?

// 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); 
}); 

这是在主UI线程工作正常,但显然我没有Image一个网络工作者的内部访问。具体的错误是:

Uncaught ReferenceError: Image is not defined at FileReader.reader.onload (process-image.js:12)

有没有另一种方式获取图像的宽度和高度?

我想支持尽可能多的文件类型,但是如果有某种类型的库可以执行此操作并且将在网络工作者中运行,那么现在只需要JPG即可。


下面是从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)})); 
     }); 
    } 

唯一这里值得注意的是,id只是一个随机UUID,并fileFile。我将整件事传递给网络工作者,以便我可以在那里完成所有的处理。

回答

3

我觉得可能是一个简单的解决方案:

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

我设法大小不使用的FileReader可言:

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}) 
}); 
+1

Awww yes! 'createImageBitmap'看起来像我正在寻找的。甚至可能帮助调整大小,这是我的下一个任务。请尽快试用,谢谢! – mpen

+0

对不起,复制粘贴真正快速发布答案,将编辑,谢谢! – PiniH

1

我设法得到了大多数JPEG的宽度和高度,遵循this spec

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); 
}); 

这段代码虽然很怪,但却令人惊讶地发挥作用。我仍在寻找更强大的解决方案。

+1

'createImageBitmap'绝对是更容易,并且将支持浏览器支持的所有支持的图像类型,但是如果您需要支持较旧的浏览器,我也会选择wri te [这里的东西](https://stackoverflow.com/questions/42540903/sort-by-image-resolution-in-gallery/42649964#42649964),您可以从中提取其他格式的代码。 – Kaiido