11<template lang="html">
22 <div class =" qrcode-reader" >
33 <div class =" qrcode-reader__inner-wrapper" >
4- <div class =" qrcode-reader__overlay" >
4+ <div
5+ class =" qrcode-reader__overlay"
6+ @drop.prevent.stop =" onDrop"
7+ @dragover.prevent.stop
8+ @dragenter.prevent.stop
9+ @dragleave.prevent.stop
10+ >
511 <slot ></slot>
612 </div>
713
1925</template >
2026
2127<script >
22- import * as Scanner from ' ../misc/Scanner.js'
23- import Camera from ' ../misc/Camera.js'
28+ import * as Scanner from ' ../misc/scanner.js'
29+ import Camera from ' ../misc/camera.js'
30+ import { imageDataFromFile , imageDataFromUrl } from ' ../misc/image-data.js'
2431import isBoolean from ' lodash/isBoolean'
2532
2633export default {
@@ -186,28 +193,76 @@ export default {
186193 this .camera .stop ()
187194 }
188195
189- this .camera = await Camera (this .constraints , this .$refs .video )
196+ if (this .videoConstraints === false ) {
197+ this .camera = null
198+ } else {
199+ this .camera = await Camera (this .constraints , this .$refs .video )
200+ }
190201 },
191202
192203 startScanning () {
193204 Scanner .keepScanning (this .camera , {
194- decodeHandler: this .onDecode ,
195205 locateHandler: this .onLocate ,
206+ detectHandler : scanResult => this .onDetect (' stream' , scanResult),
196207 shouldContinue : () => this .shouldScan ,
197208 minDelay: this .scanInterval ,
198209 })
199210 },
200211
201- onDecode (content ) {
202- this .$emit (' decode' , content)
203- },
204-
205212 onLocate (location ) {
206213 if (this .trackRepaintFunction !== null ) {
207214 this .repaintTrack (location)
208215 }
209216 },
210217
218+ async onDetect (source , promise ) {
219+ this .$emit (' detect' , (async () => {
220+ const data = await promise
221+
222+ return { source, ... data }
223+ })())
224+
225+ try {
226+ const { content } = await promise
227+
228+ if (content !== null ) {
229+ this .$emit (' decode' , content)
230+ }
231+ } catch (error) {
232+ // fail silently
233+ }
234+ },
235+
236+ onDrop ({ dataTransfer }) {
237+ const droppedFiles = [... dataTransfer .files ]
238+
239+ droppedFiles .forEach (this .onDropFile )
240+
241+ const droppedUrl = dataTransfer .getData (' text' )
242+
243+ if (droppedUrl !== ' ' ) {
244+ this .onDropUrl (droppedUrl)
245+ }
246+ },
247+
248+ async onDropFile (file ) {
249+ this .onDetect (' file' , (async () => {
250+ const imageData = await imageDataFromFile (file)
251+ const scanResult = Scanner .scan (imageData)
252+
253+ return scanResult
254+ })())
255+ },
256+
257+ async onDropUrl (url ) {
258+ this .onDetect (' url' , (async () => {
259+ const imageData = await imageDataFromUrl (url)
260+ const scanResult = Scanner .scan (imageData)
261+
262+ return scanResult
263+ })())
264+ },
265+
211266 /**
212267 * The coordinates are based on the original camera resolution but the
213268 * video element is responsive and scales with space available. Therefore
@@ -220,14 +275,16 @@ export default {
220275 const widthRatio = this .camera .displayWidth / this .camera .resolutionWidth
221276 const heightRatio = this .camera .displayHeight / this .camera .resolutionHeight
222277
223- Object .keys (location).forEach (key => {
224- const { x , y } = location[key]
225-
226- location[key].x = Math .floor (x * widthRatio)
227- location[key].y = Math .floor (y * heightRatio)
278+ const normalizeEntry = ({ x, y }) => ({
279+ x: Math .floor (x * widthRatio),
280+ y: Math .floor (y * heightRatio),
228281 })
229282
230- return location
283+ const joinObjects = (objA , objB ) => ({ ... objA, ... objB })
284+
285+ return Object .entries (location)
286+ .map (([ key , val ]) => [ key, normalizeEntry (val) ])
287+ .reduce (joinObjects, {})
231288 }
232289 },
233290
@@ -258,7 +315,6 @@ export default {
258315}
259316
260317.qrcode-reader__inner-wrapper {
261- display : inline-block ;
262318 position : relative ;
263319}
264320
0 commit comments