繁体   English   中英

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

[英]Firebase Cloud Function to resize image on firestore create

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

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

直到这个,我已经完成了。 现在,我需要调整上传的图像大小。

为此,我正在尝试使用云功能,每当新条目添加到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告诉我如何进行图像大小调整操作。

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

适用于云功能的Firebase SDK快速入门 - 云存储触发器

我也在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
      })
    });

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

我的情况是用户会上传一些图像,但他们选择了一个作为缩略图。 我修改了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
     })
})

当我们的用户创建或更新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);
    });

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM