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