841-biborokuWebフロントエンドの備忘録

Node.jsライブラリsharpを使って2枚を1枚の画像に合成・圧縮する自動化mjsを作る

やりたいこと


パッケージのインストール

npm i sharp path fs


構成

├ 📁 images
│ └ 📁 convert
│ └ 📁 dir1
│ └ 📁 dir2
├ convertImages.mjs
package.json

convertImages.mjs

import fs from "fs/promises";
import path from "path";
import sharp from "sharp";

const __dirname = path.resolve();

const inputDir1Path = path.join(__dirname, 'images', 'dir1');
const inputDir2Path = path.join(__dirname, 'images', 'dir2');
const outputConvertPath = path.join(__dirname, 'images', 'convert');

const dir1Images = [];
const dir2Images = [];

async function readDir1Files() {
  try {
    const dir1Files = await fs.readdir(inputDir1Path);
    dir1Images.push(...dir1Files.map(file => path.join(inputDir1Path, file)));
  } catch (err) {
    console.error('Error reading Dir1 folder:', err);
  }
}

async function readDir2Files() {
  try {
    const dir2Files = await fs.readdir(inputDir2Path);
    dir2Images.push(...dir2Files.map(file => path.join(inputDir2Path, file)));
  } catch (err) {
    console.error('Error reading Dir2 folder:', err);
  }
}

async function convertImgs(dir1Images, dir2Images) {
  for (let index = 0; index < dir1Images.length; index++) {
    const dir1ImagePath = dir1Images[index];
    const dir2ImagePath = dir2Images[index];

    //Dir1->image info
    const dir1ImageInfo = await sharp(dir1ImagePath).metadata();
    const dir1ImgWidth = dir1ImageInfo.width;
    const dir1ImgHeight = dir1ImageInfo.height;

    //Dir2->image info
    const dir2ImageInfo = await sharp(dir2ImagePath).metadata();
    const dir2ImgWidth = dir2ImageInfo.width;
    const dir2ImgHeight = dir2ImageInfo.height;

    const convertWidth = dir1ImgWidth + dir2ImgWidth + 100; //100は、画像と画像の間分
    const convertHeight = Math.max(dir1ImgHeight, dir2ImgHeight);  //画像の高さを比較し高いサイズを採用->生成する画像の高さになる

    const convertFilePath = dir1ImagePath.replace(/.(jpeg|png)/g, '.jpg'); //強制的に拡張子をjpgに置き換え

    await sharp({ create: { width: convertWidth, height: convertHeight, channels: 4, background: { r: 255, g: 255, b: 255, alpha: 1 } } }) //背景を黒にする場合は、alpha: 0
      .jpeg({
        quality: 50, //圧縮 品質を50に設定
        progressive: true
      })
      .composite([
        {
          input: dir1ImagePath,
          left: 0,
          top: 0,
          gravity: 'northwest'
        },
        {
          input: dir2ImagePath,
          left: dir1ImgWidth + 100, // 1枚目との間を100px空ける
          top: 0,
          gravity: 'northeast'
        }
      ])
      .toFile(path.join(outputConvertPath, path.basename(convertFilePath))); //合成したファイル名
  }
}

async function main() {
  await readDir1Files();
  await readDir2Files();
  await convertImgs(dir1Images, dir2Images);
  console.log('Images conversion complete.');
}

main().catch(error => {
  console.error('Error:', error);
});
node convertImages.mjs


実行すると画像が生成されました!