loading...
Cover image for Pixelate characters with canvas, and draw generative art!

Pixelate characters with canvas, and draw generative art!

ohbarye profile image Masato Ohba Updated on ・9 min read

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.

What's String Pixelater

image

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:

2018-05-12 22 49 04

Artworks with String Pixelater

Just with StringPixelater.pixelate('hello'):

2018-05-12 22 49 04

We can get pixelated emoji as like StringPixelater.pixelate('🐈').

2018-05-12 22 52 36


I would be glad if anyone would have an interest in generative art or string-pixelater through this article. :)

Posted on by:

Discussion

markdown guide
 

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.

function setup() {
  createCanvas(600, 400);
  frameRate(4)
}

function draw() {
  background(255) // clear background at every frame

  for (var i = 100; i < 400; i++) {
    var r = random(200);

    stroke(color(random(r),random(i),random(i), 60));   

    line(300, r, i, 100)
    line(300, i, i, 100)

    line(i, i, i, 300)
    line(i, i, r, 300)
    line(i, r, i, 300)

    line(500, r + 200, i + 200, i)
  }
}

Aside from that, it's exciting to search artworks on Pinterest or anything with the keyword "generative art". That definitely motivates you.