Як витягнути вбудоване зображення з файлу SVG?


26

У мене є файл SVG, який містить принаймні одне вбудоване зображення JPG / PNG всередині. Я хочу витягти JPG / PNG зображення з цього SVG-файлу та зберегти їх на диску.

Я додаю inkscapeтег, оскільки це програма, яку я використовую для редагування файлів SVG, але також приймаю рішення за допомогою інших інструментів.


1
Якщо нічого іншого, Python, ймовірно, може зробити це за допомогою спеціального клею, використовуючи lxml та PIL (або еквівалент).
Кіт

@Keith, дійсно, я щойно написав сценарій Python для вирішення цього питання. Тут використовується вбудована xml.etreeбібліотека.
Denilson Sá Maia

Відповіді:


30

Моє власне рішення (або ... вирішення):

  1. Виберіть зображення в Inkscape
  2. Відкрийте вбудований XML Editor( Shift+ Ctrl+ X)
  3. Виберіть xlink:hrefатрибут, який буде містити зображення як дані: URI
  4. Скопіюйте весь data:URI
  5. Вставте цей data:URI у браузер і збережіть його звідти.

Крім того, я можу відкрити файл SVG у будь-якому текстовому редакторі, знайти data:URI та скопіювати його звідти.

Хоча це рішення працює, воно начебто громіздке, і я хотів би навчитися кращому.


2
+1 - Я експортував зображення 3,5 Мб за допомогою цього методу, який зайняв деякий час, але працював. Якось функція «Витягнути зображення» для мене не працювала.
Мартін


17

Натомість краще рішення:

перейдіть туди Extensions -> Images -> Extract Image..., там ви можете зберегти вибране растрове зображення як файл. Однак це розширення працює дивно і якось працює досить повільно (але ідеально добре).

Ще одна примітка: це розширення громіздке і мовчки вмирає на різних великих зображеннях. Крім того, при великій кількості растрових зображень це може спричинити використання пам'яті Inkscape до жахливих рівнів (наприклад, 3 ГБ після отримання лише декількох знімків).

Оскільки у мене є близько 20 svg-файлів з приблизно 70 растровими зображеннями в кожному, кожне зображення розміром не менше 1 Мб, мені було потрібно інше рішення. Після короткої перевірки за допомогою підказки Denilson Sá я розробив наступний скрипт 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 Dev це краще.


Примітка: Ваш сценарій підтримує лише одну data:URL-адресу на рядок і не підтримує нові рядки всередині атрибута href (Inkscape додає їх для URL-адрес даних, а базовий параметр6464 навіть наказує, що рядки не повинні перевищувати 76 символів ). Хороший сценарій для швидкого злому, але він не працює з усіма видами SVG.
Denilson Sá Maia

@Johnny_Bit +1 за використання суми md5 для запобігання дублювання файлів. Я підкреслюю ваш сценарій нижче .
Іван Z

добре, березень 2019 року і працював легкий грандіозний з досить великим іміджем. І досить старий ноутбук / ubuntu / inkscape 0.48.4. Спасибі!
gaoithe

9

Нарешті, через роки я написав сценарій, щоб правильно витягти всі зображення з SVG-файлу, використовуючи належну бібліотеку XML для розбору SVG-коду.

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

Цей сценарій написаний для Python 2.7, але його слід досить легко перетворити на Python 3. Ще краще, після перетворення на Python 3.4 можна видалити близько 50 рядків, завдяки новим функціям, введеним у цій версії.


Дякую, адже це працює. Але це набагато повільніше, ніж обхід PDF. Ви думали про паралельну обробку? Зараз сценарій використовує лише одне ядро ​​/ потік процесора.
DanMan

@DanMan На жаль, зробити його паралельним не є магічним рішенням для пришвидшення нічого. Мені потрібно профайлювати код, щоб визначити вузьке місце. Якщо вузьким місцем є аналіз XML, вибачте, цю частину неможливо виконати паралельно. Чи можете ви надішліть мені по електронній пошті точні файли SVG, які занадто повільно? Кожен раз, коли у мене є час, я можу розслідувати виконання.
Denilson Sá Maia

Так, я спробував це зробити самостійно, і виявилося, що аналіз XML - це повільна частина, а не декодування зображень. Це, cElementTreeмабуть, буде швидше. Але, можливо, щось на кшталт Sax теж працює.
DanMan

@DanMan cElementTree, швидше за все, швидше. Однак на Python 3.3 обидва будуть однаковими . В якийсь момент я, ймовірно, оновить цей сценарій на Python 3.
Denilson Sá Maia

5

Як чергове вирішення, ви можете зберегти як PDF, а потім відкрити цей документ за допомогою Inkscape.

Зніміть прапорець "Вставити зображення" та бінго, всі pngs / jpegs будуть виведені у ваш домашній каталог.

Брудний, але швидше, ніж гуляти з даними: URL.


Де ви знайшли цю опцію "вставляти зображення"?
mik01aj

1
Коли ви відкриєте документ PDF у Inkscape, він знаходиться в наступному діалоговому вікні.
Ніколас Вілсон

У мене був PDF-файл, з якого я намагався витягти зображення, імпортуючи його в Inkscape. У такому випадку можливість зробити це вже під час імпорту, а не після імпорту стає ще зручнішим.
користувач149408

Я не впевнений, але таким чином будь-які вбудовані профілі ICC, здається, втрачаються в процесі. У зображеннях, які я витягнув прямо з SVG за допомогою сценарію Python, вбудовані профілі ICC.
DanMan

1

Я вдосконалюю php-скрипт @Johnny_Bit . Новий випуск сценарію може використовувати 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), і він повинен експортувати лише вибрану растрову карту.


Мені це рішення не подобається, оскільки воно перекодуватиме зображення. Я вважаю за краще рішення, яке витягує зображення в оригінальному форматі.
Denilson Sá Maia

1
Так, здається, Inkscape повторно кодує зображення, але це зберігає зображення PNG за замовчуванням. Тож я припускаю, що перекодування є принаймні без втрат.
Кріс

1
Ну не дуже. Вбудоване зображення могло мати перетворення (масштабування, обертання…), можливо, було вирізане або навіть щось інше, про що я не знаю. Inkscape неодмінно експортує вибраний об’єкт після застосування всіх цих перетворень, а це означає, що це рішення не є точно втратним.
Denilson Sá Maia
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.