2018-12-20 14:45:23 +00:00
/ * *
* @ author j433866 [ j433866 @ gmail . com ]
* @ copyright Crown Copyright 2018
* @ license Apache - 2.0
* /
import Operation from "../Operation" ;
import OperationError from "../errors/OperationError" ;
import Magic from "../lib/Magic" ;
import jsqr from "jsqr" ;
import jimp from "jimp" ;
/ * *
* Parse QR Code operation
* /
class ParseQRCode extends Operation {
/ * *
* ParseQRCode constructor
* /
constructor ( ) {
super ( ) ;
this . name = "Parse QR Code" ;
this . module = "Image" ;
2018-12-25 21:54:38 +00:00
this . description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.<br><br><u>Normalise Image</u><br>Attempts to normalise the image before parsing it to improve detection of a QR code." ;
2018-12-20 14:45:23 +00:00
this . infoURL = "https://wikipedia.org/wiki/QR_code" ;
this . inputType = "byteArray" ;
this . outputType = "string" ;
2018-12-21 11:24:31 +00:00
this . args = [
{
"name" : "Normalise image" ,
"type" : "boolean" ,
2018-12-25 21:54:38 +00:00
"value" : false
2018-12-21 11:24:31 +00:00
}
] ;
2018-12-20 14:45:23 +00:00
}
/ * *
* @ param { byteArray } input
* @ param { Object [ ] } args
* @ returns { string }
* /
async run ( input , args ) {
const type = Magic . magicFileType ( input ) ;
2018-12-21 11:24:31 +00:00
const [ normalise ] = args ;
2018-12-25 21:54:38 +00:00
2018-12-20 14:45:23 +00:00
// Make sure that the input is an image
2018-12-25 21:54:38 +00:00
if ( type && type . mime . indexOf ( "image" ) === 0 ) {
let image = input ;
if ( normalise ) {
2018-12-21 11:24:31 +00:00
// Process the image to be easier to read by jsqr
// Disables the alpha channel
// Sets the image default background to white
// Normalises the image colours
// Makes the image greyscale
2018-12-25 21:54:38 +00:00
// Converts image to a JPEG
image = await new Promise ( ( resolve , reject ) => {
2018-12-21 11:24:31 +00:00
jimp . read ( Buffer . from ( input ) )
. then ( image => {
image
. rgba ( false )
. background ( 0xFFFFFFFF )
. normalize ( )
. greyscale ( )
. getBuffer ( jimp . MIME _JPEG , ( error , result ) => {
2018-12-25 21:54:38 +00:00
resolve ( result ) ;
2018-12-20 14:45:23 +00:00
} ) ;
2018-12-21 11:24:31 +00:00
} )
. catch ( err => {
reject ( new OperationError ( "Error reading the image file." ) ) ;
2018-12-20 14:45:23 +00:00
} ) ;
2018-12-21 11:24:31 +00:00
} ) ;
}
2018-12-25 21:54:38 +00:00
if ( image instanceof OperationError ) {
throw image ;
2018-12-21 11:24:31 +00:00
}
2018-12-25 21:54:38 +00:00
2018-12-21 11:24:31 +00:00
return new Promise ( ( resolve , reject ) => {
2018-12-25 21:54:38 +00:00
jimp . read ( Buffer . from ( image ) )
2018-12-21 11:24:31 +00:00
. then ( image => {
2018-12-25 21:54:38 +00:00
if ( image . bitmap != null ) {
2018-12-21 11:24:31 +00:00
const qrData = jsqr ( image . bitmap . data , image . getWidth ( ) , image . getHeight ( ) ) ;
2018-12-25 21:54:38 +00:00
if ( qrData != null ) {
2018-12-21 11:24:31 +00:00
resolve ( qrData . data ) ;
} else {
reject ( new OperationError ( "Couldn't read a QR code from the image." ) ) ;
}
} else {
2018-12-25 21:54:38 +00:00
reject ( new OperationError ( "Error reading the image file." ) ) ;
2018-12-21 11:24:31 +00:00
}
2018-12-20 14:45:23 +00:00
} )
. catch ( err => {
2018-12-25 21:54:38 +00:00
reject ( new OperationError ( "Error reading the image file." ) ) ;
2018-12-20 14:45:23 +00:00
} ) ;
} ) ;
2018-12-25 21:54:38 +00:00
} else {
2018-12-20 14:45:23 +00:00
throw new OperationError ( "Invalid file type." ) ;
}
}
}
export default ParseQRCode ;