/* **************************************** GLOBAL VARIABLES **************************************** */ var APP_VERSION = '0.4.0'; var qr_version = 1; //Current QR version (1-9) var qr_pixel_size = 10; //Current view size of QR code (pixel per module) var qr_pixel_size_togglesave = 10; //Last toggle view size of QR code (pixel per module) var qr_size = 17+(qr_version*4); //Current size of QR code var qr_array = []; //Main array to store QR data var qr_format_array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; //Store QR format information var active_painter = "0"; //Current active painter tool (0,1,2) var fill_painter = false; //Is flood fill tool active? var changed_state = false; //Is document in changed state and not saved yet? var show_grey = true; //Show grey modules in Decode mode var extract_info_mode = false; //Is Extract QR Information active? var brute_force_mode = false; //Is Brute-force Format Info active? var analysis_mode = false; //Is Data Analysis tool active? var masking_mode = false; //Is Masking active? var qr_temp_array = []; //Temporary variable to handle qr_array duplicates var qr_data_block = []; //Array to store data block in "Data Analysis tool" var is_data_module = []; //Store data that separate between data module and fixed module (function pattern, alignment pattern, etc) var history_array = []; //Store history information and its qr_array data var active_history = -1; //Current active history const maxSupportedSize = 177; // max is 177 for v40 const maxVersion = 40; // max is not 50 /*** * * generate QR table based on qr_array * ***/ function generateTable(version){ qr_array = JSON.parse(JSON.stringify(generate_qr(version))); if (version > 9 && version <= 20){ qr_pixel_size = 5; } else if (version > 20 && version <=35){ qr_pixel_size = 2; } else if (version > 35 ){ qr_pixel_size = 1; } changed_state = false; var element = ""; var size = 17+(version*4); for(var i=0; i < qr_array.length; i++){ element += ""; for(var j=0; j < qr_array.length; j++){ if(qr_array[i][j] == 0) element += ""; else if(qr_array[i][j] == 1) element += ""; else element += ""; } element += ""; } $("#qr-table").html(element); getInformation(size); resize(qr_pixel_size); is_data_module = getDataModule(qr_array); updateToolbox(); clearHistory(); updateHistory("New QR code"); } /*** * * get format information value * ***/ function getInformation(size){ //Information top-left beside Finder for(var i=0; i < 9; i++){ if(i == 6) continue; $("#qr-"+i+"-8").removeClass("static").addClass("info"); qr_array[i][8] = 0; } //Information top-left below Finder for(var i=0; i < 9; i++){ if(i == 6) continue; $("#qr-8-"+i).removeClass("static").addClass("info"); qr_array[8][i] = 0; } //Information top-right below Finder for(var i=size-8; i < size; i++){ $("#qr-8-"+i).removeClass("static").addClass("info"); qr_array[8][i] = 0; } //Information bottom-left beside Finder and get Dark module for(var i=size-8; i < size; i++){ if(i != size-8){ $("#qr-"+i+"-8").removeClass("static").addClass("info"); qr_array[i][8] = 0; } } } /*** * * generate QR table in format information overlay dialog * ***/ function generateInfoTable(position){ position = position || "TOP_LEFT"; $("#qr-format-info").html(""); $("#select-format-info-pos").val(position); var pattern_array = function_pattern_with_format_info[position]; if(position == "TOP_LEFT"){ var start_index = 0; var end_index = 15; } else if(position == "TOP_RIGHT"){ var start_index = 0; var end_index = 8; } else if(position == "BOTTOM_LEFT"){ var start_index = 8; var end_index = 15; } for(var i=0; i < pattern_array.length; i++){ var element = ""; for(var j=0; j < pattern_array[i].length;j++){ if(pattern_array[i][j] == 0){ element += ""; } else if(pattern_array[i][j] == 1){ element += ""; } else { element += ""; } } element += ""; $("#qr-format-info").append(element); } for(var i=start_index; i < end_index; i++){ if(qr_format_array[i] == 1){ $("td#qr-info-"+i).addClass("black"); } else { $("td#qr-info-"+i).addClass("white"); } } } /*** * * Save format information value to qr_format_array * ***/ function saveInfoTable(size){ for(var i=0; i < 8; i++){ if(i > 5) qr_array[i+1][8] = parseInt(qr_format_array[i]); else qr_array[i][8] = parseInt(qr_format_array[i]); qr_array[8][size-(i+1)] = parseInt(qr_format_array[i]); } var index = 0; for(var i=14; i >= 8; i--){ if(index > 5) qr_array[8][index+1] = parseInt(qr_format_array[i]); else qr_array[8][index] = parseInt(qr_format_array[i]); qr_array[size-(index+1)][8] = parseInt(qr_format_array[i]); index++; } refreshTable(); $("#format-information-box").hide(); changed_state = true; } /*** * * Reload QR table based on qr_array value * ***/ function refreshTable(){ for(var i=0; i < qr_array.length; i++){ for(var j=0; j < qr_array[i].length; j++){ if(!$("#qr-"+i+"-"+j).hasClass("static")){ $("#qr-"+i+"-"+j).removeClass("black"); $("#qr-"+i+"-"+j).removeClass("white"); if(qr_array[i][j] == 1){ $("#qr-"+i+"-"+j).addClass("black"); } else if(qr_array[i][j] == 0) { $("#qr-"+i+"-"+j).addClass("white"); } } } } } /*** * * Update qr_array from new array (exclude fixed pattern: function pattern, alignment pattern, timing, and version information) * ***/ function updateQRArray(new_data){ for(var i=0; i < qr_array.length; i++){ for(var j=0; j < qr_array[i].length; j++){ if(is_data_module[i][j]){ qr_array[i][j] = new_data[i][j]; } } } //update format information when using image upload var size = qr_size; for(var i=0; i < 8; i++){ if(i > 5) qr_array[i+1][8] = new_data[i+1][8]; else qr_array[i][8] = new_data[i][8]; qr_array[8][size-(i+1)] = new_data[8][size-(i+1)]; } var index = 0; for(var i=14; i >= 8; i--){ if(index > 5) qr_array[8][index+1] = new_data[8][index+1]; else qr_array[8][index] = new_data[8][index];; qr_array[size-(index+1)][8] = new_data[size-(index+1)][8];; index++; } } /*** * * Get format information from format information overlay dialog * ***/ function getInfoBits(){ var result = {ecc:"",mask:-1}; $("#slider-mask div.active").removeClass("active"); $("#slider-ecc div.active").removeClass("active"); var bits = ""; bits = qr_format_array.join(""); bits = bits.split("").reverse().join(""); var raw_bits = [bits.substring(0,2), bits.substring(2,5)]; var bch_bits = bits.substring(5); if(format_information_bits_raw.ecc.indexOf(raw_bits[0]) > -1){ if(format_information_bits_raw.ecc.indexOf(raw_bits[0]) == 0) result.ecc = "L"; else if(format_information_bits_raw.ecc.indexOf(raw_bits[0]) == 1) result.ecc = "M"; else if(format_information_bits_raw.ecc.indexOf(raw_bits[0]) == 2) result.ecc = "Q"; else result.ecc = "H"; } if(format_information_bits_raw.mask.indexOf(raw_bits[1]) > -1){ result.mask = format_information_bits_raw.mask.indexOf(raw_bits[1]); } if(format_information_bits[0].indexOf(bits) > -1){ result.ecc = "L"; result.mask = format_information_bits[0].indexOf(bits); } else if(format_information_bits[1].indexOf(bits) > -1){ result.ecc = "M"; result.mask = format_information_bits[1].indexOf(bits); } else if(format_information_bits[2].indexOf(bits) > -1){ result.ecc = "Q"; result.mask = format_information_bits[2].indexOf(bits); } else if(format_information_bits[3].indexOf(bits) > -1){ result.ecc = "H"; result.mask = format_information_bits[3].indexOf(bits); } console.log(bits); return result; } /*** * * Sanitize and verify qr is square before parsing it * ***/ function sanitizeQrTxt(lines) { const linesOut = []; for(let i=0;i ( x===1 ? '#' : ( x===0 ? '_' : ( show_grey ? '?' : '_' ) ) ) ).join(''); console.log(line); dump_qr += line + "\n" } return dump_qr; } /*** * * generate QR code made from canvas based on qr_array values * ***/ function generateResult(){ var c = document.getElementById("qr-result-canvas"); var size = 17+(qr_version*4); var ctx = c.getContext("2d"); c.width = qr_pixel_size*size; c.height = qr_pixel_size*size; // add quiet zone border and white fill c.width += (qr_pixel_size*4) * 2; c.height += (qr_pixel_size*4) * 2; ctx.fillStyle = "#fff"; ctx.fillRect(0,0,c.width,c.height); ctx.fillStyle = "#000"; for(var i=0; i < qr_array.length; i++){ for(var j=0; j < qr_array[i].length; j++){ var x = qr_pixel_size*j; var y = qr_pixel_size*i; //shift due to quiet zone x += qr_pixel_size*4; y += qr_pixel_size*4; if(qr_array[i][j] == 1){ ctx.fillStyle = "#000"; ctx.fillRect(x,y,qr_pixel_size,qr_pixel_size); } else if(qr_array[i][j] == 0) { ctx.fillStyle = "#fff"; ctx.fillRect(x,y,qr_pixel_size,qr_pixel_size); } else { if(show_grey){ ctx.fillStyle = "#bdbdbd"; ctx.fillRect(x,y,qr_pixel_size,qr_pixel_size); } else{ ctx.fillStyle = "#fff"; ctx.fillRect(x,y,qr_pixel_size,qr_pixel_size); } } } } $("#qr-result-dump").attr('rows', qr_version*4 +17 ); $("#qr-result-dump").attr('cols', qr_version*4 +17 ); $("#qr-result-dump").css( 'font-family', 'Courier New'); $("#qr-result-dump").css("font-size", "7px"); $("#qr-result-dump").val( dumpQRArray() ); $("#qr-result").show(); $("#qr-table").hide(); $("#qr-overlay").hide(); $("body").css("background-color","#FFFFFF"); } /*** * * Update toolbox values * ***/ function updateToolbox(){ $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); $("#qr-size").val(qr_pixel_size+"px"); } /*** * * Resize QR size * ***/ function resize(size){ $("td").each(function(){ $(this).css({"min-width":size+"px","min-height":size+"px","width":size+"px","height":size+"px"}); }) } /*** * * Toggle between Editor and Decode mode * ***/ function toggleResult(){ if(!$("#btn-switch-mode").hasClass("active")){ $(".mode-indicator button").removeClass("active"); $("#mobile-decode-mode").addClass("active"); //resize for decode ( minimum 2px module width needed for standard device decoding ) qr_pixel_size_togglesave = qr_pixel_size; if (qr_pixel_size == 1 ) { $("#btn-size-plus").trigger("click"); } generateResult(); $("#btn-switch-mode").addClass("active"); $("#div-tool-work, #box-history").hide(); $("#div-tool-result").show(); $("#btn-switch-mode").text("Decode Mode"); $("#box-tools-masking").hide(); if(brute_force_mode) $("#h6-brute-force-msg").show(); else $("#h6-brute-force-msg").hide(); if(analysis_mode){ $("#box-work").show(); $("#box-tools-analysis").hide(); } } else { $(".mode-indicator button").removeClass("active"); $("#mobile-editor-mode").addClass("active"); //restore to previous encode mode pixel size if (qr_pixel_size - qr_pixel_size_togglesave >= 0){ for (i = qr_pixel_size - qr_pixel_size_togglesave ; i > 0 ; i-- ){ $("#btn-size-min").trigger("click"); } } else { for (i = qr_pixel_size_togglesave - qr_pixel_size ; i > 0 ; i-- ){ $("#btn-size-plus").trigger("click"); } } $("#qr-result").hide(); $(".qr-tab").show(); $("#btn-switch-mode").removeClass("active"); $("body").css("background-color","#eceff1"); $("#div-tool-result").hide(); $("#div-tool-work, #box-history").show(); $("#btn-switch-mode").text("Editor Mode"); if(analysis_mode){ $("#box-work").hide(); $("#box-tools-analysis").show(); } } } /*** * * Load image from file and put to {target} * ***/ function loadImage(input, target){ if(input.files && input.files[0]){ var reader = new FileReader(); reader.onload = function(e){ $(target).attr("src",e.target.result); } reader.readAsDataURL(input.files[0]); } } /*** * * Save project to LocalStorage * ***/ function saveProject(projectName){ if(projectName == ""){ alert("Please, enter name of your Project!"); return; } var saveData = [qr_array, qr_version, qr_format_array]; var dataList = JSON.parse(localStorage.getItem("dataList")); var timeNow = new Date(); var timeData = timeNow.toDateString(); var projectNameList = []; if(dataList == undefined){ dataList = []; } for(var i=0; i < dataList.length; i++){ projectNameList[i] = dataList[i][0]; } if(!projectNameList.includes(projectName)) { dataList.push([projectName, timeData]); } else { var index = projectNameList.indexOf(projectName); dataList[index][1] = timeData; } localStorage.setItem("saveData_"+projectName,JSON.stringify(saveData)); localStorage.setItem("dataList",JSON.stringify(dataList)); $("#div-save").hide(); changed_state = false; } /*** * * Load project from LocalStorage * ***/ function loadProject(name){ if(changed_state){ if(!confirm("Are you sure want to proceed?\nYour unsaved progress will be lost!")) return; } var loadedData = JSON.parse(localStorage.getItem("saveData_"+name)); qr_version = loadedData[1]; qr_size = 17+(qr_version*4); generateTable(qr_version); qr_array = loadedData[0]; qr_format_array = loadedData[2]; brute_force_mode = false; $("#tools-brute-force, #tools-unmasking").removeClass("active"); refreshTable(); $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); $("#div-load").hide(); if($("#btn-switch-mode").hasClass("active")){ toggleResult(); } if($("#div-extract").css("display") != "none"){ $("#btn-tools-extract").trigger("click"); } if(analysis_mode){ $("#tools-data-analysis").trigger("click"); } $("#box-tools-masking").hide(); $("#qr-overlay").html(""); clearHistory(); updateHistory("Load project"); } /*** * * Remove project from LocalStorage * ***/ function removeProject(name, origin){ if(confirm("Are you sure want to permanently delete this project?")){ var dataList = JSON.parse(localStorage.getItem("dataList")); var projectNameList = []; for(var i=0; i < dataList.length; i++){ projectNameList[i] = dataList[i][0]; } var index = projectNameList.indexOf(name); if(index >= 0){ dataList.remove(index); localStorage.removeItem("saveData_"+name); localStorage.setItem("dataList",JSON.stringify(dataList)); refreshLoadList(origin); } } } /*** * * Refresh list of project in LocalStorage * ***/ function refreshLoadList(origin){ var dataList = JSON.parse(localStorage.getItem("dataList")); if(dataList == undefined){ $("#list-"+origin).html("
There's no saved project in Local Storage.
"); } else { var element = ""; for(var i=0; i < dataList.length; i++){ element += "
"+dataList[i][0]+"
"+dataList[i][1]+"
"; } $("#list-"+origin).html(element); } } /*** * * Decode Base64 to image * ***/ function decodeFromBase64(img, callback){ qrcode.callback = callback; qrcode.decode(img, callback); } function importFromImage(src, cb){ var img = new Image(); img.crossOrigin = "Anonymous"; console.log(src); img.onload = function(){ var canvas_qr = document.createElement("canvas"); var context = canvas_qr.getContext('2d'); var nheight = img.height; var nwidth = img.width; if(img.width*img.height>qrcode.maxImgSize){ var ir = img.width / img.height; nheight = Math.sqrt(qrcode.maxImgSize/ir); nwidth=ir*nheight; } canvas_qr.width = nwidth; canvas_qr.height = nheight; context.drawImage(img, 0, 0, canvas_qr.width, canvas_qr.height ); qrcode.width = canvas_qr.width; qrcode.height = canvas_qr.height; try{ qrcode.imagedata = context.getImageData(0, 0, canvas_qr.width, canvas_qr.height); }catch(e){ cb(e); return; } var image = qrcode.grayScaleToBitmap(qrcode.grayscale()); var detector = new Detector(image); try { var qRCodeMatrix = detector.detect(); } catch(error){ console.log(error); cb(error); return; } var qrArray = qRCodeMatrix.bits.bits; var size = qRCodeMatrix.bits.width; if(size > maxSupportedSize){ alert("QR version is unsupported"); return; } qr_size = size; qr_version = (size-17)/4; updateToolbox(); var result = []; for(var x=0; x < size; x++){ result[x] = []; for(var y=0; y < size; y++){ result[x][y] = qRCodeMatrix.bits.get_Renamed(y,x) ? 1 : 0; } } cb(result); } img.src = src; } /*** * * Flood fill algorithm to perform paint-like bucket tool * * Reference : https://jsfiddle.net/eWxNE/2/ * ***/ function floodFill(x, y, oldVal, newVal){ x = parseInt(x); y = parseInt(y); if(oldVal == null){ oldVal = parseInt(qr_array[x][y]); } if(qr_array[x][y] !== oldVal){ return; } if(is_data_module[x][y]) qr_array[x][y] = parseInt(newVal); else return; if (x > 0){ floodFill(x-1, y, oldVal, newVal); } if(y > 0){ floodFill(x, y-1, oldVal, newVal); } if(x < qr_size-1){ floodFill(x+1, y, oldVal, newVal); } if(y < qr_size-1){ floodFill(x, y+1, oldVal, newVal); } } /*** * * Update history * ***/ function updateHistory(msg){ if(active_history < 10) active_history++; history_array = history_array.slice(0, active_history); if(history_array.length == 10){ history_array.shift(); } history_array.push([msg, JSON.stringify(qr_array)]); var html = ""; for(var i=history_array.length-1; i >= 0; i--){ if(i == history_array.length-1){ html += "
"+history_array[i][0]+"
"; } else { html += "
"+history_array[i][0]+"
"; } } $(".history").html(html); } /*** * * Get history value and refresh QR table * ***/ function getHistory(index){ qr_array = JSON.parse(history_array[index][1]); if(qr_array.length != qr_size){ qr_size = qr_array.length; qr_version = (qr_size-17)/4; updateToolbox(); } refreshTable(); } /*** * * Clear all history value * ***/ function clearHistory(){ history_array = []; active_history = -1; $(".history").html(""); } /*** * * Display information text result in Extract QR Information tool and * load it to #div-extract * ***/ function extractInfo(){ var data_array = JSON.stringify(qr_array); var result = QRDecode(JSON.parse(data_array)); var size = 17+(qr_version*4); console.log(result); var html = "
QR version : "+qr_version+" ("+size+"x"+size+")
\
Error correction level : "+result.ecc+"
\
Mask pattern : "+result.mask_pattern+"
\
\
Number of missing bytes (erasures) : "+result.erasure_count+" bytes ("+(result.erasure_count/result.data_module_count * 100).toFixed(2)+"%)
\
\
Data blocks :
\
"+result.data_blocks+"
\
"; if($("#btn-extract-show-rs").hasClass("active")){ for(var i=0; i < result.rs_block.length; i++){ html += "
----------------Block "+(i+1)+"----------------
\
Reed-Solomon Block : "+result.rs_block[i]+"
"; if(result.syndrome[i] != undefined && result.error_count[i] != undefined){ console.log(result.syndrome[i], result.error_count); html +="
Syndrome : "+result.syndrome[i]+"
\
Number of Errors : "+result.error_count[i]+"
\
Coefficient of the error location polynomial : "+result.coeff_error[i]+"
\
Error Position : "+result.error_position[i]+"
\
Error Magnitude : "+result.error_magnitude[i]+"
\
"; } else { html += "
"; } } } html += "
Final data bits :
\
"+result.data_bits+"
\
"; for(var i=0; i < result.data_bits_count; i++){ html += "
"+result.data_bits_block[i]+"
\
Mode Indicator : "+result.mode[i]+"
\
Character Count Indicator : "+result.count[i]+"
\
Decoded data : "+result.decoded[i]+"
\
"; } html += "
Final Decoded string : "+result.message+"
"; if($("#btn-extract-show-error").hasClass("active") && result.error.length > 0){ html += "
Error :
"; for(var i=0; i < result.error.length; i++){ html += "
- "+result.error[i]+"
"; } } $("#div-extract").html(html); } var brute_result = []; var brute_result_index = []; var current_brute_result = 0; function callbackBruteForce(){ console.log(brute_result); if(brute_result.length != 32) return; for(var i=0; i < brute_result.length; i++){ if(brute_result[i] != "error decoding QR Code"){ brute_result_index.push(i); } } var true_count = brute_result_index.length; current_brute_result = 0; if(true_count > 0){ var ecc = Math.floor(brute_result_index[0] / 8); var mask = brute_result_index[0] % 8; qr_format_array = format_information_bits[ecc][mask].split("").reverse(); if(ecc == 0) ecc = "L"; else if(ecc == 1) ecc = "M"; else if(ecc == 2) ecc = "Q"; else if(ecc == 3) ecc = "H"; $("#brute-force-msg-wait").hide(); $("#brute-force-msg-fail").hide(); $("#brute-force-content").show(); $("#btn-brute-force-apply-pattern").show(); $("#brute-force-decoded-data").val(brute_result[brute_result_index[current_brute_result]]); $("#brute-force-ecc span").text(ecc); $("#brute-force-mask span").text(mask); $("#brute-force-result-counter").text("1 of "+true_count+" result"); saveInfoTable(qr_size); generateResult(); $("#tools-brute-force").trigger("click"); } else { $("#brute-force-msg-wait").hide(); $("#brute-force-msg-fail").show(); $("#btn-brute-force-apply-pattern").show(); qr_format_array = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]; saveInfoTable(qr_size); generateResult(); updateHistory("Update format info pattern"); } } function bruteForceFormatInfo(){ brute_result = []; brute_result_index = []; var possible_ecc = ["L","M","Q","H"]; var possible_mask = [0,1,2,3,4,5,6,7]; for(var i=0; i < possible_ecc.length; i++){ for(var j=0; j < possible_mask.length; j++){ qr_format_array = format_information_bits[i][j].split("").reverse(); saveInfoTable(qr_size); generateResult(); var image = document.getElementById("qr-result-canvas").toDataURL(); if(i == 3 && j == 7){ decodeFromBase64(image, function(data){ brute_result.push(data); callbackBruteForce(); }) } else { decodeFromBase64(image, function(data){ brute_result.push(data); }) } } } } /*** * * Mask qr_array with mask_pattern and refresh QR table * ***/ function maskDataBits(){ var mask_pattern = getFormatInfo(qr_array).mask; qr_array = maskData(qr_array, mask_pattern); refreshTable(); updateHistory("Data masking"); } function showMaskPatternArea(){ var qr_mask_array = []; for(var i=0; i < qr_array.length; i++){ qr_mask_array[i] = []; for(var j=0; j < qr_array[i].length; j++){ qr_mask_array[i][j] = 0; } } var mask_pattern = getFormatInfo(qr_array).mask; qr_mask_array = maskData(qr_mask_array, mask_pattern); $("#qr-overlay").html(""); for(var i=0; i < qr_array.length; i++){ var html = ""; for(var j=0; j < qr_array[i].length; j++){ if($("#qr-"+i+"-"+j).hasClass("info") || $("#qr-"+i+"-"+j).hasClass("static")){ html += ""; } else { if(qr_mask_array[i][j] == 0) html += ""; else html += ""; } } html += ""; $("#qr-overlay").append(html); } resize(qr_pixel_size); } function patchingRecovery(result){ var warning = 0; $("#qr-dummy").html(""); $("#div-patch-rec-warning, #div-patch-rec-error").hide(); $("#div-patch-rec-data, #btn-patch-rec-apply").show() if(typeof result == "string"){ $("#div-patch-rec-error").show(); $("#div-patch-rec-error textarea").val(result); $("#div-patch-rec-warning, #div-patch-rec-data, #btn-patch-rec-apply").hide(); return; } for(var i=0; i < result.result_array.length; i++){ var elem = ""; for(var j=0; j < result.result_array[i].length; j++){ if(qr_array[i][j] != result.result_array[i][j]){ if(result.result_array[i][j] == 0) elem += ""; else if(result.result_array[i][j] == 1) elem += ""; else elem += ""; } else { if(result.result_array[i][j] == 0) elem += ""; else if(result.result_array[i][j] == 1) elem += ""; else elem += ""; } } elem += ""; $("#qr-dummy").append(elem); resize(qr_pixel_size); } for(var i=0; i < result.after.length; i++){ if(result.before.charAt(i) != "?"){ if(result.after.charAt(i) != result.before.charAt(i)){ warning++; } } } if(warning){ $("#div-patch-rec-warning").show(); $("#div-patch-rec-warning textarea").val("There's are " + warning +" modules conflict with the already known module of original QR code. Correction may fail.") } $("#patch-rec-before").val(result.before); $("#patch-rec-after").val(result.after); qr_temp_array = Array.prototype.slice.call(result.result_array); } /*** * * Perform Reed-Solomon decode * ***/ function reedSolomonDecode(data, nysm){ var result = []; //console.log('nysm: '+nysm, 'data: '+data); for(var i=0; i < data.length; i++){ var err_pos = []; for(var j=0; j < data[i].length; j++){ if(data[i][j] == 0) err_pos.push(j); } var decoded = RS.decode(data[i], nysm, err_pos); if(typeof decoded == "string"){ $("#rs-decoder-error").text("ERROR: "+decoded).removeClass("invisible"); $("#rs-decoder-output, #rs-decoder-final-msg").val(""); return; } result = result.concat(decoded); } $("#rs-decoder-output").val(result.join(",")); var data_bits = ""; for(var i=0; i < result.length; i++){ var pad = "00000000"; var text = parseInt(result[i]).toString(2); var remain = (pad+text).length - 8; text = (pad + text).slice(remain); data_bits += text; } var readed_data = readDataBits(data_bits); if(readed_data != '') $("#rs-decoder-final-msg").val(readed_data); else { $("#rs-decoder-error").text("ERROR: Data can't be readed").removeClass("invisible"); $("#rs-decoder-final-msg").val(""); } } function showQRTableOverlay(){ $("#qr-overlay").html(""); for(var i=0; i < qr_array.length; i++){ var html = ""; for(var j=0; j < qr_array[i].length; j++){ if($("#qr-"+i+"-"+j).hasClass("info") || $("#qr-"+i+"-"+j).hasClass("static")){ html += ""; } else { html += ""; } } html += ""; $("#qr-overlay").append(html); } resize(qr_pixel_size); } function activateAnalysisMode(status){ status = status || "true"; if(status === "true"){ $("#qr-table tr td").css({"pointer-events":"none","border-color":"transparent"}); $("#qr-table tr td.static, #qr-table tr td.info").css("opacity","0.2"); generateDataBlocks(); } else if(status === "false") { $("#qr-table tr td").css({"opacity":"1","pointer-events":"auto","border-color":"#434A54"}); $("#qr-table tr td.static, #qr-table tr td.info").css("opacity","1"); $("#qr-overlay").html(""); } } var module_order = []; function pushBlock(type,value,decoded){ var modules = []; for(var k=0; k < value.length; k++){ modules.push(module_order.shift()); } var obj = {value:value,type:type,decoded:decoded,modules:modules}; qr_data_block.push(obj); } function generateDataBlocks(){ qr_data_block = []; var format_info = getFormatInfo(qr_array); var mask_pattern = format_info.mask; var ecc_level = format_info.ecc; if(RS_block_num_table[qr_version-1][ecc_level] > 1){ alert('Interleaved blocks is not supported yet!'); return; } var unmasked_data_array = maskData(qr_array, mask_pattern); var decoded_data = readDataBlock(qr_array); var data_block = decoded_data.blocks; module_order = decoded_data.module_order; while(data_block.length != 1){ if(data_block.substring(0,4) == "0001"){ var enc_mode = "Numeric mode"; } else if(data_block.substring(0,4) == "0010"){ var enc_mode = "Alphanumeric mode"; } else if(data_block.substring(0,4) == "0100"){ var enc_mode = "Binary mode"; } else if(data_block.substring(0,4) == "0000") { var enc_mode = "Terminator"; } else { break; } pushBlock( "Mode indicator", data_block.substring(0,4), enc_mode ); data_block = data_block.substring(4); if(enc_mode == "Numeric mode"){ var data_length = parseInt(data_block.substring(0,10), 2); pushBlock( "Char. count indicator", data_block.substring(0,10), data_length ); data_block = data_block.substring(10); for(var k=0; k < Math.floor((data_length + 2) / 3); k++){ var temp_value = ""; var temp_decoded = ""; if(k == Math.floor((data_length + 2) / 3) - 1){ if(data_length % 3 == 0){ temp_value = data_block.substring(0,10); temp_decoded = parseInt(data_block.substring(0,10), 2); data_block = data_block.substring(10); } else if(data_length % 3 == 1){ temp_value = data_block.substring(0,4); temp_decoded = parseInt(data_block.substring(0,4), 2); data_block = data_block.substring(4); } else { temp_value = data_block.substring(0,7); temp_decoded = parseInt(data_block.substring(0,7), 2); data_block = data_block.substring(7); } } else { temp_value = data_block.substring(0,10); temp_decoded = parseInt(data_block.substring(0,10), 2); data_block = data_block.substring(10); } pushBlock( "Message data", temp_value, temp_decoded ); } } else if(enc_mode == "Alphanumeric mode"){ var data_length = parseInt(data_block.substring(0,9), 2); pushBlock( "Char. count indicator", data_block.substring(0,9), data_length ); data_block = data_block.substring(9); for(var i=0; i < Math.floor((data_length + 1) / 2); i++){ if(i == Math.floor((data_length + 1) / 2) - 1){ if(data_length % 2 == 0){ var num = parseInt(data_block.substring(0,11), 2); temp_value = data_block.substring(0,11); temp_decoded = alphanumeric_table[Math.floor(num / 45)] + alphanumeric_table[num % 45]; data_block = data_block.substring(11); } else { var num = parseInt(data_block.substring(0,6), 2); temp_value = data_block.substring(0,6); temp_decoded = alphanumeric_table[num]; data_block = data_block.substring(6); } } else { var num = parseInt(data_block.substring(0,11), 2); temp_value = data_block.substring(0,11); temp_decoded = alphanumeric_table[Math.floor(num / 45)] + alphanumeric_table[num % 45] data_block = data_block.substring(11); } pushBlock( "Message data", temp_value, temp_decoded ); } } else if(enc_mode == "Binary mode"){ var data_length = parseInt(data_block.substring(0,8), 2); pushBlock( "Char. count indicator", data_block.substring(0,8), data_length ); data_block = data_block.substring(8); for(var i=0; i < data_length; i++){ temp_value = data_block.substring(0,8); temp_decoded = String.fromCharCode(parseInt(data_block.substring(0,8), 2)); data_block = data_block.substring(8); pushBlock( "Message data", temp_value, temp_decoded ); } } else if(enc_mode == "Terminator"){ } else { break; } } //console.log(data_block); var error_correction_level = getFormatInfo(qr_array).ecc; var offset = data_block.length - error_correction_code_table[qr_version - 1][error_correction_level]*8; pushBlock( "Padding bits", data_block.substring(0,offset), "" ); data_block = data_block.substring(offset); while(data_block.length >= 8){ pushBlock( "Error correction", data_block.substring(0,8), parseInt(data_block.substring(0,8), 2) ); data_block = data_block.substring(8); } console.log(qr_data_block); showQRTableOverlay(); //Generate QR Overlay for(var i=0; i < qr_data_block.length; i++){ for(var j=0; j < qr_data_block[i].modules.length; j++){ var module = qr_data_block[i].modules[j]; $("#qr-overlay td[index="+module+"]").addClass("hoverable data-block-"+i); } for(var j=0; j < qr_data_block[i].modules.length; j++){ var module = qr_data_block[i].modules[j].split('-'); generateSeparator(module[0], module[1], "data-block-"+i); } } } //Generate separator border between blocks function generateSeparator(i,j,cls){ i = parseInt(i); j = parseInt(j); var up = $("#qr-overlay td[index="+(i-1)+"-"+j+"]"); var down = $("#qr-overlay td[index="+(i+1)+"-"+j+"]"); var left = $("#qr-overlay td[index="+i+"-"+(j-1)+"]"); var right = $("#qr-overlay td[index="+i+"-"+(j+1)+"]"); if(!left.hasClass(cls)){ $("#qr-"+i+"-"+j).css("border-left","solid 1px #f44336"); } if(!right.hasClass(cls)){ $("#qr-"+i+"-"+j).css("border-right","solid 1px #f44336"); } if(!up.hasClass(cls)){ $("#qr-"+i+"-"+j).css("border-top","solid 1px #f44336"); } if(!down.hasClass(cls)){ $("#qr-"+i+"-"+j).css("border-bottom","solid 1px #f44336"); } } function selectBlock(cls){ var index = cls.substring(11); $("#data-analysis-value").val(qr_data_block[index].value); $("#data-analysis-type").val(qr_data_block[index].type); $("#data-analysis-decoded").val(qr_data_block[index].decoded); } function updateBlock(value, cls){ var index = cls[cls.length-2].substring(11); if(value == qr_data_block[index].value){ //return; } if(value.length != qr_data_block[index].value.length || !/^[01\?]+$/g.test(value)){ alert('Invalid value!'); $("#data-analysis-value").val(qr_data_block[index].value).focus(); return; } qr_data_block[index].value = value; var mask_pattern = getFormatInfo(qr_array).mask; for(var i=0; i < qr_data_block[index].modules.length; i++){ var cord = qr_data_block[index].modules[i].split('-'); var new_val = value.substring(i,i+1); console.log(new_val, qr_array[cord[0]][cord[1]]); if(new_val == '?') new_val = -1; else new_val = parseInt(new_val); /*if(mask(mask_pattern, cord[0], cord[1])){ if(new_val == 1) new_val = 0; else if(new_val == 0) new_val = 1; }*/ qr_array[cord[0]][cord[1]] = new_val; } refreshTable(); activateAnalysisMode(); updateHistory("Modules edited"); $("#data-analysis-value").val(""); $("#data-analysis-type").val(""); $("#data-analysis-decoded").val(""); } /******************************************************************* * * EVENT LISTENER USING JQUERY * ********************************************************************/ $(document).ready(function(){ $("#home-new").click(function(){ $("#home-box").hide(); $("#div-new").show(); }) $("#home-load").click(function(){ $("#home-box").hide(); $("#div-load").show(); var dataList = JSON.parse(localStorage.getItem("dataList")); if(dataList == undefined){ $("#list-load").html("
There's no saved project in Local Storage.
"); } else { var element = ""; for(var i=0; i < dataList.length; i++){ element += "
"+dataList[i][0]+"
"+dataList[i][1]+"
"; } $("#list-load").html(element); } }) $("#new-btn-new").click(function(){ generateTable(qr_version); qr_format_array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; if($("#btn-switch-mode").hasClass("active")){ toggleResult(); } if($("#div-extract").css("display") != "none"){ $("#btn-tools-extract").trigger("click"); } brute_force_mode = false; extract_info_mode = false; if(analysis_mode){ $("#tools-data-analysis").trigger("click"); } $("#tools-brute-force, #tools-unmasking").removeClass("active"); $("#qr-overlay").html(""); $("#box-tools-masking").hide(); $("#div-new").hide(); }) $("#new-btn-import-img").click(function(){ $("#import-img").click(); return false; }) $("#import-img").change(function(){ if(this.files && this.files[0]){ var reader = new FileReader(); reader.onload = function(e){ $("#hidden-img").attr("src",e.target.result); importFromImage($("#hidden-img").attr("src"), function(data){ if(Array.isArray(data)){ $("#div-new").hide(); generateTable(qr_version); updateQRArray(data); clearHistory(); updateHistory("Load from image"); refreshTable(); changed_state = true; } else { alert(data); } }) } reader.readAsDataURL(this.files[0]); } }) $("#new-btn-import-txt").click(function(){ $("#import-txt").click(); return false; }) $("#import-txt").change(function(){ if(this.files && this.files[0]){ var reader = new FileReader(); reader.onload = function (e) { const file = e.target.result; const lines = file.split(/\r\n|\n/); $("#hidden-txt").val(lines.join('\n')); $("#div-new").hide(); qr_size = lines[0].length; qr_version = (qr_size-17)/4; generateTable( qr_version ); data = loadTxt2Array(lines); updateQRArray(data); clearHistory(); updateHistory("Load from image"); refreshTable(); changed_state = true; }; reader.readAsText(this.files[0]); } }) $("#menu-new").click(function(){ if(changed_state){ if(!confirm("Are you sure want to proceed?\nYour unsaved progress will be lost!")) return; } $("#home-box").hide(); $("#div-new").show(); }) $("#menu-save").click(function(){ $("#div-save").show(); var dataList = JSON.parse(localStorage.getItem("dataList")); if(dataList == undefined){ $("#div-save-ext").hide(); } else { var element = ""; for(var i=0; i < dataList.length; i++){ element += "
"+dataList[i][0]+"
"+dataList[i][1]+"
"; } $("#list-save").html(element); $("#div-save-ext").show(); } }) $("#menu-load").click(function(){ $("#div-load").show(); var dataList = JSON.parse(localStorage.getItem("dataList")); if(dataList == undefined){ $("#list-load").html("
There's no saved project in Local Storage.
"); } else { var element = ""; for(var i=0; i < dataList.length; i++){ element += "
"+dataList[i][0]+"
"+dataList[i][1]+"
"; } $("#list-load").html(element); } }) $("#menu-tools").click(function(){ $("#div-tools").show(); }) $(document).on("click", "#list-load div", function(e){ var projectName = $(this).find("h5").text(); if(e.target.nodeName != "SPAN"){ loadProject(projectName); } else { removeProject(projectName, "load"); } }) $(document).on("click", "#list-save div", function(e){ var projectName = $(this).find("h5").text(); if(e.target.nodeName != "SPAN"){ saveProject(projectName); } else { removeProject(projectName, "save"); } }) $("#painter-box div").click(function(){ $("#painter-box div.active").removeClass("active") $(this).addClass("active"); active_painter = $(this).attr("index"); }) $("#painter-fill").click(function(){ if(fill_painter){ $(this).removeClass("active"); fill_painter = false; } else { $(this).addClass("active"); fill_painter = true; } }) $("#btn-version-plus").click(function(){ if(changed_state){ if(confirm("Are you sure want to proceed?\nYour unsaved progress will be lost!")){ if(qr_version != maxVersion){ qr_version += 1; qr_size = 17+(qr_version*4); $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); generateTable(qr_version); } } } else { if(qr_version != maxVersion){ qr_version += 1; qr_size = 17+(qr_version*4); $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); generateTable(qr_version); } } }) $("#btn-version-min").click(function(){ if(changed_state){ if(confirm("Are you sure want to proceed?\nYour unsaved progress will be lost!")){ if(qr_version != 1){ qr_version -= 1; qr_size = 17+(qr_version*4); $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); generateTable(qr_version); } } } else { if(qr_version != 1){ qr_version -= 1; qr_size = 17+(qr_version*4); $("#qr-version").val(qr_size+"x"+qr_size+" (ver. "+qr_version+")"); generateTable(qr_version); } } }) $("#btn-size-plus").click(function(){ if(qr_pixel_size != 50 && qr_pixel_size >= 10){ qr_pixel_size += 5; } else if(qr_pixel_size < 10){ qr_pixel_size += 1; } $("#qr-size").val(qr_pixel_size+"px"); resize(qr_pixel_size); if($("#btn-switch-mode").hasClass("active")){ generateResult(); } }) $("#btn-size-min").click(function(){ if(qr_pixel_size > 10){ qr_pixel_size -= 5; } else if(qr_pixel_size != 1){ qr_pixel_size -= 1; } $("#qr-size").val(qr_pixel_size+"px"); resize(qr_pixel_size); if($("#btn-switch-mode").hasClass("active")){ generateResult(); } }) $("#btn-show-grey-pixel").click(function(){ if($(this).hasClass("active")){ $(this).removeClass("active"); show_grey = false; } else { $(this).addClass("active"); show_grey = true; } generateResult(); }) $("#btn-qr-decode").click(function(){ if(brute_force_mode){ $("#btn-brute-force-apply-pattern").hide(); $("#brute-force-msg-wait").show(); $("#brute-force-msg-fail").hide(); $("#brute-force-content").hide(); $("#div-brute-force-loader").show(); bruteForceFormatInfo(); } else { var image = document.getElementById("qr-result-canvas").toDataURL(); $("#decode-message").val(""); $("#div-decode").show(); decodeFromBase64(image, function(decodedData){ if(decodedData != "error decoding QR Code"){ $("#decode-message").val(decodedData); //resize for text based on QR version $("#decode-message").css("height", (17+4*qr_version)*3+"px"); } }); } }) $("#btn-switch-mode").click(function(){ toggleResult(); }) /**************************** Extract QR Information ****************************/ $("#tools-extract").click(function(){ $("#div-tools").hide(); if($(this).hasClass("active")){ $("#btn-tools-extract").trigger("click"); return; } $(".side-box").each(function(){ $(this).hide(); }); $(".right-box").hide(); $("#box-tools-extract").show(); $("#qr-table").hide(); $("#qr-result, #qr-overlay").hide(); $("#div-extract").show(); $(".footer .mode-indicator").hide(); $("body").css("background-color","#fff"); $(this).addClass("active"); extractInfo(); extract_info_mode = true; }) $("#btn-extract-show-rs, #btn-extract-show-error").click(function(){ if($(this).hasClass("active")){ $(this).removeClass("active"); } else { $(this).addClass("active"); } extractInfo(); }) $("#btn-tools-extract").click(function(){ $("#div-tools").hide(); $("#tools-extract").removeClass("active"); $(".side-box").show(); $(".right-box").show(); $("#box-tools-extract").hide(); $("#qr-table").show(); if(analysis_mode){ $("#qr-overlay").show(); } $("#btn-switch-mode").removeClass("active"); $("#div-tool-result").hide(); $("#div-tool-work").show(); $("#btn-switch-mode").text("Editor Mode"); $("#div-extract").hide(); $(".footer .mode-indicator").show(); $("body").css("background-color","#eceff1"); if(analysis_mode) { $("#box-work").hide(); } else { $("#box-tools-analysis").hide(); } extract_info_mode = false; }) /**************************** Brute-force Format info ****************************/ $("#tools-brute-force").click(function(){ if($(this).hasClass("active")){ $(this).removeClass("active"); //qr_format_array = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; brute_force_mode = false; updateHistory("Update format info pattern"); } else { $(this).addClass("active"); brute_force_mode = true; qr_format_array = [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]; } saveInfoTable(qr_size); }) $("#btn-brute-force-counter-prev").click(function(){ if(current_brute_result > 0) current_brute_result -= 1; var ecc = Math.floor(brute_result_index[current_brute_result] / 8); var mask = brute_result_index[current_brute_result] % 8; qr_format_array = format_information_bits[ecc][mask].split("").reverse(); if(ecc == 0) ecc = "L"; else if(ecc == 1) ecc = "M"; else if(ecc == 2) ecc = "Q" else if(ecc == 3) ecc = "H" $("#brute-force-decoded-data").val(brute_result[brute_result_index[current_brute_result]]); $("#brute-force-ecc span").text(ecc); $("#brute-force-mask span").text(mask); $("#brute-force-result-counter").text((current_brute_result+1)+" of "+brute_result_index.length+" result"); saveInfoTable(qr_size); generateResult(); }) $("#btn-brute-force-counter-next").click(function(){ if(current_brute_result < brute_result_index.length-1) current_brute_result += 1; var ecc = Math.floor(brute_result_index[current_brute_result] / 8); var mask = brute_result_index[current_brute_result] % 8; qr_format_array = format_information_bits[ecc][mask].split("").reverse(); if(ecc == 0) ecc = "L"; else if(ecc == 1) ecc = "M"; else if(ecc == 2) ecc = "Q" else if(ecc == 3) ecc = "H" $("#brute-force-decoded-data").val(brute_result[brute_result_index[current_brute_result]]); $("#brute-force-ecc span").text(ecc); $("#brute-force-mask span").text(mask); $("#brute-force-result-counter").text((current_brute_result+1)+" of "+brute_result_index.length+" result"); saveInfoTable(qr_size); generateResult(); }) /**************************** Data Masking ****************************/ $("#tools-masking").click(function(){ var current_mask = getFormatInfo(qr_array).mask; $("#data-masking-slider div.active").removeClass("active"); $("#data-masking-slider div[data="+current_mask+"]").addClass("active"); $("#div-data-masking").show(); $("#div-tools").hide(); }) $("#data-masking-slider div").click(function(){ $("#data-masking-slider div.active").removeClass("active"); $(this).addClass("active"); }) $("#btn-data-masking-apply").click(function(){ var mask = $("#data-masking-slider div.active").attr("data"); var ecc = getFormatInfo(qr_array).ecc; if(ecc == 0) ecc = 1; else if(ecc == 1) ecc = 0; else if(ecc == 2) ecc = 3; else if(ecc == 3) ecc = 2; qr_format_array = format_information_bits[ecc][mask].split("").reverse(); saveInfoTable(qr_size); maskDataBits(); $("#div-data-masking").hide(); //masking toogle visual if($("#tools-masking").hasClass("active")){ masking_mode = false; $("#tools-masking").removeClass("active"); } else { masking_mode = true; $("#tools-masking").addClass("active"); } }) $("#btn-mask-show-pattern-area").click(function(){ if($(this).hasClass("active")){ $(this).removeClass("active"); $("#qr-overlay").html(""); } else { $(this).addClass("active"); showMaskPatternArea(); $("#qr-overlay").show(); } }) /**************************** Padding Bits Recovery ****************************/ $("#tools-pad-recovery").click(function(){ patchingRecovery(recoverPaddingBits(JSON.parse(JSON.stringify(qr_array)))); $("#div-patching-recovery-title").text("Padding Bits Recovery"); $("#div-patching-recovery").show(); $("#div-tools").hide(); }) $("#btn-patch-rec-apply").click(function(){ qr_array = JSON.parse(JSON.stringify(qr_temp_array)); refreshTable(); updateHistory( $("#div-patching-recovery-title").text() ); $("#div-patching-recovery").hide(); changed_state = true; }) $("#btn-patch-rec-cancel").click(function(){ $("#div-patching-recovery").hide(); }) /**************************** Reed-Solomon Decoder ****************************/ var current_rs_decoder_page = 1; $("#tools-rs-decoder").click(function(){ current_rs_decoder_page = 1; $("#div-rs-decoder").show(); $("#div-tools").hide(); $("#btn-rs-decoder-prev, #btn-rs-decoder-apply").hide(); $("#rs-decoder-page-1, #btn-rs-decoder-next").show(); $("#rs-decoder-page-2").hide(); var ecc = getFormatInfo(qr_array).ecc; var nblocks = RS_block_num_table[qr_version-1][ecc]; var html = ""; var data_array = JSON.stringify(qr_array); var rs_block = QRDecode(JSON.parse(data_array)).rs_block; for(var i=1; i <= nblocks; i++){ html += "
Encoded Reed-Solomon blocks ["+i+"] :
\ \
"; } $("#rs-decoder-page-1 div").html(html); }) $("#btn-rs-decoder-next").click(function(){ $("#rs-decoder-page-1").hide(); $("#rs-decoder-page-2").show(); $("#rs-decoder-error").addClass("invisible"); $("#btn-rs-decoder-prev, #btn-rs-decoder-apply").show(); var rs_blocks = []; var ecc = getFormatInfo(qr_array).ecc; var nysm = error_correction_code_table[qr_version-1][ecc]; $(this).hide(); $(".rs-decoder-input").each(function(){ rs_blocks.push($(this).val().replace(/[^0-9,]+/g, "").split(",")); }) reedSolomonDecode(rs_blocks, nysm); }) $("#btn-rs-decoder-prev").click(function(){ $("#btn-rs-decoder-prev, #btn-rs-decoder-apply").hide(); $("#rs-decoder-page-1, #btn-rs-decoder-next").show(); $("#rs-decoder-page-2").hide(); }) $("#btn-rs-decoder-apply").click(function(){ }) /**************************** Data Sequence Analysis ****************************/ $("#tools-data-analysis").click(function(){ if($(this).hasClass("active")){ analysis_mode = false; $(this).removeClass("active"); $("#box-work").show(); $("#box-tools-analysis").hide(); activateAnalysisMode("false"); } else { analysis_mode = true; $("#data-analysis-value").val(""); $("#data-analysis-type").val(""); $("#data-analysis-decoded").val(""); $(this).addClass("active"); $("#box-work").hide(); $("#box-tools-analysis").show(); activateAnalysisMode(); } $("#div-tools").hide(); }) $("#data-analysis-value").blur(function(){ if( $("#qr-overlay td.active").length){ updateBlock($(this).val(), $("#qr-overlay td.active").attr("class").split(" ")); } }).on("keydown", function(e){ if(e.keyCode == "13"){ updateBlock($(this).val(), $("#qr-overlay td.active").attr("class").split(" ")); } }) /**************************** Load Sample ****************************/ $("#sample-file").change(function(){ loadImage(this, "#img-sample"); $("#img-sample").show(); }) /**************************** Painter stuff ****************************/ $(document).on("click","td.info", function(){ $("#format-information-box").show(); if(brute_force_mode){ $("#format-info-content").hide(); $("#btn-save-info").hide(); $("#format-info-msg").show(); } else { for(var i=0; i < 8; i++){ if(i > 5) qr_format_array[i] = qr_array[i+1][8]; else qr_format_array[i] = qr_array[i][8]; qr_format_array[i] = qr_array[8][qr_size-(i+1)]; } var index = 0; for(var i=14; i >= 8; i--){ if(index > 5) qr_format_array[i] = qr_array[8][index+1]; else qr_format_array[i] = qr_array[8][index]; qr_format_array[i] = qr_array[qr_size-(index+1)][8]; index++; } var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; if(i <= 8 && j <= 8) position = "TOP_LEFT"; else if(j == 8 && i > 8) position = "BOTTOM_LEFT"; else position = "TOP_RIGHT"; $("#slider-ecc div.active").removeClass("active"); $("#slider-mask div.active").removeClass("active"); generateInfoTable(position); var desc = getInfoBits(position); if(desc.ecc != ""){ $("#slider-ecc #ecc-"+desc.ecc.toLowerCase()).addClass("active"); } if(desc.mask != -1){ $("#slider-mask #mask-"+desc.mask).addClass("active"); } $("#format-info-content").show(); $("#btn-save-info").show(); $("#format-info-msg").hide(); } }) $(document).on("mouseover", ".info", function(){ $(".info:not(.black)").each(function(){ $(this).css("opacity","0.8"); }) }) $(document).on("mouseleave", ".info", function(){ $(".info:not(.black)").each(function(){ $(this).css("opacity","1"); }) }) $(document).on("mouseover", ".hoverable:not(.active)", function(){ var cls = $(this).attr("class").split(" ").pop(); $("#qr-overlay td."+cls).each(function(){ $(this).css("opacity","0.5"); }) if(!$("#qr-overlay td.active:not(."+cls+")").length){ //selectBlock(cls); } }) $(document).on("mouseleave", ".hoverable:not(.active)", function(){ var cls = $(this).attr("class").split(" ").pop(); $("#qr-overlay td."+cls).each(function(){ $(this).css("opacity","0"); }) }) $(document).on("click", ".hoverable", function(){ $("#qr-overlay td.active").css("opacity","0").removeClass("active"); var cls = $(this).attr("class").split(" ").pop(); $("#qr-overlay td."+cls).each(function(){ $(this).css("opacity","0.75").addClass("active"); }) selectBlock(cls); }) $(document).on("mousedown", "#qr-table td", function(){ if(!$(this).hasClass("static") && !$(this).hasClass("info")){ if(active_painter == "0"){ if($(this).hasClass("black")){ $(this).removeClass("black"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; qr_array[i][j] = -1; changed_state = true; updateHistory("Painter"); } else { if(!fill_painter){ $(document).on("mousemove", startDragging); $(document).on("mouseup", stopDragging); $(this).removeClass("white"); $(this).addClass("black"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; qr_array[i][j] = 1; } else { var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; var original_color = qr_array[i][j]; floodFill(i,j,original_color,1); refreshTable(); updateHistory("Flood fill"); } changed_state = true; } } else if(active_painter == "1"){ if($(this).hasClass("white")){ $(this).removeClass("white"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; qr_array[i][j] = -1; changed_state = true; updateHistory("Painter"); } else { if(!fill_painter){ $(document).on("mousemove", startDragging); $(document).on("mouseup", stopDragging); $(this).removeClass("black"); $(this).addClass("white"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; qr_array[i][j] = 0; } else { var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; var original_color = qr_array[i][j]; floodFill(i,j,original_color,0); refreshTable(); updateHistory("Flood fill"); } changed_state = true; } } else if(active_painter == "2"){ if(!fill_painter){ $(document).on("mousemove", startDragging); $(document).on("mouseup", stopDragging); $(this).removeClass("black"); $(this).removeClass("white"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; qr_array[i][j] = -1; } else { var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; var original_color = qr_array[i][j]; floodFill(i,j,original_color,-1); refreshTable(); updateHistory("Flood fill"); } changed_state = true; } } }) var startDragging = function(e){ var x = e.clientX; var y = e.clientY; var elem = document.elementFromPoint(x, y); var id = elem.id; if(elem.tagName == "TD" && elem.className.search("static") == -1 && elem.className.search("info") == -1){ var i = /\d{1,2}/.exec(id)[0]; var j = /\d{1,2}$/.exec(id)[0]; if(active_painter == "0"){ elem.className = "black"; qr_array[i][j] = 1; } else if(active_painter == "1"){ elem.className = "white"; qr_array[i][j] = 0; } else if(active_painter == "2"){ elem.className = ""; qr_array[i][j] = -1; } } } var stopDragging = function(){ $(document).off("mousemove"); $(document).off("mouseup"); updateHistory("Painter"); } $(document).on("click","#qr-format-info td", function(){ if(!$(this).hasClass("static")){ if($(this).hasClass("black")){ $(this).removeClass("black"); $(this).addClass("white"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; qr_format_array[i] = 0; } else { $(this).removeClass("white"); $(this).addClass("black"); var id = $(this)[0].id; var i = /\d{1,2}/.exec(id)[0]; qr_format_array[i] = 1; } } var desc = getInfoBits(); if(desc.ecc != ""){ $("#slider-ecc #ecc-"+desc.ecc.toLowerCase()).addClass("active"); } else { $("#slider-ecc div.active").removeClass("active"); } if(desc.mask != -1){ $("#slider-mask #mask-"+desc.mask).addClass("active"); } else { $("#slider-mask div.active").removeClass("active"); } }) $("#select-format-info-pos").change(function(){ var position = $(this).val(); generateInfoTable(position); }) $("#slider-ecc div").click(function(){ var position = $("#select-format-info-pos").val(); $("#slider-ecc div.active").removeClass("active"); $(this).addClass("active"); var i = /\w$/.exec($(this)[0].id)[0]; if(i == "l") i = 0; else if(i == "m") i = 1; else if(i == "q") i = 2; else if(i == "h") i = 3; if($("#slider-mask div.active").length){ var j = /\d$/.exec($("#slider-mask div.active")[0].id)[0]; qr_format_array = format_information_bits[i][j].split("").reverse(); } else { qr_format_array = (format_information_bits_raw.ecc[i]+"0000000000000").split("").reverse(); } generateInfoTable(position); }) $("#slider-mask div").click(function(){ var position = $("#select-format-info-pos").val(); $("#slider-mask div.active").removeClass("active"); $(this).addClass("active"); var j = /\d$/.exec($(this)[0].id)[0]; if($("#slider-ecc div.active").length){ var i = /\w$/.exec($("#slider-ecc div.active")[0].id)[0]; if(i == "l") i = 0; else if(i == "m") i = 1; else if(i == "q") i = 2; else if(i == "h") i = 3; qr_format_array = format_information_bits[i][j].split("").reverse(); } else { qr_format_array = ("00"+format_information_bits_raw.mask[j]+"0000000000").split("").reverse(); } generateInfoTable(position); }) $("#btn-save-info").click(function(){ var size = 17+(qr_version*4); saveInfoTable(size); updateHistory("Update format info pattern"); }) //Undo/Redo in History $(document).on("click",".history div", function(){ var index = $(this)[0].id.substring(8); $(".history div.active").removeClass("active"); $(this).addClass("active"); getHistory(index); active_history = parseInt(index); }) $(".menu-bar").click(function(){ if(!$(this).hasClass("active")){ $(".header div.right").show(); $(this).addClass("active"); } else { $(".header div.right").hide(); $(this).removeClass("active"); } }) $(document).click(function(e){ if(!$(e.target).closest(".menu-bar").length && $(".menu-bar").css("display") == "block"){ $(".header div.right").hide(); $(".menu-bar").removeClass("active"); } }) $(".float-nav.left").click(function(){ if(!$(this).hasClass("active")){ $(".left-box").show().animate({left:'0'},350); $(this).addClass("active"); } else { $(".left-box").animate({left:'-280px'},350, function(){$(this).hide()}); $(this).removeClass("active"); } }) $(".float-nav.right").click(function(){ if(!$(this).hasClass("active")){ $(".right-box").show().animate({right:'0'},350); $(this).addClass("active"); } else { $(".right-box").animate({right:'-340px'},350, function(){$(this).hide()}); $(this).removeClass("active"); } }) $("#txt-version").text('QRazyBox v'+APP_VERSION); $("#mobile-editor-mode, #mobile-decode-mode").click(function(){ toggleResult(); }) $(window).resize(function(){ if(document.body.clientWidth > 900){ $("#header-menu").css({"display":""}); $(".left-box").css({"left":"","display":""}); if(!extract_info_mode){ $(".right-box").css({"right":"","display":""}); } $(".float-nav, .menu-bar").removeClass("active"); } }) $(document).keydown(function(e){ if(!$("input[type=text], textarea").is(":focus") && !$("#tools-extract").hasClass("active")){ //Shortcut key : Tab if(e.keyCode == 9){ e.preventDefault(); $("#btn-switch-mode").trigger("click"); } //Shortcut key : - else if(e.keyCode == 173 || e.keyCode == 109 || e.keyCode == 189){ e.preventDefault(); $("#btn-size-min").trigger("click"); } //Shortcut key : = else if(e.keyCode == 61 || e.keyCode == 187){ e.preventDefault(); $("#btn-size-plus").trigger("click"); } //Shortcut key : Q else if(e.keyCode == 81){ $("#painter-black").trigger("click"); } //Shortcut key : W else if(e.keyCode == 87){ $("#painter-white").trigger("click"); } //Shortcut key : E else if(e.keyCode == 69){ $("#painter-eraser").trigger("click"); } //Shortcut key : G else if(e.keyCode == 71){ $("#painter-fill").trigger("click"); } //Shortcut key : Z else if(e.keyCode == 90){ $(".history div.active").next().trigger("click"); } //Shortcut key : X else if(e.keyCode == 88){ $(".history div.active").prev().trigger("click"); } } }) //Prevent page from closing window.onbeforeunload = function(){ if(changed_state) return "Do you really want to close? Your unsaved progress will be lost!"; }; })