I understand that Stackoverflow is for help with code, but I figured I'd ask anyways.
I found from the post here that it is possible to put a .svg file into a tkinter window, but after days of searching, I still can't find any place where I could install cairo and rsvg from.
I am currently using Windows 10 with python 3.6.
EDIT:
I have found out how to install cairo and rsvg. Cairo is working but
rsvg is not. I have managed to put SVGs in Tkinter with cairo and not rsvg, though. For
anyone curious about this, you may want to check post out:
Putting .SVG images into tkinter Frame.
Thanks in advance.
Edit: Ok, so pip won't work for installing pycairo. Found that out.
And the other options haven't worked for me either. I am about to be
away from my computer, but I'll give you some of the things I found.
This
This
and
This
Sorry I couldn't be more help. Hope you figure it out!
First, use pip install pycairo
Unfortunately, rsvg is unavailable for windows, but cairographics.org have a simple wrapper.
Save the following as rsvg.py in the same folder as your script:
#some code to give rsvg.render_cairo(ctx) ability
#on windows.
import os
try:
import rsvg
WINDOWS=False
except ImportError:
print"Warning, could not import 'rsvg'"
if os.name == 'nt':
print "Detected windows, creating rsvg."
#some workarounds for windows
from ctypes import *
l=CDLL('librsvg-2-2.dll')
g=CDLL('libgobject-2.0-0.dll')
g.g_type_init()
class rsvgHandle():
class RsvgDimensionData(Structure):
_fields_ = [("width", c_int),
("height", c_int),
("em",c_double),
("ex",c_double)]
class PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
def __init__(self, path):
self.path = path
error = ''
self.handle = l.rsvg_handle_new_from_file(self.path,error)
def get_dimension_data(self):
svgDim = self.RsvgDimensionData()
l.rsvg_handle_get_dimensions(self.handle,byref(svgDim))
return (svgDim.width,svgDim.height)
def render_cairo(self, ctx):
ctx.save()
z = self.PycairoContext.from_address(id(ctx))
l.rsvg_handle_render_cairo(self.handle, z.ctx)
ctx.restore()
class rsvgClass():
def Handle(self,file):
return rsvgHandle(file)
In your script, do from rsvg import * and when you need to use it, run:
rC = rsvgClass()
h = rC.Handle("YOUR-FILE-HERE.svg")
s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
ctx = cairo.Context(s)
h.render_cairo(ctx)
Related
I am looking for a way to add soft requirements to my python module.
My module will use some external pip resources that the user may or may not install depending on their use case. I would like this to be an option rather than a requirement but a big chunk of code will require the external modules. I simply want to return an error if a class is used that does not have the correct module installed.
example:
#tkc_ext.py
try:
from tkcalendar import DateEntry
tkc_imported = True
except:
tkc_imported = False
class tkcNotImportedError(Exception):
def __init__(self):
print("tkcalendar module is not installed.\n please install it to use these widgets")
class cDateEntry(DateEntry):
def __init__(self, master, **kwargs):
if not tkc_import:
raise tkcNotImportedError
##insert code here
I'm not sure how I can disable the cDateEntry class if tkcalendar has not been installed as it will error on the class line due to DateEntry not being imported, and i cant error out before that as it will simply error if the file is imported.
I have a simple python ctypes wrapper around rsvg to be used with cairo. It seems to work on ubuntu 16 but when I try it on ubuntu 18 I get a Segmentation error. I have looked at the cairo docs for an example of how this can be done, so nothing fancy.(https://www.cairographics.org/cookbook/librsvgpython/).
from ctypes import CDLL, Structure, byref, c_byte, c_double, c_int, c_void_p
# CDLL: Instances of this class represent loaded shared libraries.
l = CDLL('librsvg-2.so.2')
class rsvgHandle():
class RsvgDimensionData(Structure):
_fields_ = [("width", c_int),
("height", c_int),
("em", c_double),
("ex", c_double)]
class PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
def __init__(self, path):
self.path = path
error = ''
self.handle = l.rsvg_handle_new_from_file(self.path, error)
def get_dimension_data(self):
svgDim = self.RsvgDimensionData()
l.rsvg_handle_get_dimensions(self.handle, byref(svgDim))
return (svgDim.width, svgDim.height)
def render_cairo(self, ctx):
ctx.save()
z = self.PycairoContext.from_address(id(ctx))
l.rsvg_handle_render_cairo(self.handle, z.ctx)
ctx.restore()
class rsvgClass():
def Handle(self, file):
return rsvgHandle(file)
rsvg = rsvgClass()
svg_handle = rsvg.Handle(fpath)
svg_width, svg_height = svg_handle.get_dimension_data()[:2]
svg_handle.render_cairo(context)
The error occurs inside get_dimension_data at the line l.rsvg_handle_get_dimensions(self.handle, byref(svgDim))
The trace isn't too helpful it says Segmenation Fault and a bunch of these
/usr/lib/x86_64-linux-gnu/librsvg-2.so.2(rsvg_handle_get_dimensions+0)
[0x7ff70b01ed50]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call_unix64+0x4c)
[0x7ff71f52adae]
/usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_call+0x22f) [0x7ff71f52a71f]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(_ctypes_callproc+0x2a4)
[0x7ff71f73dcc4]
/usr/lib/python2.7/lib-dynload/_ctypes.x86_64-linux-gnu.so(+0x106c5)
[0x7ff71f73d6c5]
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x5bf6) [0x7ff7247eb366]
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x8b5b) [0x7ff7247ee2cb]
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalCodeEx+0x7d8) [0x7ff72492a908]
/usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0(PyEval_EvalFrameEx+0x5bf6) [0x7ff7247eb366]
Does anyone know what could be going on in my ubuntu 18 environment to cause this issue ? Or alternatively how I could render an svg into an open cairo context (as shown in the last line of the code) on ubuntu 18 ? (the readymade python binding for rsvg is removed from ubuntu 18 btw which is why im trying ctypes to begin with)
It's weird, but it never happened to me before, so I do not know where I'm wrong.
I have this script:
import PyEngine
PyEngine.init()
print(PyEngine.info.pack)
The __init__ of PyEngine is this at the moment:
import subprocess, sys
class init():
def __init__(self):
__checkp__ = subprocess.check_output([sys.executable, "-m", "pip", "freeze"])
self.__packages__ = [r.decode().split("==")[0] for r in __checkp__.split()]
self.__pack__ = " ".join(self.__packages__)
print(self.__pack__)
self.__info__ = info(self)
class info():
def __init__(self, main):
self.__pye__ = main
def pack(self):
return self.__pye__.__pack__
With print(self.__pack__), I get this:
Django Jinja2 MarkupSafe PyOpenGL PyTMX PyYAML Pygments Vector2D WMI attrs euclid future glsvg inputs keyboard pbr pyPEG2 pygame pyglet pygobject pyperclip pytz qutebrowser six stevedore tmx virtualenv virtualenv-clone virtualenvwrapper wheel
But with print(PyEngine.info.pack), I get this:
<function info.pack at 0x0000000003072A60>
I can not understand...
Also, I would like to know how I could, if I wanted to, use the super class. Despite having tried so many times on this subject, honestly even now I can not fully understand how it works.
I am yet to decide what language and tools to use for my next project. I would love to use python, but I would like to implement ribbon toolbars. Some work has been done in Tk (http://www.ellogon.org/petasis/bibliography/Tcl2010/TkRibbon.pdf), but it looks like it hasn't been implemented in tkinter yet. Is there anything I can do to get this to work?
You need to create a wrapper for this and get a version of the binary you can use. I built this for use with Python 3.4 and copied it to tkribbon1.0-x86_64.zip. You should unzip this in the Python/tcl subdirectory so the version of tcl used by python can load it.
A minimal wrapper looks like this:
from tkinter import Widget
from os import path
class Ribbon(Widget):
def __init__(self, master, kw=None):
self.version = master.tk.call('package','require','tkribbon')
self.library = master.tk.eval('set ::tkribbon::library')
Widget.__init__(self, master, 'tkribbon::ribbon', kw=kw)
def load_resource(self, resource_file, resource_name='APPLICATION_RIBBON'):
"""Load the ribbon definition from resources.
Ribbon markup is compiled using the uicc compiler and the resource included
in a dll. Load from the provided file."""
self.tk.call(self._w, 'load_resources', resource_file)
self.tk.call(self._w, 'load_ui', resource_file, resource_name)
if __name__ == '__main__':
import sys
from tkinter import *
def main():
root = Tk()
r = Ribbon(root)
name = 'APPLICATION_RIBBON'
if len(sys.argv) > 1:
resource = sys.argv[1]
if len(sys.argv) > 2:
name = sys.argv[2]
else:
resource = path.join(r.library, 'libtkribbon1.0.dll')
r.load_resource(resource, name)
t = Text(root)
r.grid(sticky=(N,E,S,W))
t.grid(sticky=(N,E,S,W))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
root.mainloop()
main()
Running this uses the resources built-in to the tkribbon dll and looks like . The complicated bit is going to be getting some Ribbon markup resources into a DLL for loading.
You can use this example to load ribbons from existing applications. For instance, python Ribbon.py c:\Windows\System32\mspaint.exe MSPAINT_RIBBON will load up the ribbon resource from mspaint. The resource name in this case has to be included as the default is APPLICATION_RIBBON. For your own ribbon, using uicc to build a .rc file, then rc /r file.rc to produce a .res file and finally link -dll -out:file.dll file.rc -noentry -machine:AMD64 seems to work to produce a resource only DLL that works with this extension.
This seems to show how to set up a post install script, but I am still unclear on how to use it to add the installed directory to the path.
Which values (and where can I find them) do I need to get from the install and how can I refer to them in the post install script itself?
Here is what I have so far, all stolen from other places and stuck together, don't know how to make it work:
import _winreg
import os
from distutils.core import setup
from distutils.command.install import install as _install
REG_PATH = r"SOFTWARE\my_program\Settings"
def _post_install(dir):
if os.name == 'nt':
try:
_winreg.CreateKey(_winreg.HKEY_CURRENT_USER, REG_PATH)
registry_key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, REG_PATH, 0,
_winreg.KEY_WRITE)
_winreg.SetValueEx(registry_key, name, 0, _winreg.REG_SZ, value)
_winreg.CloseKey(registry_key)
return True
except WindowsError:
return False
class install(_install):
def run(self):
_install.run(self)
self.execute(_post_install, (self.install_lib,),
msg="Running post install task...")
setup(cmdclass={'install': install})