diff --git a/.github/workflows/release-branch.yml b/.github/workflows/build.yml similarity index 64% rename from .github/workflows/release-branch.yml rename to .github/workflows/build.yml index ecb929b..45f062b 100644 --- a/.github/workflows/release-branch.yml +++ b/.github/workflows/build.yml @@ -53,6 +53,7 @@ jobs: runs-on: ubuntu-latest permissions: contents: write + id-token: write steps: - name: Check out repository @@ -63,10 +64,24 @@ jobs: with: node-version: 24 cache: npm + registry-url: https://registry.npmjs.org - name: Install dependencies run: npm ci + - name: Derive release version + id: version + shell: bash + run: | + BASE_VERSION="$(node -p "require('./package.json').version")" + RELEASE_VERSION="$(node -e "const [major, minor] = process.argv[1].split('.'); process.stdout.write([major, minor, process.argv[2]].join('.'));" "$BASE_VERSION" "${GITHUB_RUN_NUMBER}")" + + echo "base_version=${BASE_VERSION}" >> "$GITHUB_OUTPUT" + echo "release_version=${RELEASE_VERSION}" >> "$GITHUB_OUTPUT" + + - name: Apply release version + run: npm version "${{ steps.version.outputs.release_version }}" --no-git-tag-version + - name: Build package run: npm run build @@ -74,7 +89,7 @@ jobs: id: package shell: bash run: | - VERSION="$(node -p "require('./package.json').version")" + VERSION="${{ steps.version.outputs.release_version }}" SHORT_SHA="${GITHUB_SHA::7}" TAG="v${VERSION}-${SHORT_SHA}" PACKAGE_TGZ="$(npm pack --silent)" @@ -84,6 +99,9 @@ jobs: echo "tag=${TAG}" >> "$GITHUB_OUTPUT" echo "package_tgz=${PACKAGE_TGZ}" >> "$GITHUB_OUTPUT" + - name: Publish to npm + run: npm publish --access public --provenance + - name: Create GitHub release env: GH_TOKEN: ${{ github.token }} @@ -91,15 +109,15 @@ jobs: run: | gh release create "${{ steps.package.outputs.tag }}" \ "${{ steps.package.outputs.package_tgz }}" \ - qr-scanner-worker.min.js \ - qr-scanner-worker.min.js.map \ - qr-scanner.legacy.min.js \ - qr-scanner.legacy.min.js.map \ - qr-scanner.min.js \ - qr-scanner.min.js.map \ - qr-scanner.umd.min.js \ - qr-scanner.umd.min.js.map \ - types/qr-scanner.d.ts \ + artifacts/qr-scanner-worker.min.js \ + artifacts/qr-scanner-worker.min.js.map \ + artifacts/qr-scanner.legacy.min.js \ + artifacts/qr-scanner.legacy.min.js.map \ + artifacts/qr-scanner.min.js \ + artifacts/qr-scanner.min.js.map \ + artifacts/qr-scanner.umd.min.js \ + artifacts/qr-scanner.umd.min.js.map \ + artifacts/types/qr-scanner.d.ts \ --target "${GITHUB_SHA}" \ --title "qr-scanner v${{ steps.package.outputs.version }} (${{ steps.package.outputs.short_sha }})" \ --generate-notes diff --git a/.gitignore b/.gitignore index c4b311b..1420ace 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules .DS_Store -tmp \ No newline at end of file +tmp +artifacts/* +!artifacts/.gitkeep \ No newline at end of file diff --git a/README.md b/README.md index fa57c1c..9c332dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # QR Scanner -Javascript QR Code Scanner based on [Cosmo Wolfe's javascript port](https://github.com/cozmo/jsqr) of [Google's ZXing library](https://github.com/zxing/zxing). +JavaScript QR Code Scanner based on [Cosmo Wolfe's javascript port](https://github.com/cozmo/jsqr) of [Google's ZXing library](https://github.com/zxing/zxing); see also the orphaned upstream npm package [`qr-scanner`](https://www.npmjs.com/package/qr-scanner). In this library, several improvements have been applied over the original port: @@ -15,35 +15,33 @@ According to [our benchmarking](https://github.com/danimoh/qr-scanner-benchmark) The library supports scanning a continuous video stream from a web cam as well as scanning of single images. -The development of this library is sponsored by [nimiq](https://www.nimiq.com), world's first browser based blockchain. - -[nimiq.com](https://nimiq.com) - - -## Demo -See [https://nimiq.github.io/qr-scanner/demo/](https://nimiq.github.io/qr-scanner/demo/) - ## Installation -To install via npm: +Install from npm if you bundle your application: ```bash -npm install --save qr-scanner +npm install @codeuctivity/qr-scanner ``` -Or simply copy `qr-scanner.min.js` and `qr-scanner-worker.min.js` to your project. + +Then import it from your application code: +```js +import QrScanner from '@codeuctivity/qr-scanner'; +``` + +If you are not using a bundler, copy `artifacts/qr-scanner.min.js` and `artifacts/qr-scanner-worker.min.js` from the published package (or a GitHub release) into your project and keep both files next to each other. ## Setup -The QR Scanner consists of two main files. `qr-scanner.min.js` is the main API file which loads the worker script `qr-scanner-worker.min.js` via a dynamic import, only if needed. If you are not using a bundler like Rollup or Webpack that handles dynamic imports automatically, you might have to copy `qr-scanner-worker.min.js` over to your dist, next to `qr-scanner.min.js` or next to the script into which you're bundling `qr-scanner.min.js`. +The QR Scanner consists of two main files. `artifacts/qr-scanner.min.js` is the main API file which loads the worker script `artifacts/qr-scanner-worker.min.js` via a dynamic import, only if needed. If you are not using a bundler like Rollup or Webpack that handles dynamic imports automatically, you might have to copy `artifacts/qr-scanner-worker.min.js` over to your dist, next to `artifacts/qr-scanner.min.js` or next to the script into which you're bundling `artifacts/qr-scanner.min.js`. -`qr-scanner.min.js` is an es6 module and can be imported as follows: +`artifacts/qr-scanner.min.js` is an es6 module and can be imported as follows: ```js -import QrScanner from 'path/to/qr-scanner.min.js'; // if using plain es6 import -import QrScanner from 'qr-scanner'; // if installed via package and bundling with a module bundler like webpack or rollup +import QrScanner from 'path/to/artifacts/qr-scanner.min.js'; // if using plain es6 import +import QrScanner from '@codeuctivity/qr-scanner'; // if installed via package and bundling with a module bundler like webpack or rollup ``` This requires the importing script to also be an es6 module or a module script tag, e.g.: ```html ``` @@ -51,27 +49,27 @@ This requires the importing script to also be an es6 module or a module script t If your project is not based on es6 modules you can - use a [dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports) to import the es6 module: ```js -import('path/to/qr-scanner.min.js').then((module) => { +import('path/to/artifacts/qr-scanner.min.js').then((module) => { const QrScanner = module.default; // do something with QrScanner }); ``` -- use the [UMD build](https://github.com/umdjs/umd) `qr-scanner.umd.min.js` for direct usage as non-module script +- use the [UMD build](https://github.com/umdjs/umd) `artifacts/qr-scanner.umd.min.js` for direct usage as non-module script ```html - + ``` -- bundle `qr-scanner.umd.min.js` directly with your non-module code with tools like [gulp](https://gulpjs.com/) or [grunt](https://gruntjs.com/). +- bundle `artifacts/qr-scanner.umd.min.js` directly with your non-module code with tools like [gulp](https://gulpjs.com/) or [grunt](https://gruntjs.com/). - bundle the lib with `require` based bundlers like [browserify](https://browserify.org/): ```js -const QrScanner = require('qr-scanner'); // if installed via package -const QrScanner = require('path/to/qr-scanner.umd.min.js'); // if not installed via package +const QrScanner = require('@codeuctivity/qr-scanner'); // if installed via package +const QrScanner = require('path/to/artifacts/qr-scanner.umd.min.js'); // if not installed via package // do something with QrScanner ``` -This library uses ECMAScript 2017 features like `async` functions. If you need to support old browsers, you can use `qr-scanner.legacy.min.js`, which is ECMAScript 2015 (ES6) compatible. It's a UMD build and can be used as a replacement for `qr-scanner.umd.min.js`, see above. Note, that the legacy build is larger as it includes some polyfills and, to support browsers that don't support dynamic imports, inlines the worker script which however would be needed to be loaded in legacy browsers anyway. You will likely not need to use the legacy build though, as general browser support is already very good for the regular build. Especially if you want to scan from the device's camera, camera support by the browser is the stricter restriction. +This library uses ECMAScript 2017 features like `async` functions. If you need to support old browsers, you can use `artifacts/qr-scanner.legacy.min.js`, which is ECMAScript 2015 (ES6) compatible. It's a UMD build and can be used as a replacement for `artifacts/qr-scanner.umd.min.js`, see above. Note that the legacy build is larger because it includes polyfills and, to support browsers that don't support dynamic imports, inlines the worker script which would have to be loaded separately in legacy browsers anyway. You will likely not need to use the legacy build though, as general browser support is already very good for the regular build. Especially if you want to scan from the device's camera, camera support by the browser is the stricter restriction. ## Usage @@ -111,8 +109,8 @@ Supported options are: | `preferredCamera` | Preference for the camera to be used. The preference can be either a device id as returned by `listCameras` or a facing mode specified as `'environment'` or `'user'`. The default is `'environment'`. Note that there is no guarantee that the preference can actually be fulfilled. | | `maxScansPerSecond` | This option can be used to throttle the scans for less battery consumption. The default is 25. [If supported by the browser](https://caniuse.com/mdn-api_htmlvideoelement_requestvideoframecallback), the scan rate is never higher than the camera's frame rate to avoid unnecessary duplicate scans on the same frame. | | `calculateScanRegion` | A method that determines a region to which scanning should be restricted as a performance improvement. This region can optionally also be scaled down before performing the scan as an additional performance improvement. The region is specified as `x`, `y`, `width` and `height`; the dimensions for the downscaled region as `downScaledWidth` and `downScaledHeight`. Note that the aspect ratio between `width` and `height` and `downScaledWidth` and `downScaledHeight` should remain the same. By default, the scan region is restricted to a centered square of two thirds of the video width or height, whichever is smaller, and scaled down to a 400x400 square. | -| `highlightScanRegion` | Set this option to `true` for rendering an outline around the scan region on the video stream. This uses an absolutely positioned `div` that covers the scan region. This `div` can either be supplied as option `overlay`, see below, or automatically created and then accessed via `qrScanner.$overlay`. It can be freely styled via CSS, e.g. by setting an outline, border, background color, etc. See the [demo](https://nimiq.github.io/qr-scanner/demo/) for examples. | -| `highlightCodeOutline` | Set this option to `true` for rendering an outline around detected QR codes. This uses an absolutely positioned `div` on which an SVG for rendering the outline will be placed. This `div` can either be supplied as option `overlay`, see below, or be accessed via `qrScanner.$overlay`. The SVG can be freely styled via CSS, e.g. by setting the fill color, stroke color, stroke width, etc. See the [demo](https://nimiq.github.io/qr-scanner/demo/) for examples. For more special needs, you can also use the `cornerPoints` directly, see below, for rendering an outline or the points yourself. | +| `highlightScanRegion` | Set this option to `true` for rendering an outline around the scan region on the video stream. This uses an absolutely positioned `div` that covers the scan region. This `div` can either be supplied as option `overlay`, see below, or automatically created and then accessed via `qrScanner.$overlay`. It can be freely styled via CSS, e.g. by setting an outline, border, background color, etc. | +| `highlightCodeOutline` | Set this option to `true` for rendering an outline around detected QR codes. This uses an absolutely positioned `div` on which an SVG for rendering the outline will be placed. This `div` can either be supplied as option `overlay`, see below, or be accessed via `qrScanner.$overlay`. The SVG can be freely styled via CSS, e.g. by setting the fill color, stroke color, stroke width, etc. For more special needs, you can also use the `cornerPoints` directly, see below, for rendering an outline or the points yourself. | | `overlay` | A custom `div` that can be supplied for use for `highlightScanRegion` and `highlightCodeOutline`. The `div` should be a sibling of `videoElem` in the DOM. If this option is supplied, the default styles for `highlightCodeOutline` are not applied as the expectation is that the element already has some custom style applied to it. | | `returnDetailedScanResult` | Enforce reporting detailed scan results, see below. | @@ -245,8 +243,8 @@ This will stop the camera stream and web worker and cleans up event listeners. The QR scanner will be dysfunctional after it has been destroyed. ## Build the project -The project is prebuild in qr-scanner.min.js in combination with qr-scanner-worker.min.js. Building yourself is only necessary if you want to change the code in -the /src folder. NodeJs is required for building. +The published npm package (and GitHub releases) include the prebuilt artifacts under `artifacts/` (e.g. `artifacts/qr-scanner.min.js` and `artifacts/qr-scanner-worker.min.js`). +To generate them locally from this repo checkout (required for the demo and integration tests), run the build steps below. NodeJs is required for building. Install required build packages: ```batch diff --git a/artifacts/.gitkeep b/artifacts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/demo/index.html b/demo/index.html index 9f1f0d0..ab3387e 100644 --- a/demo/index.html +++ b/demo/index.html @@ -62,10 +62,10 @@

Scan from File:

Detected QR code: None - - + +