302 lines
6.9 KiB
JavaScript
302 lines
6.9 KiB
JavaScript
var express = require('express')
|
|
,app = express.createServer()
|
|
,fs = require('fs')
|
|
,QRCode = require('../qrcode')
|
|
,canvasutil = require('canvasutil')
|
|
,Canvas = require('canvas')
|
|
,Image = Canvas.Image;
|
|
|
|
var path = require('path')
|
|
|
|
app.configure(function(){
|
|
app.use(express.methodOverride());
|
|
app.use(express.bodyParser());
|
|
app.use(app.router);
|
|
app.use(express.static(path.resolve(__dirname,'..')));
|
|
});
|
|
|
|
app.get('/', function(req, res){
|
|
fs.readFile(path.join(__dirname,'clientside.html'), function (err, data) {
|
|
res.send(data?data.toString():err);
|
|
});
|
|
});
|
|
|
|
var effectHandlers = {};
|
|
|
|
app.get('/generate', function(req, res){
|
|
var q = req.query||{},imageSrc;
|
|
|
|
QRCode.QRCodeDraw.color.light = q.lightColor||'#ffffff';
|
|
QRCode.QRCodeDraw.color.dark = q.darkColor||'#000000';
|
|
QRCode.QRCodeDraw.scale = +(q.scale);
|
|
|
|
if(isNaN(QRCode.QRCodeDraw.scale)) QRCode.QRCodeDraw.scale = 4;
|
|
//NOTE when i set scale to 500 something seg faulted
|
|
if(QRCode.QRCodeDraw.scale > 50) QRCode.QRCodeDraw.scale = 50;
|
|
|
|
var effect = q.effect||'plain';
|
|
if(!effectHandlers[effect]){
|
|
effect = 'plain';
|
|
}
|
|
|
|
effectHandlers[effect](q,function(error,canvas){
|
|
if(!error){
|
|
canvas.toBuffer(function(err, buf){
|
|
res.header('Content-Type','image/png');
|
|
res.send(buf);
|
|
});
|
|
} else {
|
|
var msg = error.message+"\n"+error.stack;
|
|
res.header('Content-Type','text/plain');
|
|
res.send(msg);
|
|
console.error(msg);
|
|
}
|
|
});
|
|
});
|
|
|
|
effectHandlers.node = function(args,cb){
|
|
args.src = path.join(__dirname,'fixtures','node_logo.png');
|
|
this.image(path.join(args,cb);
|
|
};
|
|
|
|
effectHandlers.npm = function(args,cb){
|
|
args.src = path.join(__dirname,'fixtures','npm_logo.png');
|
|
this.image(args,cb);
|
|
};
|
|
|
|
effectHandlers.bacon = function(args,cb){
|
|
args.src = path.join(__dirname,'fixtures','bacon-love.png');
|
|
this.image(args,cb);
|
|
};
|
|
|
|
effectHandlers.baconBikini = function(args,cb){
|
|
args.src = path.join(__dirname,'fixtures','bacon-bikini.png');
|
|
this.image(args,cb);
|
|
};
|
|
|
|
effectHandlers.rounded = function(args,cb){
|
|
QRCode.draw(args.text||'',function(err,canvas){
|
|
if(err) {
|
|
cb(err,canvas);
|
|
return;
|
|
}
|
|
|
|
var tpx = new canvasutil.PixelCore()
|
|
,luma709Only = canvasutil.conversionLib.luma709Only
|
|
,savedBuffer
|
|
,up=[],down=[],left=[],right=[]
|
|
,upPx,downPx,leftPx,rightPx,undefined,r,t,l,b,corner = 0;
|
|
|
|
tpx.threshold = 100;
|
|
|
|
tpx.iterate(canvas,function(px,i,len,pixels,w,h,pixelCore){
|
|
corner = 0;
|
|
|
|
//is dark
|
|
if(luma709Only(px.r,px.g,px.b) < pixelCore.threshold) {
|
|
|
|
if(i-w > 0){
|
|
upPx = (i-w)*4;
|
|
up[0] = pixels[upPx + 0];
|
|
up[1] = pixels[upPx + 1];
|
|
up[2] = pixels[upPx + 2];
|
|
//console.log('up',up);
|
|
}
|
|
|
|
if(i+w <= len) {
|
|
downPx = (i+w)*4;
|
|
down[0] = pixels[downPx + 0];
|
|
down[1] = pixels[downPx + 1];
|
|
down[2] = pixels[downPx + 2];
|
|
//console.log('down',down);
|
|
}
|
|
|
|
//have left pixel but no wrapping
|
|
if(i%w != 0){
|
|
leftPx = (i-1)*4;
|
|
left[0] = pixels[leftPx + 0];
|
|
left[1] = pixels[leftPx + 1];
|
|
left[2] = pixels[leftPx + 2];
|
|
//console.log('left',left);
|
|
}
|
|
|
|
if(i%w != w-1){
|
|
rightPx = (i+1)*4;
|
|
right[0] = pixels[rightPx + 0];
|
|
right[1] = pixels[rightPx + 1];
|
|
right[2] = pixels[rightPx + 2];
|
|
//console.log('right',right);
|
|
}
|
|
|
|
r = rightPx?luma709Only(right[0],right[1],right[2]):0;
|
|
t = upPx?luma709Only(up[0],up[1],up[2]):0;
|
|
l = leftPx?luma709Only(left[0],left[1],left[2]):0;
|
|
d = downPx?luma709Only(down[0],down[1],down[2]):0;
|
|
|
|
if(l > pixelCore.threshold){//if left is light and i am dark
|
|
if(t > pixelCore.threshold){//if top is light and i am dark
|
|
corner = 1;
|
|
pixels[rightPx + 4] = 100;
|
|
} else if(d > pixelCore.threshold){//if bottom is light and i am dark
|
|
pixels[rightPx + 4] = 100;
|
|
corner = 1;
|
|
}
|
|
} else if(r > pixelCore.threshold){
|
|
if(t > pixelCore.threshold){//if top is light and i am dark
|
|
corner = 1;
|
|
} else if(d > pixelCore.threshold){//if bottom is light and i am dark
|
|
corner = 1;
|
|
}
|
|
}
|
|
|
|
if(corner) {
|
|
px.a = 50;
|
|
}
|
|
}
|
|
});
|
|
cb(false,canvas);
|
|
});
|
|
};
|
|
|
|
|
|
effectHandlers.remoteImage = function(args,cb){
|
|
|
|
var src = args.src,domain,uri;
|
|
|
|
if(!src) {
|
|
cb(new Error('src required'),null);
|
|
} else {
|
|
if(src.indexof('://') != -1){
|
|
src = src.split('://').unshift();
|
|
var parts = src.split('/');
|
|
|
|
domain = parts.shift();
|
|
uri = parts.join('/');
|
|
}
|
|
}
|
|
|
|
if(!domain || !uri) {
|
|
cb(new Error('missing domain or uri '+args.src));
|
|
return;
|
|
}
|
|
|
|
var options = {
|
|
host: domain,
|
|
port: 80,
|
|
path: uri,
|
|
method: 'GET'
|
|
}
|
|
,req = http.request(options, function(res) {
|
|
if(res.statusCode < 200 || res.statusCode > 299){
|
|
cb(new Error('http '+res.statusCode+' response code'),null);
|
|
return;
|
|
}
|
|
|
|
res.setEncoding('utf8');
|
|
|
|
var data = '';
|
|
res.on('data', function (chunk) {
|
|
data += chunk;
|
|
console.log('BODY: ' + chunk);
|
|
});
|
|
|
|
res.on('complete',function(){
|
|
cb(false,data);
|
|
});
|
|
|
|
res.on('error',function(error){
|
|
cb(error,null);
|
|
cb = function(){};
|
|
});
|
|
});
|
|
|
|
req.end();
|
|
};
|
|
|
|
effectHandlers.image = function(args,cb){
|
|
src = args.src||'';
|
|
|
|
var img = new Image(),convert = canvasutil.conversionLib;
|
|
img.onload = function(){
|
|
QRCode.draw(args.text||'',function(err,canvas){
|
|
if(err) {
|
|
cb(err,false);
|
|
return;
|
|
}
|
|
|
|
var codeCtx = canvas.getContext('2d')
|
|
, frame = codeCtx.getImageData(0,0,canvas.width,canvas.width)
|
|
, tpx = new canvasutil.PixelCore()
|
|
, baconCanvas = new Canvas(canvas.width,canvas.width)
|
|
, ctx = baconCanvas.getContext('2d')
|
|
,topThreshold = args.darkThreshold||25
|
|
,bottomThreshold = args.lightThreshold||75;
|
|
|
|
tpx.threshold = 50;
|
|
|
|
//scale image
|
|
var w = canvas.width;
|
|
var h = canvas.height;
|
|
|
|
if(img.width>img.height) {
|
|
w = w*(canvas.height/h)
|
|
h = canvas.height;
|
|
} else {
|
|
h = h*(canvas.height/w)
|
|
w = canvas.width;
|
|
}
|
|
ctx.drawImage(img,0,0,w,h);
|
|
|
|
try{
|
|
tpx.iterate(baconCanvas,function(px,i,l,pixels,w,h,pixelCore){
|
|
var luma = (0.2125*px.r + 0.7154*px.g + 0.0721*px.b)
|
|
, codeLuma = convert.luma709Only(frame.data[i*4],frame.data[i*4+1],frame.data[i*4+2]);
|
|
|
|
if(codeLuma > pixelCore.threshold){
|
|
if(luma < bottomThreshold) {
|
|
var yuv = convert.rgbToYuv(px.r,px.g,px.b),rgb;
|
|
|
|
rgb = convert.yuvToRgb(bottomThreshold,yuv[1],yuv[2]);
|
|
|
|
px.r = rgb[0];
|
|
px.g = rgb[1];
|
|
px.b = rgb[2];
|
|
px.a = 255;
|
|
}
|
|
} else {
|
|
if(luma > topThreshold) {
|
|
var yuv = convert.rgbToYuv(px.r,px.g,px.b),rgb;
|
|
|
|
rgb = convert.yuvToRgb(topThreshold,yuv[1],yuv[2]);
|
|
|
|
px.r = rgb[0];
|
|
px.g = rgb[1];
|
|
px.b = rgb[2];
|
|
}
|
|
}
|
|
});
|
|
} catch(e){
|
|
cb(err,false);
|
|
}
|
|
|
|
cb(false,baconCanvas);
|
|
});
|
|
};
|
|
|
|
img.onerror = function(error){
|
|
error.message += ' ('+src+')';
|
|
cb(error,null);
|
|
}
|
|
|
|
img.src = src;
|
|
};
|
|
|
|
effectHandlers.plain = function(args,cb){
|
|
var text = args.text||'';
|
|
QRCode.draw(text||'',function(err,canvas){
|
|
cb(err,canvas);
|
|
});
|
|
};
|
|
|
|
app.listen(3031);
|
|
console.log('listening on 3031');
|