fabricjs / fabric.js

Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser
http://fabricjs.com
Other
28.72k stars 3.49k forks source link

[Bug]: Issue with loadSVGFromString/URL and image masks with base64 encoded images #8437

Open ghost opened 1 year ago

ghost commented 1 year ago

Version

5.2.4

In What environments are you experiencing the problem?

Chrome, Node.js

Node Version (if applicable)

16.10.0

Link To Reproduction

http://jsfiddle.net/jonnyMitts/m8ndkq0h/1/

Steps To Reproduce

I have an svg that uses both a mask and base 64 encoded image. For some reason that combination looks like it causes issues with FabricJS.

Not sure if this is because of the clipping mask in the SVG or the base 64 encoded image, but the images within the svg are coming through with a white clipping image and no base image. Not sure what is going here. Here is the fiddle.

The top image rendering in the browser is the FabricJS rendering on the canvas and the bottom is the browser rendering of the same svg. You can see both by scrolling up and down.

http://jsfiddle.net/jonnyMitts/m8ndkq0h/1/

here is the javascript:

var svgString = `<svg
   version="1.1"
   id="svg2"
   width="1280.0126"
   height="720"
   viewBox="0 0 1280.0126 720"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <defs
     id="defs6">
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath16">
      <path
         d="M 0,0.028 H 959.981 V 539.999 H 0 Z"
         clip-rule="evenodd"
         id="path14" />
    </clipPath>
    <mask
       maskUnits="userSpaceOnUse"
       x="0"
       y="0"
       width="1"
       height="1"
       id="mask24">
      <image
         width="1"
         height="1"
         style="image-rendering:optimizeSpeed"
         preserveAspectRatio="none"
         xlink:href="data:image/png;base64,..."
         id="image26" />
    </mask>
  </defs>
  <g
     id="g8"
     transform="matrix(1.3333333,0,0,-1.3333333,0,720)">
    <g
       id="g10">
      <g
         id="g12"
         clip-path="url(#clipPath16)">
        <path
           d="M 0,540 H 959.981 V 0.028 L 0,0.028 Z"
           style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
           id="path18" />
        <path
           d="M 0,540 H 960.009 V 0 H 0 Z"
           style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none"
           id="path20" />
        <g
           id="g22"
           transform="matrix(806.088,0,0,236.296,76.932,134.731)">
          <image
             width="1"
             height="1"
             style="image-rendering:optimizeSpeed"
             preserveAspectRatio="none"
             transform="matrix(1,0,0,-1,0,1)"
             xlink:href="data:image/png;base64,..."
             mask="url(#mask24)"
             id="image28" />
        </g>
        <g
           id="g30">
          <text
             xml:space="preserve"
             transform="matrix(1,0,0,-1,43.313,25.512)"
             style="font-variant:normal;font-weight:normal;font-size:9.014px;font-family:Helvetica;-inkscape-font-specification:Helvetica;writing-mode:lr-tb;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
             id="text34"><tspan
               x="0 6.6072621 9.1041403 14.115924 19.217848 24.229631 29.241417 31.837448 38.246403 43.348328 48.360111 51.361771 57.365097 62.467018 67.478806 70.480469 75.58239 77.781807 82.387962 87.399742 91.996887 97.008667 102.1106 107.12238 109.12348 114.22541 119.23719 123.14025 125.63713 128.134 133.23593 138.24771 144.75583 147.2527 149.35297 155.26614 157.35739 159.35851 161.85538 164.85704 166.94829 171.96008 176.97186 179.5679 184.07489 186.67093 189.57344 194.67535 199.18236 204.28429 207.28595 211.88309 216.89487 221.90665"
               y="0"
               id="tspan32">© 2022 NearShore Technology, LLC. All rights reserved.</tspan></text>
        </g>
      </g>
    </g>
  </g>
</svg>
`// Do some initializing stuff

const width = 2560; 
const height = 1440;
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.StaticCanvas('c', { width, height });

fabric.loadSVGFromString(svgString, (objects, options) => {
      var loadedObject = fabric.util.groupSVGElements(objects, options);
      canvas.add(loadedObject);
      canvas.renderAll();
      console.log(canvas.toJSON())
});

and here is the HTML

<canvas id="c" width="300" height="300"></canvas>
<div>
<svg
   version="1.1"
   id="svg2"
   width="1280.0126"
   height="720"
   viewBox="0 0 1280.0126 720"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <defs
     id="defs6">
    <clipPath
       clipPathUnits="userSpaceOnUse"
       id="clipPath16">
      <path
         d="M 0,0.028 H 959.981 V 539.999 H 0 Z"
         clip-rule="evenodd"
         id="path14" />
    </clipPath>
    <mask
       maskUnits="userSpaceOnUse"
       x="0"
       y="0"
       width="1"
       height="1"
       id="mask24">
      <image
         width="1"
         height="1"
         style="image-rendering:optimizeSpeed"
         preserveAspectRatio="none"
         xlink:href="data:image/png;base64,..."
         id="image26" />
    </mask>
  </defs>
  <g
     id="g8"
     transform="matrix(1.3333333,0,0,-1.3333333,0,720)">
    <g
       id="g10">
      <g
         id="g12"
         clip-path="url(#clipPath16)">
        <path
           d="M 0,540 H 959.981 V 0.028 L 0,0.028 Z"
           style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
           id="path18" />
        <path
           d="M 0,540 H 960.009 V 0 H 0 Z"
           style="fill:#333333;fill-opacity:1;fill-rule:evenodd;stroke:none"
           id="path20" />
        <g
           id="g22"
           transform="matrix(806.088,0,0,236.296,76.932,134.731)">
          <image
             width="1"
             height="1"
             style="image-rendering:optimizeSpeed"
             preserveAspectRatio="none"
             transform="matrix(1,0,0,-1,0,1)"
             xlink:href="data:image/png;base64,..."
             mask="url(#mask24)"
             id="image28" />
        </g>
      </g>
    </g>
  </g>
</svg>
</div>```

The base64 image code is replaced with ... in the above sample because of caharacter limits. The full same is in the fiddle.

The Fabric canvas.toJSON() out is logged in the console.

Also, I am doing the loadSVGFromString on the server, but the output seems to be the same as when it is done in the browser.

I have tried loading from URL and from a string. Both have the same output.

### Expected Behavior

The expected behavior would be for the SVG to render on the canvas using fabric in the same way that the SVG render that is on the bottom of the browser in the fiddle.

### Actual Behavior

The images are not rendering correctly is the issue.

### Error Message & Stack Trace

```bash
no error messages.
asturur commented 1 year ago

hi @jonnymura the SVG is a bit weird. The image is a white image, while the mask has the actual graphic on it. fabricJS does not support masks yet ( there is an old PR for that that you could try maybe )

Do you have a single svg with mask or your use case is fully about masks and so you are stuck?

Is there any reason why you want to load this svg as a group of objects rather than a plain image, and in that case it would probably work out of the box?

Telling us a bit more about your use case could help understand what you could actually do