将图像数据作为base64编码的JSON;我将其转换为Nodejs Buffer类型的对象,如何从已保存的缓冲区数据中再次显示图像?

djmepvbi  于 2023-06-05  发布在  Node.js
关注(0)|答案(2)|浏览(369)

我的情况如下。
我正在从OpenAI的DALLE-2 API中检索一些图像数据。响应以base64编码的JSON形式提供数据。检索后,我将其存储在MongoDB数据库中,作为Schema. Types. Buffer。我正在使用GraphQL的Apollo实现作为我的API查询语言。我需要创建一个自定义的标量类型,这样我就可以为Image模型的 binData 字段分配自定义的标量类型 ImgBinData。请看下面我的类型图片定义:

对于自定义标量类型,我需要在Apollo Server提供的GraphQLScalarType类示例中定义处理逻辑。在这里我创建了Nodejs Buffer并将其保存到图像的 binData 字段。

我不确定我所做的是否正确的地方是,一旦我想检索存储在图像的binData字段中的缓冲区数据。我该怎么做才能把这个二进制数据转换回它所代表的图像?我是否需要更改自定义标量的 serialize 方法中发生的事情?到目前为止,它只是返回Buffer数组中的整数序列:

我想使用此二进制数据作为视图层中图像元素的源值。

@Traynor,这是我的React函数组件代码:

import React from "react";
import { useQuery } from "@apollo/client";
import { GET_IMAGE_BY_ID } from "../utils/queries";

const ProfilePicture = () => {
  // run query here
  const { loading, error, data } = useQuery(GET_IMAGE_BY_ID, {
    variables: { imageId: "64715e7413b66dd4d30eea3b" },
  });

  if (loading) return null;
  if (error) return `Error! ${error}`;
  const imgBinData = data?.imageByImageId.binData.data;
  console.log(imgBinData);
  const imgType = "image/png";
  const blob = new Blob([new Uint8Array(imgBinData)], { type: imgType});
  const src = URL.createObjectURL(blob);
  return (
    <img
      src={src}
      className=""
      alt="A headshot of the user"
    />
  );
};

export default ProfilePicture;

下面是我的自定义标量逻辑:

const { GraphQLScalarType, Kind } = require("graphql");

const imgBinDataScalar = new GraphQLScalarType({
  name: "ImgBinData",
  description:
    "Custom scalar for storing image bin data in form of Nodejs Buffer type",
  serialize: (bufferObj) => bufferObj,
  parseValue: (value) => Buffer.from(value, "base64"),
  parseLiteral: (ast) => Buffer.from(ast.value, "base64"),
});

module.exports = {
  imgBinDataScalar,
};

下面是我从OpenAI的API收到的base64编码的JSON的快照。属性 b64_json 的值是我在上面的自定义标量示例中传递给parseValue方法的值。所有base64编码的字符都被输入Buffer.from方法。我想向你展示这个,这样我就不会在从OpenAI接收数据的那一刻留下任何空白,通过数据转换,直到想要在img元素中显示它。

此外,以下是Chrome DevTools网络选项卡和元素选项卡的快照:

z9gpfhce

z9gpfhce1#

所以,服务器发送buffer为JSON,这意味着你需要将其转换为blob,然后将其转换为URL,这样你就可以将其分配为img.src,以便可以显示。
因此,将数据数组(我认为是data.imageByImageId.binData.data,这就是为什么你应该发布代码,而不是截图)转换为Uint8Array(另外,你需要将图像类型存储到数据库中,并检索它),然后创建一个Blob,然后将Blob转换为URL并将其分配给src属性(你可能需要调整选择器)
试试这个:

// make sure you pass the image data array property
const responseImage = data.imageByImageId.binData.data;

// you'll need to store and retrieve image type as well
const imgType = 'image/jpeg';

const blob = new Blob([new Uint8Array(responseImage)], {type:imgType});

// get the img element, and add image to src
document.querySelector('.profile__details__div--image img').src = window.URL.createObjectURL(blob);
blmhpbnm

blmhpbnm2#

看起来你的Scalar实现并没有做你想要的。函数parseValueparseLiteral采用base64的String并将其转换为Buffer。我假设您希望在服务器上使用Buffer类型,并且对于传输层,您希望使用base64字符串,类似于OpenAI所做的。这些函数可以通过验证和检查来改进,你实际上得到的是字符串,但除此之外,它们看起来很好。
同样,假设您希望在服务器上使用Buffer类型,并且用于传输层,那么您的serialize函数是错误的。它返回普通缓冲区。这就是为什么在GraphiQL中,你会得到一个奇怪的对象:

{
  type: 'Buffer',
  data: [...],
}

让我们修复这个问题,返回一个base64字符串。您可以使用BuffertoString方法。

serialize: (value) => value.toString('base64')

现在,看起来你在react方面的想法实际上相当不错!您没有添加代码,但浏览器屏幕截图似乎几乎是您想要的(小心,您在image/jpeg中有一个错字)。您可以创建使用base64编码数据的源URL。

const url = `data:image/jpeg;base64,${imageByImgId.binData}`;

return <img src={url} />

应该就是这里了

相关问题