// ==UserScript== // @name bangumi blur image // @namespace https://github.com/22earth // @description a tool for bluring image before upload // @include /^https?:\/\/(bangumi|bgm|chii)\.(tv|in)\/.*(upload_img|new)$/ // @updateURL https://raw.githubusercontent.com/bangumi/scripts/master/a_little/bangumi_blur_image.user.js // @grant GM_addStyle // @version 0.2.4 // @note 0.2 add loading and main entry function // ==/UserScript== /* * greasyfork.org don't allow code uses an unapproved external script * copy StackBlur source code at below */ ;(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.StackBlur = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o> shg_sum; if (pa != 0) { pa = 255 / pa; pixels[yi] = ((r_sum * mul_sum) >> shg_sum) * pa; pixels[yi+1] = ((g_sum * mul_sum) >> shg_sum) * pa; pixels[yi+2] = ((b_sum * mul_sum) >> shg_sum) * pa; } else { pixels[yi] = pixels[yi+1] = pixels[yi+2] = 0; } r_sum -= r_out_sum; g_sum -= g_out_sum; b_sum -= b_out_sum; a_sum -= a_out_sum; r_out_sum -= stackIn.r; g_out_sum -= stackIn.g; b_out_sum -= stackIn.b; a_out_sum -= stackIn.a; p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; r_in_sum += (stackIn.r = pixels[p]); g_in_sum += (stackIn.g = pixels[p+1]); b_in_sum += (stackIn.b = pixels[p+2]); a_in_sum += (stackIn.a = pixels[p+3]); r_sum += r_in_sum; g_sum += g_in_sum; b_sum += b_in_sum; a_sum += a_in_sum; stackIn = stackIn.next; r_out_sum += (pr = stackOut.r); g_out_sum += (pg = stackOut.g); b_out_sum += (pb = stackOut.b); a_out_sum += (pa = stackOut.a); r_in_sum -= pr; g_in_sum -= pg; b_in_sum -= pb; a_in_sum -= pa; stackOut = stackOut.next; yi += 4; } yw += width; } for (x = 0; x < width; x++) { g_in_sum = b_in_sum = a_in_sum = r_in_sum = g_sum = b_sum = a_sum = r_sum = 0; yi = x << 2; r_out_sum = radiusPlus1 * (pr = pixels[yi]); g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); a_out_sum = radiusPlus1 * (pa = pixels[yi+3]); r_sum += sumFactor * pr; g_sum += sumFactor * pg; b_sum += sumFactor * pb; a_sum += sumFactor * pa; stack = stackStart; for (i = 0; i < radiusPlus1; i++) { stack.r = pr; stack.g = pg; stack.b = pb; stack.a = pa; stack = stack.next; } yp = width; for (i = 1; i <= radius; i++) { yi = (yp + x) << 2; r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); g_sum += (stack.g = (pg = pixels[yi+1])) * rbs; b_sum += (stack.b = (pb = pixels[yi+2])) * rbs; a_sum += (stack.a = (pa = pixels[yi+3])) * rbs; r_in_sum += pr; g_in_sum += pg; b_in_sum += pb; a_in_sum += pa; stack = stack.next; if(i < heightMinus1) { yp += width; } } yi = x; stackIn = stackStart; stackOut = stackEnd; for (y = 0; y < height; y++) { p = yi << 2; pixels[p+3] = pa = (a_sum * mul_sum) >> shg_sum; if (pa > 0) { pa = 255 / pa; pixels[p] = ((r_sum * mul_sum) >> shg_sum) * pa; pixels[p+1] = ((g_sum * mul_sum) >> shg_sum) * pa; pixels[p+2] = ((b_sum * mul_sum) >> shg_sum) * pa; } else { pixels[p] = pixels[p+1] = pixels[p+2] = 0; } r_sum -= r_out_sum; g_sum -= g_out_sum; b_sum -= b_out_sum; a_sum -= a_out_sum; r_out_sum -= stackIn.r; g_out_sum -= stackIn.g; b_out_sum -= stackIn.b; a_out_sum -= stackIn.a; p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; r_sum += (r_in_sum += (stackIn.r = pixels[p])); g_sum += (g_in_sum += (stackIn.g = pixels[p+1])); b_sum += (b_in_sum += (stackIn.b = pixels[p+2])); a_sum += (a_in_sum += (stackIn.a = pixels[p+3])); stackIn = stackIn.next; r_out_sum += (pr = stackOut.r); g_out_sum += (pg = stackOut.g); b_out_sum += (pb = stackOut.b); a_out_sum += (pa = stackOut.a); r_in_sum -= pr; g_in_sum -= pg; b_in_sum -= pb; a_in_sum -= pa; stackOut = stackOut.next; yi += width; } } return imageData; } function processCanvasRGB(canvas, top_x, top_y, width, height, radius) { if (isNaN(radius) || radius < 1) return; radius |= 0; var imageData = getImageDataFromCanvas(canvas, top_x, top_y, width, height); imageData = processImageDataRGB(imageData, top_x, top_y, width, height, radius); canvas.getContext('2d').putImageData(imageData, top_x, top_y); } function processImageDataRGB(imageData, top_x, top_y, width, height, radius) { var pixels = imageData.data; var x, y, i, p, yp, yi, yw, r_sum, g_sum, b_sum, r_out_sum, g_out_sum, b_out_sum, r_in_sum, g_in_sum, b_in_sum, pr, pg, pb, rbs; var div = radius + radius + 1; var w4 = width << 2; var widthMinus1 = width - 1; var heightMinus1 = height - 1; var radiusPlus1 = radius + 1; var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; var stackStart = new BlurStack(); var stack = stackStart; for (i = 1; i < div; i++) { stack = stack.next = new BlurStack(); if (i == radiusPlus1) var stackEnd = stack; } stack.next = stackStart; var stackIn = null; var stackOut = null; yw = yi = 0; var mul_sum = mul_table[radius]; var shg_sum = shg_table[radius]; for (y = 0; y < height; y++) { r_in_sum = g_in_sum = b_in_sum = r_sum = g_sum = b_sum = 0; r_out_sum = radiusPlus1 * (pr = pixels[yi]); g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); r_sum += sumFactor * pr; g_sum += sumFactor * pg; b_sum += sumFactor * pb; stack = stackStart; for (i = 0; i < radiusPlus1; i++) { stack.r = pr; stack.g = pg; stack.b = pb; stack = stack.next; } for (i = 1; i < radiusPlus1; i++) { p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2); r_sum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i); g_sum += (stack.g = (pg = pixels[p+1])) * rbs; b_sum += (stack.b = (pb = pixels[p+2])) * rbs; r_in_sum += pr; g_in_sum += pg; b_in_sum += pb; stack = stack.next; } stackIn = stackStart; stackOut = stackEnd; for (x = 0; x < width; x++) { pixels[yi] = (r_sum * mul_sum) >> shg_sum; pixels[yi+1] = (g_sum * mul_sum) >> shg_sum; pixels[yi+2] = (b_sum * mul_sum) >> shg_sum; r_sum -= r_out_sum; g_sum -= g_out_sum; b_sum -= b_out_sum; r_out_sum -= stackIn.r; g_out_sum -= stackIn.g; b_out_sum -= stackIn.b; p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2; r_in_sum += (stackIn.r = pixels[p]); g_in_sum += (stackIn.g = pixels[p+1]); b_in_sum += (stackIn.b = pixels[p+2]); r_sum += r_in_sum; g_sum += g_in_sum; b_sum += b_in_sum; stackIn = stackIn.next; r_out_sum += (pr = stackOut.r); g_out_sum += (pg = stackOut.g); b_out_sum += (pb = stackOut.b); r_in_sum -= pr; g_in_sum -= pg; b_in_sum -= pb; stackOut = stackOut.next; yi += 4; } yw += width; } for (x = 0; x < width; x++) { g_in_sum = b_in_sum = r_in_sum = g_sum = b_sum = r_sum = 0; yi = x << 2; r_out_sum = radiusPlus1 * (pr = pixels[yi]); g_out_sum = radiusPlus1 * (pg = pixels[yi+1]); b_out_sum = radiusPlus1 * (pb = pixels[yi+2]); r_sum += sumFactor * pr; g_sum += sumFactor * pg; b_sum += sumFactor * pb; stack = stackStart; for (i = 0; i < radiusPlus1; i++) { stack.r = pr; stack.g = pg; stack.b = pb; stack = stack.next; } yp = width; for (i = 1; i <= radius; i++) { yi = (yp + x) << 2; r_sum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i); g_sum += (stack.g = (pg = pixels[yi+1])) * rbs; b_sum += (stack.b = (pb = pixels[yi+2])) * rbs; r_in_sum += pr; g_in_sum += pg; b_in_sum += pb; stack = stack.next; if(i < heightMinus1) { yp += width; } } yi = x; stackIn = stackStart; stackOut = stackEnd; for (y = 0; y < height; y++) { p = yi << 2; pixels[p] = (r_sum * mul_sum) >> shg_sum; pixels[p+1] = (g_sum * mul_sum) >> shg_sum; pixels[p+2] = (b_sum * mul_sum) >> shg_sum; r_sum -= r_out_sum; g_sum -= g_out_sum; b_sum -= b_out_sum; r_out_sum -= stackIn.r; g_out_sum -= stackIn.g; b_out_sum -= stackIn.b; p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2; r_sum += (r_in_sum += (stackIn.r = pixels[p])); g_sum += (g_in_sum += (stackIn.g = pixels[p+1])); b_sum += (b_in_sum += (stackIn.b = pixels[p+2])); stackIn = stackIn.next; r_out_sum += (pr = stackOut.r); g_out_sum += (pg = stackOut.g); b_out_sum += (pb = stackOut.b); r_in_sum -= pr; g_in_sum -= pg; b_in_sum -= pb; stackOut = stackOut.next; yi += width; } } return imageData; } function BlurStack() { this.r = 0; this.g = 0; this.b = 0; this.a = 0; this.next = null; } module.exports = { image: processImage, canvasRGBA: processCanvasRGBA, canvasRGB: processCanvasRGB, imageDataRGBA: processImageDataRGBA, imageDataRGB: processImageDataRGB }; },{}]},{},[1])(1) }); ;(function() { function addInputFile($target) { var $input = document.createElement('input'); $input.type = 'file'; if ($target) { $target.parentElement.insertBefore($input, $target.nextElementSibling); } } function addStyle(css) { if (css) { GM_addStyle(css); } else { GM_addStyle([ '#amount { padding-left: 10px; border: 0; color: #f6931f; font-size: 20px; font-weight: bold; }', '#reset { display: inline-block; text-align: center; width: 60px; height: 30px; line-height: 30px; font-size: 18px; background-color: #f09199; text-decoration: none; color: #fff; margin-left: 50px; margin-bottom: 30px; border-radius: 5px; box-shadow:1px 1px 2px #333; }', 'canvas:active { cursor: crosshair; }', '#preview { display: block; }', '.blur-loading { width: 208px; height: 13px; background-image: url("/img/loadingAnimation.gif"); }' ].join('')); } } function insertBlurInfo($target) { const rawHTML = `


reset `; var $info = document.createElement('div'); $info.classList.add('blur-info'); $info.innerHTML = rawHTML; if ($target) { $target.parentElement.insertBefore($info, $target.nextElementSibling); } } function changeInfo($width, $radius) { var $info = document.querySelector('#amount'); var radius = $radius.value; var width = $width.value; $info.value = width + ', ' + radius; } function getMousePos(canvas, evt) { var rect = canvas.getBoundingClientRect(); return { x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width, y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height }; } function drawRec($width) { var $canvas = $width.nextElementSibling; var ctx = $canvas.getContext('2d'); var width = Number($width.value); $canvas.width = width * 1.4; $canvas.height = width * 1.4; ctx.strokeStyle = '#f09199'; ctx.strokeRect(0.2 * width, 0.2 * width, width, width); window.dispatchEvent(new Event('resize')); } function previewFile($file, $blurInfo) { //var $file = document.querySelector('input[type = file]') var $canvas = document.createElement('canvas'); var $radius = $blurInfo.querySelector('#slider-radius'); var $width = $blurInfo.querySelector('#slider-width'); $canvas.id = 'preview'; $canvas.width = 8; $canvas.height = 10; var ctx = $canvas.getContext('2d'); $blurInfo.insertBefore($canvas, $blurInfo.firstChild); var $img = new Image(); $img.addEventListener('load', function () { $canvas.width = $img.width; $canvas.height = $img.height; ctx.drawImage($img, 0, 0); window.dispatchEvent(new Event('resize')); // let img cut tool at right position }, false); blur($canvas); $file.addEventListener('change', loadImgData, false); function blur(el) { var isDrawing; var ctx = el.getContext('2d'); el.onmousedown = function (e) { isDrawing = true; var pos = getMousePos(el, e); ctx.moveTo(pos.x, pos.y); }; el.onmousemove = function (e) { if (isDrawing) { //ctx.lineTo(e.layerX, e.layerY); //ctx.stroke(); var radius = Number($radius.value); var width = Number($width.value); var pos = getMousePos(el, e); StackBlur.canvasRGBA(el, pos.x - width / 2, pos.y - width / 2, width, width, radius); } }; el.onmouseup = function () { isDrawing = false; }; } function loadImgData() { var file = $file.files[0]; var reader = new FileReader(); reader.addEventListener('load', function () { $img.src = reader.result; }, false); if (file) { reader.readAsDataURL(file); } } document.querySelector('#reset').addEventListener('click', function (e) { e.preventDefault() var file = $file.files[0]; var $fillForm = document.querySelector('.fill-form'); if (file) { $file.dispatchEvent(new Event('change')); } else if ($fillForm) { $fillForm.dispatchEvent(new Event('click')); } }); } function sendFormDataPic($form, dataURL) { var genString = Array.apply(null, Array(5)).map(function(){ return (function(charset){ return charset.charAt(Math.floor(Math.random()*charset.length)); }('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')); }).join(''); 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 = decodeURI(dataURI.split(',')[1]); // instead of unescape // 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}); } function dataURLtoFile(dataurl, filename) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], filename, {type:mime}); } // loading effect var $submit = $form.querySelector('[type=submit]'); $submit.style.display = 'none'; var $loading = document.createElement('div'); $loading.classList.add('blur-loading'); var $blurInfo = document.querySelector('.blur-info'); $form.parentElement.insertBefore($loading, $blurInfo); // ajax var fd = new FormData($form); var $file = $form.querySelector('input[type=file]'); var inputFileName = $file.name ? $file.name : 'picfile'; fd.set(inputFileName, dataURItoBlob(dataURL), genString + '.png'); var $submit = $form.querySelector('[name=submit]') if ($submit && $submit.name && $submit.value) { fd.set($submit.name, $submit.value) } var xhr = new XMLHttpRequest(); xhr.open($form.method.toLowerCase(), $form.action, true); xhr.onreadystatechange = function () { var _location; //console.log(xhr); if(xhr.readyState === 2 && xhr.status === 200){ _location = xhr.responseURL; $loading.style.display = 'none'; $submit.style.display = ''; if(_location) { location.assign(_location); } } }; xhr.send(fd); // clone form submit /* *var $cloneForm = $form.cloneNode(true) *var $file = $cloneForm.querySelector('input[type=file]') *$file.files[0] = dataURLtoFile(dataURL, genString + '.png') */ } function init() { // gm init dom addStyle(); var fs = [].slice.call(document.forms).filter(function(elem) { return elem.querySelector('input[type=file]'); }); insertBlurInfo(fs[0]); // end add dom and css // blur var $radius = document.querySelector('#slider-radius'); var $width = document.querySelector('#slider-width'); window.addEventListener('load', function (e) { drawRec($width); changeInfo($width, $radius); }, false); var $file = document.querySelector('input[type = file]'); var $blurInfo = document.querySelector('.blur-info'); $blurInfo.addEventListener('change', function(e) { if (e.target.tagName.toLowerCase() === 'input') { changeInfo($width, $radius); } if (e.target.name === 'width') { drawRec($width); } }, false); previewFile($file, $blurInfo); fs.length && fs[0].addEventListener('submit', function (e) { var $canvas = document.querySelector('#preview'); if (!$canvas) { return undefined; } if ($canvas.width === 8 && $canvas.height === 10) { return undefined; } e.preventDefault(); var dataURL = document.querySelector('#preview').toDataURL('image/png', 1); sendFormDataPic(this, dataURL); }, false); } init(); }());