Skip to content

Commit

Permalink
Merge pull request #32 from mebjas/shaderregion
Browse files Browse the repository at this point in the history
Added support for qrregion borders and dynamic update
  • Loading branch information
mebjas authored May 1, 2020
2 parents d977af2 + eaa62e3 commit 055963e
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 24 deletions.
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Use this light-weight Javascript library `(56 Kb)` to add QR Code scanning capab

[![npm](https://nodei.co/npm/html5-qrcode.png)](https://www.npmjs.com/package/html5-qrcode)

<img src="./assets/pixel3.gif" width="200px"><br>
_Figure: Running on Android, Pixel 3_

## Supported platforms
Working on adding support for more and more platforms. If you find a platform or browser where the library is not working please feel free to file an issue. Check the [demo link](https://blog.minhazav.dev/research/html5-qrcode.html) to test out.

Expand Down Expand Up @@ -54,11 +57,11 @@ Download the script from [release page](https://github.com/mebjas/html5-qrcode/r
npm i html5-qrcode
```

Add an element you want to use as placeholder for QR Code scanner
Add an element you want to use as a placeholder for QR Code scanner
```html
<div id="reader" width="600px"></div>
```
> Ideally do not set the height of this container as the height should depend on the height of the video feed from the camera. The library would honor existing width otherwise apply the default width. The height is derived from the aspect ratio of the video feed.
> Ideally do not set the height of this container as the height should depend on the height of the video feed from the camera. The library would honor the existing width otherwise apply the default width. The height is derived from the aspect ratio of the video feed.
Add `minified/html5-qrcode.min.js` in your web page.
> I would recommend using the minified version as it's transformed to standard javascript. The `html5-qrcode.js` is written with ECMAScript and may not be supported in the older version of the browsers. I wrote in this as it's easier to maintain!
Expand Down Expand Up @@ -91,7 +94,7 @@ Html5Qrcode.getCameras().then(cameras => {
});
```

**Important**: Not that this method will trigger user permission if user has not granted already.
**Important**: Not that this method will trigger user permission if the user has not granted already.
> Warning: Direct access to the camera is a powerful feature. It requires consent from the user, and your site MUST be on a secure origin (HTTPS).
>
> Warning: Asking for access to the camera on page load will result in most of your users rejecting access to it. [More info](https://developers.google.com/web/fundamentals/media/capturing-images)
Expand Down Expand Up @@ -182,12 +185,12 @@ fileinput.addEventListener('change', e => {
[blog.minhazav.dev/research/html5-qrcode.html](https://blog.minhazav.dev/research/html5-qrcode.html)

### For more information
Check this article on how to use this library, check following articles:
Check this article on how to use this library, check the following articles:
- [HTML5 QR Code scanning - launched v1.0.1 without jQuery dependency and refactored Promise based APIs](https://blog.minhazav.dev/HTML5-QR-Code-scanning-launched-v1.0.1/).
- [HTML5 QR Code scanning with javascript - Support for scanning the local file and using default camera added (v1.0.5)](https://blog.minhazav.dev/HTML5-QR-Code-scanning-support-for-local-file-and-default-camera/)

## Screenshots
![screenshot](assets/screen.png)<br>
![screenshot](assets/screen.gif)<br>
_Figure: Screenshot from Google Chrome running on Macbook Pro_

## Documentation
Expand Down Expand Up @@ -283,15 +286,15 @@ class Html5Qrcode {
```

### Extra optional `configuration` in `start()` method
This is a configuration for the QR code scanning which can effect both scanning behavior and UI. There are two optional properties right now, if you don't want them you can just pass an empty object `{}`.
This is a configuration for the QR code scanning which can effect both scanning behavior and UI. There are two optional properties right now if you don't want them you can just pass an empty object `{}`.

#### `fps` - Integer, Example = 10
A.K.A frame per second, the default value for this is 2 but it can be increased to get faster scanning. Increasing too high value could affect performance. Value `>1000` will simply fail.

#### `qrbox` - Integer, Example = 250
Use this property to limit the region of the viewfinder you want to use for scanning. The rest of the viewfinder would be shaded. For example by passing config `{ qrbox : 250 }`, the screen will look like:

<img src="./assets/screen.png" width="450px">
<img src="./assets/screen.gif">

If you do not pass any value, the whole viewfinder would be used for scanning.
**Note**: this value has to be smaller than the width and height of the `QR code HTML element`.
Expand Down
Binary file added assets/pixel3.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screen.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/screen.png
Binary file not shown.
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### Version 1.0.8
+ Added support for realtime feedbacks on viewfinder for inline scanning
|Platform|Screenshot|
|------|-----------|
|On PC | ![](./assets/screen.gif)|
|On Android|![](./assets/pixel3.gif)|

### Version 1.0.7
+ Fixed the video size issue in [issues/21](https://github.com/mebjas/html5-qrcode/issues/21)
+ Removed fixed height of viewfinder, now the height is based on the video stream. The width is honored if the input element has a default width. Otherwise default width is applied.
Expand Down
128 changes: 124 additions & 4 deletions html5-qrcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class Html5Qrcode {
static SHADED_BOTTOM = 4;
static SHADED_REGION_CLASSNAME = "qr-shaded-region";
static VERBOSE = false;
static BORDER_SHADER_DEFAULT_COLOR = "#ffffff";
static BORDER_SHADER_MATCH_COLOR = "rgb(90, 193, 56)";

/**
* Initialize QR Code scanner.
Expand Down Expand Up @@ -192,7 +194,9 @@ class Html5Qrcode {
/* dHeight= */ $this._qrRegion.height);
try {
qrcode.decode();
this._possiblyUpdateShaders(/* qrMatch= */ true);
} catch (exception) {
this._possiblyUpdateShaders(/* qrMatch= */ false);
qrCodeErrorCallback(`QR code parse error, error = ${exception}`);
}
}
Expand Down Expand Up @@ -600,10 +604,26 @@ class Html5Qrcode {
return;
}

element.append(this._createShadedElement(height, qrRegion, Html5Qrcode.SHADED_LEFT));
element.append(this._createShadedElement(height, qrRegion, Html5Qrcode.SHADED_RIGHT));
element.append(this._createShadedElement(height, qrRegion, Html5Qrcode.SHADED_TOP));
element.append(this._createShadedElement(height, qrRegion, Html5Qrcode.SHADED_BOTTOM));
const shaders = {};
shaders[Html5Qrcode.SHADED_LEFT] = this._createShadedElement(
height, qrRegion, Html5Qrcode.SHADED_LEFT);
shaders[Html5Qrcode.SHADED_RIGHT] = this._createShadedElement(
height, qrRegion, Html5Qrcode.SHADED_RIGHT);
shaders[Html5Qrcode.SHADED_TOP] = this._createShadedElement(
height, qrRegion, Html5Qrcode.SHADED_TOP);
shaders[Html5Qrcode.SHADED_BOTTOM] = this._createShadedElement(
height, qrRegion, Html5Qrcode.SHADED_BOTTOM);

Object.keys(shaders).forEach(key => element.append(shaders[key]));

if (qrRegion.x < 10 || qrRegion.y < 10) {
this.hasBorderShaders = false;
} else {
Object.keys(shaders).forEach(key =>
this._insertShaderBorders(shaders[key], qrRegion, key));
this.hasBorderShaders = true;
}

}

_createShadedElement(height, qrRegion, shadingPosition) {
Expand Down Expand Up @@ -647,6 +667,106 @@ class Html5Qrcode {
return elem;
}

_insertShaderBorders(shaderElem, qrRegion, shadingPosition) {
shadingPosition = parseInt(shadingPosition);
const $this = this;
const borderOffset = 5;
const smallSize = 5;
const largeSize = 40;
const createBorder = () => {
const elem = document.createElement("div");
elem.style.position = "absolute";
elem.style.backgroundColor
= Html5Qrcode.BORDER_SHADER_DEFAULT_COLOR;
switch (shadingPosition) {
case Html5Qrcode.SHADED_LEFT: // intentional
case Html5Qrcode.SHADED_RIGHT:
const height = largeSize + borderOffset;
elem.style.width = `${smallSize}px`;
elem.style.height = `${height}px`;
break;
case Html5Qrcode.SHADED_TOP: // intentional
case Html5Qrcode.SHADED_BOTTOM:
const width = largeSize + borderOffset;
elem.style.width = `${width}px`;
elem.style.height = `${smallSize}px`;
break;
default:
throw "Unsupported shadingPosition";
}
return elem;
}

const insertBorder = (top, left) => {
if (!(top !== null && left !== null)) {
throw "Shaders should have defined positions"
}
const borderElem = createBorder();
borderElem.style.top = `${top}px`;
borderElem.style.left = `${left}px`;
shaderElem.appendChild(borderElem);

if (!$this.borderShaders) {
$this.borderShaders = [];
}

$this.borderShaders.push(borderElem);
}

let firstTop = null;
let firstLeft = null;
let secondTop = null;
let secondLeft = null;
switch (shadingPosition) {
case Html5Qrcode.SHADED_LEFT:
firstTop = qrRegion.y - borderOffset;
firstLeft = qrRegion.x - smallSize;
secondTop = qrRegion.y + qrRegion.height - largeSize;
secondLeft = firstLeft;
break;
case Html5Qrcode.SHADED_RIGHT:
firstTop = qrRegion.y - borderOffset;
firstLeft = 0;
secondTop = qrRegion.y + qrRegion.height - largeSize;
secondLeft = firstLeft;
break;
case Html5Qrcode.SHADED_TOP:
firstTop = qrRegion.y - borderOffset;
firstLeft = -smallSize;
secondTop = firstTop;
secondLeft = qrRegion.width - largeSize;
break;
case Html5Qrcode.SHADED_BOTTOM:
firstTop = 0;
firstLeft = -smallSize;
secondTop = firstTop;
secondLeft = qrRegion.width - largeSize;
break;
default:
throw "Unsupported shadingPosition";
}

insertBorder(firstTop, firstLeft);
insertBorder(secondTop, secondLeft);
}

_possiblyUpdateShaders(qrMatch) {
if (this.qrMatch === qrMatch) {
return;
}

if (this.hasBorderShaders
&& this.borderShaders
&& this.borderShaders.length) {
this.borderShaders.forEach(shader => {
shader.style.backgroundColor = qrMatch
? Html5Qrcode.BORDER_SHADER_MATCH_COLOR
: Html5Qrcode.BORDER_SHADER_DEFAULT_COLOR;
});
}
this.qrMatch = qrMatch;
}

_possiblyCloseLastScanImageFile() {
if (this._lastScanImageFile) {
URL.revokeObjectURL(this._lastScanImageFile);
Expand Down
2 changes: 1 addition & 1 deletion minified/html5-qrcode.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "html5-qrcode",
"version": "1.0.7",
"version": "1.0.8",
"description": "a cross platform HTML5 QR Code scanner",
"main": "html5-qrcode.js",
"scripts": {
Expand Down
Loading

0 comments on commit 055963e

Please sign in to comment.