svglib icon indicating copy to clipboard operation
svglib copied to clipboard

svg2rlg cause black background

Open jason40418 opened this issue 6 years ago • 7 comments

I use plotly to draw a mesh3D and use "to_image()" to transfer into svg byte file. If use plotly "write_image()" to generate svg and png could success to export what I needed. However, when I use "io.BytesIO()" to read and "svg2rlg()" would cause black background.

Code

Plotly Layout Setting

self.__figure.update_layout(
            margin=dict(l=0, r=0, t=0, b=20),
            height=800,
            autosize=True,
            scene = dict(
                xaxis_title='trade',
                yaxis_title='inter',
                zaxis_title='Net Profit',
                xaxis = dict(nticks=15, range=[1, 30],),
                yaxis = dict(nticks=8, range=[1, 30],),
                zaxis = dict(nticks=8, range=[min_z-100000.0, max_z+100000.0],),
            )
        )

svg2rlg

from reportlab.graphics import renderPDF, renderPM

image = figure.to_image(format='svg')
figure.write_image("fig1.svg")
figure.write_image("fig1.png")
drawing = svg2rlg(io.BytesIO(image))
scaleFactor = 527/drawing.width
drawing.width *= scaleFactor
drawing.height *= scaleFactor
drawing.scale(scaleFactor, scaleFactor)

renderPM.drawToFile(drawing, 'svg_demo.png', 'PNG')

Result

  • export png from plotly write_image() fig1

  • export svg from plotly to_image()

    • Could not upload svg, so change extension to .txt svg.txt
  • After svg2rlg() to read and export by renderPM.drawToFile() svg_demo

Environments

  • Windows 10
  • Python 3.7 (32bits)
  • Pyplot 4.1.0
  • notebook 5.7.4
  • svglib 0.9.2

jason40418 avatar Sep 23 '19 07:09 jason40418

For renderPM, it looks like there is a bg option, read https://github.com/deeplook/svglib/issues/171#issuecomment-468239750. For renderPDF, the _PDFRenderer.drawImage method is using canvas.drawInlineImage instead of canvas.drawImage, and the former doesn't expose the mask parameter. I don't see what svglib can do.

claudep avatar Sep 24 '19 17:09 claudep

After trying I found that Plotly layout have bgcolor in scene and it default is rgba(0, 0, 0, 0). If I change it to rgba(255, 255, 255, 0) it would not cause black background. So, I assume that some method would cause lost alpha value and finally result it.

jason40418 avatar Sep 27 '19 09:09 jason40418

Still getting this issue...It only happens with time series plots on plotly in my case, or maybe it only happens on graphs with more than x data points. I want to think it is a plotly issue because svg2rlg works fine on histograms as well as bar graphs that are also generated from plotly....

jayceslesar avatar Jan 18 '21 18:01 jayceslesar

For renderPM, it looks like there is a bg option

Sadly, renderPM.drawTo_anything_(svglib.svg2rlg(fn), bg=0x00000000) doesn't work/allow leaving the Alpha channel low, so this workaround only works for those who need a solid, non-tranparent background.

(That said, should this issue #209 be closed as a duplicate of #171?)

James-E-A avatar May 23 '21 20:05 James-E-A

I seem to get the same bug when converting into pdf. A black background appears. My svg is generated by mapnik and seems to have an embedded raster image.

rapto avatar Apr 21 '22 07:04 rapto

I too have the same issue with Python 3.9 and following packages: plotly==5.10.0 svglib==1.4.1 kaleido==0.1.0.post1

The svg does not have transparent background but svglib makes it black Attached svg

svgviewer-output

ronak1009 avatar Dec 01 '22 11:12 ronak1009

For renderPM, it looks like there is a bg option, read #171 (comment). For renderPDF, the _PDFRenderer.drawImage method is using canvas.drawInlineImage instead of canvas.drawImage, and the former doesn't expose the mask parameter. I don't see what svglib can do.

I totally agree with @claudep. Had a same problem when generating with BaseDocTemplate. I just needed to change the source code of reportlab, and it worked flawlessly. For anyone interested, it is located in /usr/lib/python3.11/site-packages/reportlab/graphics/renderPDF.py:

    def drawImage(self, image):
        path = image.path
        # currently not implemented in other renderers
        if path and (hasattr(path,'mode') or os.path.exists(image.path)):
-            self._canvas.drawInlineImage(
+            self._canvas.drawImage(
                    path,
                    image.x, image.y,
                    image.width, image.height,
+                   mask='auto'
                    )

LuighiV avatar Jan 17 '24 00:01 LuighiV