Как сохранить изображение в кодировке base64 в AppEngine?

Я пытаюсь создать запись в хранилище блогов из объекта data-uri, но я застреваю.

По сути, я публикую через ajax data-uri как текст, пример полезной нагрузки:

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPA...

Я пытаюсь получить эту полезную нагрузку с помощью следующего обработчика. Я предполагаю, что мне нужно конвертировать data-uri вернуться в образ перед сохранением? Поэтому я использую библиотеку PIL.

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

import os
import urllib
import webapp2
from google.appengine.ext.webapp import template
from google.appengine.ext import blobstore
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.api import images

class ImageItem(db.Model):
  section = db.StringProperty(required=False)
  description = db.StringProperty(required=False)
  img_url = db.StringProperty()
  blob_info = blobstore.BlobReferenceProperty()
  when = db.DateTimeProperty(auto_now_add=True)


#Paste upload handler
class PasteUpload(webapp2.RequestHandler):
    def post(self):
        from PIL import Image
        import io
        import base64

        data = self.request.body
        #file_name = data['file_name']

        img_data = data.split('data:image/png;base64,')[1]

        #Convert base64 to jpeg bytes
        f = Image.open(io.BytesIO(base64.b64decode(img_data)))

        img = ImageItem(description=self.request.get('description'), section=self.request.get('section') )
        img.blob_info = f.key()
        img.img_url = images.get_serving_url( f.key() )
        img.put()

Это, вероятно, все виды неправильно. Я получаю следующую ошибку при публикации:

img.blob_info = f.key()
AttributeError: 'PngImageFile' object has no attribute 'key'

Что я здесь не так делаю? Есть ли более простой способ сделать это? Я думаю, мне не нужно конвертировать data-uri в изображение для хранения в виде капли?

Я также хочу, чтобы этот обработчик возвращал URL-адрес изображения, созданного в blobstore.

2 ответа

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

POST base64 для_ah/upload/...

Ваш сервис использует create_upload_url() сделать одноразовую загрузку URL/ сессии для вашего клиента. Ваш клиент создает POST для этого URL, и данные никогда не затрагивают вашу службу (без ограничений размера HTTP-запроса, без затрат времени ЦП на обработку POST). Внутренняя "служба BLOB-объектов" App Engine получает этот POST и сохраняет тело как Blob в Blobstore. Затем App Engine передает управление вашему сервису в BlobstoreUploadHandler Класс, который вы пишете, а затем вы можете определить, как вы хотите ответить на успешный POST. В случае с примером / учебником, PhotoUploadHandler перенаправляет клиента на только что загруженную фотографию.

Этот POST от вашего клиента должен быть закодирован как multipart/mixed и используйте поля, показанные в примере HTML <form>,

Составная форма может принимать необязательный параметр, Content-Transfer-Encodingи внутренний обработчик App Engine правильно декодирует данные base64. От blob_upload.py:

base64_encoding = (form_item.headers.get('Content-Transfer-Encoding') ==
                           'base64')
...

if base64_encoding:
  blob_file = cStringIO.StringIO(base64.urlsafe_b64decode(blob_file.read()))

...

Вот полная многочастная форма, которую я протестировал с помощью cURL, основываясь на полях, использованных в примере. Я узнал, как это сделать в. Есть ли способ передать содержимое файла в curl?:

myconfig.txt:

header = "Content-length: 435"
header = "Content-type: multipart/mixed; boundary=XX
data-binary = "@myrequestbody.txt"

myrequestbody.txt:

--XX
Content-Disposition: form-data; name="file"; filename="test.gif"
Content-Type: image/gif
Content-Transfer-Encoding: base64

R0lGODdhDwAPAIEAAAAAzMzM/////wAAACwAAAAADwAPAAAIcQABCBxIsODAAAACAAgAIACAAAAiSgwAIACAAAACAAgAoGPHACBDigwAoKTJkyhTqlwpQACAlwIEAJhJc6YAAQByChAAoKfPn0CDCh1KtKhRAAEAKF0KIACApwACBAAQIACAqwECAAgQAIDXr2DDAggIADs=
--XX
Content-Disposition: form-data; name="submit"

Submit
--XX--

а потом беги как:

curl --config myconfig.txt "http://127.0.0.1:8080/_ah/upload/..."

Вам нужно будет создать / макет многочастной формы в вашем клиенте.

Вы также не можете использовать Blobstore и Cloud Storage, если хотите / нуждаетесь. Следуйте документации по настройке Google Cloud Storage, а затем измените свой сервис, чтобы создать URL для загрузки по вашему выбору:

create_upload_url(gs_bucket_name=...)

Это немного сложнее, чем просто это, но чтение раздела Использование API-интерфейса Blobstore с Google Cloud Storage в документе Blobstore поможет вам в правильном направлении.

POST base64 непосредственно к вашему сервису / обработчику

Вроде того, как вы кодировали в исходном посте, ваш сервис получает POST от вашего клиента, и вы затем решаете, нужно ли вам манипулировать изображением и где вы хотите его сохранить (Datastore, Blobstore, Cloud Storage).

Если вам нужно манипулировать изображением, тогда хорошо использовать PIL:

from io import BytesIO
from PIL import Image
from StringIO import StringIO

data = self.request.body
#file_name = data['file_name']

img_data = data.split('data:image/png;base64,')[1]

# Decode base64 and open as Image
img = Image.open(BytesIO(base64.b64decode(img_data)))

# Create thumbnail
img.thumbnail((128, 128))

# Save img output as blob-able string
output = StringIO()
img.save(output, format=img.format)
img_blob = output.getvalue()

# now you choose how to save img_blob

Если вам не нужно манипулировать изображением, просто остановитесь на b64decode():

img_blob = base64.b64decode(img_data)

Объект изображения ( https://cloud.google.com/appengine/docs/standard/python/refdocs/google.appengine.api.images) не является сущностью хранилища данных, поэтому у него нет ключа. Вам действительно нужно сохранить изображение в blobstore[2] или Google Cloud Storage[1], а затем получить URL-адрес для вашего изображения.

[1] https://cloud.google.com/appengine/docs/standard/python/googlecloudstorageclient/setting-up-cloud-storage

[2] https://cloud.google.com/appengine/docs/standard/python/blobstore/

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