【问题标题】:Firebase Cloud Function to resize image on firestore createFirebase Cloud 功能在 Firestore 创建时调整图像大小
【发布时间】:2018-09-09 12:56:35
【问题描述】:

我正在努力实现以下目标。但是,我不知道,因为我是 firebase 的初学者。

  1. 用户正在尝试上传带有图片的帖子
  2. 图片是从网络浏览器中选择的
  3. 当用户单击保存按钮时,我正在将所选图像上传到 firbase 存储并获取下载 URL。
  4. 将带有下载 URL 的帖子数据插入到 Firestore 数据库。

到此为止,我已经完成了。现在,我需要调整上传图片的大小。

为此,我正在尝试使用 Cloud Functions,每当将新条目添加到 firestore 数据库时,我都会调用 Cloud fountion,它可以访问图像的下载 URL,使用此下载 URL,我需要调整大小图片。请帮忙。

如果有更好的方法来实现这一点,请告诉我。 (我知道应该有:P)

编辑 1

感谢您弗兰克的回复。

我有下面的云函数,每插入一个帖子就会调用它。我从 eventSnapshot 获取图像的下载 URL。我需要调整该位置的图像大小。请帮忙。

exports.resizeImage = functions.firestore
.document('posts/{postId}')
.onCreate(event => {
        var eventSnapshot = event.data.data();
        //In this eventSnapshot I am getting the document, and I can get the download URL from the document
});

我已经分析了创建缩略图的示例,但为此,我需要
存储对象,只有当存储对象改变时才会调用。但是,我需要在 firestore 中调用 onWrite 时创建缩略图。

 exports.generateThumbnail = functions.storage.object().onChange((event) => {
  // File and directory paths.
  const filePath = event.data.name;
});

请告诉我,如何通过检测 firestore 中的 onWrite 并使用 downLoadURL 来进行图像调整大小操作。

【问题讨论】:

  • 听起来您正在顺利构建应用程序,但在特定步骤(调整图像大小)方面遇到了问题。在这种情况下,最好将您的问题集中在那个特定的问题上,展示您尝试过的内容。最好的方法是通过creating a minimal, complete, verifiable example,它可以重现问题,而我们无需了解您的应用程序的其余部分。如果您正在为如何开始调整图像大小而苦恼,请查看此示例:github.com/firebase/functions-samples/tree/master/…
  • @FrankvanPuffelen 非常感谢您的评论,我已经编辑了这个问题。请帮忙。提前谢谢你。
  • @FrankvanPuffelen 请提出您的建议....
  • 您有没有找到可行的解决方案?我使用的是 FirebaseDatabase 而不是 Firestore,但遇到了同样的问题。我已经成功生成了一个缩略图,但将下载 URL 存储在我的用户数据中已被证明是一件令人头疼的事情。

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


【解决方案1】:

我也在 Firestore 中创建了一个文档,用作网站的后端。我也想调整图像大小(以适合卡片)并将 URL 写回 Firestore。我找到了一个解决方案,该解决方案使用与标准示例不同的模式,标准示例通过将图像上传到存储来触发。

基本上,我将图像上传到存储,然后将 URL 写入我的应用页面中的 Firestore。然后我使用 Firestore 的 onCreate() 触发器触发该函数。

该函数从 firestore 中获取“image_name”并使用它来获取存储中的文件引用。接下来,它遵循 generate-thumbnail firebase 示例的模式。

然后,诀窍是抓取 signedUrl 并将其写回 img_src 中的 firestore。

如果其他人觉得这很有用:

const functions = require('firebase-functions');
const gcs = require('@google-cloud/storage')({keyFilename: 'service-key.json'});
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

exports.createCard = functions.firestore
  .document('work_cards/{cardID}')
  .onCreate((snap, context) => {
    const newCardData = snap.data()
    const bucket = gcs.bucket('your-project-id.appspot.com')
    const file = bucket.file(newCardData.image_name)
    const tempFilePath = path.join(os.tmpdir(), file.name);
    const thumbFileName = `thumb_${file.name}`;
    const thumbFilePath = bucket.file(thumbFileName)
    const contentType = file.contentType;
    const metadata = {
      contentType: contentType
    };

    return bucket.file(file.name).download({
        destination: tempFilePath,
      })
      .then(() => {
        return spawn('convert', [tempFilePath, '-thumbnail', '250x250', tempFilePath]);
      })
      .then(() => {
        return bucket.upload(tempFilePath, {
          destination: thumbFilePath,
          metadata: metadata,
        })
      })
      .then(() => {
        return thumbFilePath.getSignedUrl({
        action: 'read',
        expires: '03-09-2491'
        })
      })
      .then(signedUrls => {
        const img_src = signedUrls[0]
        return snap.ref.set({img_src}, {merge: true});
      })
      .then(() => {
        bucket.file(file.name).delete()
        fs.unlinkSync(tempFilePath)
        return
      })
    });

【讨论】:

    【解决方案2】:

    您可以让 Cloud Storage 触发 Cloud Function 来调整图像大小,而不是从 Cloud Firestore 获取 URL。在 GitHub 上有一个很好的例子来说明如何做到这一点。

    Firebase SDK for Cloud Functions Quickstart - Cloud Storage trigger

    【讨论】:

    • 谢谢 Jason,如果我使用存储触发器创建缩略图,如何将新缩略图的下载 URL 更新回 Firestore?
    • 作为存储触发器的一部分,您可以在创建缩略图后更新 Cloud Firestore。或者,您可以简单地将_thumbnail 添加到文件名的末尾,并且您的应用可以知道找到 Firestore 中列出的文档名称,并添加此内容。
    • 感谢 Jason 的回复。 1.是的,但是,当storage trigger调用该函数时,firestore数据库不会有那个下载URL的文档,因为只有文件上传成功后,我正在将文档写入firestore。 2.如果我用_thumbnail重命名文件,它被存储为一个新文件,下载地址也是新的。如何使用原始文件的下载 URL 生成/更新此缩略图的下载 URL?
    • 实现此目的的最简单方法是使用 Firestore(20 个字符)文档 ID 命名文件。
    • 或者,您可以在 Firestore 中获得下载 URL,在 Cloud Storage 中调整图像大小的代码。使用下载 URL 从您的 Cloud Firestore 函数中获取图像并调整其大小
    【解决方案3】:

    我也需要实现这一点,但对我来说,使用 Cloud Storage 触发器并不是一个合适的解决方案,因为我不想调整所有内容的大小。

    我的场景是用户会上传许多图像,但他们选择了一个作为缩略图。我将 Birch 的代码修改为可调用函数,将文件引用数据传递给它

    exports.generateThumbnail = functions.https.onCall((data, context) => {
      const file = bucket.file(`/designs/${context.auth.uid}/${data.design}/${data.image}`)
      const tempFilePath = path.join(os.tmpdir(), `${data.image}`);
      const thumbFileName = `thumb_${data.image}`;
      const thumbFilePath = bucket.file(`/designs/${context.auth.uid}/${data.design}/${thumbFileName}`);
    
      return bucket.file(file.name).download({
           destination: tempFilePath,
         })
         .then(() => {
           return spawn('convert', [tempFilePath, '-trim','-resize', '190', tempFilePath]);
         })
         .then(() => {
           return bucket.upload(tempFilePath, {
             destination: thumbFilePath,
           })
         })
         .then(() => {
           fs.unlinkSync(tempFilePath)
           return
         })
    })
    

    【讨论】:

      【解决方案4】:

      当我们的用户创建或更新 firestore 对象时,我通过生成和设置缩略图来做到这一点。

      resizeImage.ts

      import * as admin from "firebase-admin";
      const mkdirp = require("mkdirp-promise");
      import { spawn } from "child-process-promise";
      import * as path from "path";
      import * as os from "os";
      import * as fs from "fs";
      
      export default async function resizeImage(
          filePath: string,
          size: string
      ): Promise<string> {
          // File and directory paths.
          const fileDir = path.dirname(filePath);
          const fileName = path.basename(filePath);
          const thumbFilePath = path.normalize(
              path.join(fileDir, `thumb_${size}_${fileName}`)
          );
          const tempLocalFile = path.join(os.tmpdir(), filePath);
          const tempLocalDir = path.dirname(tempLocalFile);
          const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);
      
          // Cloud Storage files.
          const bucket = admin.storage().bucket();
          const file = bucket.file(filePath);
          const thumbFile = bucket.file(thumbFilePath);
          const metadata = {
              contentType: null
              // To enable Client-side caching you can set the Cache-Control headers here. Uncomment below.
              // 'Cache-Control': 'public,max-age=3600',
          };
          await file.getMetadata().then(data => {
              if (data && data[0] && data[0]["contentType"]) {
                  metadata["contentType"] = data[0]["contentType"];
              }
          });
      
          // Create the temp directory where the storage file will be downloaded.
          await mkdirp(tempLocalDir);
          // Download file from bucket.
          await file.download({ destination: tempLocalFile });
          console.log("The file has been downloaded to", tempLocalFile);
          // Generate a thumbnail using ImageMagick.
          await spawn(
              "convert",
              [
                  tempLocalFile,
                  "-auto-orient",
                  "-thumbnail",
                  `${size}>`,
                  tempLocalThumbFile
              ],
              { capture: ["stdout", "stderr"] }
          );
          console.log("Thumbnail created at", tempLocalThumbFile);
          // Uploading the Thumbnail.
          await bucket.upload(tempLocalThumbFile, {
              destination: thumbFilePath,
              metadata: metadata
          });
          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);
          fs.unlinkSync(tempLocalThumbFile);
          return thumbFile
              .getSignedUrl({
                  action: "read",
                  expires: "03-01-2500"
              })
              .then((urls: string[]) => urls[0]);
      }
      

      resizeAvatar.ts

      const functions = require("firebase-functions");
      import { Change } from "firebase-functions";
      import resizeImage from "./resizeImage";
      
      async function resizeAvatar(snapshot: FirebaseFirestore.DocumentSnapshot) {
          const data = snapshot.data();
          const filePath = data && data.avatarPath;
          if (!data || !filePath || data.avatarUrlSmall) {
              return; // No avatar or already resized
          }
          const url = await resizeImage(filePath, "200x200");
          await snapshot.ref.set({ avatarUrlSmall: url }, { merge: true });
      }
      
      exports.resizeAvatarOnCreate = functions.firestore
          .document("users/{userID}")
          .onCreate(async (snapshot: FirebaseFirestore.DocumentSnapshot) => {
              await resizeAvatar(snapshot);
          });
      
      exports.resizeAvatarOnUpdate = functions.firestore
          .document("users/{userID}")
          .onUpdate(async (change: Change<FirebaseFirestore.DocumentSnapshot>) => {
              await resizeAvatar(change.after);
          });
      

      【讨论】:

        猜你喜欢
        • 2019-01-03
        • 2017-10-23
        • 2011-02-21
        • 2019-05-17
        • 2017-08-14
        • 2020-05-10
        • 2017-12-29
        • 1970-01-01
        • 2014-06-16
        相关资源
        最近更新 更多