I have a an 2d array of 1's and 0's and I'd like to create a black and white image from that array in my react application.
My array looks something like this but much bigger:
var items = [
[0, 1, 1, 0],
[1, 1, 1, 0],
[0, 1, 0, 1]
];
and I want to show something like:
How can I output a black and white raster plot from my array in my react application?
You could use a library that renders PNGs or other image formats, but since you have a simple list of pixels, an SVG image is not hard to render out, either. Technically this isn't a raster plot, as it's a vector image but you can render it out at 4x3 pixels if you wanted to and it'll stay crisp.
function drawSvg(tag, rows) {
// If you're sure all rows are always the same size, it's
// faster and simpler to just do `rows[0].length`.
const pixelWidth = rows.reduce((max, row) => Math.max(max, row.length), 0);
const pixelHeight = rows.length;
// The `viewBox` of a SVG tag is the viewport to draw to.
// Since we want 1 "pixel" in our vector to be 1 pixel in the output,
// the viewbox will be 0 -0.5 4 3 for our 4x3 sample image.
// The -0.5 shift upwards is because of how SVG aligns things.
tag.setAttribute('viewBox', `0 -0.5 ${pixelWidth} ${pixelHeight}`);
// The width/height of a SVG tag can be overwritten by CSS to your liking,
// but having them makes sure the image stays the correct aspect ratio.
tag.setAttribute('width', pixelWidth);
tag.setAttribute('height', pixelHeight);
const path = tag.querySelector('path');
let data = '';
for (let line = 0; line < rows.length; line++) {
// [M]ove absolutely to 0,Y
data += ` M0,${line}`;
const row = rows[line];
for (const pixel of row) {
if (pixel) {
// Draw a [h]orizontal line, 1 unit wide.
data += ` h1`;
} else {
// [m]ove relatively to +1,+0.
data += ` m1,0`;
}
}
}
// Output will be something like 'M0,0 h1 m1,0 h1'.
path.setAttribute('d', data);
// You can also create a link to a SVG by embedding it as a data URL.
// encodeURIComponent is smaller than Base64Encode.
// You could minify the input, but we don't need to bother for the sample.
const href = `data:image/svg+xml,${encodeURIComponent(tag.outerHTML)}`;
// Create an <img src="">
const img = document.createElement('img');
img.classList.add('output');
img.setAttribute('src', href);
tag.parentNode.insertBefore(img, tag);
// Works as a background image, too.
const div = document.createElement('div');
div.classList.add('output');
div.style.backgroundImage = `url("${href}")`;
tag.parentNode.insertBefore(div, tag);
}
addEventListener('DOMContentLoaded', () => {
drawSvg(document.querySelector('svg.output'), [
[0, 1, 1, 0],
[1, 1, 1, 0],
[0, 1, 0, 1]
]);
});
.output {
width: 100px;
height: auto;
border: 1px solid orange;
}
img.output {
border-color: lime;
}
div.output {
background: no-repeat 0 0;
background-size: cover;
height: 75px;
border-color: aqua;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" shape-rendering="crispEdges" class="output">
<path fill="none" stroke="#000000" d="M0" />
</svg>