您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically downscales images based on custom presets and more. Requires 4chan X.
当前为
// ==UserScript== // @name 4chan Image Resizer // @namespace https://greasyfork.org/en/users/393416 // @version 2.2 // @description Automatically downscales images based on custom presets and more. Requires 4chan X. // @author greenronia // @match *://boards.4chan.org/* // @match *://boards.4channel.org/* // @require https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.js // @grant none // @icon https://i.imgur.com/hQp5BTf.png // ==/UserScript== // //Using SparkMD5 to generate image hashes - https://github.com/satazor/js-spark-md5 // //----------DEBUG MODE-------------// var DEBUG = false;//console // //---------------------------------// const version = 2.2; //---------------------------------// if(DEBUG) console.log("[ImageResizer] Initialized"); //CSS var style = document.createElement("style"); style.innerHTML = '' + '.centerImg { margin: 0; position: absolute; top: 50%; left: 50%; -ms-transform: translate(-50%, -50%); transform: translate(-50%, -50%); max-width: 100%; max-height: 100vh; height: auto; cursor: pointer; }\n' + '.settingsOverlay { background: rgba(0,0,0,0.8); display: none; height: 100%; left: 0; position: fixed; top: 0; width: 100%; z-index: 777; } \n' + '#pvOverlay { background: rgba(0,0,0,0.9); height: 100%; left: 0; position: fixed; top: 0; width: 100%; z-index: 777; text-align: center;} \n' + '#pvHeader { position: fixed; height: 35px; width: 100%; opacity: 0; -webkit-transition: opacity 0.5s ease-in-out;}\n' + '#pvHeader:hover { opacity: 0.8; -webkit-transition: none; }\n' + '.pvOpct { opacity: 0.7 !important; } \n' + '#imgResizeMenu { position: fixed; top: 20%; left: 35%; width: 30%; min-width: 620px; padding: 2em; overflow: hidden; z-index: 8;}\n' + '#imgResizeMenu h3 { text-align: center; }\n' + '#imgResizeMenu a { cursor: pointer; }\n' + '#imgResizeMenu label { text-decoration-line: underline; }\n' + '.settingsOverlay input[type=number] { -moz-appearance: textfield; text-align: right; }\n' + '.resizer-settings { padding-bottom: 5px }\n' + '#errMsg { color: red; text-align: center; }\n' + '#ruleTable { border-collapse: collapse; }\n' + '#ruleTable td, th { padding: 8px; text-align: left; border-bottom: 1pt solid; }\n' + '#QCTable { border-collapse: collapse; }\n' + '#QCTable td, th { padding: 8px; text-align: center; border-bottom: 1pt solid; }\n' + '#QCTable p { margin: auto; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n' + '#inputContainer { text-align: center; padding-top: 1em; }\n' + '#inputContainer button { margin-top: 20px; }\n' + '.menuBtns { margin-left: 1em; }\n' + '#sideMenu { position: absolute; display: none; padding: 5px 0px 5px 0px; width: 101px; margin-left: -106px; margin-top: -2px;}\n' + '.sideMenuElement { background: inherit; display: block; cursor: pointer; padding: 2px 10px 2px 10px; text-align: left;}\n' + '.downscale-menu-off { display: none; }\n' + '.downscale-menu-on { display: block !important; }'; var styleRef = document.querySelector("script"); styleRef.parentNode.insertBefore(style, styleRef); //Load settings getSettings(); getPresets(); getQCList(); //Update downscale-settings object v2.2 (function () { if (getSettings().shortcut == null) { var settings = getSettings(); settings.shortcut = true; localStorage.setItem("downscale-settings", JSON.stringify(settings)); var info = '4chan Image Resizer updated to version ' + version + '.\nMore info on "About" tab.'; var msgDetail = {type: 'info', content: info, lifetime: 10}; var msgEvent = new CustomEvent('CreateNotification', {bubbles: true, detail: msgDetail}); document.dispatchEvent(msgEvent); } })(); function getSettings() { if (JSON.parse(localStorage.getItem("downscale-settings"))) { var settings = JSON.parse(localStorage.getItem("downscale-settings")); } else { settings = { enabled:true, notify:true, convert:false, jpegQuality:0.92, shortcut:true }; localStorage.setItem("downscale-settings", JSON.stringify(settings)); } return settings; } function getPresets() { if (JSON.parse(localStorage.getItem("downscale-presets"))) { var presets = JSON.parse(localStorage.getItem("downscale-presets")); } else { presets = []; } return presets; } function getQCList() { if (JSON.parse(localStorage.getItem("downscale-qclist"))) { var QCList = JSON.parse(localStorage.getItem("downscale-qclist")); } else { QCList = []; } return QCList; } //Checking if QuickReply dialog is open. document.addEventListener('QRDialogCreation', function(listenForQRDC) { var checkBox = document.getElementById("imgResize"); var sideMenu = document.getElementById("sideMenuArrow"); //Checking if the "resize" check box and "side menu" already exist if (!sideMenu) { appendSideMenu(); } if (!checkBox) { appendCheckBox(); } //Listening for clicks on check box document.getElementById("imgResize").addEventListener("click", checkState); checkState(1); if(DEBUG) console.log("[QRFile] Listening..."); //QRFile | Listening for QRFile, in response to: QRGetFile | Request File document.addEventListener('QRFile', function(GetFile) { if(DEBUG) console.log("[QRFile] File served: " + GetFile.detail); //Remove Remember option upon adding a (new) file. removeRemOption(); const file = GetFile.detail; //Initialize an instance of a FileReader const reader = new FileReader(); //Checking if the file is JPG or PNG if (file.type == "image/jpeg" || file.type == "image/png") { if(DEBUG) console.log("Acceptable File type: " + file.type); //Check if resizer already completed its task (to determine priority) var complete = false; var presets = getPresets(); var QCList = getQCList(); reader.onload = function(f) { var img = new Image(); img.src = reader.result; img.onload = function() { //Base64 MD5 hash of an image var imgMD5 = SparkMD5.hash(img.src); if(DEBUG) console.log("<FILTER START>"); if(DEBUG) if(getSettings().convert) console.log("[PNGConverter] Enabled"); else console.log("[PNGConverter] Disabled"); if(DEBUG) console.log("INPUT Dimensions: " + img.width + "x" + img.height); if(DEBUG) console.log("INPUT File size: " + formatBytes(file.size)); //THE priority list if (getQCList().length > 0) checkMD5(img, imgMD5); if (presets.length > 0 && !complete) checkPresets(img); if (getSettings().convert && !complete) checkPNG(img); if (!complete) { //Add QC button removeQCOption(); quickConvert(img, file, imgMD5); //Remove/Add preview buton removePreviewOption(); appendPreviewBtn(img.src, file.size, img.width, img.height, file.name); } return; } return; } function checkMD5(img, imgMD5) { if(DEBUG) console.log("[quickConvert] Checking for matching MD5: " + imgMD5); var filterCount = QCList.length; var matchFound = false; for (var i = 0; i < filterCount; i++) { //unpack md5 hash var filterMD5 = QCList[i].split(":").pop(); if (filterMD5 == imgMD5) { if(DEBUG) console.log("[quickConvert] Match found."); matchFound = true; resizer(img.width, img.height, img); break; } } if(DEBUG) if (!matchFound)console.log("[quickConvert] No matching MD5 found."); return; } function checkPresets(img) { var matchCount = 0; var rule = []; var presetCount = presets.length; for (var i = 0; i < presetCount; i++) { //unpack rules rule[i] = presets[i].split(":"); //check for matching file type if (rule[i][0] != 0) { switch (parseInt(rule[i][0])) { case 1: rule[i][0] = "image/png"; break; case 2: rule[i][0] = "image/jpeg"; } if (rule[i][0] != file.type) continue; } //check for matching dimensions if (rule[i][1] == img.width && rule[i][2] == img.height) { var MAX_WIDTH = parseInt(rule[i][3]); var MAX_HEIGHT = parseInt(rule[i][4]); matchCount++; if(DEBUG) console.log("Preset '" + i + "' matched: " + rule[i]); break; } } //failsafe if (matchCount == 0 || matchCount > 1) { if(DEBUG) console.log("Image didn't match any presets.\n------<END>------"); return; } else { resizer(MAX_WIDTH, MAX_HEIGHT, img); return; } } //PNG -> JPEG function checkPNG(img) { if (file.type == "image/png") { var MAX_WIDTH = img.width; var MAX_HEIGHT = img.height; if(DEBUG) console.log("[PNGConverter] Converting PNG to JPEG"); resizer(MAX_WIDTH, MAX_HEIGHT, img); } else { if(DEBUG) console.log("[PNGConverter] Image format isn't PNG.\n------<END>------"); return; } } //The main resize function function resizer(MAX_WIDTH, MAX_HEIGHT, img, imgMD5) { if(DEBUG && !imgMD5) console.log("<FILTER END>"); removePreviewOption(); var canvas = document.createElement("canvas"); //Input dimensions var width = img.width; var height = img.height; //Calculating dimensions/aspect ratio if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } // resize the canvas to the new dimensions canvas.width = width; canvas.height = height; // scale & draw the image onto the canvas var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height); //Converts dataURI to blob function dataURItoBlob(dataURI) { //convert base64/URLEncoded data component to raw binary data held in a string var byteString; if (dataURI.split(',')[0].indexOf('base64') >= 0) { byteString = atob(dataURI.split(',')[1]); } else { byteString = unescape(dataURI.split(',')[1]); } //separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; //write the bytes of the string to a typed array var ia = new Uint8Array(byteString.length); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ia], { type: mimeString }); } //canvas to dataURL | JPEG quality (0-1) var dataURL; if (imgMD5) dataURL = canvas.toDataURL('image/jpeg', 92); else dataURL = canvas.toDataURL('image/jpeg', parseFloat(getSettings().jpegQuality)); //dataURL to blob var blob = dataURItoBlob(dataURL); //Stop classObserver | prevent trigger loop classObserver.disconnect(); if(DEBUG) console.log("[classObserver] Stopping..."); setFile(blob, img, width, height, imgMD5); appendPreviewBtn(dataURL, blob.size, width, height, file.name); } //Set the new file to QR form function setFile(blob, img, width, height, imgMD5) { var detail = { file: blob, name: file.name }; var event = new CustomEvent('QRSetFile', { bubbles: true, detail: detail }); document.dispatchEvent(event); if (imgMD5) rememberQC(img, file, imgMD5, blob.size); if(DEBUG) console.log("[QRSetFile] File Sent"); if(DEBUG) console.log("OUTPUT Dimesnions: " + Math.round(width) + "x" + Math.round(height)); if(DEBUG) console.log("OUTPUT Filesize: " + formatBytes(blob.size)); if(DEBUG) console.log("JPEG Quality: " + getSettings().jpegQuality); //Notification var FSInfo = "Original size: (" + formatBytes(file.size) + ", " + img.width + "x" + img.height + ") \n New size: (" + formatBytes(blob.size)+ ", " + Math.round(width) + "x" + Math.round(height) +")"; if (getSettings().notify) { var msgDetail = {type: 'info', content: FSInfo, lifetime: 5}; var msgEvent = new CustomEvent('CreateNotification', {bubbles: true, detail: msgDetail}); document.dispatchEvent(msgEvent); } //Remove Quick Convert option after conversion removeQCOption(); //Restart classObserver classObserver.observe(targetNode, observerOptions); //Preset priority complete = true; if(DEBUG) console.log("------<END>------\n[classObserver] Restarting..."); } //Quick Convert (QC) image from Side Menu function quickConvert(img, file, imgMD5) { //Convert options container (future use) var container = document.createElement("div"); container.id = "qcDiv"; //Convert button var convert = document.createElement("a"); convert.id = "quickConvert"; convert.classList.add("sideMenuElement"); convert.classList.add("entry"); convert.innerHTML = "Quick Convert"; convert.title = "Convert image to JPEG"; //CSS on hover convert.onmouseover = function(){this.classList.toggle("focused")}; convert.onmouseout = function(){this.classList.toggle("focused")}; var hr = document.createElement("hr"); hr.style.borderColor = getHRColor(); //Call resizer convert.addEventListener('click', function(){ if(DEBUG) console.log("[quickConvert] Manually calling Resizer..."); resizer(img.width, img.height, img, imgMD5); },); var parent = document.getElementById("sideMenu"); parent.appendChild(container); container.appendChild(hr); container.appendChild(convert); } //Remember button function rememberQC (img, file, imgMD5, newSize) { var container = document.createElement("div"); container.id = "remDiv"; var remember = document.createElement("a"); remember.id = "rememberMD5"; remember.classList.add("sideMenuElement"); remember.classList.add("entry"); remember.innerHTML = "Remember"; remember.style.fontWeight = "bold"; remember.title = "Always convert this image." //CSS on hover remember.onmouseover = function(){this.classList.toggle("focused")}; remember.onmouseout = function(){this.classList.toggle("focused")}; var hr = document.createElement("hr"); hr.style.borderColor = getHRColor(); remember.onclick = function(){ saveImgMD5(img, file, imgMD5, newSize) }; var parent = document.getElementById("sideMenu"); parent.appendChild(container); container.appendChild(hr); container.appendChild(remember); } //Preview Image button function appendPreviewBtn(img, pvSize, pvWidth, pvHeight, pvName) { var existCheck = document.getElementById("previewImg"); if (!existCheck) { var preview = document.createElement("a"); preview.id = "previewImg"; preview.classList.add("sideMenuElement"); preview.classList.add("entry"); preview.innerHTML = "Preview Image"; //CSS on hover preview.onmouseover = function(){this.classList.toggle("focused")}; preview.onmouseout = function(){this.classList.toggle("focused")}; preview.onclick = function(){ showImage(img, pvSize, pvWidth, pvHeight, pvName) }; var parent = document.getElementById("sideMenu"); parent.appendChild(preview); } else { existCheck.onclick = function(){ showImage(img, pvSize, pvWidth, pvHeight, pvName) }; } return; } //Read the file reader.readAsDataURL(file); } else { removeQCOption(); if(DEBUG) console.log("[Error] Invalid FileType: " + file.type + "\n------<END>------"); } }, false); //Observing if a file was uploaded or not | checking if div (with id: "file-n-submit") has class named: "has-file" function callback(mutationList, observer) { if (document.getElementById("file-n-submit").classList.contains("has-file") === true && checkState(2) === true) { if(DEBUG) console.log("------<START>------\n[classObserver] File detected") //QRGetFile | Request File if(DEBUG) console.log("[QRGetFile] Requesting file..."); document.dispatchEvent(new CustomEvent('QRGetFile')); } else if (checkState(2) === false) { if(DEBUG) console.log("[classObserver] ImageResizer is disabled"); return; } else { //Remove Side menu options upon removing a file. removeQCOption(); removeRemOption(); removePreviewOption(); if(DEBUG) console.log("[classObserver] No file"); } } //MutationObserver. Checks if div (with id "file-n-submit") has its class attribute changed const targetNode = document.getElementById("file-n-submit"); var observerOptions = { attributes: true }; var classObserver = new MutationObserver(callback); if(DEBUG) console.log("[classObserver] Starting..."); classObserver.observe(targetNode, observerOptions); }, false); //*************************************************************************************// //END OF THE MAIN PROCESS //*************************************************************************************// //Add a label with a check box for ImageResize + Setting button in Side Menu function appendCheckBox() { var settingsButton = document.createElement("a"); var label = document.createElement("label"); var input = document.createElement("input"); input.type = "checkbox"; input.id = "imgResize"; label.id = "imgResizeLabel"; input.title = "Enable Image Resizer"; input.style = "margin-left: 0"; settingsButton.classList.add("sideMenuElement"); settingsButton.classList.add("entry"); label.classList.add("sideMenuElement"); //CSS on hover label.classList.add("entry"); var parent = document.getElementById("sideMenu"); parent.appendChild(label); label.appendChild(input); label.title = "Enable Image Resizer"; label.innerHTML += " Enabled"; settingsButton.title = "Image Resizer Settings"; settingsButton.innerHTML = "Settings"; parent.appendChild(settingsButton); //CSS on hover label.onmouseover = function(){this.classList.toggle("focused")}; label.onmouseout = function(){this.classList.toggle("focused")}; settingsButton.onmouseover = function(){this.classList.toggle("focused")}; settingsButton.onmouseout = function(){this.classList.toggle("focused")}; //Open settings menu settingsButton.onclick = function(){ document.getElementById("imgResizeOverlay").style.display = "block" }; //Checked by default document.getElementById("imgResize").checked = getSettings().enabled; } //Check box state function checkState(caller) { var state = document.getElementById("imgResize").checked; if (state === true) { if (caller != 2) if(DEBUG) console.log("[ImageResizer] Enabled"); return true; } else { if (caller != 2) if(DEBUG) console.log("[ImageResizer] Disabled"); //remove side menu options upon disabling ImageResizer removeQCOption(); removeRemOption(); removePreviewOption(); return false; } } //Clears error messages <p> function clearErr() { document.getElementById("errMsg").innerHTML = ""; } //Checks for any logic errors (upscaling) function basicCheck(edit, rulePos) { var inWidth = parseInt(document.getElementById("inWidth").value); var inHeight = parseInt(document.getElementById("inHeight").value); var outWidth = parseInt(document.getElementById("outWidth").value); var outHeight = parseInt(document.getElementById("outHeight").value); var imgType = parseInt(document.getElementById("imgType").value); if (outWidth <= 0 || outHeight <= 0) { document.getElementById("errMsg").innerHTML = "Invalid output dimensions"; return} else if (inWidth < outWidth || inHeight < outHeight) { document.getElementById("errMsg").innerHTML = "Cannot upscale images"; return} else finalCheck(edit, imgType, inWidth, inHeight, outWidth, outHeight, rulePos); return; } //Checks for any rule overlaps // ([0] - Image type, [1] - Input width, [2] - Input height, [3] - Output width, [4] - Output height) function finalCheck(edit, imgType, inWidth, inHeight, outWidth, outHeight, rulePos) { var e = document.getElementById("imgType"); var format = e.options[e.selectedIndex].text; var presetString = imgType + ":" + inWidth + ":" + inHeight + ":" + outWidth + ":" + outHeight; var presets = getPresets(); if (presets.length > 0) { var rule = []; var presetCount = presets.length; for (var i = 0; i < presetCount; i++) { if (edit && i === rulePos) continue; rule[i] = presets[i].split(":"); if (presetString == presets[i]) { document.getElementById("errMsg").innerHTML = "Exact preset already exists"; return } else if ((inWidth == rule[i][1] && inHeight == rule[i][2]) && (imgType == rule[i][0] || rule[i][0] == 0)) { document.getElementById("errMsg").innerHTML = "Preset with the same input dimensions for " + format + " format already exists"; return } } } //save preset clearErr(); if (edit) presets[rulePos] = presetString; else presets.push(presetString); localStorage.setItem("downscale-presets", JSON.stringify(presets)); //rebuild list document.getElementById("ruleTable").tBodies.item(0).innerHTML = ""; printList(); //hide / display document.getElementById("ruleInput").remove(); document.getElementById("addRule").style.display = "inline"; return; } //Check if possible to calculate output WIDTH function aspectCheckH() { var inWidth = document.getElementById("inWidth").value; var inHeight = document.getElementById("inHeight").value; var outWidth = document.getElementById("outWidth").value; var outHeight = document.getElementById("outHeight").value; if (outHeight > 0) { if (parseInt(inHeight) >= parseInt(outHeight)) { calcAspect("width", inWidth, inHeight, outHeight); clearErr(); } else { document.getElementById("errMsg").innerHTML = "Cannot upscale images"; } } } //Check if possible to calculate output HEIGHT function aspectCheckW() { var inWidth = document.getElementById("inWidth").value; var inHeight = document.getElementById("inHeight").value; var outWidth = document.getElementById("outWidth").value; var outHeight = document.getElementById("outHeight").value; if (outWidth > 0) { if (parseInt(inWidth) >= parseInt(outWidth)) { calcAspect("height", inWidth, inHeight, outWidth); clearErr(); } else { document.getElementById("errMsg").innerHTML = "Cannot upscale images"; } } } //Aspect ratio calculation (finds the other output dimension based on given exact input dimensions) function calcAspect(dimension, w, h, output) { if (dimension == "width") { var width = output / h * w; document.getElementById("outWidth").value = Math.round(width); } if (dimension == "height") { var height = output / w * h; document.getElementById("outHeight").value = Math.round(height); } } //Populate Presets list function printList() { var presets = getPresets(); var list = document.getElementById("imgResizeList"); var table = document.getElementById("ruleTable"); if (presets.length > 0) { var rule = []; var presetCount = presets.length; for (let i = 0; i < presetCount; i++) { rule[i] = presets[i].split(":"); switch (parseInt(rule[i][0])) { case 0: rule[i][0] = "PNG/JPEG"; break; case 1: rule[i][0] = "PNG"; break; case 2: rule[i][0] = "JPEG"; } let delRow = document.createElement("a"); let editRow = document.createElement("a"); delRow.innerHTML = "delete"; editRow.innerHTML = "edit"; //delete a rule and rebuild the list delRow.onclick = function() { if (document.getElementById("inputContainer")) document.getElementById("inputContainer").innerHTML = ""; presets.splice(delRow.parentElement.parentElement.sectionRowIndex, 1); localStorage.setItem("downscale-presets", JSON.stringify(presets)); table.tBodies.item(0).innerHTML = ""; printList(); clearErr(); document.getElementById("addRule").style.display = "inline"; }; editRow.onclick = function() { inputUI(true, rule[i], i); clearErr(); }; //Array contents: [0] - Image type, [1] - Input width, [2] - Input height, [3] - Output width, [4] - Output height var row = table.tBodies.item(0).insertRow(-1); row.insertCell(0).innerHTML = rule[i][0]; row.insertCell(1).innerHTML = '[ ' + rule[i][1] + ' x ' + rule[i][2] + ' ]'; row.insertCell(2).innerHTML = '→'; row.insertCell(3).innerHTML = '[ ' + rule[i][3] + ' x ' + rule[i][4] + ' ]'; row.insertCell(4).appendChild(editRow); row.insertCell(5).appendChild(delRow); } } } //Input field function inputUI(edit, rule, rulePos) { if (document.getElementById("inputContainer")) document.getElementById("inputContainer").innerHTML = ""; document.getElementById("addRule").style.display = "none"; var inputDiv = document.getElementById("inputContainer"); var input = document.createElement("div"); var discardRuleBtn = document.createElement("button"); discardRuleBtn.innerHTML = "Cancel"; var saveRuleBtn = document.createElement("button"); saveRuleBtn.innerHTML = "Save"; input.id = "ruleInput"; //Rules form input.innerHTML = '' + '' + '<select id="imgType" name="imgType" title="Input Format">' + '<option value="0">PNG/JPEG</option>' + '<option value="1">PNG</option>' + '<option value="2">JPEG</option>' + '</select> ' + '' + '<input type="number" id="inWidth" title="Input Width" size="2" min="0" value="0" onfocus="this.select();"></input> x ' + '' + '<input type="number" id="inHeight" title="Input Height" size="2" min="0" value="0" onfocus="this.select();"></input> ' + '  →   <input type="number" id="outWidth" title="Output Width" size="2" min="0" value="0" onfocus="this.select();"></input> x ' + '<input type="number" id="outHeight" title="Output Height" size="2" min="0" value="0" onfocus="this.select();"></input><br>'; inputDiv.appendChild(input); var inWidth = document.getElementById("inWidth"); var inHeight = document.getElementById("inHeight"); var outWidth = document.getElementById("outWidth"); var outHeight = document.getElementById("outHeight"); if (edit) { switch (rule[0]) { case "PNG/JPEG": document.getElementById("imgType").selectedIndex = 0; break; case "PNG": document.getElementById("imgType").selectedIndex = 1; break; case "JPEG": document.getElementById("imgType").selectedIndex = 2; } inWidth.value = rule[1]; inHeight.value = rule[2]; outWidth.value = rule[3]; outHeight.value = rule[4]; } //Listen for user input on target dimension input fields to automatically calculate aspect ratio outWidth.addEventListener("input", aspectCheckW); outHeight.addEventListener("input", aspectCheckH); inWidth.onkeypress = function() { outHeight.value = 0; outWidth.value = 0; return isNumber(event); }; inHeight.onkeypress = function() { outHeight.value = 0; outWidth.value = 0; return isNumber(event); }; outWidth.onkeypress = function() { return isNumber(event); }; outHeight.onkeypress = function() { return isNumber(event); }; input.appendChild(saveRuleBtn); input.appendChild(discardRuleBtn); discardRuleBtn.onclick = function(){ document.getElementById(input.id).remove(); document.getElementById("addRule").style.display = "inline"; clearErr();}; saveRuleBtn.onclick = function() { if (edit) basicCheck(true, rulePos); else basicCheck(false); }; } //Populate Quick Convert List table function printQCList() { var QCList = getQCList(); var list = document.getElementById("QCList"); var table = document.getElementById("QCTable"); var filterCount = QCList.length; if (filterCount > 0) { var QCFilter = []; for (let i = 0; i < filterCount; i++) { QCFilter[i] = QCList[i].split(":"); let delRow = document.createElement("a"); delRow.innerHTML = "delete"; delRow.onclick = function() { QCList.splice(delRow.parentElement.parentElement.sectionRowIndex, 1); localStorage.setItem("downscale-qclist", JSON.stringify(QCList)); table.tBodies.item(0).innerHTML = ""; printQCList(); }; //QCList Array: [0] - Filetype, [1] - Image Width, [2] - Image Height, [3] - Original Filesize, [4] - New Filesize, [5] - Filename, [6] - Image Base64 MD5 Hash var row = table.tBodies.item(0).insertRow(-1); row.insertCell(0).innerHTML = QCFilter[i][0]; row.insertCell(1).innerHTML = '[ ' + QCFilter[i][1] + ' x ' + QCFilter[i][2] + ' ]'; row.insertCell(2).innerHTML = QCFilter[i][3]; row.insertCell(3).innerHTML = '→'; row.insertCell(4).innerHTML = QCFilter[i][4]; row.insertCell(5).innerHTML = '<p title = "' + QCFilter[i][5] +'">' + QCFilter[i][5] + '</p>'; row.insertCell(6).appendChild(delRow); } } } //*************************************************************************************// // MENUS // //*************************************************************************************// function appendSettings() { //Button-------------------------------------------------------- var span = document.createElement("span"); var button = document.createElement("a"); button.id = "imgResizeSettings"; button.className += "fa fa-cog"; button.style = "cursor: pointer;"; button.title = "Image Resizer Settings"; var ref = document.getElementById('shortcut-settings'); ref.insertBefore(span, parent.nextSibling); span.appendChild(button); //Overlay | imgResizeOverlay------------------------------------ var overlay = document.createElement("div"); overlay.id = "imgResizeOverlay"; overlay.classList.add("settingsOverlay"); document.body.appendChild(overlay); //Settings menu links | imgResizeMenu--------------------------- var menu = document.createElement("div"); menu.id = "imgResizeMenu"; menu.classList.add("dialog"); overlay.appendChild(menu); var close = document.createElement("a"); close.className += "close fa fa-times"; close.style = "float: right;"; close.title = "Close"; menu.insertAdjacentElement('afterbegin', close); //Settings var settingsBtn = document.createElement("a"); settingsBtn.innerHTML += "Settings"; settingsBtn.classList.add("menuBtns"); settingsBtn.style = "font-weight: bold;"; settingsBtn.onclick = function() { settingsDiv.className = "downscale-menu-on"; presetsDiv.className = "downscale-menu-off"; QCListDiv.className = "downscale-menu-off"; helpDiv.className = "downscale-menu-off"; settingsBtn.style = "font-weight: bold;"; presetsBtn.style = ""; QCListBtn.style = ""; helpBtn.style = ""; }; menu.appendChild(settingsBtn); //Presets var presetsBtn = document.createElement("a"); presetsBtn.innerHTML += "Presets"; presetsBtn.classList.add("menuBtns"); presetsBtn.onclick = function() { settingsDiv.className = "downscale-menu-off"; presetsDiv.className = "downscale-menu-on"; QCListDiv.className = "downscale-menu-off"; helpDiv.className = "downscale-menu-off"; settingsBtn.style = ""; presetsBtn.style = "font-weight: bold;"; QCListBtn.style = ""; helpBtn.style = ""; }; menu.appendChild(presetsBtn); //Quick Convert List var QCListBtn = document.createElement("a"); QCListBtn.innerHTML += "Quick Convert"; QCListBtn.classList.add("menuBtns"); QCListBtn.onclick = function() { settingsDiv.className = "downscale-menu-off"; presetsDiv.className = "downscale-menu-off"; QCListDiv.className = "downscale-menu-on"; helpDiv.className = "downscale-menu-off"; settingsBtn.style = ""; presetsBtn.style = ""; QCListBtn.style = "font-weight: bold;"; helpBtn.style = ""; }; menu.appendChild(QCListBtn); //Help var helpBtn = document.createElement("a"); helpBtn.innerHTML += "About"; helpBtn.classList.add("menuBtns"); helpBtn.onclick = function() { settingsDiv.className = "downscale-menu-off"; presetsDiv.className = "downscale-menu-off"; QCListDiv.className = "downscale-menu-off"; helpDiv.className = "downscale-menu-on"; settingsBtn.style = ""; presetsBtn.style = ""; QCListBtn.style = ""; helpBtn.style = "font-weight: bold;"; }; menu.appendChild(helpBtn); var hr = document.createElement("hr"); hr.style.borderColor = getHRColor(); menu.appendChild(hr); //Content divs| imgResizeContent--------------------------------- var content = document.createElement("div"); content.id = "imgResizeContent"; menu.appendChild(content); content.innerHTML = ""; var errMsg = document.createElement("p"); errMsg.id = "errMsg"; //Settings var settingsDiv = document.createElement("div"); settingsDiv.id = "settingsDiv"; settingsDiv.classList.add("downscale-menu-on"); content.appendChild(settingsDiv); //Presets var presetsDiv = document.createElement("div"); presetsDiv.id = "presetsDiv"; presetsDiv.classList.add("downscale-menu-off"); presetsDiv.style.textAlign = "center"; content.appendChild(presetsDiv); //Quick Convert List var QCListDiv = document.createElement("div"); QCListDiv.id = "QCListDiv"; QCListDiv.classList.add("downscale-menu-off"); content.appendChild(QCListDiv); //Help var helpDiv = document.createElement("div"); helpDiv.id = "heplDiv"; helpDiv.classList.add("downscale-menu-off"); content.appendChild(helpDiv); //-------------------------------------------------------------- var title = document.createElement("h3"); title.innerHTML = "Image Resizer Settings"; settingsDiv.appendChild(title); //Enable Resizer------------------------------------------------ var enableDiv = document.createElement("div"); enableDiv.classList.add("resizer-settings"); enableDiv.innerHTML = '' + '<input type="checkbox" id="enableSet" title="" size="1"></input>' + '<label for="enableSet">Enable Resizer</label>: ' + 'Enable 4chan Image Resizer.'; settingsDiv.appendChild(enableDiv); var enableSet = document.getElementById("enableSet"); enableSet.checked = getSettings().enabled; enableSet.oninput = function() { //remove side menu options upon disabling ImageResizer if (!enableSet.checked) { removeQCOption(); removeRemOption(); removePreviewOption(); } var settings = getSettings(); settings.enabled = enableSet.checked; document.getElementById("imgResize").checked = enableSet.checked; localStorage.setItem("downscale-settings", JSON.stringify(settings)); }; //Enable Shortcut----------------------------------------------- var shortcutDiv = document.createElement("div"); shortcutDiv.classList.add("resizer-settings"); shortcutDiv.innerHTML = '' + '<input type="checkbox" id="shortcutSet" title="" size="1"></input>' + '<label for="shortcutSet">Enable Shortcut</label>: ' + 'Enable "Quick Convert" shortcut. <kbd>Ctrl</kbd> + <kbd>Q</kbd>'; settingsDiv.appendChild(shortcutDiv); var shortcutSet = document.getElementById("shortcutSet"); shortcutSet.checked = getSettings().shortcut; shortcutSet.oninput = function() { var settings = getSettings(); settings.shortcut = shortcutSet.checked; localStorage.setItem("downscale-settings", JSON.stringify(settings)); }; //Display notifications----------------------------------------- var notifySetDiv = document.createElement("div"); notifySetDiv.classList.add("resizer-settings"); notifySetDiv.innerHTML = '' + '<input type="checkbox" id="displaySet" title="" size="1"></input>' + '<label for="displaySet">Display Notifications</label>: ' + 'Display a notification when an image is downscaled.'; settingsDiv.appendChild(notifySetDiv); var notifySet = document.getElementById('displaySet'); notifySet.checked = getSettings().notify; notifySet.oninput = function() { var settings = getSettings(); settings.notify = notifySet.checked; localStorage.setItem("downscale-settings", JSON.stringify(settings)); }; //Convert all PNGs to JPEGs------------------------------------- var convertSetDiv = document.createElement("div"); convertSetDiv.classList.add("resizer-settings"); convertSetDiv.innerHTML = '' + '<input type="checkbox" id="convertSet" title="" size="1"></input>' + '<label for="convertSet">Convert All PNGs</label>: ' + 'Automatically convert all added PNGs to JPEGs. Presets apply as normal.'; settingsDiv.appendChild(convertSetDiv); var convertSet = document.getElementById('convertSet'); convertSet.checked = getSettings().convert; convertSet.oninput = function() { var settings = getSettings(); settings.convert = convertSet.checked; localStorage.setItem("downscale-settings", JSON.stringify(settings)); }; //Set JPEG quality---------------------------------------------- //RegExp ^(0(\.\d{1,2})?|1(\.0+)?)$ //Only one number (0 or 1) before decimal, and up tp 2 numbers after decimal, if there is a 0 before decimal (between 0 and 9) //e.g. 0.92 true, 1.92 false var qualitySetDiv = document.createElement("div"); qualitySetDiv.classList.add("resizer-settings"); qualitySetDiv.innerHTML = '' + '<input type="text" id="imgQuality" title="JPEG Quality" size="1"></input>' + '<label for="imgQuality">JPEG Quality</label>: ' + 'A number between 0 and 1 indicating the output image quality.'; settingsDiv.appendChild(qualitySetDiv); var inputField = document.getElementById('imgQuality'); inputField.value = getSettings().jpegQuality; inputField.onkeypress = function() { return isDecimalNumber(event); }; //Check input field validity inputField.oninput = function() { var inputField = document.getElementById('imgQuality'); var r = new RegExp(/^(0(\.\d{1,2})?|1(\.0+)?)$/); if(r.test(document.getElementById('imgQuality').value)) { inputField.setCustomValidity(""); var settings = getSettings(); settings.jpegQuality = inputField.value; localStorage.setItem("downscale-settings", JSON.stringify(settings)); } else inputField.setCustomValidity("Set the value between 1 and 0 up to 2 numbers after the decimal point."); }; //Preset table | ruleTable---------------------------------------- var tableWrapper = document.createElement("div"); tableWrapper.style.overflowY = "auto"; tableWrapper.style.maxHeight = "220px"; var table = document.createElement("table"); var thead = document.createElement("thead"); var tbody = document.createElement("tbody"); var presetsTitle = document.createElement("h3"); presetsTitle.innerHTML = "Presets"; presetsDiv.appendChild(presetsTitle); table.appendChild(thead); table.appendChild(tbody); table.id = "ruleTable"; var row = thead.insertRow(0); row.insertCell(0).outerHTML = "<th>Format</th>"; row.insertCell(1).outerHTML = "<th>Input</th>"; row.insertCell(2).outerHTML = "<th></th>"; row.insertCell(3).outerHTML = "<th>Output</th>"; row.insertCell(4).outerHTML = "<th></th>"; row.insertCell(5).outerHTML = "<th></th>"; presetsDiv.appendChild(tableWrapper); tableWrapper.appendChild(table); //Input container | inputContainer------------------------------ var inputDiv = document.createElement("div"); inputDiv.id = "inputContainer"; presetsDiv.appendChild(inputDiv); var addRuleBtn = document.createElement("button"); addRuleBtn.id = "addRule"; addRuleBtn.innerHTML = "New Preset"; printList(); presetsDiv.appendChild(addRuleBtn); presetsDiv.appendChild(errMsg); button.onclick = function(){ overlay.style.display = "block"; }; close.onclick = function(){ overlay.style.display = "none"; }; window.addEventListener('click', function(closeSettingsMenu) { if (closeSettingsMenu.target == overlay) overlay.style.display = "none"; }); addRuleBtn.onclick = function(){ inputUI(false); }; //import/export buttons var bottomPresets = document.createElement("div"); bottomPresets.style = "float: left;"; var separator1 = document.createElement("span"); separator1.innerHTML = " | "; var importPresets = document.createElement("a"); var exportPresets = document.createElement("a"); importPresets.innerHTML = "Import"; exportPresets.innerHTML = "Export"; importPresets.classList.add("menuBtns"); bottomPresets.innerHTML += '<input id="importPresetsFile-input" type="file" accept=".json" style="display: none;" />'; //file-input importPresets.onclick = function(){ document.getElementById('importPresetsFile-input').click(); }; exportPresets.onclick = function(){ downloadObjectAsJson(getPresets(), "4chan Image Resizer v" + version + " Presets List - " + Date.now()); }; //call file exporter bottomPresets.appendChild(importPresets); bottomPresets.appendChild(separator1); bottomPresets.appendChild(exportPresets); presetsDiv.appendChild(bottomPresets); //import document.getElementById('importPresetsFile-input').addEventListener('change', function() { var jsonPresetsFile = new FileReader(); jsonPresetsFile.onload = function() { var originalPresets = getPresets(); var duplicateCount1 = 0; var tempDuplicateCount1 = 0; //parse raw text var importedPresets = JSON.parse(jsonPresetsFile.result); //check if array if (Array.isArray(importedPresets)) { for (let i = 0; i < importedPresets.length; i++) { var line1 = importedPresets[i].split(':'); if (line1.length != 5) { if(DEBUG) console.log("[Error] Imported array does not match the required length (5)"); if(DEBUG) console.log(line1); alert("Error: Array length mismatch.\nThis file is either outdated or invalid."); return; } else { //check for duplicate entries for (let j = 0; j < originalPresets.length; j++) { var tempLine = line1[0] + ":" + line1[1] + ":" + line1[2] + ":" + line1[3] + ":" + line1[4]; if (tempLine == originalPresets[j]) { tempDuplicateCount1++; break; } } //if not a dupe, push to the original array if (tempDuplicateCount1 == 0) { originalPresets.push(importedPresets[i]); } //count all duplicate entries else { duplicateCount1 += tempDuplicateCount1; tempDuplicateCount1 = 0; } } } //add the final result to local storage localStorage.setItem("downscale-presets", JSON.stringify(originalPresets)); //rebuild list document.getElementById("ruleTable").tBodies.item(0).innerHTML = ""; printList(); var newEntries1 = importedPresets.length - duplicateCount1; alert("Succesfully imported " + importedPresets.length + " entries.\nDuplicate entries skipped: " + duplicateCount1 + "\nNew entries added: " + newEntries1); } else { alert("Error: Invalid data type."); if(DEBUG) console.log("[Error] Imported data object is not an array.") } } jsonPresetsFile.readAsText(this.files[0]); }); //Quick Convert table | QCTable---------------------------------- var QCTableWrapper = document.createElement("div"); QCTableWrapper.style.overflowY = "auto"; QCTableWrapper.style.maxHeight = "220px"; var QCTable = document.createElement("table"); var QCThead = document.createElement("thead"); var QCTbody = document.createElement("tbody"); var QCTitle = document.createElement("h3"); QCTitle.innerHTML = "Quick Convert List"; QCListDiv.appendChild(QCTitle); QCListDiv.innerHTML += "<p style='text-align: center;'>Images on this list will be automatically converted to JPEG with a quality setting of 92.</p>"; QCTable.appendChild(QCThead); QCTable.appendChild(QCTbody); QCTable.id = "QCTable"; var QCRow = QCThead.insertRow(0); QCRow.insertCell(0).outerHTML = "<th>Format</th>"; QCRow.insertCell(1).outerHTML = "<th>Dimensions</th>"; QCRow.insertCell(2).outerHTML = "<th>Original Size</th>"; QCRow.insertCell(3).outerHTML = "<th></th>"; QCRow.insertCell(4).outerHTML = "<th>New Size</th>"; QCRow.insertCell(5).outerHTML = "<th>Filename</th>"; QCRow.insertCell(6).outerHTML = "<th></th>"; QCListDiv.appendChild(QCTableWrapper); QCTableWrapper.appendChild(QCTable); //import/export buttons var bottomQCL = document.createElement("div"); bottomQCL.style = "padding-top: 1em;"; var separator2 = document.createElement("span"); separator2.innerHTML = " | "; var importQCList = document.createElement("a"); var exportQCList = document.createElement("a"); importQCList.innerHTML = "Import"; exportQCList.innerHTML = "Export"; importQCList.classList.add("menuBtns"); bottomQCL.innerHTML += '<input id="importQCLFile-input" type="file" accept=".json" style="display: none;" />'; //file-input importQCList.onclick = function(){ document.getElementById('importQCLFile-input').click(); }; exportQCList.onclick = function(){ downloadObjectAsJson(getQCList(), "4chan Image Resizer v" + version + " Quick Convert List - " + Date.now()); }; //call file exporter bottomQCL.appendChild(importQCList); bottomQCL.appendChild(separator2); bottomQCL.appendChild(exportQCList); QCListDiv.appendChild(bottomQCL); //import document.getElementById('importQCLFile-input').addEventListener('change', function() { var jsonFile = new FileReader(); jsonFile.onload = function() { var originalQCL = getQCList(); var duplicateCount2 = 0; var tempDuplicateCount2 = 0; //parse raw text var importedQCL = JSON.parse(jsonFile.result); //check if array if (Array.isArray(importedQCL)) { for (let i = 0; i < importedQCL.length; i++) { var line = importedQCL[i].split(':'); if (line.length != 7 || line[6].length != 32) { if(DEBUG) console.log("[Error] Imported array does not match the required length (7) or contains an invalid MD5 hash."); if(DEBUG) console.log(line); alert("Error: Array length mismatch.\nThis file is either outdated or invalid."); return; } else { //check for duplicate MD5 hashes for (let j = 0; j < originalQCL.length; j++) { var originalLine2 = originalQCL[j].split(':'); if (line[6] == originalLine2[6]) { tempDuplicateCount2++; break; } } //if not a dupe, push to the original array if (tempDuplicateCount2 == 0) { originalQCL.push(importedQCL[i]); } //count all duplicate entries else { duplicateCount2 += tempDuplicateCount2; tempDuplicateCount2 = 0; } } } //add the final result to local storage localStorage.setItem("downscale-qclist", JSON.stringify(originalQCL)); //rebuild list document.getElementById("QCTable").tBodies.item(0).innerHTML = ""; printQCList(); var newEntries2 = importedQCL.length - duplicateCount2; alert("Succesfully imported " + importedQCL.length + " entries.\nDuplicate entries skipped: " + duplicateCount2 + "\nNew entries added: " + newEntries2); } else { alert("Error: Invalid data type."); if(DEBUG) console.log("[Error] Imported data object is not an array.") } } jsonFile.readAsText(this.files[0]); }); //delete all QCL entries var delAll = document.createElement("a"); var emptyArray = []; delAll.innerHTML = "Delete All"; delAll.style = "float: right; margin-right: 1em;"; delAll.onclick = function(){ if (confirm(" WARNING!\nAre you sure you want to DELETE ALL entries from the \"Quick Convert List\"?")) { localStorage.setItem("downscale-qclist", JSON.stringify(emptyArray)); document.getElementById("QCTable").tBodies.item(0).innerHTML = ""; } }; bottomQCL.appendChild(delAll); //INITIAL PRINT OF QUICK CONVERT LIST printQCList(); //Help---------------------------------------------------------- var helpTitle = document.createElement("h3"); helpTitle.innerHTML = "About"; helpDiv.appendChild(helpTitle); var rant = document.createElement("p"); rant.innerHTML = '<strong>4chan Image <span style="text-decoration-line: line-through;">Resizer</span></strong> <s>Downscaler</s> automatically downscales images based on custom presets. Originally developed to downscale anime/vidya screenshots "on the fly".<br><br>' + 'To get started, you first have to create a preset by choosing an input image format and entering input and output dimensions (pixels). Then just add an image to a quick reply form. ' + '<br>If it meets any of the presets input requirements, the image will be automatically downscaled to specified dimensions as a <strong>JPEG</strong>. ' + '<br><br><strong>Note</strong> that output dimensions are constrained by input dimensions <strong>aspect ratio</strong>. ' + '<br><strong>Also note</strong> that <strong>setting JPEG output quality to 1</strong> may result in filesizes larger than that of the original image, and should be considered as a placebo.' + '<br><br><strong> "Quick Convert"</strong> allows you to quickly convert images (PNG/JPEG) to JPEG at a quality of 92.' + '<br>This is very useful when an image exceeds 4chan image size limit of <strong>4 MB</strong>.' + '<br>It works well on super high resolution images (+3000px), sometimes drastically cutting the filesize without any noticeble quality loss.' + ' However, <strong>it is not recommended to use it on grayscale PNG images</strong>, i.e. manga pages, because most of the time <strong>it will result in larger than original filesizes</strong>.' + '<br>Once you are satisfied with the <strong>"Quick Convert"</strong> results, you can click <strong>"Remember"</strong> on the side menu to add the image MD5 hash to the <strong>"Quick Convert List"</strong>, which will always automatically convert this image for you.' + '<br><br><span style="font-weight:bold; color: red;">*NEW*</span><br> Added <strong>Import/Export</strong> feature for both lists. <strong>Import</strong> works by merging list entries instead of overwriting them, so you can export/import items between domains without any worry.' + '<br>Added a <kbd>Ctrl</kbd> + <kbd>Q</kbd> keyboard shortcut for <strong>"Quick Convert"</strong> to actually make it quick. Press again to <strong>"Remember"</strong> the image.' + '<br><br><div style="float: right;" >[ <a href="https://greasyfork.org/en/scripts/391758-4chan-image-resizer" target="_blank">version ' + version + '</a> ]</div>'; helpDiv.appendChild(rant); } //Only when QR form is open. function appendSideMenu() { //Arrow | sideMenuArrow---------------------------------------------------------- var arrow = document.createElement("a"); arrow.id = "sideMenuArrow"; arrow.title = "Side Menu"; arrow.style.cursor = "pointer"; arrow.innerHTML = "◀"; var arrowRef = document.getElementById("autohide"); arrowRef.parentNode.insertAdjacentElement("beforebegin", arrow); arrow.onclick = function(){ sideMenu.classList.toggle("downscale-menu-on"); }; //Side Menu | sideMenu---------------------------------------------------------- var sideMenu = document.createElement("div"); sideMenu.id = "sideMenu"; sideMenu.classList.add("dialog"); var sideMenuRef = document.getElementById("qr"); sideMenuRef.insertAdjacentElement("afterbegin", sideMenu); //Close side menu dialog by clicking anywhere but here: window.addEventListener('click', function(event) { var getSideMenu = document.getElementById("sideMenu"); if (!event.target.matches('#sideMenuArrow') && !event.target.matches('#sideMenu') && !event.target.matches('#imgResize') && !event.target.matches('#quickConvert') && !event.target.matches('#imgResizeLabel')) { if (getSideMenu.classList.contains('downscale-menu-on')) getSideMenu.classList.remove('downscale-menu-on'); } }); } appendSettings(); //*************************************************************************************// //END OF MENUs // //*************************************************************************************// //Saves image details to local storage function saveImgMD5 (img, file, imgMD5, newSize) { removeRemOption(); var QCList = getQCList(); //"file/jpeg" -> "JPEG" var filetype = file.type.split("/").pop().toUpperCase(); //remove filetype var filename = file.name.split(".").slice(0,-1).join("."); //replace seperators filename = filename.replace(/:/g,"_"); var orig_filesize = formatBytes(file.size); var new_filesize = formatBytes(newSize); //QCList Array [0] - Filetype, [1] - Image Width, [2] - Image Height, [3] - Original Filesize, [4] - New Filesize, [5] - Filename, [6] - Image Base64 MD5 Hash var QCString = filetype + ":" + img.width + ":" + img.height + ":" + orig_filesize + ":" + new_filesize + ":" + filename + ":" + imgMD5; QCList.push(QCString); localStorage.setItem("downscale-qclist", JSON.stringify(QCList)); //Show notification var info = file.name + '\nAdded to the "Quick Convert List"'; var msgDetail = {type: 'info', content: info, lifetime: 5}; var msgEvent = new CustomEvent('CreateNotification', {bubbles: true, detail: msgDetail}); document.dispatchEvent(msgEvent); //rebuild list document.getElementById("QCTable").tBodies.item(0).innerHTML = ""; printQCList(); } //Removes these Side Menu options function removeQCOption() { var checkQC = document.getElementById("qcDiv"); if (checkQC) checkQC.remove(); } function removeRemOption() { var checkRem = document.getElementById("remDiv"); if (checkRem) checkRem.remove(); } function removePreviewOption() { var checkPreview = document.getElementById("previewImg"); if (checkPreview) checkPreview.remove(); } //Get border color for <hr> hack function getHRColor () { var sample = document.getElementById("imgResizeMenu"); return window.getComputedStyle(sample, null).getPropertyValue("border-bottom-color"); } //Image viewer function showImage(img, size, width, height, filename) { var overlay = document.createElement("div"); overlay.id = "pvOverlay"; //----------------------------------------------- var pvHeader = document.createElement("div"); pvHeader.id = "pvHeader"; pvHeader.className = "dialog"; //opacity hack pvHeader.classList.add("pvOpct"); pvHeader.innerHTML = filename + "<br>(" + formatBytes(size)+ ", " + Math.round(width) + "x" + Math.round(height) + ")"; //----------------------------------------------- var closePv = document.createElement("a"); closePv.className = "close fa fa-times"; closePv.style = "float: right;"; closePv.onclick = function(){ overlay.remove(); }; //----------------------------------------------- var pvImg = document.createElement("img"); pvImg.id = "pvImg"; pvImg.classList.add("centerImg"); pvImg.title = "Click to close"; pvImg.src = img; pvImg.onclick = function(){ overlay.remove(); }; //----------------------------------------------- document.body.appendChild(overlay); //overlay.appendChild(closePv); overlay.appendChild(pvImg); overlay.appendChild(pvHeader); //opacity hack setTimeout(function() { pvHeader.classList.toggle("pvOpct"); }, 2000); } //json file exporter function downloadObjectAsJson(exportObj, exportName) { var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj)); var downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", exportName + ".json"); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); } //Prevent multiple event listeners var scListenerExists = false; //Quick Convert shortcut | Ctrl+Q if (getSettings().shortcut && !scListenerExists) { document.addEventListener('keyup', qCShortcut); scListenerExists = true ; } function qCShortcut(e) { var convertBtn = document.getElementById("quickConvert"); var rememberBtn = document.getElementById("rememberMD5"); //if shortcut is enabled, simulate clicks if (getSettings().shortcut) { if (e.ctrlKey && e.keyCode == 81 && convertBtn) { convertBtn.click(); } else if (e.ctrlKey && e.keyCode == 81 && rememberBtn) { rememberBtn.click(); } } } //Bloat function isDecimalNumber(e){var h=e.which?e.which:e.keyCode;return!(46!=h&&h>31&&(h<48||h>57));} function isNumber(e){var i=(e=e||window.event).which?e.which:e.keyCode;return!(i>31&&(i<48||i>57));} function formatBytes(a,b){if(0==a)return"0 Bytes";var c=1024,d=b||2,e=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],f=Math.floor(Math.log(a)/Math.log(c));return parseFloat((a/Math.pow(c,f)).toFixed(d))+" "+e[f];}