【问题标题】:Resize all images stored in Firebase Storage调整存储在 Firebase 存储中的所有图像的大小
【发布时间】:2020-11-12 12:38:53
【问题描述】:
我在 Firebase 存储桶上上传了大约 10k 张高分辨率图片。到目前为止,由于带宽很高,我需要在不删除原始图像的情况下缩小存储桶中的这些图像。
Firebase 图片调整大小扩展功能解决了这个问题,但仅适用于那些新上传的图片,它不适用于已经上传的图片。
那么,有没有办法做到这一点。我知道我们使用云函数来调整图像大小,但我不确定我将如何实现这一点,因为云函数无法工作。
【问题讨论】:
标签:
image
firebase
google-cloud-storage
image-resizing
【解决方案1】:
有一个官方的云函数sample,它展示了如何调整图像大小(它实际上与作为调整图像大小扩展基础的云函数非常相似)。
此示例 Cloud Function 在将文件上传到 Firebase 项目的默认 Cloud Storage 存储桶时触发,但它应该很容易调整其触发器。
例如,您可以编写一个 callable Cloud Function,使用 Node.js Admin SDK getFiles() 方法列出存储桶的所有文件并调整每个文件的大小。
由于您有很多文件要处理,因此您很可能应该批量处理,因为 Cloud Function 执行的时间限制为 9 分钟。
【解决方案2】:
这是一个快速而肮脏的 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]);
}
}
【解决方案3】:
如果您的内容已上传到 Cloud Storage 存储分区,则无需部署任何类型的 Cloud Function 或简单代码来自动完成所有这些操作。 Cloud Functions 仅响应存储桶内发生的事件,例如对象的创建或删除。
您最终要做的就是向list all your objects 编写一些代码,然后为每个download it 在本地修改它,然后将修改后的版本upload 返回到存储桶。它可能很长,具体取决于您拥有多少内容。如果您只想一次性执行此操作,最好只编写一个脚本并在 Cloud Shell 中运行它,这样您就可以最大限度地减少传输对象所花费的时间。
【解决方案5】:
Firebase 图像大小调整扩展在事件 “google.storage.object.finalize” 上触发。
所以作为gcp documentation 说:
在桶中创建新对象(或覆盖现有对象,并创建该对象的新一代)时发送此事件
对于覆盖的对象,我们需要创建一个具有相同名称的对象的副本,为了完成此操作,我们可以使用 Node.js Admin SDK 的方法getFiles() 感谢Renaud Tarnec,然后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();