Jak przekonwertować plik svgna pngw w Pythonie? Przechowuję svgw instancji StringIO. Czy powinienem korzystać z biblioteki pyCairo? Jak napisać ten kod?
Ten wątek nie rozwiązał problemu. Zaakceptowana odpowiedź pochodziła od pytającego, który udostępnił swoją nieudaną próbę kodu. Inna odpowiedź sugerowała ImageMagick, ale komentator powiedział, że ImageMagick wykonuje „okropną robotę interpretacji SVG”. Nie chcę, aby moje pliki PNG wyglądały okropnie, więc ponownie zadaję pytanie.
Przykłady w tym łączu są specyficzne dla Win32. Używam Linuksa.
ram1
Spójrz na ten post na blogu, wygląda na to, że może być to, czego potrzebujesz.
giodamelio
Odpowiedzi:
60
Odpowiedzią jest „ pyrsvg ” - powiązanie Pythona z librsvg .
Dostarcza go pakiet Ubuntu python-rsvg . Wyszukiwanie w Google jego nazwy jest słabe, ponieważ jego kod źródłowy wydaje się być zawarty w repozytorium GIT projektu Gnome „gnome-python-desktop”.
Zrobiłem minimalistyczny „hello world”, który renderuje SVG na powierzchni kairu i zapisuje na dysku:
Aktualizacja : od 2014 r potrzebnej pakiet dla dystrybucji Fedora Linux jest: gnome-python2-rsvg. Powyższa lista fragmentów nadal działa tak, jak jest.
Świetnie, ładnie działa. Ale czy istnieje sposób, aby samodzielnie cairookreślić WYSOKOŚĆ i SZEROKOŚĆ obrazu? Zajrzałem do *.svgpliku, aby wyodrębnić stamtąd HEIGHT i WIDTH, ale oba są ustawione na 100%. Oczywiście mogę przyjrzeć się właściwościom obrazu, ale ponieważ jest to tylko jeden krok w przetwarzaniu obrazu, tego nie chcę.
quapka
1
Jeśli "szerokość" i "wysokość" twoich plików są ustawione na 100%, nie ma magicznego Kairu ani rsvg, który mógłby odgadnąć rozmiar: takie pliki SVG pozostawały niezależne od rozmiaru przez oprogramowanie twórcy (/ osobę). Otaczający kod HTML do zaimportowania pliku SVG zapewniłby rozmiar fizyczny. Jednak obiekt "Handle" rsvg ma .get_dimension_data()metodę, która działała dla mojego przykładowego pliku (dobrze zachowany SVG) - spróbuj.
jsbueno
1
od 2014 r. dla ubuntu można użyć: apt-get install python-
rsvg
1
Czy istnieje szybkie polecenie dodania białego tła do obrazu, jeśli jego bieżące tło jest przezroczyste?
fiatjaf
@jsbueno Używam Windows 8.1 i Pythona 2.7.11 Jak mogę zainstalować cairo i rsvg i sprawić, by to działało. Walczyłem, żeby to zadziałało. BTW +1 za szczegółowe wyjaśnienie.
Cześć. Czy wiesz, jak mogę zrobić to samo, ale bez zapisywania do pliku? Muszę przesłać zawartość png do przeglądarki z serwera WWW, aby użytkownik mógł pobrać obraz. Zapisywanie pliku png nie jest poprawną opcją w naszym projekcie, dlatego potrzebuję tego w ten sposób. Dzięki
estemendoza
4
Sam to robiłem. Zasadniczo zależy to od tego, jakie narzędzia lub struktury masz pod ręką podczas obsługi żądań internetowych, ale bez względu na to, co to jest, podstawową ideą jest to, że svg2pngprzyjmuje streamobiekt w write_toparametrze i może to być albo twój obiekt odpowiedzi HTTP (który w większość frameworków to obiekt podobny do pliku) lub inny strumień, który następnie podajesz przeglądarce za pomocą Content-Dispositionnagłówka. patrz tutaj: stackoverflow.com/questions/1012437/…
nemesisfixx
4
Dla tych, którzy mają problemy z tym kodem, tak jak ja: 1). bytestringakceptuje bajty, więc najpierw przekonwertuj ciąg z bytestring=bytes(svg,'UTF-8') 2). tryb plików powinien być binarny, więcopen('output.png','wb')
Serj Zaharchenko
3
cairosvg obsługuje tylko Python 3.4+.
Porzucili
1
Nie było svg2pngdla mnie, musiałem użyć cairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png').
tobltobs
39
Zainstaluj Inkscape i wywołaj go jako wiersz poleceń:
Możesz również przyciągnąć określony prostokątny obszar tylko za pomocą parametru -j, np. Współrzędna „0: 125: 451: 217”
${INKSCAPE_PATH}-z -f ${source_svg}-w ${width}-j -a ${coordinates}-e ${dest_png}
Jeśli chcesz pokazać tylko jeden obiekt w pliku SVG, możesz określić parametr -iz identyfikatorem obiektu, który ustawiłeś w pliku SVG. Ukrywa wszystko inne.
${INKSCAPE_PATH}-z -f ${source_svg}-w ${width}-i ${object}-j -a ${coordinates}-e ${dest_png}
+1, ponieważ jest to również bardzo przydatne w przypadku skryptów powłoki. Zobacz inkscape.org/doc/inkscape-man.html, aby uzyskać pełną dokumentację w wierszu poleceń Inkscape.
To nie jest odpowiedź. To obejście. OP poprosił o rozwiązanie w języku Python.
lamino
31
Używam Wand-py (implementacja opakowania Wand wokół ImageMagick) do importowania całkiem zaawansowanych plików SVG i do tej pory widziałem świetne rezultaty! To jest cały kod, którego potrzebuje:
with wand.image.Image( blob=svg_file.read(), format="svg")as image:
png_image = image.make_blob("png")
Właśnie dziś to odkryłem i poczułem, że warto się nim podzielić z innymi, którzy mogą natknąć się na tę odpowiedź, ponieważ minęło trochę czasu, odkąd udzielono odpowiedzi na większość tych pytań.
UWAGA: Technicznie podczas testów odkryłem, że nie musisz nawet przekazywać parametru formatu dla ImageMagick, więc with wand.image.Image( blob=svg_file.read() ) as image: było to wszystko, co było naprawdę potrzebne.
EDYCJA: Z próby edycji dokonanej przez qris, oto pomocny kod, który pozwala używać ImageMagick z plikiem SVG z przezroczystym tłem:
Różdżka działała dużo lepiej niż Kair dla moich plików PNG.
qris
3
Otrzymuję błąd image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
adrienlucca.wordpress.com
2
svg_filezakłada się, że jest to obiekt „plik” w tym przykładzie, ustawienie svg_filebędzie wyglądać następująco:svg_file = File.open(file_name, "r")
streetlogics
2
Dzięki, cairoi rsvg„przyjęty” metoda nie działa na moim PDF. pip install wandi twój fragment
załatwił sprawę
5
Jeśli masz SVG strpotem trzeba najpierw do kodowania w formacie binarnym jak ten: svg_blob = svg_str.encode('utf-8'). Teraz można użyć metody powyżej, zastępując blob=svg_file.read()z blob=svg_blob.
@Simon, czy możesz to zrobić, proszę? Jestem zbyt zajęty i będę w ciągu najbliższych 1-2 miesięcy.
Ray
2
@Ray, właściwie opcja -d / --dpi istnieje już od jakiegoś czasu i powiedziano mi, że obsługa <clippath> została dodana kilka tygodni temu w wersji git.
Użyłem ekstrakcji szerokości i wysokości svg. Nie jestem pewien co do standardu SVG, ale w niektórych moich plikach SVG po szerokości lub wysokości następował ciąg nienumeryczny, taki jak „mm” lub „px” (np. „250mm”). Int („250mm”) zgłasza wyjątek i musiałem wprowadzić kilka dodatkowych poprawek.
WigglyWorld
5
Żadna z odpowiedzi nie była satysfakcjonująca. Wszystkie wymienione biblioteki mają jakiś problem lub inny, jak np. W Kairze porzucenie wsparcia dla Pythona 3.6 (porzuciły obsługę Pythona 2 jakieś 3 lata temu!). Również instalacja wspomnianych bibliotek na komputerze Mac była uciążliwa.
Wreszcie znalazłem najlepszym rozwiązaniem jest svglib + reportlab . Obie instalowane bez żadnych problemów za pomocą pip i pierwszego połączenia do konwersji z SVG na PNG działały pięknie! Bardzo zadowolony z rozwiązania.
Tylko 2 polecenia załatwiają sprawę:
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
drawing = svg2rlg("my.svg")
renderPM.drawToFile(drawing,"my.png", fmt="PNG")
Czy są jakieś ograniczenia, o których powinienem wiedzieć?
Korzystanie z pycairo i librsvg udało mi się uzyskać skalowanie SVG i renderowanie do mapy bitowej. Zakładając, że twój SVG nie ma dokładnie 256x256 pikseli, pożądane wyjście, możesz wczytać w SVG do kontekstu kairskiego za pomocą rsvg, a następnie przeskalować go i zapisać do PNG.
Dzięki za to okazał się bardzo przydatny w moim projekcie. Chociaż Handle.get_dimension_datanie działa dla mnie. Musiałem go zastąpić prostym pobieraniem self.props.widthi self.props.height. Najpierw próbowałem zdefiniować RsvgDimensionDataStrukturę zgodnie z opisem na stronie internetowej Cairo, ale bez powodzenia.
JeanOlivier
Próbuję to wykorzystać w moim projekcie. Jak uzyskać wymagane pliki DLL?
Andoo
0
Oto podejście, w którym Inkscape jest wywoływany przez Python.
Zauważ, że blokuje pewne wyjście crufty, które Inkscape zapisuje na konsoli (w szczególności stderr i stdout) podczas normalnej, wolnej od błędów operacji. Dane wyjściowe są przechwytywane w dwóch zmiennych łańcuchowych outi err.
import subprocess # May want to use subprocess32 instead
cmd_list =['/full/path/to/inkscape','-z','--export-png','/path/to/output.png','--export-width',100,'--export-height',100,'/path/to/input.svg']# Invoke the command. Divert output that normally goes to stdout or stderr.
p = subprocess.Popen( cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE )# Below, < out > and < err > are strings or < None >, derived from stdout and stderr.
out, err = p.communicate()# Waits for process to terminate# Maybe do something with stdout output that is in < out ># Maybe do something with stderr output that is in < err >if p.returncode:raiseException('Inkscape error: '+(err or'?'))
Na przykład, gdy wykonałem określone zadanie w moim systemie Mac OS, outskończyło się na:
Background RRGGBBAA: ffffff00
Area0:0:339:339 exported to 100 x 100 pixels (72.4584 dpi)Bitmap saved as:/path/to/output.png
(Plik wejściowy SVG miał rozmiar 339 na 339 pikseli).
Nie jest to Python typu end-to-end, jeśli polegasz na Inkscape.
Joel
1
@Joel: Pierwsza linijka została zmodyfikowana w celu usunięcia Twojego sprzeciwu. Ale oczywiście nawet „czyste” rozwiązanie Pythona opiera się na elementach spoza języka podstawowego i ostatecznie jest uruchamiane w języku maszynowym, więc być może nie ma czegoś takiego jak kompleksowe rozwiązanie!
Iron Pillow
0
Właściwie nie chciałem być zależny od czegokolwiek innego poza Pythonem (Kair, Ink… itp.). Moje wymagania miały być tak proste, jak to tylko możliwe, co najwyżej proste pip install "savior"wystarczyłoby, dlatego żadne z powyższych nie ” t pasuje do mnie.
Odpowiedzi:
Odpowiedzią jest „ pyrsvg ” - powiązanie Pythona z librsvg .
Dostarcza go pakiet Ubuntu python-rsvg . Wyszukiwanie w Google jego nazwy jest słabe, ponieważ jego kod źródłowy wydaje się być zawarty w repozytorium GIT projektu Gnome „gnome-python-desktop”.
Zrobiłem minimalistyczny „hello world”, który renderuje SVG na powierzchni kairu i zapisuje na dysku:
Aktualizacja : od 2014 r potrzebnej pakiet dla dystrybucji Fedora Linux jest:
gnome-python2-rsvg
. Powyższa lista fragmentów nadal działa tak, jak jest.źródło
cairo
określić WYSOKOŚĆ i SZEROKOŚĆ obrazu? Zajrzałem do*.svg
pliku, aby wyodrębnić stamtąd HEIGHT i WIDTH, ale oba są ustawione na100%
. Oczywiście mogę przyjrzeć się właściwościom obrazu, ale ponieważ jest to tylko jeden krok w przetwarzaniu obrazu, tego nie chcę..get_dimension_data()
metodę, która działała dla mojego przykładowego pliku (dobrze zachowany SVG) - spróbuj.Oto, co zrobiłem, używając cairosvg :
I działa jak urok!
Zobacz więcej: dokument cairosvg
źródło
svg2png
przyjmujestream
obiekt wwrite_to
parametrze i może to być albo twój obiekt odpowiedzi HTTP (który w większość frameworków to obiekt podobny do pliku) lub inny strumień, który następnie podajesz przeglądarce za pomocąContent-Disposition
nagłówka. patrz tutaj: stackoverflow.com/questions/1012437/…bytestring
akceptuje bajty, więc najpierw przekonwertuj ciąg zbytestring=bytes(svg,'UTF-8')
2). tryb plików powinien być binarny, więcopen('output.png','wb')
svg2png
dla mnie, musiałem użyćcairosvg.surface.PNGSurface.convert(svg_str, write_to='output.png')
.Zainstaluj Inkscape i wywołaj go jako wiersz poleceń:
Możesz również przyciągnąć określony prostokątny obszar tylko za pomocą parametru
-j
, np. Współrzędna „0: 125: 451: 217”Jeśli chcesz pokazać tylko jeden obiekt w pliku SVG, możesz określić parametr
-i
z identyfikatorem obiektu, który ustawiłeś w pliku SVG. Ukrywa wszystko inne.źródło
Używam Wand-py (implementacja opakowania Wand wokół ImageMagick) do importowania całkiem zaawansowanych plików SVG i do tej pory widziałem świetne rezultaty! To jest cały kod, którego potrzebuje:
Właśnie dziś to odkryłem i poczułem, że warto się nim podzielić z innymi, którzy mogą natknąć się na tę odpowiedź, ponieważ minęło trochę czasu, odkąd udzielono odpowiedzi na większość tych pytań.
UWAGA: Technicznie podczas testów odkryłem, że nie musisz nawet przekazywać parametru formatu dla ImageMagick, więc
with wand.image.Image( blob=svg_file.read() ) as image:
było to wszystko, co było naprawdę potrzebne.EDYCJA: Z próby edycji dokonanej przez qris, oto pomocny kod, który pozwala używać ImageMagick z plikiem SVG z przezroczystym tłem:
źródło
image.read(blob=svg_file.read(), format="svg") NameError: name 'svg_file' is not defined
svg_file
zakłada się, że jest to obiekt „plik” w tym przykładzie, ustawieniesvg_file
będzie wyglądać następująco:svg_file = File.open(file_name, "r")
cairo
irsvg
„przyjęty” metoda nie działa na moim PDF.pip install wand
i twój fragmentstr
potem trzeba najpierw do kodowania w formacie binarnym jak ten:svg_blob = svg_str.encode('utf-8')
. Teraz można użyć metody powyżej, zastępującblob=svg_file.read()
zblob=svg_blob
.Spróbuj tego: http://cairosvg.org/
Witryna mówi:
Aktualizacja 25 listopada 2016 :
źródło
<clipPath><rect ... /></clipPath>
. Po drugie, nie przyjmuje opcji -d (DPI).Inne rozwiązanie, które właśnie znalazłem. Jak wyrenderować przeskalowany SVG do QImage?
PySide można łatwo zainstalować z pakietu binarnego w systemie Windows (i używam go do innych rzeczy, więc jest to dla mnie łatwe).
Jednak zauważyłem kilka problemów podczas konwersji flag krajów z Wikimedia, więc być może nie jest to najbardziej niezawodny parser / renderer svg.
źródło
Małe rozszerzenie odpowiedzi jsbueno:
źródło
Żadna z odpowiedzi nie była satysfakcjonująca. Wszystkie wymienione biblioteki mają jakiś problem lub inny, jak np. W Kairze porzucenie wsparcia dla Pythona 3.6 (porzuciły obsługę Pythona 2 jakieś 3 lata temu!). Również instalacja wspomnianych bibliotek na komputerze Mac była uciążliwa.
Wreszcie znalazłem najlepszym rozwiązaniem jest svglib + reportlab . Obie instalowane bez żadnych problemów za pomocą pip i pierwszego połączenia do konwersji z SVG na PNG działały pięknie! Bardzo zadowolony z rozwiązania.
Tylko 2 polecenia załatwiają sprawę:
Czy są jakieś ograniczenia, o których powinienem wiedzieć?
źródło
Skalowanie SVG i renderowanie PNG
Korzystanie z pycairo i librsvg udało mi się uzyskać skalowanie SVG i renderowanie do mapy bitowej. Zakładając, że twój SVG nie ma dokładnie 256x256 pikseli, pożądane wyjście, możesz wczytać w SVG do kontekstu kairskiego za pomocą rsvg, a następnie przeskalować go i zapisać do PNG.
main.py
Wiązanie RSVG C.
Ze strony internetowej Cario z niewielkimi modyfikacjami. Również dobry przykład, jak wywołać bibliotekę C z Pythona
źródło
Handle.get_dimension_data
nie działa dla mnie. Musiałem go zastąpić prostym pobieraniemself.props.width
iself.props.height
. Najpierw próbowałem zdefiniowaćRsvgDimensionData
Strukturę zgodnie z opisem na stronie internetowej Cairo, ale bez powodzenia.Oto podejście, w którym Inkscape jest wywoływany przez Python.
Zauważ, że blokuje pewne wyjście crufty, które Inkscape zapisuje na konsoli (w szczególności stderr i stdout) podczas normalnej, wolnej od błędów operacji. Dane wyjściowe są przechwytywane w dwóch zmiennych łańcuchowych
out
ierr
.Na przykład, gdy wykonałem określone zadanie w moim systemie Mac OS,
out
skończyło się na:(Plik wejściowy SVG miał rozmiar 339 na 339 pikseli).
źródło
Właściwie nie chciałem być zależny od czegokolwiek innego poza Pythonem (Kair, Ink… itp.). Moje wymagania miały być tak proste, jak to tylko możliwe, co najwyżej proste
pip install "savior"
wystarczyłoby, dlatego żadne z powyższych nie ” t pasuje do mnie.Przeszedłem przez to (idąc dalej niż w badaniach Stackoverflow). https://www.tutorialexample.com/best-practice-to-python-convert-svg-to-png-with-svglib-python-tutorial/
Jak na razie wygląda dobrze. Więc udostępniam to na wypadek, gdyby ktoś był w tej samej sytuacji.
źródło