如何使 fabric.js 输出包含 alpha 颜色的 svg?
How do I make fabric.js output svg including alpha color?
我需要将织物 canvas 绘图的结果输出到 SVG 文件。
我使用的是 fabric.js 版本 1.7.6,当我将一条路径绘制到 canvas 并使用 rgba(255,0,0,.15)
之类的 rgba 填充时,生成的 SVG 具有 rgb(0,0,0)
。是否需要启用某些设置才能使其输出 alpha 通道?
在我的示例代码中,紫色圆圈正确转换为 SVG,但矩形只显示为黑色。
样本HTML:
<html>
<head>
<script src="fabric.js"></script>
</head>
<body>
<div id="canvasHolder" style="border: 3px solid black;">
<canvas id="canvasElement" width="400" height="400" />
</div>
<div id="svgHolder" style="border: 3px solid blue;">
</div>
</body>
<script>
var canvas = new fabric.Canvas('canvasElement');
var rect = new fabric.Path('M,0,0,h,100,v,100,h,-100,z',{
top:100,
left:100,
stroke: 'green',
fill: 'rgba(255,0,0,.15)'
});
canvas.add(rect);
var circ = new fabric.Circle({
radius: 30,
top:30,
left:30,
stroke: 'blue',
fill: 'purple'
});
canvas.add(circ);
canvas.renderAll();
// Make an SVG object out of the fabric canvas
var SVG = canvas.toSVG();
document.getElementById('svgHolder').innerHTML = SVG;
</script>
</html>
输出 SVG:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="400" viewBox="0 0 400 400" xml:space="preserve">
<desc>Created with Fabric.js 1.7.6</desc>
<defs>
</defs>
<path d="M 0 0 h 100 v 100 h -100 z" style="stroke: rgb(0,128,0); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(150.5 150.5) translate(-50, -50) " stroke-linecap="round"></path>
</svg>
正如我在评论中所说,这看起来像是一个错误,您应该报告 project's issue tracker。
颜色全部转换为 rgb()(rgba、hsl、hsla、hex、关键字),因此不支持 alpha 通道...
目前,这是一个繁重的解决方法:
toSVG
接受一个 reviver 函数,它将接收所有 svg 节点标记。从那里,您可以重新应用正确的样式,但并不那么容易。
我能找到的唯一允许我们识别哪个对象对应于我们获得的 svg 标记的参数是 id
参数。
- 所以首先,我们将构建一个字典,它将按 id 存储我们的颜色。
- 然后,我们将为织物的对象分配 ID 和颜色。
- 最后,在 reviver 中,我们将解析标记以将其转换为 svg 节点,检查其
id
属性,然后更改其 style.fill
和 style.stroke
属性,在返回此修改节点的序列化之前。
var canvas = new fabric.Canvas('canvasElement');
var colors_dict = {};
// an helper function to generate and store our colors objects
function getColorId(fill, stroke) {
var id = 'c_' + Math.random() * 10e16;
return colors_dict[id] = {
id: id,
fill: fill || 'black',
stroke: stroke || 'black' // weirdly fabric doesn't support 'none'
}
}
// first ask for the color object of the rectangle
var rect_color = getColorId('hsla(120, 50%, 50%, .5)', 'rgba(0,0,255, .25)');
var rect = new fabric.Path('M,0,0,h,100,v,100,h,-100,z', {
top: 60,
left: 60,
stroke: rect_color.stroke, // set the required stroke
fill: rect_color.fill, // fill
id: rect_color.id // and most importantly, the id
});
canvas.add(rect);
var circ_color = getColorId('rgba(200, 0,200, .7)');
var circ = new fabric.Circle({
radius: 30,
top: 30,
left: 30,
stroke: circ_color.stroke,
fill: circ_color.fill,
id: circ_color.id
});
canvas.add(circ);
canvas.renderAll();
var parser = new DOMParser();
var serializer = new XMLSerializer();
function reviveColors(svg){
// first we parse the markup we get, and extract the node we're interested in
var svg_doc = parser.parseFromString('<svg xmlns="http://www.w3.org/2000/svg">' + svg + '</svg>', 'image/svg+xml');
var svg_node = svg_doc.documentElement.firstElementChild;
var id = svg_node.getAttribute('id');
if (id && id in colors_dict) { // is this one of the colored nodes
var col = colors_dict[id]; // get back our color object
svg_node.style.fill = col.fill; // reapply the correct styles
svg_node.style.stroke = col.stroke;
// return the new markup
return serializer.serializeToString(svg_node).replace('xmlns="http://www.w3.org/2000/svg', '');
}
return svg;
}
// Make an SVG object out of the fabric canvas
var SVG = canvas.toSVG(null, reviveColors);
document.getElementById('svgHolder').innerHTML = SVG;
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.12/fabric.js"></script>
<div id="canvasHolder" style="border: 3px solid black;">
<!-- beware canvas tag can't be self-closing -->
<canvas id="canvasElement" width="400" height="200"></canvas>
</div>
<div id="svgHolder" style="border: 3px solid blue;">
颜色被转换为 RGB,因为 svg 规范需要 CSS2 格式的颜色,因此不支持 rgba。
引用:https://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#value-def-color
织物通过填充不透明度规则实现透明度。关键是 fabric.Color 颜色解析器看起来像是被 alpha 通道的 .15
表示法所窒息。
请使用 0.15 即可。
我同意 fabric.Color 可以解决这个问题。
我需要将织物 canvas 绘图的结果输出到 SVG 文件。
我使用的是 fabric.js 版本 1.7.6,当我将一条路径绘制到 canvas 并使用 rgba(255,0,0,.15)
之类的 rgba 填充时,生成的 SVG 具有 rgb(0,0,0)
。是否需要启用某些设置才能使其输出 alpha 通道?
在我的示例代码中,紫色圆圈正确转换为 SVG,但矩形只显示为黑色。
样本HTML:
<html>
<head>
<script src="fabric.js"></script>
</head>
<body>
<div id="canvasHolder" style="border: 3px solid black;">
<canvas id="canvasElement" width="400" height="400" />
</div>
<div id="svgHolder" style="border: 3px solid blue;">
</div>
</body>
<script>
var canvas = new fabric.Canvas('canvasElement');
var rect = new fabric.Path('M,0,0,h,100,v,100,h,-100,z',{
top:100,
left:100,
stroke: 'green',
fill: 'rgba(255,0,0,.15)'
});
canvas.add(rect);
var circ = new fabric.Circle({
radius: 30,
top:30,
left:30,
stroke: 'blue',
fill: 'purple'
});
canvas.add(circ);
canvas.renderAll();
// Make an SVG object out of the fabric canvas
var SVG = canvas.toSVG();
document.getElementById('svgHolder').innerHTML = SVG;
</script>
</html>
输出 SVG:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="400" height="400" viewBox="0 0 400 400" xml:space="preserve">
<desc>Created with Fabric.js 1.7.6</desc>
<defs>
</defs>
<path d="M 0 0 h 100 v 100 h -100 z" style="stroke: rgb(0,128,0); stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;" transform="translate(150.5 150.5) translate(-50, -50) " stroke-linecap="round"></path>
</svg>
正如我在评论中所说,这看起来像是一个错误,您应该报告 project's issue tracker。
颜色全部转换为 rgb()(rgba、hsl、hsla、hex、关键字),因此不支持 alpha 通道...
目前,这是一个繁重的解决方法:
toSVG
接受一个 reviver 函数,它将接收所有 svg 节点标记。从那里,您可以重新应用正确的样式,但并不那么容易。
我能找到的唯一允许我们识别哪个对象对应于我们获得的 svg 标记的参数是 id
参数。
- 所以首先,我们将构建一个字典,它将按 id 存储我们的颜色。
- 然后,我们将为织物的对象分配 ID 和颜色。
- 最后,在 reviver 中,我们将解析标记以将其转换为 svg 节点,检查其
id
属性,然后更改其style.fill
和style.stroke
属性,在返回此修改节点的序列化之前。
var canvas = new fabric.Canvas('canvasElement');
var colors_dict = {};
// an helper function to generate and store our colors objects
function getColorId(fill, stroke) {
var id = 'c_' + Math.random() * 10e16;
return colors_dict[id] = {
id: id,
fill: fill || 'black',
stroke: stroke || 'black' // weirdly fabric doesn't support 'none'
}
}
// first ask for the color object of the rectangle
var rect_color = getColorId('hsla(120, 50%, 50%, .5)', 'rgba(0,0,255, .25)');
var rect = new fabric.Path('M,0,0,h,100,v,100,h,-100,z', {
top: 60,
left: 60,
stroke: rect_color.stroke, // set the required stroke
fill: rect_color.fill, // fill
id: rect_color.id // and most importantly, the id
});
canvas.add(rect);
var circ_color = getColorId('rgba(200, 0,200, .7)');
var circ = new fabric.Circle({
radius: 30,
top: 30,
left: 30,
stroke: circ_color.stroke,
fill: circ_color.fill,
id: circ_color.id
});
canvas.add(circ);
canvas.renderAll();
var parser = new DOMParser();
var serializer = new XMLSerializer();
function reviveColors(svg){
// first we parse the markup we get, and extract the node we're interested in
var svg_doc = parser.parseFromString('<svg xmlns="http://www.w3.org/2000/svg">' + svg + '</svg>', 'image/svg+xml');
var svg_node = svg_doc.documentElement.firstElementChild;
var id = svg_node.getAttribute('id');
if (id && id in colors_dict) { // is this one of the colored nodes
var col = colors_dict[id]; // get back our color object
svg_node.style.fill = col.fill; // reapply the correct styles
svg_node.style.stroke = col.stroke;
// return the new markup
return serializer.serializeToString(svg_node).replace('xmlns="http://www.w3.org/2000/svg', '');
}
return svg;
}
// Make an SVG object out of the fabric canvas
var SVG = canvas.toSVG(null, reviveColors);
document.getElementById('svgHolder').innerHTML = SVG;
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.12/fabric.js"></script>
<div id="canvasHolder" style="border: 3px solid black;">
<!-- beware canvas tag can't be self-closing -->
<canvas id="canvasElement" width="400" height="200"></canvas>
</div>
<div id="svgHolder" style="border: 3px solid blue;">
颜色被转换为 RGB,因为 svg 规范需要 CSS2 格式的颜色,因此不支持 rgba。
引用:https://www.w3.org/TR/2008/REC-CSS2-20080411/syndata.html#value-def-color
织物通过填充不透明度规则实现透明度。关键是 fabric.Color 颜色解析器看起来像是被 alpha 通道的 .15
表示法所窒息。
请使用 0.15 即可。
我同意 fabric.Color 可以解决这个问题。