ropensci / rsvg

SVG renderer for R based on librsvg2
Other
97 stars 1 forks source link

Scaling leads to incorrectly cropped images. #35

Closed mb706 closed 1 year ago

mb706 commented 1 year ago

When I apply scaling by specifying a width or height, the resulting image has the correct size, but the content is incorrectly cropped. It looks like the underlying picture is scaled twice.

This works (using the example from #30):

library(rsvg)
#> Linking to librsvg 2.52.9
# Twitter Icon
svg_text <- "<svg xmlns=\"http://www.w3.org/2000/svg\"\naria-label=\"Twitter\" role=\"img\"\nviewBox=\"0 0 512 512\"><rect\nwidth=\"512\" height=\"512\"\nrx=\"15%\"\nfill=\"#1da1f2\"/><path fill=\"#fff\" d=\"M437 152a72 72 0 01-40 12a72 72 0 0032-40a72 72 0 01-45 17a72 72 0 00-122 65a200 200 0 01-145-74a72 72 0 0022 94a72 72 0 01-32-7a72 72 0 0056 69a72 72 0 01-32 1a72 72 0 0067 50a200 200 0 01-105 29a200 200 0 00309-179a200 200 0 0035-37\"/></svg>"

bitmap <- rsvg(charToRaw(svg_text))
im <- magick::image_read(bitmap)
grid::grid.raster(im)

original size

Scaling the image 2x does not work; the resulting image has the correct width 1024, but the image looks like it was scaled 4x and then cropped:

library(rsvg)
#> Linking to librsvg 2.52.9
# Twitter Icon
svg_text <- "<svg xmlns=\"http://www.w3.org/2000/svg\"\naria-label=\"Twitter\" role=\"img\"\nviewBox=\"0 0 512 512\"><rect\nwidth=\"512\" height=\"512\"\nrx=\"15%\"\nfill=\"#1da1f2\"/><path fill=\"#fff\" d=\"M437 152a72 72 0 01-40 12a72 72 0 0032-40a72 72 0 01-45 17a72 72 0 00-122 65a200 200 0 01-145-74a72 72 0 0022 94a72 72 0 01-32-7a72 72 0 0056 69a72 72 0 01-32 1a72 72 0 0067 50a200 200 0 01-105 29a200 200 0 00309-179a200 200 0 0035-37\"/></svg>"

bitmap <- rsvg(charToRaw(svg_text), width = 1024)
im <- magick::image_read(bitmap)
grid::grid.raster(im)

scaled x2

This may be due to a change in the librsvg API since scaling used to work until recently. I am not sure to what degree this is related to https://github.com/ropensci/rsvg/issues/30, but since the specific example in that issue currently works I am opening a new issue.

Session Info

 version 4.1.3 (2022-03-10)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: Fedora Linux 35 (Thirty Five)

Matrix products: default
BLAS/LAPACK: /usr/lib64/libflexiblas.so.3.2

locale:
 [1] LC_CTYPE=en_US.utf8       LC_NUMERIC=C             
 [3] LC_TIME=en_US.utf8        LC_COLLATE=en_US.utf8    
 [5] LC_MONETARY=en_US.utf8    LC_MESSAGES=en_US.utf8   
 [7] LC_PAPER=en_US.utf8       LC_NAME=C                
 [9] LC_ADDRESS=C              LC_TELEPHONE=C           
[11] LC_MEASUREMENT=en_US.utf8 LC_IDENTIFICATION=C      

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] rsvg_2.3.2

loaded via a namespace (and not attached):
[1] compiler_4.1.3    data.table_1.14.4
jeroen commented 1 year ago

Hmm interesting, it looks like the values for sx and sy in the C code are twice what they should be, but no idea why.

jeroen commented 1 year ago

I've added a workaround but I need to investigate why this started happening. I'm pretty sure I tested this before. Maybe it depends on whether or not the svg has a viewport set?

jeroen commented 1 year ago

OK I have pushed a new version with this fix to CRAN. I'm still not sure where this problem started appearing but it looks like the fix is easy.

robchallen commented 1 year ago

Hi didn't know whether best to open a new issue or resurrect this one:

I'm still getting this problem (or similar) in 2.4.0 in the rsvg_pdf and rsvg_svg calls. I hope this is enough to demonstrate, (and is not just an issue with my setup):

library(rsvg)
svg_text <- '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   width="100pt"
   height="100pt"
   viewBox="0 0 100 100"
   version="1.1"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
   <g>
    <rect
       style="fill:#b3b3b3;stroke:#000000;"
       width="90"
       height="90"
       x="5"
       y="5" />
    <rect
       style="fill:#b3b3b3;stroke:#000000;"
       width="20"
       height="20"
       x="60"
       y="60" />
  </g>
</svg>
'

# a simple box centred in the pdf with a smaller box in the bottom right
expected = tempfile(fileext = ".expected.pdf")
rsvg::rsvg_pdf(charToRaw(svg_text),file = expected)
rstudioapi::viewer(expected)

# I expect the same image to be scaled to 50x50
# instead I see only the top left corner
observed = tempfile(fileext = ".observed.pdf")
rsvg::rsvg_pdf(charToRaw(svg_text),file = observed,width = 50,height = 50)
rstudioapi::viewer(observed)

# rsvg to svg also produces image that is not scaled but viewport is smaller.
observed2 = tempfile(fileext = ".observed.svg")
rsvg::rsvg_svg(charToRaw(svg_text),file = observed2,width = 50,height = 50)
rstudioapi::viewer(observed2)

# Inspecting the new SVG there is only one path element - the smaller box is no
# longer there.
readLines(observed2)

# rsvg to bitmap works as expected
bitmap = rsvg::rsvg(charToRaw(svg_text),width = 50,height = 50)
im <- magick::image_read(bitmap)
grid::grid.raster(im)

# sessionInfo()
# R version 4.2.2 Patched (2022-11-10 r83330)
# Platform: x86_64-pc-linux-gnu (64-bit)
# Running under: Ubuntu 22.04.1 LTS
#
# Matrix products: default
# BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.10.0
# LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
#
# locale:
#   [1] LC_CTYPE=en_GB.UTF-8       LC_NUMERIC=C               LC_TIME=en_GB.UTF-8        LC_COLLATE=en_GB.UTF-8     LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_GB.UTF-8    LC_PAPER=en_GB.UTF-8       LC_NAME=C                  LC_ADDRESS=C
# [10] LC_TELEPHONE=C             LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C
#
# attached base packages:
#   [1] stats     graphics  grDevices datasets  utils     methods   base
#
# other attached packages:
#   [1] rsvg_2.4.0

N.B. my librsvg2-2 is at version 2.52.2+dfsg-3 if that is relevant

file1532e38e37382.expected.pdf file1532e378b02d1.observed.pdf