برنامه نویسی

تولید خودکار عکس پاسخگو با قلاب Astro

تصاویر تغییر اندازه، فشرده و فرمت شده. از قلاب Astro برای فرمت خودکار تصاویر استفاده کنید. من در این پست از تایپ اسکریپت استفاده می کنم. کد کامل نوشته شده در این پست را می توانید در GitHub Gist بیابید: ImageCompressorIntegration.ts.

معرفی

از تصاویر سایت خود بیشترین بهره را ببرید. من ریز عکسها را در وبلاگ شخصی خود بهینه کردم، این قسمت تولید تصویر آن است.

روش های مختلفی که برای قالب بندی تصاویر استفاده کردم:

  • تغییر اندازه به اندازه های مختلف
  • تبدیل به فرمت WebP
  • فشرده کردن
  • تمام ابرداده ها را حذف کنید

برای تولید متدها، من یک هوک Astro ساختم که در build اجرا می شود.

پیاده سازی روش ها

برپایی

بیایید از یک کلاس برای این استفاده کنیم. اسمش را هر طور که می خواهید بگذارید، من استفاده کردم ImageGenerator.

class ImageGenerator {}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

یک نوع سفارشی خاص مورد نیاز است. اندازه های مربوط به تصویر اغلب استفاده می شود.

type imageSize = { width: number, height: number };
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای تغییر اندازه تصاویر باید یک قرارداد نامگذاری ایجاد شود، زیرا چندین تصویر تولید می شود. نمونه ای که استفاده می شود این است: [NAME]-[WIDTH]-[HEIGHT].[EXTENSION]. برای مثال اگر اندازه آن تغییر کند image.png به عرض 600 و ارتفاع 315 و تغییر فرمت آن به WebP نام تصویر خواهد بود image-600-315.webp. این نسل نام اغلب استفاده می شود، بنابراین بیایید یک روش برای آن ایجاد کنیم. این NAME، WIDTH و HEIGHT، EXTENSION پارامترها هستند. زیرا در پایان فقط استفاده خواهد شد wepb، بجای EXTENSION من از یک بولین استفاده خواهم کرد که نشان می دهد پسوند فایل نتیجه است یا خیر webp یا نه.

import path from 'path';

class ImageGenerator {
  static generateName(filePath: string, size: imageSize, isWebp: boolean = false) {
    const extension = (isWebp ? ".webp" : path.extname(filePath));
    const justName = path.join(path.dirname(filePath), path.basename(filePath, path.extname(filePath))); // /directory/file.txt -> /directory/file
    return [justName, String(size.width), String(size.height)].join("-") + extension; // join the 3 parts and add extension
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من می‌خواهم اندازه‌های ریز عکس‌هایم را از پیش تعریف کنم.

class ImageGenerator {
  public static readonly thumbnailMetaSizes = [
    { width: 1200, height: 630 },
    { width: 600, height: 315 },
    { width: 360, height: 189 },
    { width: 736, height: 414 },
  ];
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای ویرایش واقعی تصاویر، ما قصد داریم از آن استفاده کنیم sharp. شارپ یک کتابخانه پردازش تصویر با کارایی بالا است. شما می توانید تمام کارهای جالبی که ما می خواهیم با آن انجام دهیم. کتابخانه را نصب کنید سپس آن را با آن وارد کنید import sharp from 'sharp'.

روند

بیایید تصاویر را ویرایش کنیم.

ابتدا تصویر را با شارپ بارگذاری کنید.

class ImageGenerator {
  static processImage(filepath: string) { // without a filepath we can't open it :D
    const image = sharp(filepath);
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

باید اندازه تصویر را به چندین اندازه تغییر دهیم و هر کدام را ویرایش کنیم. به همین دلیل است که الف imageSize[] پارامتر مورد نیاز است. تغییر اندازه تصاویر با وضوح بسیار آسان است، همچنین امکان انتخاب شیء متناسب تصویر را فراهم می کند. تناسب شی نشان می دهد که اگر نسبت تغییر اندازه با نسبت اصلی نباشد، تصویر چگونه باید باشد. با فیت شی، می توانم تعریف کنم که همیشه قسمت مرکزی تصویر را نشان می دهد. ما باید قبل از انجام هر کاری تصویر را کلون کنیم، بنابراین تغییر اندازه همیشه با تصویر اصلی انجام می شود.

class ImageGenerator {
  static processImage(filepath: string, sizes: imageSize[]) {
    const image = sharp(filepath);
    for (const size of sizes) {
      const resizedImage = image.clone().resize(size.width, size.height, { fit: 'cover', withoutEnlargement: true });
      // compress, remove metadata, save to png and webp
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس فایل را به WebP فرمت کنید. من می خواهم این را اختیاری بگذارم، بنابراین needWebp آرگومان به تعریف متد ما اضافه خواهد شد. toFormat روش برای تبدیل بین فرمت ها استفاده می شود.

class ImageGenerator {
  static async processImage(filepath: string, sizes: imageSize[], needWebp: boolean = false) {
    const image = //...
    for (const size of sizes) {
      const resizedImage = //...
      for (const isWebp of (needWebp ? [true, false] : [false])) { // we are going to run compress and metadata modification for each format
        await resizedImage.toFormat((isWebp ? "webp" : path.extname(filepath).slice(1) as any));
      }
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای فشرده سازی، اضافه کنید {quality: 100} به عنوان پارامتری برای toFormat روش. برای حذف فراداده تماس بگیرید withMetadata بعد از اینکه قالب بندی انجام شد

await resizedImage.toFormat((isWebp ? "webp" : path.extname(filepath).slice(1) as any), { quality: 100 }).withMetadata();
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

آخرین چیز این است که تصاویر جدید را ذخیره کنید. قبلا اجرا کردیم generateName، فقط باید از آن استفاده کنیم.

class ImageGenerator {
  static async processImage(filepath: string, sizes: imageSize[], needWebp: boolean = false) {
    const image = //...
    const basePath = path.dirname(filepath) + path.sep;
    for (const size of sizes) {
      //...
      for (const isWebp of (needWebp ? [true, false] : [false])) {
        const outPath = ImageCompressorIntegration.generateName(filepath, size, isWebp);
        await resizedImage.toFormat((isWebp ? "webp" : path.extname(filepath).slice(1) as any), { quality: 100 }).withMetadata().toFile(outPath);
      }
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

من به تصویر اصلی نیازی ندارم، بنابراین گزینه ای برای حذف خودکار آن اضافه کردم.

import fs from 'fs';

class ImageGenerator {
  static async processImage(filepath: string, sizes: imageSize[], needWebp: boolean = false, removeOriginal: boolean = false) {
    //...
    if (removeOriginal) {
      fs.rm(filepath, () => { }); // rm to remove
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کارمان تمام شد ImageGenerator کلاس

قلاب Astro

برای تولید خودکار تصاویر یک ادغام Astro سفارشی مورد نیاز است.

3 قلاب مربوط به ساخت وجود دارد: start، setup، generated. قرار است استفاده کنیم astro:build:generated، پس از اتمام کامل ساخت Astro اجرا می شود.

داخل همان فایل TypeScript ما ImageGenerator class Export تابعی است که تنظیمات ادغام را برمی گرداند.

import type { AstroIntegration } from "astro";

export default function createPlugin(): AstroIntegration {
  return {
    name: "ImageCompressorIntegration",
    hooks: {
      "astro:build:generated": async (options: { dir: URL }) => {} // make it async because our processImage is async too
    }
  };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

تنها کاری که باید انجام دهیم این است که تماس بگیریم processImage برای تمام تصاویری که می خواهیم پردازش کنیم. من می‌خواهم تمام فایل‌های موجود در آن را پردازش کنم thumbnail فهرست راهنما. مسیر پروژه ساخته شده را می توان از طریق options dir بحث و جدل.

export default function createPlugin(): AstroIntegration {
  return {
    name: "ImageCompressorIntegration",
    hooks: {
      "astro:build:generated": async (options: { dir: URL }) => {
        const distPath = options.dir.pathname;
        const allFiles = readDirectoryRecursive(path.join(distPath, "thumbnail"));
        for (const [i, imgPath] of allFiles.entries()) {
          await ImageGenerator.processImage(imgPath, ImageGenerator.thumbnailMetaSizes, true, true);
          console.log(`${path.basename(imgPath)} image sizes generated (${i+1}/${allFiles.length})`);
        }
      }
    }
  };
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

readDirectoryRecursive کد تابع را می توان در GitHub Gist پیدا کرد: ImageCompressorIntegration.ts

برای تکمیل آن، از ادغام خود در استفاده کنید astro.config.mjs.

در قسمت بعدی نحوه استفاده از تصاویر سایت را نشان خواهم داد.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا