LoginSignup
0
1

More than 1 year has passed since last update.

ダミー画像生成api(placeなんちゃら)をnode.js + expressで作るためのメモ

Posted at

はじめに

placekittenとかplaceholdみたいなダミー画像生成サービスを作りたいと思ったのでちょっと試してみた記録です。
正直秒で作れたので特に言うことはないです。

完成形イメージ

スクリーンショット 2023-03-20 20.54.13.png
スクリーンショット 2023-03-20 20.53.49.png
スクリーンショット 2023-03-20 20.54.00.png

それじゃ実装を説明します。

実装

事前準備

まずは適当なフォルダ作ってその中で、下記のような形で必要なライブラリをインストールしましょう。

npm init -y
npm install express cors sharp

sharpは画像リサイズ用のライブラリです(https://sharp.pixelplumbing.com/)

ファイル構成は下記のような形にします。index.htmlは中身適当でいいですが、下記に一応自分のを置いときます。
私の画像はwaifu diffusionで生成したものを利用していますが、何でもOKです。(jsのサイズ指定部分を合わせて変更して下さい。)

.
├── images
│   ├── 1.png
│   ├── 2.png
│   ├── 3.png
│   ├── 4.png
│   ├── 5.png
│   ├── 6.png
│   ├── 7.png
│   ├── 8.png
│   ├── 9.png
│   └── 10.png
├── index.html
├── index.js
├── node_modules
├── package-lock.json
├── package.json
└── readme.md

index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>placeImage</title>
  </head>
  <body>
    <h1>placeImage</h1>
    <img src="http://localhost:3000/400/300" />
    <h2>使い方</h2>
    <p>下記のように幅と高さを指定すれば画像を取得できます。</p>
    <p class="caution">
      注意:幅512px、高さ512px以上の指定は、512pxにそれぞれリサイズされますのでご注意下さい。<br />
      また、3桁以上の数字を入力した場合や数値以外の値を入力した場合は404エラーとなります。
    </p>
    <p class="link">
      例:<a href="http://localhost:3000/400/300" target="_blank"
        >http://localhost:3000/400/300</a
      >
    </p>
  </body>
</html>

あと、package.jsonにindex.jsを起動するための記述を追加して下さい。

"scripts": {
    "start": "node index.js"
}

apiの実装

コードの全体像が下記です。先程作成したindex.js内に記述して下さい。

const express = require("express");
const path = require("path");
const cors = require("cors");
const sharp = require("sharp");

const app = express();

// 画像の数を入れる定数
const imagesLength = 10;

// 他のサービスで利用する場合にCORSエラーが起きないようにするやつ(ローカルだけならいらない)
app.use(cors());

// indexページの生成
app.get("/", (req, res) => {
  res.sendFile(__dirname + "/index.html");
});

// widthとheightを1~4桁で取ってランダムな画像をトリミングして表示
app.get("/:width([0-9]{1,3})/:height([0-9]{1,3})", async (req, res) => {
  const width = Math.min(Number(req.params.width), 512);
  const height = Math.min(Number(req.params.height), 512);

  let fileName = Math.floor(Math.random() * imagesLength) + 1 + ".png";
  let filepath = path.join(__dirname, `images/${fileName}`);

  try {
    const resizedBuffer = await sharp(filepath)
      .resize(width, height, { fit: "cover" })
      .toBuffer();

    const encodedBuffer = resizedBuffer.toString("base64");

    var img = Buffer.from(encodedBuffer, "base64");

    res.writeHead(200, {
      "Content-Type": "image/png",
      "Content-Length": img.length,
    });
    res.end(img);
  } catch (e) {
    res.status(404).send("<h1>404 page not found</h1>");
  }
});

// 404ページ
app.all("*", (req, res) => {
  res.status(404).send("<h1>404 page not found</h1>");
});

const port = process.env.PORT || 3000;
app.listen(port, () => console.log("listen on port:", port));

重要な画像の取得部分のみ説明します。

// widthとheightを1~4桁で取ってランダムな画像をトリミングして表示
app.get("/:width([0-9]{1,3})/:height([0-9]{1,3})", async (req, res) => {
  const width = Math.min(Number(req.params.width), 512);
  const height = Math.min(Number(req.params.height), 512);

  let fileName = Math.floor(Math.random() * imagesLength) + 1 + ".png";
  let filepath = path.join(__dirname, `images/${fileName}`);

  try {
    const resizedBuffer = await sharp(filepath)
      .resize(width, height, { fit: "cover" })
      .toBuffer();

    const encodedBuffer = resizedBuffer.toString("base64");

    var img = Buffer.from(encodedBuffer, "base64");

    res.writeHead(200, {
      "Content-Type": "image/png",
      "Content-Length": img.length,
    });
    res.end(img);
  } catch (e) {
    res.status(404).send("<h1>404 page not found</h1>");
  }
});

expressではパスに正規表現を利用できるため、下記のような形で横幅と高さのパラメータを制限しています。
今回は数値かつ、1~3桁の範囲で指定しています。
"/:width([0-9]{1,3})/:height([0-9]{1,3})"

下記で横幅、高さを指定します。今回は最大値を512にしていますが、好きに変更して下さい。

const width = Math.min(Number(req.params.width), 512);
const height = Math.min(Number(req.params.height), 512);

ここで画像ファイルをランダムに取得しています。

let fileName = Math.floor(Math.random() * imagesLength) + 1 + ".png";
let filepath = path.join(__dirname, `images/${fileName}`);

最後に画像をバッファにしてレスポンスに渡しています。
何らかの理由で画像が表示できなければ404ページを表示します。

try {
    const resizedBuffer = await sharp(filepath)
      .resize(width, height, { fit: "cover" })
      .toBuffer();

    const encodedBuffer = resizedBuffer.toString("base64");

    var img = Buffer.from(encodedBuffer, "base64");

    res.writeHead(200, {
      "Content-Type": "image/png",
      "Content-Length": img.length,
    });
    res.end(img);
  } catch (e) {
    res.status(404).send("<h1>404 page not found</h1>");
  }

以上です。

それでは〜〜〜

p.s.
1年前に転職してから一個も記事あげられてなかったのですが、ようやく記事を書けました...

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1