@@ -30,8 +30,8 @@ $.onReady(function () {
3030 const elLoadFileInput = $ . id ( "loadFileInput" ) ;
3131 const elLoadImage = $ . id ( "loadImage" ) ;
3232 const elLoadImageInput = $ . id ( "loadImageInput" ) ;
33- const elLoadQrcode = $ . id ( "loadQrcode " ) ;
34- const elLoadQrcodeInput = $ . id ( "loadQrcodeInput " ) ;
33+ const elLoadCode = $ . id ( "loadCode " ) ;
34+ const elLoadCodeInput = $ . id ( "loadCodeInput " ) ;
3535 const elOeGroup = $ . id ( "oeGroup" ) ;
3636 const elOeGroupBtns = $ . all ( "#oeGroup .btn:not(.dropdown-toggle)" ) ;
3737 const elOexBtn = $ . id ( "oex" ) ;
@@ -512,11 +512,11 @@ $.onReady(function () {
512512 }
513513 } ) ;
514514
515- $ . on ( elLoadQrcode , "click" , function ( ) {
516- elLoadQrcodeInput . click ( ) ;
515+ $ . on ( elLoadCode , "click" , function ( ) {
516+ elLoadCodeInput . click ( ) ;
517517 } ) ;
518518
519- $ . on ( elLoadQrcodeInput , "change" , async function ( ) {
519+ $ . on ( elLoadCodeInput , "change" , async function ( ) {
520520 if ( this . files . length === 0 ) {
521521 return ;
522522 }
@@ -525,10 +525,10 @@ $.onReady(function () {
525525 this . value = "" ;
526526
527527 try {
528- updateValue ( await readQrcodeAsync ( file ) ) ;
529- showTooltip ( elLoadBtn , elLoadQrcode . getAttribute ( "data-load-message" ) , 2000 ) ;
528+ updateValue ( await readCodeAsync ( file ) ) ;
529+ showTooltip ( elLoadBtn , elLoadCode . getAttribute ( "data-load-message" ) , 2000 ) ;
530530 } catch ( ex ) {
531- showMessageDialog ( elLoadQrcode . getAttribute ( "data-load-error-message" ) ) ;
531+ showMessageDialog ( elLoadCode . getAttribute ( "data-load-error-message" ) ) ;
532532 }
533533 } ) ;
534534
@@ -1019,32 +1019,83 @@ $.onReady(function () {
10191019 return ret . data . text ;
10201020 }
10211021
1022- async function readQrcodeAsync ( file ) {
1023- await loadScriptAsync ( "#scriptJsqr" ) ;
1024-
1022+ async function readCodeAsync ( file ) {
10251023 const img = await readFileAsImageAsync ( file ) ;
10261024
1027- const code = readQrcodeFromImage ( img , [ 600 , 200 , 1000 , 400 , 800 , 1200 , 1400 , 1600 ] ) ;
1025+ let code = await detectCodeAsync ( img ) ;
10281026 if ( code === null ) {
1029- reject ( new Error ( "Could not parse." ) ) ;
1030- return ;
1027+ code = await detectCodeByZXingAsync ( img ) ;
1028+ }
1029+ if ( code === null ) {
1030+ throw new Error ( "Could not parse." ) ;
1031+ }
1032+
1033+ return code ;
1034+ }
1035+
1036+ async function detectCodeAsync ( img ) {
1037+ if ( ! ( "BarcodeDetector" in window ) ) {
1038+ return null ;
1039+ }
1040+
1041+ const canvas = toCanvas ( img , 1.0 , "white" ) ;
1042+
1043+ const detector = new BarcodeDetector ( ) ;
1044+ const barcodes = await detector . detect ( canvas ) ;
1045+
1046+ if ( barcodes . length === 0 ) {
1047+ return null ;
10311048 }
10321049
1033- let data ;
1034- if ( code . data . length === 0 && 0 < code . binaryData . length ) {
1035- // If the QR code cannot be parsed as UTF-8 text
1050+ const code = Array . from ( barcodes , ( barcode ) => barcode . rawValue ) . join ( "\n" ) ;
1051+
1052+ if ( code . length === 0 ) {
1053+ return null ;
1054+ }
1055+
1056+ return code ;
1057+ }
1058+
1059+ async function detectCodeByZXingAsync ( img ) {
1060+ await loadScriptAsync ( "#scriptZXing" ) ;
1061+
1062+ const codeReader = new ZXing . BrowserMultiFormatReader ( ) ;
1063+ const hints = new Map ( [
1064+ [ ZXing . DecodeHintType . TRY_HARDER , true ]
1065+ ] ) ;
1066+
1067+ let parsedOrgSize = false ;
1068+ let result = null ;
1069+ for ( let maxSize of [ 480 , 640 , 800 , 1024 , 1280 , 1600 , 1920 , 2160 ] ) {
1070+ const scale = calcImageScale ( img , maxSize ) ;
1071+ if ( scale === 1.0 ) {
1072+ if ( parsedOrgSize ) {
1073+ continue ;
1074+ }
1075+ parsedOrgSize = true ;
1076+ }
1077+
1078+ const canvas = toCanvas ( img , scale , "white" ) ;
1079+
10361080 try {
1037- // Parse the binary data as JIS X 0208 (Shift_JIS) text
1038- data = new TextDecoder ( "shift-jis" , { fatal : true } ) . decode ( Uint8Array . from ( code . binaryData ) ) ;
1081+ result = await codeReader . decodeFromImageUrl ( canvas . toDataURL ( "image/png" ) , hints ) ;
1082+ break ;
10391083 } catch ( ex ) {
1040- // Convert the binary data to hex string
1041- data = code . binaryData . map ( ( b ) => ( "0" + ( b & 0xFF ) . toString ( 16 ) ) . slice ( - 2 ) ) . join ( "" ) ;
1084+ continue ;
10421085 }
1043- } else {
1044- data = code . data ;
10451086 }
10461087
1047- return data ;
1088+ if ( result === null ) {
1089+ return null ;
1090+ }
1091+
1092+ let code = result . getText ( ) ;
1093+ if ( code . includes ( "\uFFFD" ) ) {
1094+ // Binary to hex string
1095+ code = Array . from ( result . getRawBytes ( ) , ( b ) => b . toString ( 16 ) . padStart ( 2 , "0" ) ) . join ( "" ) ;
1096+ }
1097+
1098+ return code ;
10481099 }
10491100
10501101 function updateValue ( val ) {
@@ -1250,38 +1301,27 @@ function readFileAsImageAsync(file) {
12501301 } ) ;
12511302}
12521303
1253- function readQrcodeFromImage ( imgElm , maxSizes ) {
1254- const minImgSize = Math . min ( imgElm . width , imgElm . height ) ;
1255-
1304+ function calcImageScale ( img , maxSize ) {
1305+ const maxImgSize = Math . max ( img . naturalWidth , img . naturalHeight ) ;
1306+ const scale = Math . min ( 1.0 , 1.0 * maxSize / maxImgSize ) ;
1307+ return scale ;
1308+ }
1309+
1310+ function toCanvas ( img , scale , bgColor ) {
12561311 const canvas = document . createElement ( "canvas" ) ;
1312+ canvas . width = img . naturalWidth * scale ;
1313+ canvas . height = img . naturalHeight * scale ;
12571314
1258- let code = null ;
1259- let parsedOrgSize = false ;
1260- for ( const maxSize of maxSizes ) {
1261- const r = Math . min ( 1.0 , 1.0 * maxSize / minImgSize ) ;
1262-
1263- if ( 1.0 <= r ) {
1264- if ( parsedOrgSize ) {
1265- break ;
1266- }
1267- parsedOrgSize = true ;
1268- }
1269-
1270- canvas . width = imgElm . width * r ;
1271- canvas . height = imgElm . height * r ;
1272-
1273- const ctx = canvas . getContext ( "2d" ) ;
1274- ctx . scale ( r , r ) ;
1275- ctx . drawImage ( imgElm , 0 , 0 ) ;
1276- const imageData = ctx . getImageData ( 0 , 0 , canvas . width , canvas . height ) ;
1277-
1278- code = jsQR ( imageData . data , imageData . width , imageData . height ) ;
1279- if ( code !== null ) {
1280- break ;
1281- }
1315+ const ctx = canvas . getContext ( "2d" ) ;
1316+ if ( bgColor ) {
1317+ ctx . fillStyle = bgColor ;
1318+ ctx . fillRect ( 0 , 0 , canvas . width , canvas . height ) ;
12821319 }
1320+ ctx . imageSmoothingEnabled = true ;
1321+ ctx . imageSmoothingQuality = "high" ;
1322+ ctx . drawImage ( img , 0 , 0 , canvas . width , canvas . height ) ;
12831323
1284- return code ;
1324+ return canvas ;
12851325}
12861326
12871327function separateThousand ( num ) {
0 commit comments