Skip to content

Commit

Permalink
Version 2.0.0 (#385)
Browse files Browse the repository at this point in the history
* Add support for qrbox size as function

Developers can now pass qrbox config as a function of type

```ts
/**
  * A function that takes in the width and height of the video stream
* and returns QrDimensions.
*
* Viewfinder refers to the video showing camera stream.
*/
export type QrDimensionFunction =
    (viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
```

To set the values dynamically that works across form factors

* misc fixes

* Update html5-qrcode.min.js

* Code review fixes.
  • Loading branch information
mebjas authored Feb 19, 2022
1 parent 61b6310 commit 86af5f0
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 38 deletions.
37 changes: 32 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,15 @@ interface QrDimensions {
height: number;
}

/**
* A function that takes in the width and height of the video stream
* and returns QrDimensions.
*
* Viewfinder refers to the video showing camera stream.
*/
type QrDimensionFunction =
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;

/** Format of detected code. */
class QrcodeResultFormat {
public readonly format: Html5QrcodeSupportedFormats;
Expand Down Expand Up @@ -432,8 +441,10 @@ interface Html5QrcodeCameraScanConfig {
fps: number | undefined;

/**
* Optional, edge size or dimension of QR scanning box, this should be
* smaller than the width and height of the full region.
* Optional, edge size, dimension or calculator function for QR scanning
* box, the value or computed value should be smaller than the width and
* height of the full region.
*
* This would make the scanner look like this:
* ----------------------
* |********************|
Expand All @@ -446,12 +457,14 @@ interface Html5QrcodeCameraScanConfig {
* ----------------------
*
* Instance of {@interface QrDimensions} can be passed to construct a non
* square rendering of scanner box.
* square rendering of scanner box. You can also pass in a function of type
* {@type QrDimensionFunction} that takes in the width and height of the
* video stream and return QR box size of type {@interface QrDimensions}.
*
* If this value is not set, no shaded QR box will be rendered and the scanner
* will scan the entire area of video stream.
*/
qrbox?: number | QrDimensions | undefined;
qrbox?: number | QrDimensions | QrDimensionFunction | undefined;

/**
* Optional, Desired aspect ratio for the video feed. Ideal aspect ratios
Expand Down Expand Up @@ -661,7 +674,7 @@ Configuration object that can be used to configure both the scanning behavior an
#### `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``QrDimensions` (Optional), Example = `{ width: 250, height: 250 }`
#### `qrbox``QrDimensions` or `QrDimensionFunction` (Optional), Example = `{ width: 250, height: 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 : { width: 250, height: 250 } }`, the screen will look like:

<img src="./assets/screen.gif">
Expand All @@ -672,6 +685,20 @@ This can be used to set a rectangular scanning area with config like:
let config = { qrbox : { width: 400, height: 150 } }
```

This config also accepts a function of type
```ts
/**
* A function that takes in the width and height of the video stream
* and returns QrDimensions.
*
* Viewfinder refers to the video showing camera stream.
*/
type QrDimensionFunction =
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
```

This allows you to set dynamic QR box dimensions based on the video dimensions. See this blog article for example: [Setting dynamic QR box size in Html5-qrcode - ScanApp blog](https://scanapp.org/blog/2022/01/09/setting-dynamic-qr-box-size-in-html5-qrcode.html)

> This might be desirable for bar code scanning.
If this value is not set, no shaded QR box will be rendered and the scanner will scan the entire area of video stream.
Expand Down
42 changes: 42 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,45 @@
### Version 2.2.0
- `config.qrbox` now supports consuming function of type

```ts
/**
* A function that takes in the width and height of the video stream
* and returns QrDimensions.
*
* Viewfinder refers to the video showing camera stream.
*/
export type QrDimensionFunction =
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;
```

This will allow developers to define custom QR box dimensions for their
implementations.

Example:
```js
function onScanSuccess(decodedText, decodedResult) {
// handle the scanned code as you like, for example:
console.log(`Code matched = ${decodedText}`, decodedResult);
}
// Square QR box with edge size = 70% of the smaller edge of the viewfinder.
let qrboxFunction = function(viewfinderWidth, viewfinderHeight) {
let minEdgePercentage = 0.7; // 70%
let minEdgeSize = Math.min(viewfinderWidth, viewfinderHeight);
let qrboxSize = Math.floor(minEdgeSize * minEdgePercentage);
return {
width: qrboxSize,
height: qrboxSize
};
}
let html5QrcodeScanner = new Html5QrcodeScanner(
"reader",
{ fps: 10, qrbox: qrboxFunction },
/* verbose= */ false);
html5QrcodeScanner.render(onScanSuccess);
```

### Version 2.1.6
- Add `alt` information to info icon to improve accessibility.

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": "2.1.6",
"version": "2.2.0",
"description": "A cross platform HTML5 QR Code & bar code scanner",
"main": "./cjs/index.js",
"module": "./esm/index.js",
Expand Down
9 changes: 9 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ export interface QrDimensions {
height: number;
}

/**
* A function that takes in the width and height of the video stream
* and returns QrDimensions.
*
* Viewfinder refers to the video showing camera stream.
*/
export type QrDimensionFunction =
(viewfinderWidth: number, viewfinderHeight: number) => QrDimensions;

/**
* Defines bounds of detected QR code w.r.t the scan region.
*/
Expand Down
86 changes: 55 additions & 31 deletions src/html5-qrcode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ import {
Html5QrcodeConstants,
Html5QrcodeResult,
isNullOrUndefined,
QrDimensions
QrDimensions,
QrDimensionFunction
} from "./core";

import { Html5QrcodeStrings } from "./strings";
Expand Down Expand Up @@ -111,8 +112,10 @@ export interface Html5QrcodeCameraScanConfig {
fps: number | undefined;

/**
* Optional, edge size or dimension of QR scanning box, this should be
* smaller than the width and height of the full region.
* Optional, edge size, dimension or calculator function for QR scanning
* box, the value or computed value should be smaller than the width and
* height of the full region.
*
* This would make the scanner look like this:
* ----------------------
* |********************|
Expand All @@ -125,12 +128,14 @@ export interface Html5QrcodeCameraScanConfig {
* ----------------------
*
* Instance of {@interface QrDimensions} can be passed to construct a non
* square rendering of scanner box.
* square rendering of scanner box. You can also pass in a function of type
* {@type QrDimensionFunction} that takes in the width and height of the
* video stream and return QR box size of type {@interface QrDimensions}.
*
* If this value is not set, no shaded QR box will be rendered and the
* scanner will scan the entire area of video stream.
*/
qrbox?: number | QrDimensions | undefined;
qrbox?: number | QrDimensions | QrDimensionFunction | undefined;

/**
* Optional, Desired aspect ratio for the video feed. Ideal aspect ratios
Expand Down Expand Up @@ -164,12 +169,12 @@ export interface Html5QrcodeCameraScanConfig {
* Internal implementation of {@interface Html5QrcodeConfig} with util & factory
* methods.
*/
class InternalHtml5QrcodeConfig implements InternalHtml5QrcodeConfig {
class InternalHtml5QrcodeConfig implements Html5QrcodeCameraScanConfig {

// TODO(mebjas) Make items that doesn't need to be public private.
public fps: number;
public disableFlip: boolean;
public qrbox: number | QrDimensions | undefined;
public qrbox: number | QrDimensions | QrDimensionFunction | undefined;
public aspectRatio: number | undefined;
public videoConstraints: MediaTrackConstraints | undefined;

Expand Down Expand Up @@ -370,11 +375,6 @@ export class Html5Qrcode {
this.shouldScan = true;
this.element = element;

// Validate before insertion
if (isShadedBoxEnabled) {
this.validateQrboxSize(internalConfig, rootElementWidth);
}

const $this = this;
const toScanningStateChangeTransaction: StateManagerTransaction
= this.stateManagerProxy.startTransition(Html5QrcodeScannerState.SCANNING);
Expand Down Expand Up @@ -970,11 +970,13 @@ export class Html5Qrcode {
* Validates if the passed config for qrbox is correct.
*/
private validateQrboxSize(
internalConfig: InternalHtml5QrcodeConfig,
rootElementWidth: number) {
viewfinderWidth: number,
viewfinderHeight: number,
internalConfig: InternalHtml5QrcodeConfig) {
const qrboxSize = internalConfig.qrbox!;
this.validateQrboxConfig(qrboxSize);
let qrDimensions = this.toQrdimensions(qrboxSize);
let qrDimensions = this.toQrdimensions(
viewfinderWidth, viewfinderHeight, qrboxSize);

const validateMinSize = (size: number) => {
if (size < Constants.MIN_QR_BOX_SIZE) {
Expand All @@ -992,11 +994,11 @@ export class Html5Qrcode {
* @param configWidth the width of qrbox set by users in the config.
*/
const correctWidthBasedOnRootElementSize = (configWidth: number) => {
if (configWidth > rootElementWidth) {
if (configWidth > viewfinderWidth) {
this.logger.warn("`qrbox.width` or `qrbox` is larger than the"
+ " width of the root element. The width will be truncated"
+ " to the width of root element.");
configWidth = rootElementWidth;
configWidth = viewfinderWidth;
}
return configWidth;
};
Expand All @@ -1016,8 +1018,13 @@ export class Html5Qrcode {
*
* It's expected to be either a number or of type {@interface QrDimensions}.
*/
private validateQrboxConfig(qrboxSize: number | QrDimensions) {
private validateQrboxConfig(
qrboxSize: number | QrDimensions | QrDimensionFunction) {
if (typeof qrboxSize === "number") {
return;
}

if (typeof qrboxSize === "function") {
// This is a valid format.
return;
}
Expand All @@ -1033,9 +1040,20 @@ export class Html5Qrcode {
* Possibly converts {@param qrboxSize} to an object of type
* {@interface QrDimensions}.
*/
private toQrdimensions(qrboxSize: number | QrDimensions): QrDimensions {
private toQrdimensions(
viewfinderWidth: number,
viewfinderHeight: number,
qrboxSize: number | QrDimensions | QrDimensionFunction): QrDimensions {
if (typeof qrboxSize === "number") {
return { width: qrboxSize, height: qrboxSize};
} else if (typeof qrboxSize === "function") {
try {
return qrboxSize(viewfinderWidth, viewfinderHeight);
} catch (error) {
throw new Error(
"qrbox config was passed as a function but it failed with "
+ "unknown error" + error);
}
}
return qrboxSize;
}
Expand All @@ -1044,39 +1062,45 @@ export class Html5Qrcode {
/**
* Setups the UI elements, changes the state of this class.
*
* @param width derived width of viewfinder.
* @param height derived height of viewfinder.
* @param viewfinderWidth derived width of viewfinder.
* @param viewfinderHeight derived height of viewfinder.
*/
private setupUi(
width: number,
height: number,
viewfinderWidth: number,
viewfinderHeight: number,
internalConfig: InternalHtml5QrcodeConfig): void {

// Validate before insertion
if (internalConfig.isShadedBoxEnabled()) {
this.validateQrboxSize(
viewfinderWidth, viewfinderHeight, internalConfig);
}

// If `qrbox` size is not set, it will default to the dimensions of the
// viewfinder.
const qrboxSize = isNullOrUndefined(internalConfig.qrbox) ?
{width: width, height: height}: internalConfig.qrbox!;
{width: viewfinderWidth, height: viewfinderHeight}: internalConfig.qrbox!;

this.validateQrboxConfig(qrboxSize);
let qrDimensions = this.toQrdimensions(qrboxSize);
if (qrDimensions.height > height) {
let qrDimensions = this.toQrdimensions(viewfinderWidth, viewfinderHeight, qrboxSize);
if (qrDimensions.height > viewfinderHeight) {
this.logger.warn("[Html5Qrcode] config.qrbox has height that is"
+ "greater than the height of the video stream. Shading will be"
+ " ignored");
}

const shouldShadingBeApplied
= internalConfig.isShadedBoxEnabled()
&& qrDimensions.height <= height;
&& qrDimensions.height <= viewfinderHeight;
const defaultQrRegion: QrcodeRegionBounds = {
x: 0,
y: 0,
width: width,
height: height
width: viewfinderWidth,
height: viewfinderHeight
};

const qrRegion = shouldShadingBeApplied
? this.getShadedRegionBounds(width, height, qrDimensions)
? this.getShadedRegionBounds(viewfinderWidth, viewfinderHeight, qrDimensions)
: defaultQrRegion;

const canvasElement = this.createCanvasElement(
Expand All @@ -1090,7 +1114,7 @@ export class Html5Qrcode {
this.element!.append(canvasElement);
if (shouldShadingBeApplied) {
this.possiblyInsertShadingElement(
this.element!, width, height, qrDimensions);
this.element!, viewfinderWidth, viewfinderHeight, qrDimensions);
}

this.createScannerPausedUiElement(this.element!);
Expand Down

0 comments on commit 86af5f0

Please sign in to comment.