SVGファイルから埋め込み画像を抽出する方法は?


26

内部に少なくとも1つの埋め込みJPG / PNGイメージを含むSVGファイルがあります。そのSVGファイルからJPG / PNG画像を抽出し、ディスクに保存したい。

inkscapeSVGファイルの編集に使用するプログラムであるため、タグを追加していますが、他のツールを使用したソリューションも受け入れます。


1
他に何もなければ、PythonはおそらくlxmlとPIL(または同等のもの)を使用してカスタム接着剤でそれを行うことができます。
キース

@キース、確かに、私はちょうどこの質問を解決するためにPythonスクリプトを書いところです。組み込みxml.etreeライブラリを使用します。
デニルソンサマイア

回答:


30

私自身のソリューション(または...回避策):

  1. Inkscapeで画像を選択します
  2. 組み込みXML EditorShift+ Ctrl+ X)を開きます
  3. データxlink:hrefとして画像を含む属性を選択します:URI
  4. data:URI 全体をコピーします
  5. そのdata:URIをブラウザーに貼り付け、そこから保存します。

または、テキストエディターでSVGファイルを開き、data:URIを見つけてそこからコピーすることもできます。

このソリューションは機能しますが、ちょっと面倒ですし、もっと良いものを学びたいです。


2
+1-この方法を使用して3.5 MBのイメージをエクスポートしましたが、しばらく時間がかかりましたが機能しました。どういうわけか「画像の抽出」機能が機能しませんでした。
マーティン

この目的のためのコマンドラインPythonスクリプトもご覧ください。
サマイア14年

17

代わりに、より良い解決策があります。

に移動するとExtensions -> Images -> Extract Image...、選択したラスターイメージをファイルとして保存できます。ただし、この拡張機能は奇妙に動作し、どういうわけかかなりゆっくり動作します(ただし、完全に良好です)。

別の注意:この拡張機能は扱いにくく、さまざまな大きな画像で静かに終了します。また、多数のラスターイメージを使用すると、inkscapeのメモリ使用量が途方もないレベルに達する可能性があります(ほんの一握りのイメージを抽出した後の3GBなど)。

それぞれが少なくとも1MBのサイズの約70個のラスターイメージを含む約20個のsvgファイルを持っているため、別のソリューションが必要でした。DenilsonSátipを使用した簡単なチェックの後、svgファイルから画像を抽出する次のphpスクリプトを考案しました。

#!/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:1行につき1 つのURL のみをサポートし、href属性内の改行をサポートしません(inkscapeはデータURLに改行を追加し、base64仕様では、行が76文字を超えないように義務付けています)。簡単なハック用の素晴らしいスクリプトですが、すべての種類のSVGでは機能しません。
デニルソンサマイア

ファイルの重複を防ぐためにmd5 sumを使用する場合は、@ Johnny_Bit +1。以下のスクリプトを削除します。
イヴァンZ

良い、2019年3月、かなり大きなイメージで簡単に壮大に働いた。そして、かなり古いラップトップ/ ubuntu / inkscape 0.48.4。ありがとう!
gaoithe

9

最後に、数年後、適切なXMLライブラリを使用してSVGコードを解析し、S​​VGファイルからすべての画像を正しく抽出するスクリプトを作成しました。

http://bitbucket.org/denilsonsa/small_scripts/src/tip/extract_embedded_images_from_svg.py

このスクリプトはPython 2.7用に書かれていますが、Python 3への変換は非常に簡単です。さらに良いことに、そのバージョンで導入された新機能により、Python 3.4への変換後に約50行を削除できます。


それが機能するので、ありがとう。ただし、PDFの回避策よりもはるかに遅くなります。並列処理について考えたことはありますか?現在、スクリプトは単一のCPUコア/スレッドのみを使用しています。
ダンマン

@DanMan残念ながら、並列化することは、速度を上げるための魔法の解決策ではありません。ボトルネックを特定するために、コードのプロファイルを作成する必要があります。ボトルネックがXML解析である場合、申し訳ありませんが、その部分を並行して行うことはできません。遅すぎる正確なSVGファイルを電子メールで送信してください。時間があれば、パフォーマンスを調査することがあります。
デニルソンサマイア

ええ、私は自分でやってみましたが、画像をデコードするのではなく、XML解析が遅い部分であることがわかりました。とcElementTreeは言うものの、より高速になるはずです。しかし、Saxのようなものもうまく機能しているのかもしれません。
ダンマン

@DanMan cElementTreeはおそらくより高速です。ただし、Python 3.3では、両方とも同じです。いつか、そのスクリプトをPython 3に更新するでしょう。
DenilsonSáMaia

5

さらに別の回避策として、PDFとして保存し、Inkscapeでそのドキュメントを開くことができます。

「埋め込み画像」のチェックを外すと、ビンゴ、すべてのpng / jpegがホームディレクトリに吐き出されます。

厄介ですが、URLのデータをだまし取るよりも速いです。


「画像を埋め込む」オプションはどこで見つけましたか?
mik01aj

1
PDFドキュメントをinkscapeで開くと、次のダイアログが表示されます。
ニコラスウィルソン

Inkscapeにインポートして画像を抽出しようとしたPDFがありました。その場合には、これを行うことができることはなく、インポート後に、インポートがさらに便利になります。
user149408

よくわかりませんが、この方法では、埋め込みICCプロファイルがプロセスで失われるようです。そのPythonスクリプトを介してSVGから直接抽出した画像には、ICCプロファイルが埋め込まれています。
ダンマン

1

私は改善@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>';
}

?>

0

Inkscapeでファイルを開き、エクスポートするビットマップを選択します。[ファイル]-> [ビットマップのエクスポート](Ctrl + Shift + E)をクリックすると、選択したビットマップのみがエクスポートされます。


画像を再エンコードするため、このソリューションは好きではありません。元の形式で画像を抽出するソリューションを希望します。
デニルソンサマイア

1
はい、Inkscapeは画像を再エンコードするようですが、デフォルトではPNG画像を保存します。そのため、再エンコードは少なくともロスレスであると想定しています。
クリス

1
まあ、そうでもない。埋め込まれた画像には、変換(スケーリング、回転など)があったり、クリップされたり、知らない何かがあったりします。Inkscapeは、これらすべての変換を適用した後、選択したオブジェクトを確実にエクスポートします。つまり、このソリューションは完全にロスレスではありません。
デニルソンサマイア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.