2017-09-26 3 views
2

Hier ist mein Code:Wie bekomme ich Bildbreite und -höhe in einem Web-Arbeiter?

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

Dies wurde in dem Haupt-UI-Thread funktioniert gut, aber anscheinend habe ich keinen Zugriff auf Image innerhalb eines Web-Arbeiters. Der spezifische Fehler ist:

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

Gibt es eine andere Möglichkeit, die Breite und Höhe eines Bildes zu erhalten?

Ich möchte so viele Dateitypen wie möglich unterstützen, aber nur JPG ist gut genug für jetzt, wenn es eine Art von Bibliothek gibt, die dies tun kann und in einem Web-Arbeiter ausgeführt wird.


Hier ist das entsprechende Bit aus dem UI-Thread:

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

Das Einzige, was wert hier erwähnen ist, dass id nur eine zufällige UUID ist, und file ist ein File. Ich gebe das Ganze an den Web-Arbeiter weiter, damit ich dort die gesamte Verarbeitung machen kann.

Antwort

3

Ich denke, es könnte eine einfachere Lösung sein:

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

ich es geschafft, um die Größe zu erhalten, ohne überhaupt mit 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 ja! 'createImageBitmap' sieht genau so aus, wie ich gesucht habe. Könnte sogar bei der Größenanpassung helfen, was meine nächste Aufgabe war. Werde das bald versuchen, danke! – mpen

+0

YE Entschuldigung, kopiert eingefügt wirklich schnell, um die Antwort zu posten, wird bearbeiten, danke! – PiniH

1

Ich habe es geschafft, die Breite und Höhe der meisten JPEGs zu erhalten, indem Sie this spec folgen.

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

Dieser Code ist flakey wie heck, aber überraschend funktioniert es. Ich bin immer noch auf der Suche nach einer robusteren Lösung.

+1

'createImageBitmap' definitiv einfacher und unterstützt alle unterstützten Bildtypen, die der Browser unterstützt, aber für den Fall, dass Sie auch ältere Browser unterstützen müssen, habe ich wri te [etwas hier] (https://stackoverflow.com/questions/42540903/sort-by-image-resolution-in-gallery/42649964#42649964), aus dem Sie Code für andere Formate extrahieren können. – Kaiido

Verwandte Themen