2014-09-27 20 views
20

Tworzę prosty API w kolbie, który akceptuje obraz zakodowany w base64, a następnie dekoduje go do dalszego przetwarzania za pomocą Pillow.Podstawa dekodowania64 z POST do użycia w PIL

szukałem w niektórych przykładach (1, 2, 3) i myślę, że mogę istotę tego procesu, ale wciąż otrzymuję błąd gdzie Poduszka nie może odczytać ciąg dałem.

Oto co mam do tej pory:

import cStringIO 
from PIL import Image 
import base64 

data = request.form 
image_string = cStringIO.StringIO(base64.b64decode(data['img'])) 
image = Image.open(image_string) 

co daje błąd:

IOError: cannot identify image file <cStringIO.StringIO object at 0x10f84c7a0> 
+0

można wkleić na przykład tego, co dostajesz w 'danych [ 'img']'? Wyloguj się lub wydrukuj. – OregonTrail

+0

Oto przykład: http://jsfiddle.net/gn0x0wvc/. Umieściłem go w znaczniku 'img', aby upewnić się, że dane obrazu nie są uszkodzone. –

+0

Jakie dane wyglądają po 'b64decode()'? Czy jest inne kodowanie, np. urlencoding? Czy to naprawdę obraz obsługiwany przez PIL? – mhawke

Odpowiedz

39

Należy spróbować czegoś takiego:

będę zmienić ciąg obrazu dla przykład wziąłem z google tylko dla celów czytelności.

from PIL import Image 
from io import BytesIO 
import base64 

data['img'] = '''R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLlN48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==''' 

im = Image.open(BytesIO(base64.b64decode(data))) 

Twoje dane [ 'img'] napis nie powinien zawierać znaczniki HTML lub parametry dane: image/jpeg; base64,, które są w przykładowym jsfiddle.

+2

Dziękuję bardzo! To działało idealnie. Poprawiłem twoją odpowiedź. –

16

W polu img znajduje się prefiks metadanych o numerze data:image/jpeg;base64,. Zwykle te metadane są używane w identyfikatorze URI danych CSS lub HTML podczas osadzania danych obrazu w dokumencie lub arkuszu stylów. Ma on zapewniać typ MIME i kodowanie osadzonych danych w przeglądarce renderowania.

Możesz odciąć prefiks przed dekodowaniem base64, co powinno skutkować uzyskaniem prawidłowych danych obrazu, które PIL może załadować (patrz poniżej), ale naprawdę musisz zapytać, w jaki sposób metadane są przesyłane do twojego serwera, tak jak powinno. nie.

import re 
import cStringIO 
from PIL import Image 

image_data = re.sub('^data:image/.+;base64,', '', data['img']).decode('base64') 
image = Image.open(cStringIO.StringIO(image_data)) 
+0

Dziękuję bardzo! To działało idealnie! –

+0

@LazaroGamio: głównym punktem jest to, że prefiks nie powinien być obecny w danych opublikowanych na serwerze. Jak jest publikowany? – mhawke

+0

Przejmuję obraz przesłany przez użytkownika i wysyłam go do API za pomocą metody posta jquery.Przypuszczam, że mógłbym usunąć prefiks ze strony klienta zamiast usunąć go na serwerze. –

1

Przepraszamy za nekromancję, ale żadna z odpowiedzi nie sprawdziła się całkowicie. Oto kod działający na Pythonie 3.6 i Flask 0.13.

Serwer:

from flask import Flask, jsonify, request 
from io import BytesIO 
from web import app 
import base64 
import re 
import json 
from PIL import Image 

@app.route('/process_image', methods=['post']) 
def process_image(): 
    image_data = re.sub('^data:image/.+;base64,', '', request.form['data']) 
    im = Image.open(BytesIO(base64.b64decode(image_data))) 
    return json.dumps({'result': 'success'}), 200, {'ContentType': 'application/json'} 

JS Klient:

// file comes from file input 
var reader = new FileReader(); 
reader.onloadend = function() { 
    var fileName = file.name; 
    $.post('/process_image', { data: reader.result, name: fileName }); 
}; 
reader.readAsDataURL(file);