* Split core lib into multiple files * Refactor data encoding methods * Refactor data masking process * Improve qr code generation process * Increase minimum required node version to 0.10 * Add linter * Add tests and tests coverage * Update travis config to fix compilation issues * Add examples folder * Add missing license tag in package.json * Update build script and add sourcemap support * Publish only strictly needed files on npm * Update readme
319 lines
7.9 KiB
JavaScript
319 lines
7.9 KiB
JavaScript
var express = require('express')
|
|
var app = express.createServer()
|
|
var http = require('http')
|
|
var fs = require('fs')
|
|
var QRCode = require('../lib')
|
|
var canvasutil = require('canvasutil')
|
|
var Canvas = require('canvas')
|
|
var 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 || {}
|
|
|
|
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) {
|
|
if (!err) {
|
|
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, 'images', 'node_logo.png')
|
|
this.image(path.join(args, cb))
|
|
}
|
|
|
|
effectHandlers.npm = function (args, cb) {
|
|
args.src = path.join(__dirname, 'images', 'npm_logo.png')
|
|
this.image(args, cb)
|
|
}
|
|
|
|
effectHandlers.bacon = function (args, cb) {
|
|
args.src = path.join(__dirname, 'images', 'bacon-love.png')
|
|
this.image(args, cb)
|
|
}
|
|
|
|
effectHandlers.baconBikini = function (args, cb) {
|
|
args.src = path.join(__dirname, 'images', '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()
|
|
var luma709Only = canvasutil.conversionLib.luma709Only
|
|
var up = []
|
|
var down = []
|
|
var left = []
|
|
var right = []
|
|
var upPx
|
|
var downPx
|
|
var leftPx
|
|
var rightPx
|
|
var r
|
|
var t
|
|
var l
|
|
var d
|
|
var 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
|
|
var domain
|
|
var 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'
|
|
}
|
|
|
|
var 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) {
|
|
var src = args.src || ''
|
|
|
|
var img = new Image()
|
|
var convert = canvasutil.conversionLib
|
|
img.onload = function () {
|
|
QRCode.draw(args.text || '', function (err, canvas) {
|
|
if (err) {
|
|
cb(err, false)
|
|
return
|
|
}
|
|
|
|
var codeCtx = canvas.getContext('2d')
|
|
var frame = codeCtx.getImageData(0, 0, canvas.width, canvas.width)
|
|
var tpx = new canvasutil.PixelCore()
|
|
var baconCanvas = new Canvas(canvas.width, canvas.width)
|
|
var ctx = baconCanvas.getContext('2d')
|
|
var topThreshold = args.darkThreshold || 25
|
|
var 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)
|
|
var codeLuma = convert.luma709Only(frame.data[i * 4], frame.data[i * 4 + 1], frame.data[i * 4 + 2])
|
|
var yuv
|
|
var rgb
|
|
|
|
if (codeLuma > pixelCore.threshold) {
|
|
if (luma < bottomThreshold) {
|
|
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) {
|
|
yuv = convert.rgbToYuv(px.r, px.g, px.b)
|
|
|
|
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')
|