You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.1 KiB
190 lines
5.1 KiB
'use strict'
|
|
|
|
var u8 = require('to-uint8')
|
|
var dims = require('compute-dims')
|
|
var flat = require('arr-flatten')
|
|
var isBuffer = require('is-buffer')
|
|
var isBrowser = require('is-browser')
|
|
var flip = require('flip-pixels')
|
|
|
|
module.exports = pxls
|
|
|
|
var context
|
|
|
|
function pxls (data, step) {
|
|
if (!data) return data
|
|
|
|
// handle ndarrays
|
|
if (isNdarray(data)) {
|
|
var i = 0
|
|
// rgb array
|
|
if (data.shape[2] === 3) {
|
|
var len = data.shape[0] * data.shape[1]
|
|
var out = Array(len << 2)
|
|
var hasInt = false
|
|
for (var x = 0; x < data.shape[0]; x++) {
|
|
for (var y = 0; y < data.shape[1]; y++) {
|
|
var r = data.get(y, x, 0)
|
|
var g = data.get(y, x, 1)
|
|
var b = data.get(y, x, 2)
|
|
out[(i << 2)] = r
|
|
out[(i << 2) + 1] = g
|
|
out[(i << 2) + 2] = b
|
|
if (!hasInt && (r > 1 || g > 1 || b > 1)) hasInt = true
|
|
i++
|
|
}
|
|
}
|
|
var a = hasInt ? 255 : 1
|
|
for (var i = 0; i < len; i++) {
|
|
out[(i << 2) + 3] = a
|
|
}
|
|
data = out
|
|
}
|
|
// bitmap array
|
|
else if (data.shape[2] === 1 || !data.shape[2]) {
|
|
var len = data.shape[0] * data.shape[1]
|
|
var out = Array(len << 2)
|
|
var hasInt = false
|
|
for (var x = 0; x < data.shape[0]; x++) {
|
|
for (var y = 0; y < data.shape[1]; y++) {
|
|
var r = data.get(y, x, 0)
|
|
out[(i << 2)] = r
|
|
out[(i << 2) + 1] = r
|
|
out[(i << 2) + 2] = r
|
|
if (!hasInt && r > 1) hasInt = true
|
|
i++
|
|
}
|
|
}
|
|
var a = hasInt ? 255 : 1
|
|
for (var i = 0; i < len; i++) {
|
|
out[(i << 2) + 3] = a
|
|
}
|
|
data = out
|
|
}
|
|
// direct data
|
|
else {
|
|
data = data.data
|
|
}
|
|
|
|
return u8(data)
|
|
}
|
|
|
|
// detect w/h/step from options
|
|
var width, height
|
|
if (Array.isArray(step)) {
|
|
width = step[0]
|
|
height = step[1]
|
|
step = step[2]
|
|
}
|
|
|
|
// detect w/h from data
|
|
if (!width) width = data.shape ? data.shape[0] : data.width
|
|
if (!height) height = data.shape ? data.shape[1] : data.height
|
|
|
|
// intercept absent canvas (useful for headless-gl)
|
|
if (data.gl || data._gl || data.regl) data = data.regl ? data.regl._gl : data.gl || data._gl
|
|
|
|
// faster to use drawImage(WrbGLContext), but it has some weird async function/raf side-effect
|
|
if (data.readPixels) {
|
|
var gl = data
|
|
var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4)
|
|
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels)
|
|
|
|
return flip(pixels, gl.drawingBufferWidth, gl.drawingBufferHeight)
|
|
}
|
|
|
|
// DOM load async shortcut, expects data to be loaded though
|
|
if (isBrowser) {
|
|
if (data.canvas) data = data.canvas
|
|
if (data.tagName || typeof ImageBitmap !== 'undefined' && data instanceof ImageBitmap) {
|
|
if (!context) context = document.createElement('canvas').getContext('2d')
|
|
|
|
// clears canvas too
|
|
context.canvas.width = data.width || width
|
|
context.canvas.height = data.height || height
|
|
|
|
context.drawImage(data, 0, 0)
|
|
|
|
data = context.getImageData(0, 0, context.canvas.width, context.canvas.height)
|
|
}
|
|
}
|
|
|
|
// unfold ImageData
|
|
if (data.data) data = data.data
|
|
|
|
// detect nested data shape
|
|
if (Array.isArray(data)) {
|
|
var shape = dims(data, 3)
|
|
|
|
if (shape) {
|
|
// [[[r,g,b], [r,g,b], ...], [[r,g,b], [r,g,b], ...]]
|
|
if (shape[2]) step = shape[2]
|
|
// [[r,g,b], [r,g,b], ...]
|
|
// not [[r,g,b,a,r,g,b,a], [r,g,b,a,r,g,b,a]]
|
|
else if (shape[1] && shape[1] <= 4) step = shape[1]
|
|
}
|
|
|
|
data = flat(data)
|
|
}
|
|
|
|
// if no step detected, figure out step from width/height
|
|
if (step == null && width && height) {
|
|
step = Math.floor(data.length / (width * height))
|
|
}
|
|
|
|
// refold buffers
|
|
if (data instanceof ArrayBuffer || isBuffer(data)) data = new Uint8Array(data)
|
|
|
|
// ignore bad data
|
|
if (data.length == null) return null
|
|
|
|
// [r,g,b, r,g,b, ...]
|
|
if (step === 3) {
|
|
var len = Math.floor(data.length / 3)
|
|
var out = Array(len << 2)
|
|
var hasInt = false
|
|
for (var i = 0; i < len; i++) {
|
|
var r = data[i * 3]
|
|
var g = data[i * 3 + 1]
|
|
var b = data[i * 3 + 2]
|
|
out[(i << 2)] = r
|
|
out[(i << 2) + 1] = g
|
|
out[(i << 2) + 2] = b
|
|
if (!hasInt && (r > 1 || g > 1 || b > 1)) hasInt = true
|
|
}
|
|
var a = hasInt ? 255 : 1
|
|
for (var i = 0; i < len; i++) {
|
|
out[(i << 2) + 3] = a
|
|
}
|
|
data = out
|
|
}
|
|
// [v,v,v,v...]
|
|
else if (step === 1) {
|
|
var len = data.length
|
|
var out = Array(len << 2)
|
|
var hasInt = false
|
|
for (var i = 0; i < len; i++) {
|
|
var r = data[i]
|
|
out[(i << 2)] = r
|
|
out[(i << 2) + 1] = r
|
|
out[(i << 2) + 2] = r
|
|
if (!hasInt && r > 1) hasInt = true
|
|
}
|
|
var a = hasInt ? 255 : 1
|
|
for (var i = 0; i < len; i++) {
|
|
out[(i << 2) + 3] = a
|
|
}
|
|
data = out
|
|
}
|
|
|
|
return u8(data)
|
|
}
|
|
|
|
|
|
function isNdarray(v) {
|
|
return v &&
|
|
v.shape &&
|
|
v.stride &&
|
|
v.offset != null &&
|
|
v.dtype
|
|
}
|
|
|