Как создать поле MongoDB/mongoengine ImageField из опубликованного изображения в кодировке base64?


У меня есть небольшое приложение Python / Flask, которое должно хранить картинку в MongoDB.

  1. клиент отправляет сообщение HTTP (JSON) с одним из полей, являющимся изображением в кодировке base64.
  2. сервер должен хранить это изображение в поле MongoDB ImageField. Сейчас я использую монгоинжайн.

Модель:

class Image(db.EmbeddedDocument):
    data = db.ImageField()

Прямо сейчас соответствующий код сервера выглядит следующим образом:

import Image as PIL
import base64
import cStringIO # I'm trying to give PIL something that can handle common file operations without having to write to disk

imageData = jsondata['image']
file_like = cStringIO.StringIO(base64.decodestring(imageData))
PILImage = PIL.open(file_like)

# new mongo object
img = Image(name="imagename")
img.data = PILImage # assignment of image data
img.save()

Это дает мне ошибку #=>ValidationError: ValidationError (Местоположение: 53e37ed6844de403e0998182) (изображение.grid_id: ['images'])

Когда я изменяю назначение данных изображения на это:

img.data.put(PILImage)

Я получаю ошибку: # = > ValidationError: недопустимое изображение: read

Поэтому я подумал, что он, возможно, ищет объект, который поддерживает метод "read". Когда я изменяю назначение на это:
img.data.put(file_like)

Я получаю ошибку: # = > "ValidationError: недопустимое изображение: не удается идентифицировать файл изображения"

Итак, я могу кодировать base64, json.нагрузки(), пост, формат JSON.dumps (), base64decode и создать PIL-образ из данных, но я почему-то не могу заставить поле MongoDB ImageField принять его в качестве образа.

Может ли кто-нибудь помочь?

Одна вещь: я обнаружил, что если я просто запишу Пилимаж на диск, а затем сохраню его, сказав mongoengine

img.data.put("path/to/image/file")

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

1 2

1 ответ:

Если вам это все еще нужно, вот мое решение:

import tempfile

# this can change depending if you send the JSON by url or not
file_like = base64.b64decode(imageData)
bytes_image = bytearray(file_like)

with tempfile.TemporaryFile() as f:
    f.write(bytes_image)
    f.flush()
    f.seek(0)
    img.data.put(f)

img.save()

Надеюсь, это поможет