Continue(s)

Twitter:@dn0t_ GitHub:@ogrew

【週刊p5js】work13

let img1, img2;

function preload() {
    img1 = loadImage("src/Broccoli.jpg");
    img2 = loadImage("src/Donuts.jpg");
}

function setup() {
    createCanvas(900, 900);
    ellipseMode(CENTER);

    noStroke();
    smooth();
    frameRate(1);
}

function draw() {
    let bg;
    if (random() < 0.5) {
        bg = img1;
    } else {
        bg = img2;
    }
    background(bg);

    let cnt = 50;
    let ax, ay, bx, by, side, scale;
    for (let i = 0; i < cnt; i++) {
        aside = random(50, 300);

        ax = random(0, width - aside);
        ay = random(0, height - aside);

        let move = random(20, 120);

        bx = ax + random(-move, move);
        by = ay + random(-move, move);

        scale = random(0.6, 1.4);
        bside = aside * scale;

        copy(ax, ay, aside, aside, bx, by, bside, bside);
    }

    let rows = int(random(20, 60));
    let offset = int(random(30, 60));
    let yArea = height - 2 * offset;
    let unitH = yArea / rows;
    let size = unitH * 0.5;

    let startY;
    for (let i = 0; i < rows; i++) {
        // たまにスキップ
        if (random() < 0.1) {
            continue;
        }

        startY = offset + i * unitH;

        push();
        translate(100, startY + unitH / 2);
        let move = 0;
        for (let j = 0; j < 8; j++) {
            let rnd = random();
            let c_rnd = random();
            if (rnd < 0.6) { // ellipse
                fill(selectColor(c_rnd, 0.05, 0.09));
                ellipse(0, 0, size, size);
                move = unitH;
            } else if (rnd < 0.8) { // rect
                fill(selectColor(c_rnd, 0.03, 0.07));
                let w = random(30, 120);
                rect(-size / 2, -size / 2, w, size, size * 0.5);
                move = w * 1.2;
            } else { // empty
                if (j > 0) { // 一番左は空白にしない
                    move = random(10, 30);
                }
            }
            translate(move, 0);
        }
        pop();
    }

}

function selectColor(num, r1, r2) {
      if (num < r1) {
          return "#EDCCC5";
      } else if (num < r2) {
          return "#7F877E";
      }
      return "#FAFAFA";
}

f:id:taiga006:20200426124417j:plain

今週の作品メモ

📌 今週は所謂ピュアグリッチ?つまりjpg画像をバイト列として読み込んで、適度にいじってグリッチを加える手法を試そうと思ったんですが、残念ながらp5.jsにはloadBytes()はあるのにsaveBytes()が実装されていなかったため断念。公式のissue探ってみたら一応言及はあったんですが、しばらくは実装することもなさそうでした。
📌 ちなみにこれを調べている道中でAudacityでピュアグリッチする手法とか出てきたので今度試してみたいと思います。
📌 ということで今回は諦めてノンピュアグリッチです。肝となるのはやはりcopy()メソッドでしょうか。

copy(sx, sy, sw, sh, dx, dy, dw, dh)
sx: コピーしたいエリアの左上のX座標
sy: コピーしたいエリアの左上のY座標
sw: コピーしたいエリアの幅
sh: コピーしたいエリアの高さ
dx: コピー先のエリアの左上のX座標
dy: コピー先のエリアの左上のY座標
dw: コピー先のエリアの幅
dh: コピー先のエリアの高さ

📌 単純ですね。これを適当に繰り返すだけでグリッチやった風になります。
📌 それ以外のテキストっぽいのに関しては説明不要かと思います。ちょっと位置調が整雑ですが、欲しい感じの結果ができました。
📌 使用しているイメージは偶然Unsplashで見つけたAnnie Sprattさんの写真です。素敵ですね。

今週の雑談

📌 #週刊p5jsが仕事になりそうな光が見えたかと思ったらシュンと消えてしまった😭
📌 募集中。ポスター / ステッカー / フライヤーなど規模にもよるけどしばらくは無償で作るよ🌼
📌 『Ray Tracing in One Weekend』をやってみました。レイトレというのが何をどうやっているのか、という基本的なところの理解が深まりました🌈これに関しては、楽しかったのと難しかったのとで、もう少し深ぼって感想記事を後ほど書きます🧲 =>書きました!『Ray Tracing in One Weekend』をやってみたら楽しかった - 1225 f:id:taiga006:20200426011647p:plain
📌 今さらなんですが、『Monument Valley 2』を購入。在宅ワークの隙間時間にちまちまプレイ。なんだかんだとどハマリした1週間😜


📌 金曜日にTDSW vol.025に参加しました。19時ジャストに仕事を終えてそのままオンライン勉強会に移行するのは結構体力的に疲れることがわかりました。でも、非常に楽しかったので👌
📌 会社の在宅ワーク期間を5月末まで伸ばす、という告知がありまして、普段出不精なのに、嗚呼、この閉鎖された8畳で続く日々はさすがにそろそろ窮屈だなぁと感じた週末でした💫

今週のラジオ

📌 今週もコロナ禍で疲れた男子二人がビールを片手に45分ほど駄弁りました。ぜひ、お聞きください。
open.spotify.com

📌 あれ?Spotifyもしかして埋め込みコード廃止した!?

PNMフォーマットに関する調査。

PNMはPortable Any Mapの略で、以下の3つの画像フォーマットに対する総称のようです。

- PPM (Portable Pixmap Format) : RGBフルカラー
- PGM (Portable Graymap Format) : グレイスケール
- PBM (Portable Bitmap Format) : ビットマップ(白黒2値)

最初の2バイトがそれらを判別するマジックナンバーになっており、その下に縦横のピクセル数、そしてPPMであればRGBの最大値を書きます。 #でコメントも書けるみたいですが、必須ではありません。

ためしにPPMを生成するC++のコードを書いてみます。

#include <iostream>

int main()
{
    int nx = 100;
    int ny = 100;
    int max = 255;

    std::cout << "P3\n" << nx << " " << ny << "\n" << max << "\n";

    for (int x = 1; x <= nx; x++)
    {
        for (int y = 1; y <= ny; y++)
        {
            int r = max * int(x) / int(nx);
            int g = max * int(y) / int(ny);
            int b = 50;

            std::cout << r << "  " << g << "  " << b << "\n";
        }
    }
}

これをコンパイルして実行するとppmファイルを作れるはず…。

P3
100 100
255
0  2  2
0  2  5
...
...
...
0  255  252
0  255  255

これをPhotoshopで開くと、以下のような画像ができます。Red / Greenでやったのでよく見るUVマップのグラデーションみたいになりました。 f:id:taiga006:20200421201358p:plain

と、まあただそれだけなんですが、なぜか出力された画像をそのまま開こうとするとヘッダーが壊れている的なメッセージが出て開けません。 f:id:taiga006:20200421202215p:plain

じゃあ、どうやって上の画像を出したかといえば、適当にネットから拾ってきたPPM画像の中身を差し替えただけです。一体何が違うのか。 改行やwhitespaceなどはだいぶ寛容なフォーマットのようだし…。

とまあ、謎が少し残ってしまいましたが、結果は出たので一応、満足です。

参考

http://tech.ckme.co.jp/pnm.shtml
https://www.mm2d.net/main/prog/c/image_io-01.html
http://paulbourke.net/dataformats/ppm
http://www.not-enough.org/abe/manual/command/netpbm/ppm.html