As I posted before, I'm learning generative art with p5.js.
In this article, I introduce a tool, "String Pixelater", which I made through the learning process.
- GitHub: https://github.com/ohbarye/string-pixelater
- npm: https://www.npmjs.com/package/string-pixelater
What's String Pixelater
This is a simple tool to pixelate any characters. pixelate
means to "convert a character to a two-dimensional array" so that we can deal with the tabular data for several purposes. I actually compose this and p5.js for painting generative art.
Let's dig into how it works... It has only one API so far though!
> StringPixelater.pixelate('hello', {fontSize: 24})
[
[0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,1,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,1,1,1,0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,1,1,0,0,0,0,1,1,1,0,0,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,0,0],
[0,0,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,0,0,0,1,1,1,0,0,0,1,1,1,1,0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,1,1,0,0,0,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0]
]
Could you vaguely see "hello" in the above?
How does it work?
In short, it uses <canvas>
element as a temporary canvas to render characters. Then it extracts and parses rasterized image data. Its essential code is the following.
const canvas = <HTMLCanvasElement> document.createElement('canvas');
const context = <CanvasRenderingContext2D> this.canvas.getContext('2d');
context.fillText("hello", 0, 0);
let table = new Array(canvas.height);
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
for (let row = 0; row < canvas.height; row++){
table[row] = new Array(canvas.width);
for (let col = 0; col < canvas.width; col++){
const alpha = imageData.data[(canvas.width * row + col) * 4 + 3];
if (alpha >= 64) {
table[row][col] = 1;
} else {
table[row][col] = 0;
}
}
}
Usage
Just install and call StringPixelater.pixelate
method with a string which you want to pixelate.
$ npm install --save string-pixelater
or
$ yarn add string-pixelater
You can use as ES module or load through <script>
tag
import StringPixelater from 'string-pixelater';
const table = StringPixelater.pixelate('Hello, world');
<script type="text/javascript" src="path/to/dist/js/string-pixelater.js"></script>
<script type="text/javascript">
var table = StringPixelater.pixelate('Hello, world');
</script>
transpose
If you use p5.js
like me, transpose
option is quite convenient because it has inverted axes,
> StringPixelater.pixelate('B', {fontSize: 24, transpose: false})
[
[0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,1,0,0],
[0,0,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0],
[0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0]
]
> StringPixelater.pixelate('B', {fontSize: 24, transpose: true})
[
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1],
[1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,1,1,1],
[1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1],
[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
[0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
The latter looks correct when it's rendered with simple and intuitive loops.
// Note: This is just pseudo code!
function draw() {
const imageData = StringPixelater.pixelate('B', {fontSize: 24, transpose: true})
const pixelSize = 10;
imageData.forEach(function(row, i) {
row.forEach(function(cell, j) {
if (cell === 1) {
ellipse(i * pixelSize, j * pixelSize, pixelSize, pixelSize);
}
})
})
}
This results like below:
Artworks with String Pixelater
Just with StringPixelater.pixelate('hello')
:
We can get pixelated emoji as like StringPixelater.pixelate('🐈')
.
I would be glad if anyone would have an interest in generative art or string-pixelater through this article. :)
Top comments (3)
Nice results !
I used pretty much the same technique to make Fizzle. (but without P5)
the idea of generative art sound pretty dope to me, any pointers to where I can start getting into it? (I'm good with css)
@torpoise
processing.org/ is the best as far as I know. "Processing" is a language and an environment to draw visual arts with code.
If you're familiar with python, processing.py (py.processing.org/) could be a better start point. In case of JavaScript, p5.js (p5js.org/).
If you'd like to try it right now, there's an interactive online editor for p5.js. Visit either of the followings, then copy & paste my code below into the editor on the page and see what will be happening.
Aside from that, it's exciting to search artworks on Pinterest or anything with the keyword "generative art". That definitely motivates you.