Skip to content

Instantly share code, notes, and snippets.

@dlwr
Last active August 29, 2015 14:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dlwr/8f616fc605ff6b99640e to your computer and use it in GitHub Desktop.
Save dlwr/8f616fc605ff6b99640e to your computer and use it in GitHub Desktop.
ウェブページをキャプチャーしてグリッチして投稿するtaberareloo拡張パッチ
// ==Taberareloo==
// {
// "name" : "Glitch Selected Region"
// , "description" : "Glitch Selected Region"
// , "include" : ["background", "content"]
// , "match" : ["*://*/*"]
// , "version" : "1.0.2"
// , "downloadURL" : "https://gist.githubusercontent.com/dlwr/8f616fc605ff6b99640e/raw/extractor.photo.capture.glitch.tbrl.js"
// }
// ==/Taberareloo==
// c.f. glitch canvas by snorpey
// https://github.com/snorpey/glitch-canvas
(function() {
if (inContext('background')) {
Menus._register({
title: 'Photo - Capture Glitch',
contexts: ['all'],
onclick: function(info, tab) {
chrome.tabs.sendMessage(tab.id, {
request: 'contextMenusGlitchPhoto',
content: info
});
}
}, null, 'Photo - Capture', true);
Menus.create();
return;
}
TBRL.setRequestHandler('contextMenusGlitchPhoto', function(req, sender, func) {
var ctx = TBRL.createContext(TBRL.getContextMenuTarget());
ctx.contextMenu = true;
var ext = Extractors['Photo - Capture Glitch'];
TBRL.share(ctx, ext, true);
});
Extractors.register({
name: 'Photo - Capture Glitch',
ICON: chrome.extension.getURL('skin/') + 'photo.png',
TARGET_BACKGROUND: '#888',
check: function() {
return true;
},
extract: function(ctx) {
var self = this;
var target = ctx.target;
var win = ctx.window;
return defer().then(function() {
return self.selectRegion(ctx).then(function (region) {
return self.capture(win, region.position, region.dimensions).then(function (src) {
return self.glitch(src);
});
});
}).then(function (file) {
return {
type: 'photo',
item: ctx.title,
fileEntry: file
};
});
},
glitch: function(src) {
return new Promise(function(resolve) {
var params = {
amount: Math.random(),
seed: Math.random(),
quality: Math.random(),
iterations: Math.floor(Math.random() * 100)
};
var BASE64_MAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
var REVERESED_BASE4_MAP = function() {
var res = {};
BASE64_MAP.forEach(function(val, key) {res[val] = key;});
return res;
}();
var base64 = src;
var byteArray = function(str) {
var result = [];
var digitNum;
var cur;
var prev;
for (var i = 23, len = str.length; i < len; i++) {
cur = REVERESED_BASE4_MAP[str.charAt(i)];
digitNum = (i - 23) % 4;
switch(digitNum) {
case 1:
result.push(prev << 2 | cur >> 4);
break;
case 2:
result.push((prev & 0x0f) << 4 | cur >> 2);
break;
case 3:
result.push((prev & 3) << 6 | cur);
break;
}
prev = cur;
}
return result;
}(base64);
var jpgHeaderLength = function(data) {
var result = 417;
for (var i = 0, len = data.length; i < len; i++) {
if (data[i] === 0xFF && data[i + 1] === 0xDA) {
result = i + 2;
break;
}
}
return result;
}(byteArray);
for (var i = 0, len = params.iterations; i < len; i++) {
var maxIndex = byteArray.length - jpgHeaderLength - 4;
var pxMin = parseInt(maxIndex / len * i, 10);
var pxMax = parseInt(maxIndex / len * (i + 1), 10);
var delta = pxMax - pxMin;
var pxI = parseInt(pxMin + delta * params.seed, 10);
if (pxI > maxIndex) {
pxI = maxIndex;
}
var index = Math.floor(jpgHeaderLength + pxI);
byteArray[index] = Math.floor(params.amout * 256);
}
var glitchData = function(arr) {
var result = ['data:image/jpeg;base64,'];
var byteNum;
var cur;
var prev;
for (var i = 0, len = arr.length; i < len; i++) {
cur = arr[i];
byteNum = i % 3;
switch (byteNum) {
case 0:
result.push(BASE64_MAP[cur >> 2]);
break;
case 1:
result.push(BASE64_MAP[(prev & 3) << 4 | (cur >> 4)]);
break;
case 2:
result.push(BASE64_MAP[(prev & 0xf) << 2 | (cur >> 6)]);
result.push(BASE64_MAP[cur & 0x3f]);
break;
}
prev = cur;
}
if (byteNum === 0) {
result.push(BASE64_MAP[(prev & 3) << 4]);
result.push('==');
} else if (byteNum === 1) {
result.push(BASE64_MAP[(prev & 0x0f) << 2]);
result.push('=');
}
return result.join('');
}(byteArray);
var img = document.createElement('img');
img.addEventListener('load', function callee() {
img.removeEventListener('load', callee, false);
var canvas = document.createElement('canvas');
var size = {w: 0, h: 0};
var ctx = canvas.getContext('2d');
canvas.width = size.w = img.naturalWidth;
canvas.height = size.h = img.naturalHeight;
ctx.drawImage(img, 0, 0);
base64ToFileEntry(canvas.toDataURL('image/png', '')).then(resolve);
}, false);
img.src = glitchData;
});
},
capture: function (win, pos, dim, scale) {
// Google Chrome doesn't support CanvasRenderingContext2D#drawWindow
return new Promise(function (resolve) {
var width = win.innerWidth;
chrome.runtime.sendMessage(TBRL.id, {
request: 'capture'
}, function (res) {
var img = document.createElement('img');
img.addEventListener('load', function callee() {
img.removeEventListener('load', callee, false);
scale = (img.naturalWidth === width) ? null : img.naturalWidth / width;
var canvas = document.createElement('canvas');
var size = {w: 0, h: 0};
var ctx = canvas.getContext('2d');
if (scale) {
scale = scale.w ? (scale.w / dim.w) : scale.h ? (scale.h / dim.h) : scale;
canvas.width = size.w = dim.w;
canvas.height = size.h = dim.h;
dim.w *= scale;
dim.h *= scale;
pos.x *= scale;
pos.y *= scale;
} else {
canvas.width = size.w = dim.w;
canvas.height = size.h = dim.h;
}
ctx.drawImage(img, pos.x, pos.y, dim.w, dim.h, 0, 0, size.w, size.h);
// base64ToFileEntry(canvas.toDataURL('image/png', '')).then(resolve);
resolve(canvas.toDataURL('image/jpeg'));
}, false);
img.src = res;
});
});
},
selectRegion: function (ctx) {
return new Promise(function (resolve, reject) {
var doc = ctx ? ctx.document : document;
var win = doc.defaultView;
doc.documentElement.style.cursor = 'crosshair';
var style = doc.createElement('style');
style.innerHTML =
'* {\n' +
' cursor: crosshair !important;\n' +
' -webkit-user-select: none;\n' +
' user-select: none;\n' +
'}\n' +
'div.taberareloo_capture_size {\n' +
' padding: 5px !important;\n' +
' border-radius: 5px !important;\n' +
' opacity: 0.7 !important;\n' +
' position: fixed !important;\n' +
' z-index: 999999999 !important;\n' +
' background-color: gray !important;\n' +
' color: white !important;\n' +
'}\n';
doc.body.appendChild(style);
var region, p, d, moving, square, size;
function mouse(e) {
return {
x: e.clientX,
y: e.clientY
};
}
function onMouseMove(e) {
var to = mouse(e);
if (moving) {
var px = to.x - d.w, py = to.y - d.h;
if (px > window.innerWidth) {
px = window.innerWidth;
}
if (py > window.innerHeight) {
py = window.innerHeight;
}
p.x = Math.max(px, 0);
p.y = Math.max(py, 0);
}
d = {
w: to.x - p.x,
h: to.y - p.y
};
var minusW = (d.w < 0), minusH = (d.h < 0);
var s;
if (square) {
s = Math.min(Math.abs(d.w), Math.abs(d.h));
d.w = (minusW) ? -(s) : s;
d.h = (minusH) ? -(s) : s;
}
var d2 = update({}, d), p2 = update({}, p);
if (minusW || minusH) {
// 反転モード
if (d2.w < 0) {
p2.x = p.x + d2.w;
d2.w = -d2.w;
if (p2.x < 0) {
d2.w += p2.x;
p2.x = 0;
}
}
if (d2.h < 0) {
p2.y = p.y + d2.h;
d2.h = -d2.h;
if (p2.y < 0) {
d2.h += p2.y;
p2.y = 0;
}
}
d.w = (minusW) ? -(d2.w) : d2.w;
d.h = (minusH) ? -(d2.h) : d2.h;
}
var rx = p2.x + d2.w;
if (rx > window.innerWidth) {
rx = (rx - window.innerWidth);
d.w -= rx;
d2.w -= rx;
}
var ry = p2.y + d2.h;
if (ry > window.innerHeight) {
ry = (ry - window.innerHeight);
d.h -= ry;
d2.h -= ry;
}
if (square) {
if (d2.w < d2.h) {
s = d2.w;
if (minusH) {
p2.y += d2.h - s;
d.h = -(s);
} else {
d.h = s;
}
d2.h = s;
} else {
s = d2.h;
if (minusW) {
p2.x += d2.w - s;
d.w = -(s);
} else {
d.w = s;
}
d2.w = s;
}
}
// position
region.style.top = p2.y + 'px';
region.style.left = p2.x + 'px';
// dimention
region.style.width = d2.w + 'px';
region.style.height = d2.h + 'px';
$D(size);
size.appendChild($T(d2.w + ' × ' + d2.h));
// Sketch Switch
// size.appendChild($T('× / _ / ×'));
setStyle(size, {
'top' : to.y + 10 + 'px',
'left' : to.x + 10 + 'px'
});
}
function onMouseDown(e) {
cancel(e);
p = mouse(e);
region = doc.createElement('div');
setStyle(region, {
'background': '#888',
'opacity' : '0.5',
'position' : 'fixed',
'zIndex' : '999999999',
'top' : p.y + 'px',
'left' : p.x + 'px'
});
doc.body.appendChild(region);
size = $N('div', {
'class' : 'taberareloo_capture_size'
});
doc.body.appendChild(size);
doc.addEventListener('mousemove', onMouseMove, true);
doc.addEventListener('mouseup', onMouseUp, true);
win.addEventListener('keydown', onKeyDown, true);
win.addEventListener('keyup', onKeyUp, true);
}
function onKeyDown(e) {
cancel(e);
switch (keyString(e)) {
case 'SHIFT':
square = true;
return;
case 'SPACE':
moving = true;
return;
case 'ESCAPE':
finalize();
reject();
return;
}
}
function onKeyUp(e) {
cancel(e);
switch (keyString(e)) {
case 'SHIFT':
square = false;
return;
case 'SPACE':
moving = false;
return;
}
}
function onMouseUp(e) {
cancel(e);
var rect = region.getBoundingClientRect();
p = { x: Math.round(rect.left), y: Math.round(rect.top) };
finalize();
// FIXME: 暫定/左上方向への選択不可/クリックとのダブルインターフェース未実装
if (!d) {
reject();
return;
}
d.w = Math.abs(d.w);
d.h = Math.abs(d.h);
resolve({
position: p,
dimensions: d
});
}
function onClick(e) {
// リンククリックによる遷移を抑止する
cancel(e);
// mouseupよりも後にイベントが発生するため、ここで取り除く
doc.removeEventListener('click', onClick, true);
}
function finalize() {
doc.removeEventListener('mousedown', onMouseDown, true);
doc.removeEventListener('mousemove', onMouseMove, true);
doc.removeEventListener('mouseup', onMouseUp, true);
win.removeEventListener('keydown', onKeyDown, true);
win.removeEventListener('keyup', onKeyUp, true);
doc.documentElement.style.cursor = '';
region.parentNode.removeChild(region);
size.parentNode.removeChild(size);
style.parentNode.removeChild(style);
}
doc.addEventListener('mousedown', onMouseDown, true);
doc.addEventListener('click', onClick, true);
doc.defaultView.focus();
});
}
}, 'Photo - Capture');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment