p5.jsの関数まとめ part.4 preloadとloadImage()

この記事は Qiita p5js アドベントカレンダー5日目の記事です。

## これはなに
書籍[『Generative Design with p5.js』P_1_2_2_01](https://editor.p5js.org/generative-design/sketches/P_1_2_2_01)に登場する関数について理解を深める記事です。
今回はpreload()とloadImage()。


## preload()
setupやdrawと同じ、p5での描画を組み立てる関数(Structure)です。
setupよりも前に実行されるのが特徴。

### リファレンスより
> Called directly before setup(), the preload() function is used to handle asynchronous loading of external files in a blocking way. If a preload function is defined, setup() will wait until any load calls within have finished. Nothing besides load calls (loadImage, loadJSON, loadFont, loadStrings, etc.) should be inside the preload function. If asynchronous loading is preferred, the load methods can instead be called in setup() or anywhere else with the use of a callback parameter.

> setup()の直前に呼び出されるpreload()関数は、外部ファイルの非同期読み込みをブロック方式で処理するために使用されます。preload関数が定義されている場合、setup()は内部のloadコールが終了するまで待機します。ロードコール（loadImage、loadJSON、loadFont、loadStringsなど）以外のものは、プリロード関数内に入れるべきではありません。非同期のロードが必要な場合は、loadメソッドをsetup()の中やその他の場所でコールバックパラメータを使用して呼び出すことができます。(DeepL翻訳)

preloadの中で呼ばれる関数は基本的にload系に限られているようですね。
この中でなんでもかんでもしていいよというわけではなさそうです。

### Type
```typescript
preload(): void;
```
structureに分類される関数なので返り値はとくになし。

## loadImage()
画像を読み込むための`loadImage`についても触れたい思います。
名前の通り、画像データを読み込むために使用される関数です。

### リファレンスより
> The path to the image should be relative to the HTML file that links in your sketch. Loading an image from a URL or other remote location may be blocked due to your browser's built-in security.

> 画像のパスは、スケッチにリンクしているHTMLファイルからの相対パスでなければなりません。URLやその他の遠隔地からの画像の読み込みは、ブラウザの内蔵セキュリティによってブロックされることがあります。（DeepL翻訳）

相対パスで読み込む必要があるよ。ということくらいですかね。
上記は一部抜粋ですが、他には
**setup内でも呼べるけど読み込みが遅れたりするからpreload内で実行してね**
とか
**base64も読み込み可能だよ**
ということが書かれています。

ちなみにloadImage()はpreloadの中で呼ばれることが推奨されていますが、どこからでも呼べる関数です。
[P_1_2_2_01](https://editor.p5js.org/generative-design/sketches/P_1_2_2_01)では数字を入力するごとにloadImageを走らせる処理が書かれていました。

（ふと使ってる画像全てをpreload内で一度に呼び出した方が、画像変更時に遅延がなくなるのでは...と思いました。試してないけど。）


### Type
```typescript
loadImage(path: string, successCallback?: (p1: Image) => any, failureCallback?: (p1: Event) => any): Image;
```
引数

- path 画像パス
- successCallback / failureCallbac 成功時・失敗時に実行できる関数を指定できるようです。

返り値は`Image`という型で、p5内で扱えるイメージオブジェクトのようです。

### 試してみる
[P_1_2_2_01](https://editor.p5js.org/generative-design/sketches/P_1_2_2_01)のplaygroundにある画像を利用してみます。
preload内でloadImage()し、image()で画像を表示。

```javascript
var img;

function setImage(loadedImageFile) {
  img = loadedImageFile;
}

function preload() {
  // load完了後、setImageで画像をimgに格納する
  loadImage('data/pic1.jpg', setImage);
}

function setup() {
  createCanvas(600, 600);
  image(img, 0, 0)
}
```
image()の第一引数にImageを渡すだけで表示ができます。
第二、第三引数は画像の起点となるx, y座標です。

![スクリーンショット 2021-12-05 1.54.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/ec3712dc-164e-0f81-3d4c-3fcb27d51f14.png)


せっかくなのでload失敗時のEventを使う関数も作りましょう。
loadImageの第三引数には失敗時の関数、`noticeError`を渡しました。
またパスの`data`を`daa`にして読み込みに失敗させます。

```javascript
const noticeError = (event) => {
  console.log(event)
}

function preload() {
  loadImage('daa/pic1.jpg', setImage, noticeError);
}

```

画像の読み込みに失敗し、Eventの中身を取得することができました。 

```console
// console
Event {isTrusted: true, type: "error", target: null, currentTarget: null, eventPhase: 0…}
```

## どんな時に使えそうか
[P_1_2_2_01](https://editor.p5js.org/generative-design/sketches/P_1_2_2_01)は画像をバラバラに分解し、明度や彩度で色分けしたものを描画するというものです。
またそれがぐにゃぐにゃ動いたりしたら面白いんじゃないか・・といろいろ想像が働きます。
既存のものから無限に新しいものが作れるのは面白いですよね。
画像やそういったメディアを使うタイミングは多くあると思います。

---

下の画像と上で使用した画像は同じもの。
色分けをして並び替えをすることでグリッチかつピクセルアートのようにも見えますね！

![スクリーンショット 2021-12-05 2.08.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/45380991-412f-90d5-7e1a-ae81072a0014.png)