调整存储在 Firebase 存储中的所有图像的大小

Resize all images stored in Firebase Storage

我已经在 Firebase 存储桶上上传了大约 1 万张高分辨率图片。由于现在的高带宽,我需要在不删除原始图像的情况下缩小存储桶中的这些图像。

Firebase 图像调整扩展功能解决了这个问题,但仅适用于新上传的图像它不适用于已经上传的图像。

所以,有什么办法可以做到这一点。我知道我们使用云函数来调整图像的大小,但我不确定我将如何实现这一点,因为没有触发云函数的工作。

有一个官方的 Cloud Function sample 展示了如何调整图像大小(它实际上与 Resize Images 扩展的基础 Cloud Function 非常相似)。

此示例 Cloud Function 在将文件上传到 Firebase 项目的默认 Cloud Storage 存储桶时触发,但应该很容易调整其触发器。

例如,您可以编写一个 callable Cloud Function that uses the Node.js Admin SDK getFiles() 方法来列出存储桶中的所有文件并调整每个文件的大小。

由于您有很多文件要处理,您很可能应该分批处理,因为 Cloud Function 的执行时间有 9 分钟的限制。

如果您的内容已经上传到云存储桶,则没有任何类型的云函数或简单代码可以部署来自动执行所有这些操作。 Cloud Functions 仅响应存储桶内发生的事件,例如对象的创建或删除。

您最终要做的是为 list all your objects, then for each one, download it, modify it locally, then upload the modified version back to the bucket. It could be lengthy, depending on on how much content you have. If you just want to do this a single time, you're best off just writing a script and running it in Cloud Shell 编写一些代码,这样您就可以最大限度地减少传输对象所花费的时间。

这里有一个快速但不完善的 NodeJS 函数,它会触发 Firebase 图像调整大小扩展。仅适用于 jpg/jpeg 个文件。

我正在将文件复制到同一目的地。复制后再次设置以前的元数据很重要,因为它会在复制操作中丢失。

const storage = await getStorage();
const bucketName = `${process.env.PROJECT_ID}.appspot.com`; //replace this with the bucket you want to run on
const bucket = storage.bucket(bucketName);
const files = await bucket.getFiles();
for (const file of files[0]) {
  const isImage = file.name.toLowerCase().includes('jpg') || file.name.toLowerCase().includes('jpeg');
  const isThumb = file.name.toLowerCase().includes('thumbs');
  if (isImage && !isThumb) {
    console.info(`Copying ${file.name}`);
    const metadata = await file.getMetadata();
    await file.copy(file.name);
    await file.setMetadata(metadata[0]);
  }
}

或者,您可以创建一个 Google 云函数(URL 端点),用于获取将在运行时调整大小并缓存到 GCS 和 CDN 的图像。例如:

https://i.kriasoft.com/sample.jpg - 原始图像 https://i.kriasoft.com/w_200,h_100/sample.jpg - 动态调整图像大小

$ npm install image-resizing --save
const { createHandler } = require("image-resizing");

module.exports.img = createHandler({
  // Where the source images are located.
  // E.g. gs://s.example.com/image.jpg
  sourceBucket: "s.example.com",

  // Where the transformed images need to be stored.
  // E.g. gs://c.example.com/image__w_80,h_60.jpg
  cacheBucket: "c.example.com",
});

https://github.com/kriasoft/image-resizing

Firebase 图像调整大小扩展在事件 "google.storage.object.finalize".

上触发

所以作为 gcp documentation 说:

This event is sent when a new object is created (or an existing object is overwritten, and a new generation of that object is created) in the bucket

为了覆盖一个对象,我们需要创建一个同名对象的副本,为了完成这个操作,我们可以使用 Node.js Admin SDK 的方法 getFiles() thanks , and then file.copy()

const { Storage } = require("@google-cloud/storage");
const storage = new Storage();

// Don't forget to replace with your bucket name
const bucket = storage.bucket("bucket-name.appspot.com"); 

const triggerBucketEvent = async () => {
  bucket.getFiles(
    {
      prefix: "public", // you can add a path prefix
      autoPaginate: false,
    },
    async (err, files) => {
      // Copy each file on same directory with the same name
      await Promise.all(files.map((file) => file.copy(file.metadata.name)));
    }
  );
};

triggerBucketEvent();