2010-06-17 9 views
7

Mam kod, który generuje Cairo ImageSurface, a ja jej wystawiać tak:Jak zwrócić obraz w odpowiedzi HTTP z CherryPy

def preview(...): 
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
    ... 
    cherrypy.response.headers['Content-Type'] = "image/png" 
    return surface.get_data() 
preview.exposed = True 

To nie działa (przeglądarek zgłosić, że obraz zawiera błędy).

Sprawdziłem, czy działa surface.write_to_png('test.png'), ale nie jestem pewien, w co zrzucić dane, aby je zwrócić. Zgaduję jakiś obiekt podobny do pliku? Według the pycairo documentation, get_data() zwraca bufor. Ja również teraz próbowałem:

tempf = os.tmpfile() 
surface.write_to_png(tempf) 
return tempf 

Również lepiej jest stworzyć i utrzymać ten obraz w pamięci (jak próbuję zrobić) lub zapisać go na dysku jako plik temp i podawać go stamtąd ? Potrzebuję obrazu tylko raz, a następnie można go odrzucić.

+0

Co powiesz na "write_to_png_stream"? http://cairographics.org/documentation/cairomm/reference/classCairo_1_1Surface.html#b3eca5bc13abe27f470fdf08134269bb –

+0

Pycairo nie wydaje się ujawniać tej metody ... http://cairographics.org/documentation/pycairo/2/reference/surfaces. html # class-imagesurface-surface – colinmarc

Odpowiedz

15

Dodaj te Import:

from cherrypy.lib import file_generator 
import StringIO 

a następnie iść tak:

def index(self): 
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
    cherrypy.response.headers['Content-Type'] = "image/png" 

    buffer = StringIO.StringIO() 
    surface.write_to_png(buffer) 
    buffer.seek(0) 

    return file_generator(buffer) 

Dodatkowo, jeśli jesteś obsługujący plik autonomiczny (tj. nie jest częścią strony internetowej) i nie chcesz, aby był on wyświetlany w przeglądarce, ale traktowany jako plik zapisać na dysku, to trzeba jeszcze jeden nagłówek:

cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="file.png"' 

Również lepiej jest stworzyć i utrzymać ten obraz w pamięci (jak próbuję zrobić) lub zapisać go na dysku jako plik i udostępnić go tam? Wystarczy tylko jeden obraz, aby go odrzucić, a następnie .

Jeśli jedyną rzeczą, którą chcesz zrobić, to podać ten plik przeglądarce, nie ma powodu, aby go utworzyć na dysku na serwerze. Wręcz przeciwnie - pamiętaj, że dostęp do dysku twardego powoduje obniżenie wydajności.

+0

Działa świetnie! Na nagrodę, mógłbyś mi wyjaśnić, dlaczego? – colinmarc

+0

Świetna odpowiedź, zifot - Myślę, że kluczem jest użycie "write_to_png", które konwertuje surowe dane do formatu PNG. Samo użycie surface.get_data() nie zadziała, ponieważ nie jest przechowywane wewnętrznie jako dane PNG (to ARGB_32). –

+0

@Marc Novakowski - Dzięki. Masz rację, ImageSurface przechowuje dane w pamięci w jednym z formatów opisanych tutaj: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t. Format pliku wyjściowego to inna historia. – zifot

0

Czy próbowałeś już return str(surface.get_data())?

+0

po prostu próbowałeś, nie działał. – colinmarc

0

Spróbuj tego dla 'pliku w pamięci' podejście

return StringIO.StringIO(surface.get_data()) 
+0

Wciąż nie ma szczęścia ... – colinmarc

1

Zawodzisz, ponieważ nie rozumiesz działania surface.get_data(). Próbujesz wrócić mime-type image/png ale surface.get_data() powraca zwykły obraz mapy bitowej (nie jest to plik .BMP Widnows bitmapy z nagłówkiem), który zwykły obraz jest zrzut ekranu z „wirtualnym” (powierzchni)

jak to:

 
0000010000 
0000101000 
0001000100 
0010000010 
0001000100 
0000101000 
0000010000 
Powiązane problemy