2010-02-23 32 views
7

Tôi muốn hiển thị các phần của tệp svg theo tên nhưng đối với cuộc sống của tôi, tôi không thể tìm ra cách làm như vậy (sử dụng python + gtk).Làm cách nào để hiển thị * các phần * của tệp svg?

Dưới đây là file svg trong câu hỏi: http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz (Cập nhật: tập tin này không còn tồn tại, nhưng bạn có thể theo dõi nó xuống http://svg-cards.sourceforge.net/)

Trên trang web của mình, David, nói:

Bạn có thể vẽ thẻ bằng cách hiển thị tệp trên bản đồ pixmap và cắt từng thẻ theo cách thủ công hoặc bằng cách sử dụng tên của thẻ thông qua giao diện DOM . Tất cả các thẻ được nhúng vào một nhóm SVG.

Tôi không biết ý của anh ấy là giao diện DOM. Tôi đã thực hiện một số tìm kiếm và kết quả tốt nhất mà tôi thấy rằng dường như phù hợp với những gì tôi muốn làm là:

QSvgRenderer *renderer = new QSvgRenderer(QLatin1String("SvgCardDeck.svg")); 
QGraphicsSvgItem *black = new QGraphicsSvgItem(); 
QGraphicsSvgItem *red = new QGraphicsSvgItem(); 

black->setSharedRenderer(renderer); 
black->setElementId(QLatin1String("black_joker")); 

red->setSharedRenderer(renderer); 
red->setElementId(QLatin1String("red_joker")); 

Tuy nhiên, thông báo rằng đó là cho Qt và thậm chí không được viết bằng python.

Đây là những gì tôi có cho đến nay:

#!/usr/bin/env python 

from __future__ import absolute_import 

import cairo 
import gtk 
import rsvg 

from xml import xpath 
from xml.dom import minidom 

window = gtk.Window() 
window.set_title("Foo") 
window.set_size_request(256, 256) 
window.set_property("resizable", False) 
window.set_position(gtk.WIN_POS_CENTER) 
window.connect("destroy", gtk.main_quit) 
window.show() 

document = minidom.parse("cards.svg") 
element = xpath.Evaluate("//*[@id='1_club']", document)[0] 
xml = element.toxml() 

svg = rsvg.Handle() 
svg.write(xml) 

pixbuf = svg.get_pixbuf() 

image = gtk.Image() 
image.set_from_pixbuf(pixbuf) 
image.show() 

window.add(image) 

gtk.main() 

Nó không làm việc, tất nhiên.

Tôi đang thiếu gì?

Trả lời

9

Thư viện GTK cho rendering SVG được gọi RSVG. Nó có các ràng buộc python, nhưng chúng không có giấy tờ, và chúng không quấn các hàm rsvg_handle_get_pixbuf_sub()rsvg_handle_render_cairo_sub() mà bạn thường sử dụng cho mục đích đó trong C. Đây là những gì bạn phải làm theo như tôi có thể nói. Bạn trích xuất nút XML như Adam Crossland đề xuất. Để làm cho nó, bạn phải làm một cái gì đó như thế này:

import gtk 
import rsvg 
handle = rsvg.Handle() 
handle.write(buffer=xml_data) 
# xml_data is the XML string for the object you want 
image = gtk.Image() 
image.set_from_pixbuf(handle.get_pixbuf()) 

Đó là nếu bạn muốn nó trong một gtk.Image, nếu không làm điều gì đó khác với pixbuf. Bạn cũng có thể hiển thị nó theo ngữ cảnh Cairo với handle.render_cairo(cr) trong đó cr là ngữ cảnh Cairo của bạn.

EDIT:

Xin lỗi, tôi đã không đọc bindings python chặt chẽ đủ lúc đầu.Các _sub() chức năng được thực hiện bằng cách sử dụng lập luận id=, vì vậy chương trình của bạn có thể đun sôi xuống này:

#!/usr/bin/env python 

import gtk 
import rsvg 

window = gtk.Window() 
window.set_title("Foo") 
window.connect("destroy", gtk.main_quit) 
window.show() 

svg = rsvg.Handle(file='cards.svg') 
pixbuf = svg.get_pixbuf(id='#3_diamond') 

image = gtk.Image() 
image.set_from_pixbuf(pixbuf) 
image.show() 

window.add(image) 

gtk.main() 

Tôi thử nghiệm này và nó hoạt động. Tuy nhiên, cửa sổ là kích thước của toàn bộ khung SVG và được cắt bớt thành kích thước màn hình (đó là lý do tại sao tôi trả lại 3 viên kim cương thay vì một số câu lạc bộ ở góc.) Vì vậy, bạn vẫn sẽ có để tìm cách nào đó để cắt pixbuf quanh thẻ mà bạn muốn, nhưng điều đó không quá khó.

+0

Tôi thực sự đã thử cách này quá và không thể tìm ra lý do tại sao nó đã làm những gì nó đã làm (do đó tôi cố gắng giải pháp khác để xem nếu tôi muốn có được một kết quả tương tự). Mặc dù kích thước cửa sổ là kích thước của toàn bộ khung SVG, giải pháp này trả lời câu hỏi của tôi (trong khi, tất nhiên, nâng một câu hỏi khác). :) –

+0

Điều này cực kỳ hữu ích, mặc dù nhiều trợ giúp hơn sẽ hữu ích. Để render một phần của ảnh SVG, bạn có thể sử dụng handle.render_cairo (cr = c, id = "# layer_5") trong đó "c" là ngữ cảnh cairo. Phần không rõ ràng với tôi là "#" ở đầu id là bắt buộc. SVG của tôi có id như 'id =' layer_1 '' và tôi có thể hiển thị từng lớp riêng lẻ với render_cairo (cr = c, id = "# layer_1") – bodgesoc

2

Tôi tin rằng những gì ông có nghĩa là bằng cách thông qua một giao diện DOM 'là vì SVG là XML, bạn có thể tải các tập tin SVG trong minidom, hoặc một số phân tích cú pháp Python XML khác, và trích xuất các nút XML với các cụ tên mà bạn đang tìm kiếm. Nút XML đó phải đại diện cho một mục có thể được hiển thị.

+0

Làm cách nào để hiển thị nút XML? –

0

Bạn có thể làm điều đó bằng cách chỉnh sửa thẻ. Chỉnh sửa chiều rộng và chiều cao, đặt thuộc tính viewBox trên phần tử svg chính thành hình chữ nhật bạn muốn, hiển thị, lặp lại.

Xem How to show a subsection or "slice" of an SVG graphic?http://dingoskidneys.com/~dholth/svg/

+0

Điều này không giúp tôi lấy các phần của tệp SVG theo tên và sau đó hiển thị chúng. –

+0

Bạn có thể nhận được hộp giới hạn cho các phần được đặt tên của tệp SVG và đặt khung nhìn tương ứng. – joeforker

1

Đây là câu trả lời của tôi cho vấn đề về không gian trống. Đó là một hack thô nhưng nó làm việc tuyệt vời. Điều này cũng sẽ phục vụ như là một điểm khởi đầu tốt để có được thẻ cho bất cứ ai làm một trò chơi thẻ trong python.

import gtk 
import rsvg 
svg = rsvg.Handle(file="/usr/share/gnome-games-common/cards/gnomangelo_bitmap.svg") 
w, h = 202.5, 315 
card_names = map(str, range(1,11)) + ["jack", "queen", "king"] 
suites = ["club", "diamond", "heart", "spade"] 
specials = [{"name":"black_joker","x":0, "y":4}, {"name":"red_joker","x":1, "y":4}, {"name":"back","x":2, "y":4}] 
for suite_number, suite in enumerate(suites): 
    for card_number, card in enumerate(card_names): 
     print "processing", suite, card, '#'+card+'_'+suite 
     pixbuf = svg.get_pixbuf(id='#'+card+'_'+suite) 
     pixbuf.subpixbuf(int(w*card_number), int(h*suite_number), int(w), int(h)).save("./"+card+"_"+suite+".png","png", {}) 
for special in specials: 
    print "processing", special["name"] 
    pixbuf = svg.get_pixbuf(id='#'+special["name"]) 
    card_number = special["x"] 
    suite_number = special["y"] 
    pixbuf.subpixbuf(int(w*card_number), int(h*suite_number), int(w), int(h)).save("./"+special["name"]+".png","png", {}) 
Các vấn đề liên quan