我有一个SVG文件,其中至少包含一个嵌入式JPG / PNG图像。我想从该SVG文件中提取JPG / PNG图像并将其保存在磁盘上。
我添加了inkscape
标记,因为它是我用来编辑SVG文件的程序,但是我也接受使用其他工具的解决方案。
xml.etree
库。
我有一个SVG文件,其中至少包含一个嵌入式JPG / PNG图像。我想从该SVG文件中提取JPG / PNG图像并将其保存在磁盘上。
我添加了inkscape
标记,因为它是我用来编辑SVG文件的程序,但是我也接受使用其他工具的解决方案。
xml.etree
库。
Answers:
我自己的解决方案(或解决方法):
XML Editor
(Shift+ Ctrl+ X)xlink:href
将包含图像作为数据的属性:URIdata:
URIdata:
URI 粘贴到浏览器中,然后从那里保存它。另外,我可以在任何文本编辑器中打开SVG文件,找到data:
URI并从那里复制它。
尽管此解决方案有效,但它有点麻烦,我很想学习更好的解决方案。
而是有一个更好的解决方案:
转到Extensions -> Images -> Extract Image...
,您可以在其中将选定的光栅图像另存为文件。但是,此扩展名很奇怪,并且以某种方式工作得很慢(但效果很好)。
另一个注意事项:此扩展繁琐,并且在各种大型图像上都无声地消失。同样,对于大量的光栅图像,它可能使inkscape的内存使用率达到惊人的水平(例如,仅提取少量图像后就达到了3GB)。
因为我有大约20个svg文件,每个文件中包含约70个光栅图像,每个图像的大小至少为1MB,所以我需要一个不同的解决方案。在使用DenilsonSá技巧进行简短检查之后,我设计了以下php脚本,该脚本从svg文件提取图像:
#!/usr/bin/env php
<?php
$svgs = glob('*.svg');
$existing = array();
foreach ($svgs as $svg){
mkdir("./{$svg}.images");
$lines = file($svg);
$img = 0;
foreach ($lines as $line){
if (preg_match('%xlink:href="data:([a-z0-9-/]+);base64,([^"]+)"%i', $line, $regs)) {
$type = $regs[1];
$data = $regs[2];
$md5 = md5($data);
if (!in_array($md5, $existing)) {
$data = str_replace(' ', "\r\n", $data);
$data = base64_decode($data);
$type = explode('/', $type);
$save = "./{$svg}.images/{$img}.{$type[1]}";
file_put_contents($save, $data);
$img++;
$existing[] = $md5;
}
} else {
$result = "";
}
}
}
echo count($existing);
这样我就可以获取所有想要的图像,而md5可以避免重复获取图像。
我敢肯定,必须有另一种简单得多的方法,但是这取决于inkscape开发人员如何做得更好。
data:
每行一个URL,并且不支持href属性内的换行符(inkscape将它们添加为数据URL,并且base64规范甚至要求该行的长度不得超过76个字符)。不错的脚本,可以快速破解,但不适用于所有SVG。
终于,几年后,我编写了一个脚本,使用适当的XML库来解析SVG代码,从而从SVG文件中正确提取所有图像。
http://bitbucket.org/denilsonsa/small_scripts/src/tip/extract_embedded_images_from_svg.py
该脚本是为Python 2.7编写的,但应该很容易转换为Python3。更好的是,由于该版本引入了新功能,转换为Python 3.4后可以删除大约50行。
cElementTree
应该更快。但是也许像萨克斯这样的东西也更好。
cElementTree
可能更快。但是,在Python 3.3上,两者是相同的。在某些时候,我很可能会更新脚本到Python 3
作为另一种解决方法,您可以另存为PDF,然后使用Inkscape打开该文档。
取消选中“嵌入图像”和宾果游戏,所有png / jpeg都会弹出到您的主目录中。
凌乱,但比弄乱数据的速度更快:URL。
我改进了@Johnny_Bit的php脚本。新版本的脚本可以在新行中使用svg。它从svg文件提取多个图像并将其保存在外部png文件中。svg和png文件位于“ svg”目录中,但您可以在常量“ SVG_DIR”中进行更改。
<?php
define ( 'SVG_DIR', 'svg/' );
define ( 'SVG_PREFIX', 'new-' );
$svgs = glob(SVG_DIR.'*.svg');
$external = array();
$img = 1;
foreach ($svgs as $svg) {
echo '<p>';
$svg_data = file_get_contents( $svg );
$svg_data = str_replace( array("\n\r","\n","\r"), "", $svg_data);
$svg_file = substr($svg, strlen(SVG_DIR) );
echo $svg_file.': '.strlen($svg_data).' ????';
if ( preg_match_all( '|<image[^>]+>|', $svg_data, $images, PREG_SET_ORDER) ) {
foreach ($images as $image_tag) {
if ( preg_match('%xlink:href="data:([a-z0-9-/]+);base64,([^"]+)"%i', $image_tag[0], $regs) ) {
echo '<br/>Embeded image has benn saved to file: ';
$type = $old_type = $regs[1];
$data = $old_data = $regs[2];
$md5 = md5($data);
if ( array_key_exists($md5, $external) ) {
$image_file = $external[$md5];
} else {
$data = str_replace(" ", "\r\n", $data);
$data = base64_decode($data);
$type = explode('/', $type);
$image_file = substr( $svg_file, 0, strlen($svg_file)-4 ) . '-' . ($img++) . '.png';
file_put_contents(SVG_DIR.$image_file, $data);
$external[$md5] = $image_file;
}
echo $image_file;
$svg_data = str_replace('xlink:href="data:'.$old_type.';base64,'.$old_data.'"', 'xlink:href="'.$image_file.'"', $svg_data);
}
}
file_put_contents(SVG_DIR.SVG_PREFIX.'.svg', $svg_data);
}
echo '</p>';
}
?>
在Inkscape中打开文件,然后选择要导出的位图。单击文件->导出位图(Ctrl + Shift + E),它将仅导出选定的位图。