var TegakiBrush = {
brushFn: function(x, y) {
var i, ctx, dest, data, len, kernel;
x = 0 | x;
y = 0 | y;
ctx = Tegaki.ghostCtx;
dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
data = dest.data;
kernel = this.kernel;
len = kernel.length;
i = 0;
while (i < len) {
data[i] = this.rgb[0]; ++i;
data[i] = this.rgb[1]; ++i;
data[i] = this.rgb[2]; ++i;
data[i] += kernel[i] * (1.0 - data[i] / 255); ++i;
}
ctx.putImageData(dest, x, y);
},
commit: function() {
Tegaki.activeCtx.drawImage(Tegaki.ghostCanvas, 0, 0);
Tegaki.ghostCtx.clearRect(0, 0,
Tegaki.ghostCanvas.width, Tegaki.ghostCanvas.height
);
},
draw: function(posX, posY, pt) {
var offset, mx, my, fromX, fromY, dx, dy, err, derr, step, stepAcc;
offset = this.center;
step = this.stepSize;
stepAcc = this.stepAcc;
if (pt === true) {
this.stepAcc = 0;
this.posX = posX;
this.posY = posY;
this.brushFn(posX - offset, posY - offset);
return;
}
fromX = this.posX;
fromY = this.posY;
if (fromX < posX) { dx = posX - fromX; mx = 1; }
else { dx = fromX - posX; mx = -1; }
if (fromY < posY) { dy = posY - fromY; my = 1; }
else { dy = fromY - posY; my = -1; }
err = (dx > dy ? dx : -dy) / 2;
dx = -dx;
while (true) {
++stepAcc;
if (stepAcc > step) {
this.brushFn(fromX - offset, fromY - offset);
stepAcc = 0;
}
if (fromX === posX && fromY === posY) {
break;
}
derr = err;
if (derr > dx) { err -= dy; fromX += mx; }
if (derr < dy) { err -= dx; fromY += my; }
}
this.stepAcc = stepAcc;
this.posX = posX;
this.posY = posY;
},
generateBrush: function() {
var i, size, r, brush, ctx, dest, data, len, sqd, sqlen, hs, col, row,
ecol, erow, a;
size = this.size * 2;
r = size / 2;
brush = T$.el('canvas');
brush.width = brush.height = size;
ctx = brush.getContext('2d');
dest = ctx.getImageData(0, 0, size, size);
data = dest.data;
len = size * size * 4;
sqlen = Math.sqrt(r * r);
hs = Math.round(r);
col = row = -hs;
i = 0;
while (i < len) {
if (col >= hs) {
col = -hs;
++row;
continue;
}
ecol = col;
erow = row;
if (ecol < 0) { ecol = -ecol; }
if (erow < 0) { erow = -erow; }
sqd = Math.sqrt(ecol * ecol + erow * erow);
if (sqd > sqlen) {
a = 0;
}
else {
a = sqd / sqlen;
a = (Math.exp(1 - 1 / a) / a);
a = 255 - ((0 | (a * 100 + 0.5)) / 100) * 255;
}
if (this.alphaDamp) {
a *= this.alpha * this.alphaDamp;
}
else {
a *= this.alpha;
}
data[i + 3] = a;
i += 4;
++col;
}
ctx.putImageData(dest, 0, 0);
this.center = r;
this.brushSize = size;
this.brush = brush;
this.kernel = data;
},
setSize: function(size, noBrush) {
this.size = size;
if (!noBrush) this.generateBrush();
this.stepSize = Math.floor(this.size * this.step);
},
setAlpha: function(alpha, noBrush) {
this.alpha = alpha;
if (!noBrush) this.generateBrush();
},
setColor: function(color, noBrush) {
this.rgb = Tegaki.hexToRgb(color);
if (!noBrush) this.generateBrush();
},
set: function() {
this.setAlpha(this.alpha, true);
this.setSize(this.size, true);
this.setColor(Tegaki.toolColor, true);
this.generateBrush();
}
};
var TegakiPen = {
init: function() {
this.size = 4;
this.alpha = 0.5;
this.step = 0.1;
this.stepAcc = 0;
},
draw: TegakiBrush.draw,
commit: TegakiBrush.commit,
brushFn: TegakiBrush.brushFn,
generateBrush: function() {
var size, r, brush, ctx;
size = this.size;
r = size / 2;
brush = T$.el('canvas');
brush.width = brush.height = size;
ctx = brush.getContext('2d');
ctx.globalAlpha = this.alpha;
ctx.beginPath();
ctx.arc(r, r, r, 0, Tegaki.TWOPI, false);
ctx.fillStyle = '#000000';
ctx.fill();
ctx.closePath();
this.center = r;
this.brushSize = size;
this.brush = brush;
this.kernel = ctx.getImageData(0, 0, this.brushSize, this.brushSize).data;
},
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiPipette = {
size: 1,
alpha: 1,
noCursor: true,
draw: function(posX, posY) {
var c, ctx;
if (true) {
ctx = Tegaki.flatten().getContext('2d');
}
else {
ctx = Tegaki.activeCtx;
}
c = Tegaki.getColorAt(ctx, posX, posY);
Tegaki.setToolColor(c);
Tegaki.updateUI('color');
}
};
var TegakiAirbrush = {
init: function() {
this.size = 32;
this.alpha = 0.5;
this.alphaDamp = 0.2;
this.step = 0.25;
this.stepAcc = 0;
},
draw: TegakiBrush.draw,
commit: TegakiBrush.commit,
brushFn: TegakiBrush.brushFn,
generateBrush: TegakiBrush.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiPencil = {
init: function() {
this.size = 1;
this.alpha = 1.0;
this.step = 0.25;
this.stepAcc = 0;
},
draw: TegakiBrush.draw,
commit: TegakiBrush.commit,
brushFn: function(x, y) {
var i, ctx, dest, data, len, kernel, a;
x = 0 | x;
y = 0 | y;
ctx = Tegaki.ghostCtx;
dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
data = dest.data;
kernel = this.kernel;
len = kernel.length;
a = this.alpha * 255;
i = 0;
while (i < len) {
data[i] = this.rgb[0]; ++i;
data[i] = this.rgb[1]; ++i;
data[i] = this.rgb[2]; ++i;
if (kernel[i] > 0) {
data[i] = a;
}
++i;
}
ctx.putImageData(dest, x, y);
},
generateBrush: TegakiPen.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiEraser = {
init: function() {
this.size = 8;
this.alpha = 1.0;
this.step = 0.25;
this.stepAcc = 0;
},
draw: TegakiBrush.draw,
brushFn: function(x, y) {
var i, ctx, dest, data, len, kernel;
x = 0 | x;
y = 0 | y;
ctx = Tegaki.activeCtx;
dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
data = dest.data;
kernel = this.kernel;
len = kernel.length;
for (i = 3; i < len; i += 4) {
if (kernel[i] > 0) {
data[i] = 0;
}
}
ctx.putImageData(dest, x, y);
},
generateBrush: TegakiPen.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiDodge = {
init: function() {
this.size = 24;
this.alpha = 0.25;
this.alphaDamp = 0.05;
this.step = 0.25;
this.stepAcc = 0;
},
brushFn: function(x, y) {
var i, a, aa, ctx, dest, data, len, kernel;
x = 0 | x;
y = 0 | y;
ctx = Tegaki.activeCtx;
dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
data = dest.data;
kernel = this.kernel;
len = kernel.length;
i = 0;
while (i < len) {
aa = kernel[i + 3] * 0.3;
a = 1 + kernel[i + 3] / 255;
data[i] = data[i] * a + aa; ++i;
data[i] = data[i] * a + aa; ++i;
data[i] = data[i] * a + aa; ++i;
++i;
}
ctx.putImageData(dest, x, y);
},
draw: TegakiBrush.draw,
generateBrush: TegakiBrush.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiBurn = {
init: TegakiDodge.init,
brushFn: function(x, y) {
var i, a, ctx, dest, data, len, kernel;
x = 0 | x;
y = 0 | y;
ctx = Tegaki.activeCtx;
dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
data = dest.data;
kernel = this.kernel;
len = kernel.length;
i = 0;
while (i < len) {
a = 1 - kernel[i + 3] / 255;
data[i] = data[i] * a; ++i;
data[i] = data[i] * a; ++i;
data[i] = data[i] * a; ++i;
++i;
}
ctx.putImageData(dest, x, y);
},
draw: TegakiBrush.draw,
generateBrush: TegakiDodge.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiBlur = {
init: TegakiDodge.init,
brushFn: function(x, y) {
var i, j, ctx, src, size, srcData, dest, destData, lim, kernel,
sx, sy, r, g, b, a, aa, acc, kx, ky;
x = 0 | x;
y = 0 | y;
size = this.brushSize;
ctx = Tegaki.activeCtx;
src = ctx.getImageData(x, y, size, size);
srcData = src.data;
dest = ctx.createImageData(size, size);
destData = dest.data;
kernel = this.kernel;
lim = size - 1;
for (sx = 0; sx < size; ++sx) {
for (sy = 0; sy < size; ++sy) {
r = g = b = a = acc = 0;
i = (sy * size + sx) * 4;
if (kernel[(sy * size + sx) * 4 + 3] === 0
|| sx === 0 || sy === 0 || sx === lim || sy === lim) {
destData[i] = srcData[i]; ++i;
destData[i] = srcData[i]; ++i;
destData[i] = srcData[i]; ++i;
destData[i] = srcData[i];
continue;
}
for (kx = -1; kx < 2; ++kx) {
for (ky = -1; ky < 2; ++ky) {
j = ((sy - ky) * size + (sx - kx)) * 4;
aa = srcData[j + 3];
acc += aa;
r += srcData[j] * aa; ++j;
g += srcData[j] * aa; ++j;
b += srcData[j] * aa; ++j;
a += srcData[j];
}
}
destData[i] = r / acc; ++i;
destData[i] = g / acc; ++i;
destData[i] = b / acc; ++i;
destData[i] = a / 9;
}
}
ctx.putImageData(dest, x, y);
},
draw: TegakiBrush.draw,
generateBrush: TegakiDodge.generateBrush,
setSize: TegakiBrush.setSize,
setAlpha: TegakiBrush.setAlpha,
setColor: TegakiBrush.setColor,
set: TegakiBrush.set
};
var TegakiHistory = {
maxSize: 10,
undoStack: [],
redoStack: [],
pendingAction: null,
clear: function() {
this.undoStack = [];
this.redoStack = [];
this.pendingAction = null;
},
push: function(action) {
this.undoStack.push(action);
if (this.undoStack.length > this.maxSize) {
this.undoStack.shift();
}
if (this.redoStack.length > 0) {
this.redoStack = [];
}
},
undo: function() {
var action;
if (!this.undoStack.length) {
return;
}
action = this.undoStack.pop();
action.undo();
this.redoStack.push(action);
},
redo: function() {
var action;
if (!this.redoStack.length) {
return;
}
action = this.redoStack.pop();
action.redo();
this.undoStack.push(action);
}
};
var TegakiHistoryActions = {
Draw: function(layerId) {
this.canvasBefore = null;
this.canvasAfter = null;
this.layerId = layerId;
},
DestroyLayers: function(indices, layers) {
this.indices = indices;
this.layers = layers;
this.canvasBefore = null;
this.canvasAfter = null;
this.layerId = null;
},
AddLayer: function(layerId) {
this.layerId = layerId;
},
MoveLayer: function(layerId, up) {
this.layerId = layerId;
this.up = up;
}
};
TegakiHistoryActions.Draw.prototype.addCanvasState = function(canvas, type) {
if (type) {
this.canvasAfter = T$.copyCanvas(canvas);
}
else {
this.canvasBefore = T$.copyCanvas(canvas);
}
};
TegakiHistoryActions.Draw.prototype.exec = function(type) {
var i, layer;
for (i in Tegaki.layers) {
layer = Tegaki.layers[i];
if (layer.id === this.layerId) {
layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
layer.ctx.drawImage(type ? this.canvasAfter: this.canvasBefore, 0, 0);
}
}
};
TegakiHistoryActions.Draw.prototype.undo = function() {
this.exec(0);
};
TegakiHistoryActions.Draw.prototype.redo = function() {
this.exec(1);
};
TegakiHistoryActions.DestroyLayers.prototype.undo = function() {
var i, ii, len, layers, idx, layer, frag;
layers = new Array(len);
for (i = 0; (idx = this.indices[i]) !== undefined; ++i) {
layers[idx] = this.layers[i];
}
i = ii = 0;
len = Tegaki.layers.length + this.layers.length;
frag = T$.frag();
while (i < len) {
if (!layers[i]) {
layer = layers[i] = Tegaki.layers[ii];
Tegaki.layersCnt.removeChild(layer.canvas);
++ii;
}
if (this.layerId && layer.id === this.layerId) {
layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
layer.ctx.drawImage(this.canvasBefore, 0, 0);
}
frag.appendChild(layers[i].canvas);
++i;
}
Tegaki.layersCnt.insertBefore(frag, Tegaki.canvas.nextElementSibling);
Tegaki.layers = layers;
Tegaki.setActiveLayer();
Tegaki.rebuildLayerCtrl();
};
TegakiHistoryActions.DestroyLayers.prototype.redo = function() {
var i, layer, ids = [];
for (i = 0; layer = this.layers[i]; ++i) {
ids.push(layer.id);
}
if (this.layerId) {
ids.push(this.layerId);
Tegaki.mergeLayers(ids);
}
else {
Tegaki.deleteLayers(ids);
}
};
TegakiHistoryActions.MoveLayer.prototype.undo = function() {
Tegaki.setActiveLayer(this.layerId);
Tegaki.moveLayer(this.layerId, !this.up);
};
TegakiHistoryActions.MoveLayer.prototype.redo = function() {
Tegaki.setActiveLayer(this.layerId);
Tegaki.moveLayer(this.layerId, this.up);
};
TegakiHistoryActions.AddLayer.prototype.undo = function() {
Tegaki.deleteLayers([this.layerId]);
Tegaki.layerIndex--;
};
TegakiHistoryActions.AddLayer.prototype.redo = function() {
Tegaki.addLayer();
Tegaki.setActiveLayer();
};
var T$ = {
docEl: document.documentElement,
id: function(id) {
return document.getElementById(id);
},
cls: function(klass, root) {
return (root || document).getElementsByClassName(klass);
},
on: function(o, e, h) {
o.addEventListener(e, h, false);
},
off: function(o, e, h) {
o.removeEventListener(e, h, false);
},
el: function(name) {
return document.createElement(name);
},
frag: function() {
return document.createDocumentFragment();
},
extend: function(destination, source) {
for (var key in source) {
destination[key] = source[key];
}
},
selectedOptions: function(el) {
var i, opt, sel;
if (el.selectedOptions) {
return el.selectedOptions;
}
sel = [];
for (i = 0; opt = el.options[i]; ++i) {
if (opt.selected) {
sel.push(opt);
}
}
return sel;
},
copyCanvas: function(source) {
var canvas = T$.el('canvas');
canvas.width = source.width;
canvas.height = source.height;
canvas.getContext('2d').drawImage(source, 0, 0);
return canvas;
}
};
var TegakiStrings = {
// Messages
badDimensions: 'Invalid dimensions.',
promptWidth: 'Canvas width in pixels',
promptHeight: 'Canvas height in pixels',
confirmDelLayers: 'Delete selected layers?',
errorMergeOneLayer: 'You need to select at least 2 layers.',
confirmMergeLayers: 'Merge selected layers?',
errorLoadImage: 'Could not load the image.',
noActiveLayer: 'No active layer.',
hiddenActiveLayer: 'The active layer is not visible.',
confirmCancel: 'Are you sure? Your work will be lost.',
confirmChangeCanvas: 'Changing the canvas will clear all layers and history.',
// UI
color: 'Color',
size: 'Size',
alpha: 'Opacity',
layers: 'Layers',
addLayer: 'Add layer',
delLayers: 'Delete layers',
mergeLayers: 'Merge layers',
showHideLayer: 'Toggle visibility',
moveLayerUp: 'Move up',
moveLayerDown: 'Move down',
tool: 'Tool',
changeCanvas: 'Change canvas',
blank: 'Blank',
newCanvas: 'New',
undo: 'Undo',
redo: 'Redo',
close: 'Close',
finish: 'Finish',
// Tools
pen: 'Pen',
pencil: 'Pencil',
airbrush: 'Airbrush',
pipette: 'Pipette',
dodge: 'Dodge',
burn: 'Burn',
blur: 'Blur',
eraser: 'Eraser'
};
var Tegaki = {
VERSION: '0.0.1',
bg: null,
cnt: null,
canvas: null,
ctx: null,
layers: [],
layersCnt: null,
ghostCanvas: null,
ghostCtx: null,
activeCtx: null,
activeLayer: null,
layerIndex: null,
isPainting: false,
isErasing: false,
isColorPicking: false,
offsetX: 0,
offsetY: 0,
TWOPI: 2 * Math.PI,
tools: {
pencil: TegakiPencil,
pen: TegakiPen,
airbrush: TegakiAirbrush,
pipette: TegakiPipette,
dodge: TegakiDodge,
burn: TegakiBurn,
blur: TegakiBlur,
eraser: TegakiEraser
},
tool: null,
toolColor: '#000000',
bgColor: '#ffffff',
maxSize: 32,
maxLayers: 25,
baseWidth: null,
baseHeight: null,
onDoneCb: null,
onCancelCb: null,
open: function(opts) {
var bg, cnt, el, el2, tool, lbl, btn, ctrl, canvas, grp, self = Tegaki;
if (self.bg) {
self.resume();
return;
}
if (opts.bgColor) {
self.bgColor = opts.bgColor;
}
self.onDoneCb = opts.onDone;
self.onCancelCb = opts.onCancel;
cnt = T$.el('div');
cnt.id = 'tegaki-cnt';
canvas = T$.el('canvas');
canvas.id = 'tegaki-canvas';
canvas.width = self.baseWidth = opts.width;
canvas.height = self.baseHeight = opts.height;
el = T$.el('div');
el.id = 'tegaki-layers';
el.appendChild(canvas);
self.layersCnt = el;
cnt.appendChild(el);
ctrl = T$.el('div');
ctrl.id = 'tegaki-ctrl';
// Colorpicker
grp = T$.el('div');
grp.className = 'tegaki-ctrlgrp';
el = T$.el('input');
el.id = 'tegaki-color';
el.value = self.toolColor;
try {
el.type = 'color';
} catch(e) {
el.type = 'text';
}
lbl = T$.el('div');
lbl.className = 'tegaki-label';
lbl.textContent = TegakiStrings.color;
grp.appendChild(lbl);
T$.on(el, 'change', self.onColorChange);
grp.appendChild(el);
ctrl.appendChild(grp);
// Size control
grp = T$.el('div');
grp.className = 'tegaki-ctrlgrp';
el = T$.el('input');
el.id = 'tegaki-size';
el.min = 1;
el.max = self.maxSize;
el.type = 'range';
lbl = T$.el('div');
lbl.className = 'tegaki-label';
lbl.textContent = TegakiStrings.size;
grp.appendChild(lbl);
T$.on(el, 'change', self.onSizeChange);
grp.appendChild(el);
ctrl.appendChild(grp);
// Alpha control
grp = T$.el('div');
grp.className = 'tegaki-ctrlgrp';
el = T$.el('input');
el.id = 'tegaki-alpha';
el.min = 0;
el.max = 1;
el.step = 0.01;
el.type = 'range';
lbl = T$.el('div');
lbl.className = 'tegaki-label';
lbl.textContent = TegakiStrings.alpha;
grp.appendChild(lbl);
T$.on(el, 'change', self.onAlphaChange);
grp.appendChild(el);
ctrl.appendChild(grp);
// Layer control
grp = T$.el('div');
grp.className = 'tegaki-ctrlgrp';
grp.id = 'tegaki-layer-grp';
el = T$.el('select');
el.id = 'tegaki-layer';
el.multiple = true;
el.size = 3;
lbl = T$.el('div');
lbl.className = 'tegaki-label';
lbl.textContent = TegakiStrings.layers;
grp.appendChild(lbl);
T$.on(el, 'change', self.onLayerChange);
grp.appendChild(el);
el = T$.el('span');
el.title = TegakiStrings.addLayer;
el.className = 'tegaki-icon tegaki-plus';
T$.on(el, 'click', self.onLayerAdd);
grp.appendChild(el);
el = T$.el('span');
el.title = TegakiStrings.delLayers;
el.className = 'tegaki-icon tegaki-minus';
T$.on(el, 'click', self.onLayerDelete);
grp.appendChild(el);
el = T$.el('span');
el.id = 'tegaki-layer-visibility';
el.title = TegakiStrings.showHideLayer;
el.className = 'tegaki-icon tegaki-eye';
T$.on(el, 'click', self.onLayerVisibilityChange);
grp.appendChild(el);
el = T$.el('span');
el.id = 'tegaki-layer-merge';
el.title = TegakiStrings.mergeLayers;
el.className = 'tegaki-icon tegaki-level-down';
T$.on(el, 'click', self.onMergeLayers);
grp.appendChild(el);
el = T$.el('span');
el.id = 'tegaki-layer-up';
el.title = TegakiStrings.moveLayerUp;
el.setAttribute('data-up', '1');
el.className = 'tegaki-icon tegaki-up-open';
T$.on(el, 'click', self.onMoveLayer);
grp.appendChild(el);
el = T$.el('span');
el.id = 'tegaki-layer-down';
el.title = TegakiStrings.moveLayerDown;
el.className = 'tegaki-icon tegaki-down-open';
T$.on(el, 'click', self.onMoveLayer);
grp.appendChild(el);
ctrl.appendChild(grp);
// Tool selector
grp = T$.el('div');
grp.className = 'tegaki-ctrlgrp';
el = T$.el('select');
el.id = 'tegaki-tool';
for (tool in Tegaki.tools) {
el2 = T$.el('option');
el2.value = tool;
el2.textContent = TegakiStrings[tool];
el.appendChild(el2);
}
lbl = T$.el('div');
lbl.className = 'tegaki-label';
lbl.textContent = TegakiStrings.tool;
grp.appendChild(lbl);
T$.on(el, 'change', self.onToolChange);
grp.appendChild(el);
ctrl.appendChild(grp);
cnt.appendChild(ctrl);
el = T$.el('div');
el.id = 'tegaki-menu-bar';
if (opts.canvasOptions) {
btn = T$.el('select');
btn.id = 'tegaki-canvas-select';
btn.title = TegakiStrings.changeCanvas;
btn.innerHTML = '<option value="0">' + TegakiStrings.blank + '</option>';
opts.canvasOptions(btn);
T$.on(btn, 'change', Tegaki.onCanvasSelected);
T$.on(btn, 'focus', Tegaki.onCanvasSelectFocused);
el.appendChild(btn);
}
btn = T$.el('span');
btn.className = 'tegaki-tb-btn';
btn.textContent = TegakiStrings.newCanvas;
T$.on(btn, 'click', Tegaki.onNewClick);
el.appendChild(btn);
btn = T$.el('span');
btn.className = 'tegaki-tb-btn';
btn.textContent = TegakiStrings.undo;
T$.on(btn, 'click', Tegaki.onUndoClick);
el.appendChild(btn);
btn = T$.el('span');
btn.className = 'tegaki-tb-btn';
btn.textContent = TegakiStrings.redo;
T$.on(btn, 'click', Tegaki.onRedoClick);
el.appendChild(btn);
btn = T$.el('span');
btn.className = 'tegaki-tb-btn';
btn.textContent = TegakiStrings.close;
T$.on(btn, 'click', Tegaki.onCancelClick);
el.appendChild(btn);
btn = T$.el('span');
btn.id = 'tegaki-finish-btn';
btn.className = 'tegaki-tb-btn';
btn.textContent = TegakiStrings.finish;
T$.on(btn, 'click', Tegaki.onDoneClick);
el.appendChild(btn);
cnt.appendChild(el);
bg = T$.el('div');
bg.id = 'tegaki';
self.bg = bg;
bg.appendChild(cnt);
document.body.appendChild(bg);
document.body.classList.add('tegaki-backdrop');
el = T$.el('canvas');
el.id = 'tegaki-ghost-layer';
el.width = canvas.width;
el.height = canvas.height;
self.ghostCanvas = el;
self.ghostCtx = el.getContext('2d');
self.cnt = cnt;
self.centerCnt();
self.canvas = canvas;
self.ctx = canvas.getContext('2d');
self.ctx.fillStyle = self.bgColor;
self.ctx.fillRect(0, 0, opts.width, opts.height);
self.addLayer();
self.setActiveLayer();
self.initTools();
self.setTool('pencil');
self.updateUI();
self.updateCursor();
self.updatePosOffset();
T$.on(self.bg, 'mousemove', self.onMouseMove);
T$.on(self.bg, 'mousedown', self.onMouseDown);
T$.on(self.layersCnt, 'contextmenu', self.onDummy);
T$.on(document, 'mouseup', self.onMouseUp);
T$.on(window, 'resize', self.updatePosOffset);
T$.on(window, 'scroll', self.updatePosOffset);
},
initTools: function() {
var tool;
for (tool in Tegaki.tools) {
(tool = Tegaki.tools[tool]) && tool.init && tool.init();
}
},
hexToRgb: function(hex) {
var c = hex.match(/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i);
if (c) {
return [
parseInt(c[1], 16),
parseInt(c[2], 16),
parseInt(c[3], 16)
];
}
return null;
},
centerCnt: function() {
var aabb, cnt;
cnt = Tegaki.cnt;
aabb = cnt.getBoundingClientRect();
if (aabb.width > T$.docEl.clientWidth || aabb.height > T$.docEl.clientHeight) {
if (aabb.width > T$.docEl.clientWidth) {
cnt.classList.add('tegaki-overflow-x');
}
if (aabb.height > T$.docEl.clientHeight) {
cnt.classList.add('tegaki-overflow-y');
}
}
else {
cnt.classList.remove('tegaki-overflow-x');
cnt.classList.remove('tegaki-overflow-y');
}
cnt.style.marginTop = -Math.round(aabb.height / 2) + 'px';
cnt.style.marginLeft = -Math.round(aabb.width / 2) + 'px';
},
getCursorPos: function(e, axis) {
if (axis === 0) {
return e.clientX + window.pageXOffset + Tegaki.bg.scrollLeft - Tegaki.offsetX;
}
else {
return e.clientY + window.pageYOffset + Tegaki.bg.scrollTop - Tegaki.offsetY;
}
},
resume: function() {
Tegaki.bg.classList.remove('tegaki-hidden');
document.body.classList.add('tegaki-backdrop');
Tegaki.centerCnt();
Tegaki.updatePosOffset();
T$.on(document, 'mouseup', Tegaki.onMouseUp);
T$.on(window, 'resize', Tegaki.updatePosOffset);
T$.on(window, 'scroll', Tegaki.updatePosOffset);
},
hide: function() {
Tegaki.bg.classList.add('tegaki-hidden');
document.body.classList.remove('tegaki-backdrop');
T$.off(document, 'mouseup', Tegaki.onMouseUp);
T$.off(window, 'resize', Tegaki.updatePosOffset);
T$.off(window, 'scroll', Tegaki.updatePosOffset);
},
destroy: function() {
T$.off(Tegaki.bg, 'mousemove', Tegaki.onMouseMove);
T$.off(Tegaki.bg, 'mousedown', Tegaki.onMouseDown);
T$.off(Tegaki.layersCnt, 'contextmenu', Tegaki.onDummy);
T$.off(document, 'mouseup', Tegaki.onMouseUp);
T$.off(window, 'resize', Tegaki.updatePosOffset);
T$.off(window, 'scroll', Tegaki.updatePosOffset);
Tegaki.bg.parentNode.removeChild(Tegaki.bg);
TegakiHistory.clear();
document.body.classList.remove('tegaki-backdrop');
Tegaki.bg = null;
Tegaki.cnt = null;
Tegaki.canvas = null;
Tegaki.ctx = null;
Tegaki.layers = [];
Tegaki.layerIndex = 0;
Tegaki.activeCtx = null;
},
flatten: function() {
var i, layer, canvas, ctx;
canvas = T$.el('canvas');
canvas.width = Tegaki.canvas.width;
canvas.height = Tegaki.canvas.height;
ctx = canvas.getContext('2d');
ctx.drawImage(Tegaki.canvas, 0, 0);
for (i = 0; layer = Tegaki.layers[i]; ++i) {
if (layer.canvas.classList.contains('tegaki-hidden')) {
continue;
}
ctx.drawImage(layer.canvas, 0, 0);
}
return canvas;
},
updateUI: function(type) {
var i, ary, el, tool = Tegaki.tool;
ary = type ? [type] : ['size', 'alpha', 'color'];
for (i = 0; type = ary[i]; ++i) {
el = T$.id('tegaki-' + type);
el.value = type === 'color' ? Tegaki.toolColor : tool[type];
if (el.type === 'range') {
el.previousElementSibling.setAttribute('data-value', tool[type]);
}
}
},
rebuildLayerCtrl: function() {
var i, layer, sel, opt;
sel = T$.id('tegaki-layer');
sel.textContent = '';
for (i = Tegaki.layers.length - 1; layer = Tegaki.layers[i]; i--) {
opt = T$.el('option');
opt.value = layer.id;
opt.textContent = layer.name;
sel.appendChild(opt);
}
},
getColorAt: function(ctx, posX, posY) {
var rgba = ctx.getImageData(posX, posY, 1, 1).data;
return '#'
+ ('0' + rgba[0].toString(16)).slice(-2)
+ ('0' + rgba[1].toString(16)).slice(-2)
+ ('0' + rgba[2].toString(16)).slice(-2);
},
renderCircle: function(r) {
var i, canvas, ctx, d, e, x, y, dx, dy, idata, data, c, color;
e = 1 - r;
dx = 0;
dy = -2 * r;
x = 0;
y = r;
d = 33;
c = 16;
canvas = T$.el('canvas');
canvas.width = canvas.height = d;
ctx = canvas.getContext('2d');
idata = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
data = idata.data;
color = 255;
data[(c + (c + r) * d) * 4 + 3] = color;
data[(c + (c - r) * d) * 4 + 3] = color;
data[(c + r + c * d) * 4 + 3] = color;
data[(c - r + c * d) * 4 + 3] = color;
while (x < y) {
if (e >= 0) {
y--;
dy += 2;
e += dy;
}
++x;
dx += 2;
e += dx;
data[(c + x + (c + y) * d) * 4 + 3] = color;
data[(c - x + (c + y) * d) * 4 + 3] = color;
data[(c + x + (c - y) * d) * 4 + 3] = color;
data[(c - x + (c - y) * d) * 4 + 3] = color;
data[(c + y + (c + x) * d) * 4 + 3] = color;
data[(c - y + (c + x) * d) * 4 + 3] = color;
data[(c + y + (c - x) * d) * 4 + 3] = color;
data[(c - y + (c - x) * d) * 4 + 3] = color;
}
if (r > 0) {
for (i = 0; i < 3; ++i) {
data[(c + c * d) * 4 + i] = 127;
}
data[(c + c * d) * 4 + i] = color;
}
ctx.putImageData(idata, 0, 0);
return canvas;
},
setToolSize: function(size) {
Tegaki.tool.setSize && Tegaki.tool.setSize(size);
Tegaki.updateCursor();
},
setToolAlpha: function(alpha) {
Tegaki.tool.setAlpha && Tegaki.tool.setAlpha(alpha);
},
setToolColor: function(color) {
Tegaki.toolColor = color;
Tegaki.tool.setColor && Tegaki.tool.setColor(color);
Tegaki.updateCursor();
},
setTool: function(tool) {
tool = Tegaki.tools[tool];
Tegaki.tool = tool;
tool.set && tool.set();
},
debugDumpPixelData: function(canvas) {
var i, idata, data, len, out, el;
idata = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
data = idata.data;
len = data.length;
out = '';
for (i = 0; i < len; i += 4) {
out += data[i] + ' ' + data[i+1] + ' ' + data[i+2] + ' ' + data[i+3] + '%0a';
}
el = document.createElement('a');
el.href = 'data:,' + out;
el.download = 'dump.txt';
document.body.appendChild(el);
el.click();
document.body.removeChild(el);
},
debugDrawColors: function(sat) {
var i, ctx, grad, a;
Tegaki.resizeCanvas(360, 360);
ctx = Tegaki.activeCtx;
a = ctx.globalAlpha;
ctx.globalAlpha = 1;
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, 360, 360);
for (i = 0; i < 360; ++i) {
if (sat) {
grad = ctx.createLinearGradient(0, 0, 10, 360);
grad.addColorStop(0, 'hsl(' + i + ', 0%, ' + '50%)');
grad.addColorStop(1, 'hsl(' + i + ', 100%, ' + '50%)');
ctx.strokeStyle = grad;
}
else {
ctx.strokeStyle = 'hsl(' + i + ', 100%, ' + '50%)';
}
ctx.beginPath();
ctx.moveTo(i, 0);
ctx.lineTo(i, 360);
ctx.stroke();
ctx.closePath();
}
if (!sat) {
grad = ctx.createLinearGradient(0, 0, 10, 360);
grad.addColorStop(0, '#000000');
grad.addColorStop(1, 'rgba(0,0,0,0)');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, 360, 360);
}
ctx.globalAlpha = a;
},
onNewClick: function() {
var width, height, tmp;
width = prompt(TegakiStrings.promptWidth, Tegaki.canvas.width);
if (!width) { return; }
height = prompt(TegakiStrings.promptHeight, Tegaki.canvas.height);
if (!height) { return; }
width = +width;
height = +height;
if (width < 1 || height < 1) {
alert(TegakiStrings.badDimensions);
return;
}
tmp = {};
Tegaki.copyContextState(Tegaki.activeCtx, tmp);
Tegaki.resizeCanvas(width, height);
Tegaki.copyContextState(tmp, Tegaki.activeCtx);
TegakiHistory.clear();
Tegaki.centerCnt();
Tegaki.updatePosOffset();
},
onUndoClick: function() {
TegakiHistory.undo();
},
onRedoClick: function() {
TegakiHistory.redo();
},
onDoneClick: function() {
Tegaki.hide();
Tegaki.onDoneCb();
},
onCancelClick: function() {
if (!confirm(TegakiStrings.confirmCancel)) {
return;
}
Tegaki.destroy();
Tegaki.onCancelCb();
},
onColorChange: function() {
Tegaki.setToolColor(this.value);
},
onSizeChange: function() {
this.previousElementSibling.setAttribute('data-value', this.value);
Tegaki.setToolSize(+this.value);
},
onAlphaChange: function() {
this.previousElementSibling.setAttribute('data-value', this.value);
Tegaki.setToolAlpha(+this.value);
},
onLayerChange: function() {
var selectedOptions = T$.selectedOptions(this);
if (selectedOptions.length > 1) {
Tegaki.activeLayer = null;
}
else {
Tegaki.setActiveLayer(+this.value);
}
},
onLayerAdd: function() {
TegakiHistory.push(Tegaki.addLayer());
Tegaki.setActiveLayer();
},
onLayerDelete: function() {
var i, ary, sel, opt, selectedOptions, action;
sel = T$.id('tegaki-layer');
selectedOptions = T$.selectedOptions(sel);
if (Tegaki.layers.length === selectedOptions.length) {
return;
}
if (!confirm(TegakiStrings.confirmDelLayers)) {
return;
}
if (selectedOptions.length > 1) {
ary = [];
for (i = 0; opt = selectedOptions[i]; ++i) {
ary.push(+opt.value);
}
}
else {
ary = [+sel.value];
}
action = Tegaki.deleteLayers(ary);
TegakiHistory.push(action);
},
onLayerVisibilityChange: function() {
var i, ary, sel, opt, flag, selectedOptions;
sel = T$.id('tegaki-layer');
selectedOptions = T$.selectedOptions(sel);
if (selectedOptions.length > 1) {
ary = [];
for (i = 0; opt = selectedOptions[i]; ++i) {
ary.push(+opt.value);
}
}
else {
ary = [+sel.value];
}
flag = !Tegaki.getLayerById(ary[0]).visible;
Tegaki.setLayerVisibility(ary, flag);
},
onMergeLayers: function() {
var i, ary, sel, opt, selectedOptions, action;
sel = T$.id('tegaki-layer');
selectedOptions = T$.selectedOptions(sel);
if (selectedOptions.length > 1) {
ary = [];
for (i = 0; opt = selectedOptions[i]; ++i) {
ary.push(+opt.value);
}
}
else {
ary = [+sel.value];
}
if (ary.length < 2) {
alert(TegakiStrings.errorMergeOneLayer);
return;
}
if (!confirm(TegakiStrings.confirmMergeLayers)) {
return;
}
action = Tegaki.mergeLayers(ary);
TegakiHistory.push(action);
},
onMoveLayer: function(e) {
var id, action, sel;
sel = T$.id('tegaki-layer');
id = +sel.options[sel.selectedIndex].value;
if (action = Tegaki.moveLayer(id, e.target.hasAttribute('data-up'))) {
TegakiHistory.push(action);
}
},
onToolChange: function() {
Tegaki.setTool(this.value);
Tegaki.updateUI();
Tegaki.updateCursor();
},
onCanvasSelected: function() {
var img;
if (!confirm(TegakiStrings.confirmChangeCanvas)) {
this.selectedIndex = +this.getAttribute('data-current');
return;
}
if (this.value === '0') {
Tegaki.ctx.fillStyle = Tegaki.bgColor;
Tegaki.ctx.fillRect(0, 0, Tegaki.baseWidth, Tegaki.baseHeight);
}
else {
img = T$.el('img');
img.onload = Tegaki.onImageLoaded;
img.onerror = Tegaki.onImageError;
this.disabled = true;
img.src = this.value;
}
},
onImageLoaded: function() {
var el, tmp = {};
el = T$.id('tegaki-canvas-select');
el.setAttribute('data-current', el.selectedIndex);
el.disabled = false;
Tegaki.copyContextState(Tegaki.activeCtx, tmp);
Tegaki.resizeCanvas(this.naturalWidth, this.naturalHeight);
Tegaki.activeCtx.drawImage(this, 0, 0);
Tegaki.copyContextState(tmp, Tegaki.activeCtx);
TegakiHistory.clear();
Tegaki.centerCnt();
Tegaki.updatePosOffset();
},
onImageError: function() {
var el;
el = T$.id('tegaki-canvas-select');
el.selectedIndex = +el.getAttribute('data-current');
el.disabled = false;
alert(TegakiStrings.errorLoadImage);
},
resizeCanvas: function(width, height) {
var i, layer;
Tegaki.canvas.width = width;
Tegaki.canvas.height = height;
Tegaki.ghostCanvas.width = width;
Tegaki.ghostCanvas.height = height;
Tegaki.ctx.fillStyle = Tegaki.bgColor;
Tegaki.ctx.fillRect(0, 0, width, height);
for (i = 0; layer = Tegaki.layers[i]; ++i) {
Tegaki.layersCnt.removeChild(layer.canvas);
}
Tegaki.activeCtx = null;
Tegaki.layers = [];
Tegaki.layerIndex = 0;
T$.id('tegaki-layer').textContent = '';
Tegaki.addLayer();
Tegaki.setActiveLayer();
},
getLayerIndex: function(id) {
var i, layer, layers = Tegaki.layers;
for (i = 0; layer = layers[i]; ++i) {
if (layer.id === id) {
return i;
}
}
return -1;
},
getLayerById: function(id) {
return Tegaki.layers[Tegaki.getLayerIndex(id)];
},
addLayer: function() {
var id, cnt, opt, canvas, layer, nodes, last;
canvas = T$.el('canvas');
canvas.className = 'tegaki-layer';
canvas.width = Tegaki.canvas.width;
canvas.height = Tegaki.canvas.height;
id = ++Tegaki.layerIndex;
layer = {
id: id,
name: 'Layer ' + id,
canvas: canvas,
ctx: canvas.getContext('2d'),
visible: true,
empty: true,
opacity: 1.0
};
Tegaki.layers.push(layer);
cnt = T$.id('tegaki-layer');
opt = T$.el('option');
opt.value = layer.id;
opt.textContent = layer.name;
cnt.insertBefore(opt, cnt.firstElementChild);
nodes = T$.cls('tegaki-layer', Tegaki.layersCnt);
if (nodes.length) {
last = nodes[nodes.length - 1];
}
else {
last = Tegaki.canvas;
}
Tegaki.layersCnt.insertBefore(canvas, last.nextElementSibling);
return new TegakiHistoryActions.AddLayer(id);
},
deleteLayers: function(ids) {
var i, id, len, sel, idx, indices, layers;
sel = T$.id('tegaki-layer');
indices = [];
layers = [];
for (i = 0, len = ids.length; i < len; ++i) {
id = ids[i];
idx = Tegaki.getLayerIndex(id);
sel.removeChild(sel.options[Tegaki.layers.length - 1 - idx]);
Tegaki.layersCnt.removeChild(Tegaki.layers[idx].canvas);
indices.push(idx);
layers.push(Tegaki.layers[idx]);
Tegaki.layers.splice(idx, 1);
}
Tegaki.setActiveLayer();
return new TegakiHistoryActions.DestroyLayers(indices, layers);
},
mergeLayers: function(ids) {
var i, id, sel, idx, canvasBefore, destId, dest, action;
sel = T$.id('tegaki-layer');
destId = ids.pop();
idx = Tegaki.getLayerIndex(destId);
dest = Tegaki.layers[idx].ctx;
canvasBefore = T$.copyCanvas(Tegaki.layers[idx].canvas);
for (i = ids.length - 1; i >= 0; i--) {
id = ids[i];
idx = Tegaki.getLayerIndex(id);
dest.drawImage(Tegaki.layers[idx].canvas, 0, 0);
}
action = Tegaki.deleteLayers(ids);
action.layerId = destId;
action.canvasBefore = canvasBefore;
action.canvasAfter = T$.copyCanvas(dest.canvas);
Tegaki.setActiveLayer(destId);
return action;
},
moveLayer: function(id, up) {
var idx, sel, opt, canvas, tmp, tmpId;
sel = T$.id('tegaki-layer');
idx = Tegaki.getLayerIndex(id);
canvas = Tegaki.layers[idx].canvas;
opt = sel.options[Tegaki.layers.length - 1 - idx];
if (up) {
if (!Tegaki.ghostCanvas.nextElementSibling) { return false; }
canvas.parentNode.insertBefore(canvas,
Tegaki.ghostCanvas.nextElementSibling.nextElementSibling
);
opt.parentNode.insertBefore(opt, opt.previousElementSibling);
tmpId = idx + 1;
}
else {
if (canvas.previousElementSibling.id === 'tegaki-canvas') { return false; }
canvas.parentNode.insertBefore(canvas, canvas.previousElementSibling);
opt.parentNode.insertBefore(opt, opt.nextElementSibling.nextElementSibling);
tmpId = idx - 1;
}
Tegaki.updateGhostLayerPos();
tmp = Tegaki.layers[tmpId];
Tegaki.layers[tmpId] = Tegaki.layers[idx];
Tegaki.layers[idx] = tmp;
Tegaki.activeLayer = tmpId;
return new TegakiHistoryActions.MoveLayer(id, up);
},
setLayerVisibility: function(ids, flag) {
var i, len, sel, idx, layer, optIdx;
sel = T$.id('tegaki-layer');
optIdx = Tegaki.layers.length - 1;
for (i = 0, len = ids.length; i < len; ++i) {
idx = Tegaki.getLayerIndex(ids[i]);
layer = Tegaki.layers[idx];
layer.visible = flag;
if (flag) {
sel.options[optIdx - idx].classList.remove('tegaki-strike');
layer.canvas.classList.remove('tegaki-hidden');
}
else {
sel.options[optIdx - idx].classList.add('tegaki-strike');
layer.canvas.classList.add('tegaki-hidden');
}
}
},
setActiveLayer: function(id) {
var ctx, idx;
idx = id ? Tegaki.getLayerIndex(id) : Tegaki.layers.length - 1;
if (idx < 0 || idx > Tegaki.maxLayers) {
return;
}
ctx = Tegaki.layers[idx].ctx;
if (Tegaki.activeCtx) {
Tegaki.copyContextState(Tegaki.activeCtx, ctx);
}
Tegaki.activeCtx = ctx;
Tegaki.activeLayer = idx;
T$.id('tegaki-layer').selectedIndex = Tegaki.layers.length - idx - 1;
Tegaki.updateGhostLayerPos();
},
updateGhostLayerPos: function() {
Tegaki.layersCnt.insertBefore(
Tegaki.ghostCanvas,
Tegaki.activeCtx.canvas.nextElementSibling
);
},
copyContextState: function(src, dest) {
var i, p, props = [
'lineCap', 'lineJoin', 'strokeStyle', 'fillStyle', 'globalAlpha',
'lineWidth', 'globalCompositeOperation'
];
for (i = 0; p = props[i]; ++i) {
dest[p] = src[p];
}
},
updateCursor: function() {
var radius;
radius = 0 | (Tegaki.tool.size / 2);
if (Tegaki.tool.noCursor || radius < 1) {
Tegaki.layersCnt.style.cursor = 'default';
return;
}
Tegaki.layersCnt.style.cursor = 'url("'
+ Tegaki.renderCircle(radius).toDataURL('image/png')
+ '") 16 16, default';
},
updatePosOffset: function() {
var aabb = Tegaki.canvas.getBoundingClientRect();
Tegaki.offsetX = aabb.left + window.pageXOffset + Tegaki.cnt.scrollLeft;
Tegaki.offsetY = aabb.top + window.pageYOffset + Tegaki.cnt.scrollTop;
},
onMouseMove: function(e) {
if (Tegaki.isPainting) {
Tegaki.tool.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
}
else if (Tegaki.isColorPicking) {
TegakiPipette.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
}
},
onMouseDown: function(e) {
if (e.target.parentNode === Tegaki.layersCnt) {
if (Tegaki.activeLayer === null) {
alert(TegakiStrings.noActiveLayer);
return;
}
if (!Tegaki.layers[Tegaki.activeLayer].visible) {
alert(TegakiStrings.hiddenActiveLayer);
return;
}
}
else if (e.target !== Tegaki.bg) {
return;
}
if (e.which === 3 || e.altKey) {
Tegaki.isColorPicking = true;
TegakiPipette.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
}
else {
Tegaki.isPainting = true;
TegakiHistory.pendingAction = new TegakiHistoryActions.Draw(
Tegaki.layers[Tegaki.activeLayer].id
);
TegakiHistory.pendingAction.addCanvasState(Tegaki.activeCtx.canvas, 0);
Tegaki.tool.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1), true);
}
},
onMouseUp: function(e) {
if (Tegaki.isPainting) {
Tegaki.tool.commit && Tegaki.tool.commit();
TegakiHistory.pendingAction.addCanvasState(Tegaki.activeCtx.canvas, 1);
TegakiHistory.push(TegakiHistory.pendingAction);
Tegaki.isPainting = false;
}
else if (Tegaki.isColorPicking) {
e.preventDefault();
Tegaki.isColorPicking = false;
}
},
onDummy: function(e) {
e.preventDefault();
e.stopPropagation();
}
};
// Bienvenido a Internet
function topen() {
console.log(document.forms["imgform"].dataset.w);
console.log(document.forms["imgform"].dataset.h);
Tegaki.open({
onDone: function() {
document.getElementById('status').innerHTML = 'Subiendo...';
document.getElementById('buttons').style.display = 'none';
document.getElementById('links').style.display = 'none';
document.getElementById('filebase').value = Tegaki.flatten().toDataURL('image/png');
document.forms["imgform"].submit();
},
onCancel: function() { history.back(-1); },
width: document.forms["imgform"].dataset.w,
height: document.forms["imgform"].dataset.h
});
}
window.onload = function() {
document.getElementById('topen').addEventListener('click', topen);
topen();
};