2010-06-17 34 views
7

tôi có mã mà tạo ra một Cairo ImageSurface, và tôi tiếp xúc với nó như vậy:Làm thế nào để trở lại một hình ảnh trong một phản ứng HTTP với 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 

này không hoạt động (trình duyệt báo cáo rằng hình ảnh có lỗi).

Tôi đã thử nghiệm rằng surface.write_to_png('test.png') hoạt động, nhưng tôi không chắc chắn nên đưa dữ liệu vào để trả lại dữ liệu. Tôi đoán một số đối tượng giống như tập tin? Theo số the pycairo documentation, get_data() trả về bộ đệm. Tôi cũng đã thử:

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

Ngoài ra, tốt hơn là tạo và giữ hình ảnh này trong bộ nhớ (như tôi đang cố gắng làm) hoặc ghi nó vào đĩa ? Tôi chỉ cần hình ảnh một lần, sau đó nó có thể được loại bỏ.

+0

Làm thế nào về 'write_to_png_stream'? http://cairographics.org/documentation/cairomm/reference/classCairo_1_1Surface.html#b3eca5bc13abe27f470fdf08134269bb –

+0

pycairo dường như không hiển thị phương pháp đó ... http://cairographics.org/documentation/pycairo/2/reference/surfaces. html # class-imagesurface-surface – colinmarc

Trả lời

15

Thêm các hàng nhập khẩu:

from cherrypy.lib import file_generator 
import StringIO 

và sau đó đi như thế này:

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) 

Additionaly, nếu bạn phục vụ tệp độc lập (nghĩa là nó không phải là một phần của trang web) và bạn không muốn nó được hiển thị trong trình duyệt mà được coi là tệp để lưu trên đĩa thì bạn cần phải thêm một tiêu đề:

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

Ngoài ra, nó là tốt hơn để tạo và giữ hình ảnh này trong bộ nhớ (giống như tôi đang cố gắng để làm ) hoặc ghi nó vào đĩa như một tập tin tạm thời và phục vụ nó từ đó? Tôi chỉ cần hình ảnh một lần, sau đó có thể bị xóa .

Nếu điều duy nhất bạn muốn làm là phân phát tệp này cho trình duyệt, không có lý do gì để tạo tệp trên một đĩa trên máy chủ. Hoàn toàn ngược lại - hãy nhớ rằng việc truy cập đĩa cứng mang lại hiệu suất phạt.

+0

Hoạt động tuyệt vời! Đối với tiền thưởng, bạn có thể giải thích cho tôi tại sao? – colinmarc

+0

Câu trả lời hay, zifot - Tôi nghĩ rằng khóa đang sử dụng "write_to_png" để chuyển đổi dữ liệu thô thành định dạng PNG. Chỉ cần sử dụng surface.get_data() sẽ không hoạt động vì nó không được lưu trữ nội bộ dưới dạng dữ liệu PNG (đó là ARGB_32). –

+0

@Marc Novakowski - Cảm ơn. Bạn nói đúng, ImageSurface giữ dữ liệu trong bộ nhớ theo một trong các định dạng được mô tả ở đây: http://cairographics.org/manual/cairo-image-surface.html#cairo-format-t. Định dạng của tệp đầu ra là một câu chuyện khác. – zifot

0

Bạn đã thử return str(surface.get_data()) chưa?

+0

vừa thử, không hoạt động. – colinmarc

0

Hãy thử điều này cho 'tập tin trong bộ nhớ' cách tiếp cận

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

Vẫn không có may mắn ... – colinmarc

1

Bạn đang thất bại vì không hiểu hoạt động của surface.get_data(). Bạn đang cố gắng trở mime-type image/png nhưng surface.get_data() lợi nhuận hình ảnh bitmap đơn giản (không phải là một tập tin BMP Widnows Bitmap với tiêu đề) mà là đồng bằng bãi hình ảnh từ "màn hình ảo" (bề mặt)

Như thế này:

 
0000010000 
0000101000 
0001000100 
0010000010 
0001000100 
0000101000 
0000010000 
Các vấn đề liên quan