假设我有一个 svg 文件的 xml 内容,如下所示:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with matplotlib (http://matplotlib.org/) -->
<svg height="344.88pt" version="1.1" viewBox="0 0 460.8 344.88" width="460.8pt"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
...
我的问题是,如何将此字符串复制到Windows剪贴板,不是作为字符串,而是作为“image/svg+xml”数据类型,可以将其作为svg图像粘贴到powerpoint中?
据我所知,唯一支持 Mime 类型的剪贴板库是 QtClipboard:https://doc.qt.io/qtforpython/PySide2/QtGui/QClipboard.html
您可能想看一下。
可能在您可以使用
setMimeData
设置的 Mime 类型中还有 image/svg+xml
示例:
from PyQt5 import QtCore
d = QtCore.QMimeData()
print(d.formats()) # Now it is an empty list "[]" because you still didn't set the data and the mime type
# Set data in the object with the required mime type
d.setData("image/svg+xml", b'<?xml version="1.0" encoding="utf-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><!-- Created with matplotlib (http://matplotlib.org/) --><svg height="344.88pt" version="1.1" viewBox="0 0 460.8 344.88" width="460.8pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">')
print(d.formats()) # Now it prints: ['image/svg+xml']
从这里您可以将其带到QClipboard。
我引用文档:http://doc.qt.io/archives/qt-4.8/qclipboard.html
setMimeData() 函数具有终极的灵活性:它允许 您可以将任何 QMimeData 添加到剪贴板中。
为了扩展 @Luca Angioloni 的答案,我编写了一个完整的函数,使用带有 MimeTypes 的 PyQt6 将 Plotly 图形作为 SVG 和 PNG 复制到剪贴板。
值得注意的是,在设置剪贴板 MimeData 时,我需要指定一个
mode
参数,如这个答案中所述。
它可能并不完美,但到目前为止我一直在使用它,没有出现任何问题。所以我希望其他人将来会发现它很有用。
import io
from typing import Optional
import plotly.express as px
import plotly.graph_objects as go
from PyQt6 import QtCore, QtGui, QtWidgets
def copy_figure(
fig: go.Figure,
width: Optional[int] = None,
height: Optional[int] = None,
scale: Optional[float] = None,
**kwargs,
):
"""Copy a Plotly figure to the system clipboard as a vector and raster.
Parameters
----------
fig : go.Figure
Plotly figure
width : Optional[int], optional
The width of the image, by default None.
height : Optional[int], optional
The height of the image, by default None.
scale : Optional[float], optional
The scale of the image, by default None.
**kwargs
Additional keyword arguments to pass to `.write_image()`.
"""
with io.BytesIO() as buf_png, io.BytesIO() as buf_svg:
# Need to create QApplication before doing anything else. Passing `[__name__]`
# emulates passing sys.argv. If the application isn't stored in a variable, (I
# think) it gets garbage collected (it won't work), so we store it in
# the 'unused' variable "_".
_ = QtWidgets.QApplication([__name__])
try:
fig.write_image(
buf_png, format="png", width=width, height=height, scale=scale, **kwargs
)
buf_png.seek(0)
png_image = QtGui.QImage()
png_image.loadFromData(buf_png.getvalue(), format="png")
except Exception as e:
print(f"Error converting to PNG: {e}")
png_image = None
try:
fig.write_image(
buf_svg, format="svg", width=width, height=height, scale=scale, **kwargs
)
buf_svg.seek(0)
except Exception as e:
print(f"Error converting to SVG: {e}")
buf_svg = None
if png_image is None and buf_svg is None:
return
if clipboard := QtGui.QGuiApplication.clipboard():
mime_data = QtCore.QMimeData()
if png_image is not None:
mime_data.setImageData(png_image)
if buf_svg is not None:
mime_data.setData("image/svg+xml", buf_svg.getvalue())
# This didn't work for me unless I specified the mode.
clipboard.setMimeData(mime_data, mode=clipboard.Mode.Clipboard)
else:
# If this is raised, the application probably wasn't started correctly.
raise RuntimeError("Could not access clipboard")
if __name__ == "__main__":
fig = px.line(x=[1, 2, 3], y=[4, 5, 6])
copy_figure(fig, width=640, height=480, scale=1.5)
在 Windows 上测试:Python 3.12.4、Plotly 5.19.0、Kaleido 0.1.0.post1、pyqt6 6.6.1。
注意:我知道 Plotly 在导出到 PNG/SVG 时遇到了一些问题 - 如果您无法正常导出到这些格式中的任何一种,则此功能将不适合您。