Как загрузить изображение (строку) в кодировке base64 непосредственно в корзину Google Cloud Storage с помощью Node.js?

В настоящее время я использую пакет NPM @ google-cloud / storage для загрузки файла непосредственно в корзину Google Cloud Storage. Это требует некоторой хитрости, поскольку у меня есть только закодированная строка base64 изображения. Мне пришлось:

  • Расшифровать строку
  • Сохраните это как файл
  • Отправьте путь к файлу в приведенный ниже скрипт для загрузки в Google Cloud Storage.
  • Удалить локальный файл

Я бы хотел вообще не сохранять файл в файловой системе, так как я использую Google App Engine и не хочу перегружать файловую систему / оставлять там ненужные файлы, если по какой-либо причине операция удаления не работает. Вот как сейчас выглядит мой скрипт загрузки:

// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var base64Img = require('base64-img');
var filePath = base64Img.imgSync(req.body.base64Image, 'user-uploads', 'image-name');

// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
    bucket = gcs.bucket('google-cloud-storage-bucket-name');

// Upload the image to the bucket
bucket.upload(__dirname.slice(0, -15) + filePath, {
    destination: 'profile-images/576dba00c1346abe12fb502a-original.jpg',
    public: true,
    validation: 'md5'
}, function(error, file) {

    if (error) {
        sails.log.error(error);
    }

    return res.ok('Image uploaded');
});

Есть ли способ напрямую загрузить закодированную в base64 строку изображения вместо необходимости преобразовывать ее в файл, а затем загружать по пути?

7 ответов

Решение

Решение, я считаю, заключается в использовании file.createWriteStream функциональность, которая bucket.upload Функция обертывания в Google Cloud Node SDK.

У меня очень мало опыта работы с потоками, поэтому постарайтесь терпеть меня, если это не сработает сразу.

Прежде всего, нам нужно взять данные base64 и поместить их в поток. Для этого мы собираемся включить stream библиотека, создайте буфер из данных base64 и добавьте буфер в конец потока.

var stream = require('stream');
var bufferStream = new stream.PassThrough();
bufferStream.end(new Buffer(req.body.base64Image, 'base64'));

Подробнее о декодировании base64 и создании потока.

Затем мы собираемся направить поток в поток записи, созданный file.createWriteStream функция.

var gcs = require('@google-cloud/storage')({
  projectId: 'grape-spaceship-123',
  keyFilename: '/path/to/keyfile.json'
});

//Define bucket.
var myBucket = gcs.bucket('my-bucket');
//Define file & file name.
var file = myBucket.file('my-file.jpg');
//Pipe the 'bufferStream' into a 'file.createWriteStream' method.
bufferStream.pipe(file.createWriteStream({
    metadata: {
      contentType: 'image/jpeg',
      metadata: {
        custom: 'metadata'
      }
    },
    public: true,
    validation: "md5"
  }))
  .on('error', function(err) {})
  .on('finish', function() {
    // The file upload is complete.
  });

Информация о file.createWriteStream, Файл документов, bucket.upload и bucket.upload код метода в Node SDK.

Таким образом, вышеприведенный код работает так, чтобы определить область, в которую вы хотите поместить файл, а затем определить файл и имя файла. Мы не устанавливаем здесь параметры загрузки. Затем мы отправим bufferStream переменная, которую мы только что создали в file.createWriteStream метод, который мы обсуждали ранее. В этих опциях мы определяем метаданные и другие опции, которые вы хотите реализовать. Было очень полезно взглянуть непосредственно на код узла на Github, чтобы выяснить, как они ломают bucket.upload функции, и рекомендую вам это сделать. Наконец, мы добавляем пару событий, когда загрузка заканчивается и когда происходит ошибка.

Публикация моей версии ответа в ответ на запрос @krlozadan выше:

// Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
var mimeTypes = require('mimetypes');

var image = req.body.profile.image,
    mimeType = image.match(/data:([a-zA-Z0-9]+\/[a-zA-Z0-9-.+]+).*,.*/)[1],
    fileName = req.profile.id + '-original.' + mimeTypes.detectExtension(mimeType),
    base64EncodedImageString = image.replace(/^data:image\/\w+;base64,/, ''),
    imageBuffer = new Buffer(base64EncodedImageString, 'base64');

// Instantiate the GCP Storage instance
var gcs = require('@google-cloud/storage')(),
    bucket = gcs.bucket('my-bucket');

// Upload the image to the bucket
var file = bucket.file('profile-images/' + fileName);

file.save(imageBuffer, {
    metadata: { contentType: mimeType },
    public: true,
    validation: 'md5'
}, function(error) {

    if (error) {
        return res.serverError('Unable to upload the image.');
    }

    return res.ok('Uploaded');
});

Это работало очень хорошо для меня. Не обращайте внимания на некоторые дополнительные логики в первых нескольких строках, так как они относятся только к приложению, которое я создаю.

Если вы хотите сохранить строку как файл в Google Cloud Storage, вы можете легко сделать это с помощью file.save метод:

const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const myBucket = storage.bucket('my-bucket');

const file = myBucket.file('my-file.txt');
const contents = 'This is the contents of the file.';

file.save(contents).then(() => console.log('done'));

:) что за проблема!! Попробовали и получили проблему Изображение было загружено в хранилище firebase, но не загружено, и просто загрузчик перемещается вокруг и вокруг... Потратив время... Получил успех, чтобы загрузить изображение в хранилище firebase с загрузкой... Было проблема в токене доступа...

check the screenshot

Если вы отметите раздел расположения файла в правом нижнем углу, есть опция "создать токен доступа" и не отобразить там какой-либо "токен доступа", если вы создадите там токен доступа вручную, тогда обновите изображение страницы, которое будет отображаться... Итак, теперь вопрос в том, как создать его по коду...

просто используйте приведенный ниже код для создания токена доступа

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();
metadata: { firebaseStorageDownloadTokens: uuid }

Ниже приведен полный код для загрузки изображения в хранилище image в хранилище firebase

const functions = require('firebase-functions')
var firebase = require('firebase');
var express = require('express');
var bodyParser = require("body-parser");

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "-----BEGIN PRIVATE KEY-----\jr5x+4AvctKLonBafg\nElTg3Cj7pAEbUfIO9I44zZ8=\n-----END PRIVATE KEY-----\n",
        "client_email": "xxxx@xxxx.iam.gserviceaccount.com",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);

Вам нужно преобразовать base64 в буфер изображений, а затем загрузить, как показано ниже, вам необходимо предоставить image_data_from_html переменная в качестве данных, которые вы извлекаете из события HTML.

const base64Text = image_data_from_html.split(';base64,').pop();
const imageBuffer = Buffer.from(base64Text, 'base64');
const contentType = data.image_data.split(';base64,')[0].split(':')[1];
const fileName = 'myimage.png';
const imageUrl = 'https://storage.googleapis.com/bucket-url/some_path/' + fileName;

await admin.storage().bucket().file('some_path/' + fileName).save(imageBuffer, {
    public: true,
    gzip: true,
    metadata: {
        contentType,
        cacheControl: 'public, max-age=31536000',
    }
});

console.log(imageUrl);

Мне удалось передать строку base64 в корзину Cloud Storage с помощью всего одной строчки кода.

var decodedImage = new Buffer(poster64, 'base64');
        

// Store Poster to storage
let posterFile = await client.file(decodedImage, `poster_${path}.jpeg`, { path: 'submissions/dev/', isBuffer: true, raw: true });
let posterUpload = await client.upload(posterFile, { metadata: { cacheControl: 'max-age=604800' }, public: true, overwrite: true });
let permalink = posterUpload.permalink

Следует помнить, что если вы находитесь в среде Nodejs, вы не сможете использовать atob().

Главный ответ этого поста показал мне мои ошибки! Кодирование / декодирование изображений в NodeJS base64 не совсем работает

      const { Storage } = require('@google-cloud/storage');
const storage = new Storage() // start with your creadentials 
const contents = "data:image/jpeg..." // raw image data base64 encoded
const bucketName = "your google cloud bucket name";
const fileExtension = contents.split(";")[0].split("/")[1];
const destFileName = `${v4().toString()}.${fileExtension || "jpg"}` // random file name
const bucket = storage.bucket(bucketName);
// Create a reference to a file object
const file = bucket.file(destFileName || "filename.jpg");

// Create a pass through stream from a string
const passthroughStream = new stream.PassThrough();
passthroughStream.write(Buffer.from(contents.replace(/^data:image\/(png|gif|jpeg);base64,/, ''), 'base64'));
passthroughStream.end();

      async function streamFileUpload() {
        return new Promise((resolve, reject) => {
          passthroughStream.pipe(file.createWriteStream({
            gzip: true,
            metadata: {
              contentType,
              metadata: {
                custom: 'metadata'
              }
            }
          }))
            .on('finish', () => {
              resolve({
                url: `https://storage.googleapis.com/${bucketName}/${destFileName}`,
                title: destFileName,
              })
            }).on("error", (err) => {
              reject(err)
            });

          // console.log(result);
          console.log(`uploaded to '${bucketName}' as '${destFileName}'.`);
        })
      }

const result = await streamFileUpload().catch(console.error);

Результат содержит URL-адрес и название файла, загруженного в облако Google.

Другие вопросы по тегам