Firebase Cloud功能用于在firestore创建时调整图像大小

时间:2018-03-30 13:14:59

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

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

  1. 用户正在尝试上传带有图片的帖子
  2. 从网络浏览器中选择图片
  3. 当用户点击保存按钮时,我将所选图像上传到firbase存储并获取下载URL。
  4. 将带有下载URL的帖子数据插入到firestore数据库。
  5. 直到此,我已经完成了。现在,我需要调整上传的图像大小。

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

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

    修改1

    感谢 Frank 的回复。

    我有以下云功能,将为每个帖子插入调用。我从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告诉我如何进行图像大小调整操作。

4 个答案:

答案 0 :(得分:1)

您可以让Cloud Storage触发云功能来调整图像大小,而不是从Cloud Firestore获取URL。在GitHub上有一个很好的例子。

Firebase SDK for Cloud Functions Quickstart - Cloud Storage trigger

答案 1 :(得分:1)

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

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

该功能抓取' image_name'来自firestore并使用它来获取存储中的文件引用。接下来,它遵循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 :(得分:0)

我也需要实现这一目标,但是对我而言,使用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
     })
})

答案 3 :(得分:0)

当用户创建或更新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);
    });
相关问题