Python:在 Windows 剪贴板中将 svg 字符串复制为“image/svg+xml”格式,因此可以将其粘贴为 svg 图像

问题描述 投票:0回答:2

假设我有一个 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中?

python string svg mime
2个回答
3
投票

据我所知,唯一支持 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 添加到剪贴板中。


0
投票

为了扩展 @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 时遇到了一些问题 - 如果您无法正常导出到这些格式中的任何一种,则此功能将不适合您。

© www.soinside.com 2019 - 2024. All rights reserved.