p5.jsで作品を額縁にかざる方法

# サマリ🎨
p5.jsで作成したスケッチを額縁にかざる方法をシェアいたします。
結論からいいますと、今回の成果物`PictureFrame Class`を使うとできるよという話です。

# 成果物
https://gist.github.com/tetunori/cedbcc6fcbdbc0a6be7e15e2242fc8f1

※ 本記事の下のほうにもソースコードをおいておきました。(ライセンスはpublic domain)

これを使うと、このようにアート作品をそれっぽくバーチャル展示できますよ！

[神奈川沖浪裏 x p5.pattern](https://openprocessing.org/sketch/1362259)
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">&quot;神奈川沖浪裏 x p5.pattern&quot;<br>This is the 1st piece from <a href="https://twitter.com/hashtag/Generative%E5%AF%8C%E5%B6%BD%E4%B8%89%E5%8D%81%E5%85%AD%E6%99%AF?src=hash&amp;ref_src=twsrc%5Etfw">#Generative富嶽三十六景</a> .<a href="https://t.co/CJoM90IQXp">https://t.co/CJoM90IQXp</a><a href="https://twitter.com/hashtag/creativecoding?src=hash&amp;ref_src=twsrc%5Etfw">#creativecoding</a> <a href="https://twitter.com/hashtag/generativeart?src=hash&amp;ref_src=twsrc%5Etfw">#generativeart</a> <a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> <a href="https://t.co/JPhKVn3Q3A">pic.twitter.com/JPhKVn3Q3A</a></p>&mdash; Tetsunori NAKAYAMA | 中山 哲法 (@tetunori_lego) <a href="https://twitter.com/tetunori_lego/status/1462235915070291970?ref_src=twsrc%5Etfw">November 21, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# きっかけ
ツカモトさん([@tkmts5](https://twitter.com/tkmts5))の作成された作品の中に、額装されているものがあり、とても美しかったので、自分でもトライしてみようと思ったのがきっかけです。下記ツイートが発端ですが、壁紙の表現とかもうつくしいですよねー。
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://twitter.com/hashtag/creativecoding?src=hash&amp;ref_src=twsrc%5Etfw">#creativecoding</a> <a href="https://twitter.com/hashtag/generativeart?src=hash&amp;ref_src=twsrc%5Etfw">#generativeart</a> <a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a> <a href="https://twitter.com/hashtag/illustration?src=hash&amp;ref_src=twsrc%5Etfw">#illustration</a> <a href="https://twitter.com/hashtag/3DCG?src=hash&amp;ref_src=twsrc%5Etfw">#3DCG</a> <a href="https://twitter.com/hashtag/%E4%BA%8C%E7%82%B9%E9%80%8F%E8%A6%96%E5%9B%B3%E6%B3%95?src=hash&amp;ref_src=twsrc%5Etfw">#二点透視図法</a> <a href="https://t.co/goP2Ncuexh">pic.twitter.com/goP2Ncuexh</a></p>&mdash; ツカモト (@tkmts5) <a href="https://twitter.com/tkmts5/status/1459877788861620225?ref_src=twsrc%5Etfw">November 14, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 使い方
`pictureFrame.js`を読み込んだ前提で、飾りたい画像(`img(p5.image)`)を引数に`PictureFrame`を`new`し、描画先のx/y座標を指定して`draw`メソッドをcallしてください。現場からは以上です。

```javascript
const pF = new PictureFrame(img);  
pF.draw(0, 0);
```

実際の使用例は[神奈川沖浪裏 x p5.pattern](https://openprocessing.org/sketch/1362259)をご覧ください。

# 細かい使い方
コンストラクタ、メソッド共にOptionalな引数をつけているので、マージン・ベゼルの幅や色、額縁全体のサイズが気に入らない場合はいじることができます。詳しくは下記のコードとコメントをみてみてください。

# コード

```javascript:pictureFrame.js
/*
  Class for Drawing picture frame mounting your image.

  Usage example.
 
    const pF = new PictureFrame(img);  
    pF.draw(0, 0);
  
  Reference: ツカモトsan(@tkmts5)'s tweet https://twitter.com/tkmts5/status/1459877788861620225
*/

class PictureFrame {
  // Syntax
  //   PictureFrame(img, [marginSize], [bezelSize], [bezelColor], [marginColor])
  // Parameters
  //   img: p5.Image: image to be mounted.
  //   marginSize: Number: size of margin. Optional and default value is 80;
  //   marginColor:  p5.Color|gray scale etc... : color of margin Optional and default value is '#f1ece6';
  //   bezelSize: Number: size of bezel. Optional and default value is 20;
  //   bezelColor:  p5.Color|gray scale etc... : color of bezel. Optional and default value is 50(=dark gray);
  constructor(img, marginSize = 80, marginColor = '#f1ece6', bezelSize = 20, bezelColor = 50) {
    this.img = img;

    // Parameters for frame
    this.marginSize = marginSize;
    this.marginColor = marginColor;
    this.bezelSize = bezelSize;
    this.bezelColor = bezelColor;

    // Whole picture frame width/heigth size
    this.width = this.img.width + 2 * this.marginSize;
    this.height = this.img.height + 2 * this.marginSize;
  }

  // Syntax
  //   draw(x, y, [w],[h])
  // Parameters
  //   x: Number: x-coordinate of the frame.
  //   y: Number: y-coordinate of the frame.
  //   w: Number: width of the frame. (Optional) Default value is image width + both margin.
  //   h: Number: height of the frame. (Optional) Default value is image height + both margin.
  draw(x, y, w = this.img.width + 2 * this.marginSize, h = this.img.height + 2 * this.marginSize) {
    push();
    {
      // Draw frame(by stroke!)
      stroke(this.bezelColor);
      strokeWeight(this.bezelSize);
      drawingContext.shadowBlur = 10;
      drawingContext.shadowColor = '#00000055';
      drawingContext.shadowOffsetX = 5;
      drawingContext.shadowOffsetY = 5;

      // Draw margin
      fill(this.marginColor);
      rect(x, y, w, h);
    }
    pop();

    // Mount image.
    const imageWidth = w - 2 * this.marginSize;
    const imageHeight = h - 2 * this.marginSize;
    image(this.img, x + this.marginSize, y + this.marginSize, imageWidth, imageHeight);
  }
}
```
Gist側も再掲

https://gist.github.com/tetunori/cedbcc6fcbdbc0a6be7e15e2242fc8f1