【问题标题】:Multiple image sizes | Firebase storage多种图像尺寸 | Firebase 存储
【发布时间】:2019-01-18 00:24:45
【问题描述】:

我正在尝试根据上传的文件创建缩略图,但我不确定这是否是实现此目的的正确方法。现在下面的代码不断创建缩略图。 if (fileName.startsWith(THUMB_PREFIX)) {这部分是问题所在。

是否有基于此示例创建多个缩略图的更简单方法? https://github.com/firebase/functions-samples/blob/master/generate-thumbnail/functions/index.js

exports.onFileChange = functions.storage.object()
    .onFinalize((object) => {
        const sizes = [200, 50];
        const timestamp = + new Date();

        sizes.forEach((size, index) => {

            // File and directory paths.
            const filePath = object.name;
            const contentType = object.contentType; // This is the image MIME type
            const fileDir = path.dirname(filePath);
            let fileName = path.basename(filePath);
            let newFileName = path.basename(filePath)
            let currentThumbURL = '';
            const filename = fileName.substr(0, fileName.indexOf('.'));
            let fileExtension = fileName.split('.').pop();

            fileName = filename + timestamp + '.' + fileExtension;

            const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}-${size}-${fileName}`));
            const tempLocalFile = path.join(os.tmpdir(), filePath);
            const tempLocalDir = path.dirname(tempLocalFile);
            const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);

            var folder = fileDir.substr(0, fileDir.indexOf('/'));

            if (folder !== 'profile') return null;

            if (!contentType.startsWith('image/')) {
                console.log('This is not a profile image.');
                return null;
            }

            // if (index === sizes.length - 1) {
            // Exit if the image is already a thumbnail.
            if (fileName.startsWith(THUMB_PREFIX)) {
                console.log('Already a Thumbnail.');
                return null;
            }
            // }
            // Cloud Storage files
            const bucket = gcs.bucket(object.bucket);
            const file = bucket.file(filePath);
            const thumbFile = bucket.file(thumbFilePath);
            const metadata = {
                contentType: contentType,
                // To enable Client-side caching you can set the Cache-Control headers here. Uncomment below.
                // 'Cache-Control': 'public,max-age=3600',
            };

            // Create the temp directory where the storage file will be downloaded.
            return mkdirp(tempLocalDir).then(() => {
                // Download file from bucket.
                return file.download({ destination: tempLocalFile });
            }).then(() => {
                console.log('The file has been downloaded to', tempLocalFile);
                // Generate a thumbnail using ImageMagick.
                return spawn('convert', [tempLocalFile, '-thumbnail', `${size}x${size}>`, tempLocalThumbFile], { capture: ['stdout', 'stderr'] });
            }).then(() => {
                console.log('Thumbnail created at', tempLocalThumbFile);
                // Uploading the Thumbnail.
                return bucket.upload(tempLocalThumbFile, { destination: thumbFilePath, metadata: metadata });
            }).then(() => {
                console.log('Thumbnail uploaded to Storage at', thumbFilePath);
                // Once the image has been uploaded delete the local files to free up disk space.
                console.log('Delet tempLocalFile', tempLocalFile)
                console.log('Delete tepLocalThumbFile', tempLocalThumbFile)
                fs.unlinkSync(tempLocalFile);
                fs.unlinkSync(tempLocalThumbFile);
                // Get the Signed URLs for the thumbnail and original image.
                const config = {
                    action: 'read',
                    expires: '03-01-2500',
                };
                return Promise.all([
                    thumbFile.getSignedUrl(config),
                    file.getSignedUrl(config),
                ]);
            }).then((results) => {

                const thumbResult = results[0];
                const originalResult = results[1];
                const thumbFileUrl = thumbResult[0];
                const fileUrl = originalResult[0];

                // Add the URLs to the Database
                ...


            }).then(() => {

                console.log('Thumbnail URLs saved to database. Delete original uploaded image.')

                // bucket.file(`/profile/${filename}/${filename}.png`)
                //     .delete().then(() => console.log('File deleted'))
                //     .catch(error => console.log(error))
            }

            ).catch(error => console.log(error));
        });
    });

【问题讨论】:

  • 你得到什么样的错误? if (fileName.startsWith(THUMB_PREFIX)) 通常不会“导致”任何错误,它只是检查触发云功能的文件是否还不是缩略图。在这种情况下,云函数会停止,因为没有理由处理此文件(因为它已经是缩略图)。
  • 没有错误。我不应该说错误。即使创建了缩略图,它也会不断创建更多。我希望它在第二次迭代后停止。
  • 您是否修改了示例中的代码?通常它不应该创建更多的缩略图。
  • 我确实修改了它。我需要它来创建两个缩略图。一个 200x200 的缩略图和一个 50x50 的缩略图。我还需要它为图像名称添加时间戳。这样图像就会刷新。
  • 你的两个缩略图的文件名是什么?

标签: javascript firebase google-cloud-functions firebase-storage


【解决方案1】:

从我们上面的 cmets 看来,您的问题似乎来自您“没有使用 fileName.startsWith(THUMB_PREFIX)”“检查正确的文件名”这一事实,因为您的文件名遵循 userkey + -size- + timestamp 模式。

但是,恕我直言,您的代码中还有另一个问题:您使用 sizes.forEach((size, index) => {}) 触发了两次 Cloud Function 代码。

原始 Cloud Function 代码(来自 Firebase 官方示例)链接多个异步操作以生成缩略图。原始 Cloud Function 代码仅返回一个承诺,即在链末尾解析的承诺。

如果您想在 Cloud Function 中执行此代码两次,则应修改 Promise 链以仅返回一个 Promise。


你可以按照这些思路做一些事情。这只是关于如何复制异步操作​​以并行处理两个文件的第一个草案提案。可能有很大的空间来简化代码 - 避免重复 - 请注意它根本没有经过测试!)

return mkdirp(tempLocalDir)
  .then(() => {
    // Download files from bucket.
    const promises = [];
    promises.push(file_1.download({ destination: tempLocalFile_1 }));
    promises.push(file_2.download({ destination: tempLocalFile_2 }));
    return Promise.all(promises);
  })
  .then(() => {
    const promises = [];
    promises.push(
      spawn(
        'convert',
        [
          tempLocalFile,
          '-thumbnail',
          `${THUMB_MAX_WIDTH_1}x${THUMB_MAX_HEIGHT_1}>`,
          tempLocalThumbFile_1
        ],
        { capture: ['stdout', 'stderr'] }
      )
    );

    promises.push(
      spawn(
        'convert',
        [
          tempLocalFile,
          '-thumbnail',
          `${THUMB_MAX_WIDTH_2}x${THUMB_MAX_HEIGHT_2}>`,
          tempLocalThumbFile_2
        ],
        { capture: ['stdout', 'stderr'] }
      )
    );

    return Promise.all(promises);
  })
  .then(() => {
    //console.log('Thumbnail created at', tempLocalThumbFile);
    // Uploading the Thumbnail.

    const promises = [];
    promises.push(
      bucket.upload(tempLocalThumbFile_1, {
        destination: thumbFilePath_1,
        metadata: metadata
      })
    );
    promises.push(
      bucket.upload(tempLocalThumbFile_1, {
        destination: thumbFilePath_1,
        metadata: metadata
      })
    );
    return Promise.all(promises);
  })
  .then(() => {
    console.log('Thumbnail uploaded to Storage at', thumbFilePath);
    // Once the image has been uploaded delete the local files to free up disk space.
    fs.unlinkSync(tempLocalFile_1);
    fs.unlinkSync(tempLocalThumbFile_1);
    fs.unlinkSync(tempLocalFile_2);
    fs.unlinkSync(tempLocalThumbFile_2);
    // Get the Signed URLs for the thumbnail and original image.
    const config = {
      action: 'read',
      expires: '03-01-2500'
    };
    return Promise.all([
      thumbFile_1.getSignedUrl(config),
      file_1.getSignedUrl(config),
      thumbFile_2.getSignedUrl(config),
      file_2.getSignedUrl(config)
    ]);
  })
  .then(results => {....}}

另外,我建议你观看 Firebase 视频系列中关于“JavaScript Promises”的 3 个视频:https://firebase.google.com/docs/functions/video-series/

【讨论】:

  • 是的。我不认为这是创建多个缩略图的正确方法。谢谢!我会看看我能想出什么。
  • 我刚刚通过修改示例中的原始代码的 proposal 更新了我的答案。这只是关于如何复制异步操作​​以并行处理两个文件的初稿。它尚未经过测试!
  • 我会测试它。谢谢。
  • @Ciprian 嗨,您有时间根据提案制定解决方案吗?
  • 你好。不,我意识到正在上传的图像已经调整大小。所以我只是从中创建了一个缩略图。感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 2013-02-05
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
相关资源
最近更新 更多