'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 }