Bir SVG dosyasından gömülü görüntü nasıl ayıklanır?


26

İçinde en az bir katıştırılmış JPG / PNG görüntü içeren bir SVG dosyası var. JPG / PNG görüntülerini bu SVG dosyasından ayıklamak ve diske kaydetmek istiyorum.

inkscapeSVG dosyalarını düzenlemek için kullandığım program olduğu için etiketi ekliyorum , ancak diğer araçları kullanarak çözümleri de kabul ediyorum.


1
Başka bir şey yoksa, Python muhtemelen lxml ve PIL (veya eşdeğeri) kullanarak bazı özel tutkalla yapabilir.
Keith

@Keith, gerçekten, bu soruyu çözmek için bir Python betiği yazdım . Yerleşik xml.etreekütüphaneyi kullanır .
Denilson Sá Maia

Yanıtlar:


30

Kendi çözümüm (veya ... geçici çözümüm):

  1. Inkscape'te görüntüyü seçin
  2. Yerleşikini açın XML Editor( Shift+ Ctrl+ X)
  3. xlink:hrefGörüntüyü veri olarak içerecek özelliği seçin : URI
  4. Tüm data:URI'yi kopyala
  5. Bu data:URI'yi bir tarayıcıya yapıştırın ve oradan kaydedin.

Alternatif olarak, SVG dosyasını herhangi bir metin düzenleyicide açabilir, URI'yi bulabilir data:ve oradan kopyalayabilirim.

Bu çözüm işe yarıyor olsa da, biraz hantal ve daha iyi bir çözüm öğrenmek isterim.


2
+1 - Bu yöntemi kullanarak 3,5 MB'lık bir görüntü verdim, bu biraz zaman aldı ama çalıştı. Bir şekilde "Görüntüyü Ayıkla" işlevi benim için çalışmadı.
Martin


17

Bunun yerine daha iyi bir çözüm var:

gidin Extensions -> Images -> Extract Image..., bir dosya olarak seçilen tarama görüntü var kaydedebilirsiniz. Ancak bu uzantı tuhaf çalışıyor ve bir şekilde oldukça yavaş çalışıyor (ama mükemmel derecede iyi).

Başka bir not: Bu uzantı hantal ve çeşitli büyük görüntülerde sessizce ölüyor. Ayrıca, çok sayıda raster görüntü ile, inkscape'in bellek kullanımını korkunç seviyelere çıkarabilir (sadece bir avuç görüntü çıkarıldıktan sonra 3GB gibi).

Her birinde en az 1 MB boyutunda, her birinde yaklaşık 70 tarama görüntüsü bulunan yaklaşık 20 svg dosyam olduğu için farklı bir çözüme ihtiyacım vardı. Denilson Sá ipucunu kullanarak kısa bir kontrol yaptıktan sonra svg dosyalarından görüntüleri ayıklayan aşağıdaki php betiğini tasarladım:

#!/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);

Bu şekilde istediğim tüm görüntüleri alabilirim ve md5 beni tekrarlanan görüntülerden kurtarır.

Bahse girerim, çok daha basit başka bir yol olmalı, ancak daha iyi yapmak için inkscape geliştiricilere kalmış.


Not: Betiğiniz data:satır başına yalnızca tek bir URL'yi destekler ve href özelliği içindeki satırları desteklemez (inkscape bunları veri URL'leri için ekler ve base64 spesifikasyonu satırların 76 karakterden uzun olmaması gerektiğini belirtir ). Hızlı bir kesmek için güzel bir senaryo, ancak her türlü SVG ile çalışmaz.
Denilson Sá Maia

@Johnny_Bit +1, dosyaların çoğaltılmasını önlemek için md5 toplamının kullanımı içindir. Senaryonuzu aşağıdan yüklüyorum .
Ivan Z

iyi, Mart 2019 ve oldukça büyük bir görüntü ile kolay grand çalıştı. Ve oldukça eski dizüstü bilgisayar / ubuntu / inkscape 0.48.4. Teşekkürler!
Mart'ta

9

Son olarak, yıllar sonra, SVG kodunu ayrıştırmak için uygun bir XML kitaplığı kullanarak bir SVG dosyasındaki tüm görüntüleri doğru bir şekilde ayıklamak için bir komut dosyası yazdım.

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

Bu komut dosyası Python 2.7 için yazılmıştır, ancak Python 3'e dönüştürmek oldukça kolay olmalıdır. Daha da iyisi, bu sürümde sunulan yeni özellikler nedeniyle Python 3.4'e dönüştürüldükten sonra yaklaşık 50 satır silinebilir.


Çalıştığı için teşekkürler. Ancak PDF geçici çözümünden çok daha yavaştır. Paralel işlemeyi düşündünüz mü? Şu anda, komut dosyası yalnızca tek bir CPU çekirdeği / iş parçacığı kullanıyor.
DanMan

@DanMan Ne yazık ki, paralel hale getirmek hiçbir şeyi hızlandırmak için sihirli bir çözüm değil. Darboğazı tanımlamak için kodu profillemem gerekir. Darboğaz XML ayrıştırma ise, üzgünüm, bu bölüm paralel olarak yapılamaz. Çok yavaş olan SVG dosyalarını bana e-posta ile gönderebilir misiniz? Biraz zamanım olduğunda, performansı araştırabilirim.
Denilson Sá Maia

Evet, kendim yapmayı denedim ve XML ayrıştırma görüntülerin kodunu çözmemek için yavaş kısım olduğu ortaya çıktı. Bununla birlikte, cElementTreedaha hızlı olması gerekiyordu. Ama belki Sax gibi bir şey daha iyi çalışır.
DanMan

@DanMan cElementTreemuhtemelen daha hızlıdır. Ancak, Python 3.3'te her ikisi de aynıdır . Bir noktada bu komut dosyasını Python 3'e güncelleyeceğim.
Denilson Sá Maia

5

Başka bir geçici çözüm olarak PDF olarak kaydedebilir, ardından bu belgeyi Inkscape ile açabilirsiniz.

"Gömme resimleri" nin işaretini kaldırın ve tombala, tüm pngs / jpegs ana dizininize gönderilecektir.

Dağınık, ancak verilerle ilgili olmaktan daha hızlı: URL.


Bu "resimleri yerleştir" seçeneğini nerede buldunuz?
mik01aj

1
PDF belgesini inkscape içinde açtığınızda, bir sonraki iletişim kutusundadır.
Nicholas Wilson

Inkscape'e aktararak bir görüntüyü çıkarmaya çalıştığım bir PDF'im vardı. Bu durumda, bunu içe aktarmadan sonra içe aktarma üzerinde yapabilmek daha da kullanışlı olur.
user149408

Emin değilim ama bu şekilde gömülü ICC profilleri bu süreçte kayboluyor gibi görünüyor. Bu Python betiği ile doğrudan SVG'den çıkardığım görüntülerde ICC profilleri gömülü.
DanMan

1

@Johnny_Bit php-script geliştirmek . Betiğin yeni sürümü svg'yi yeni satırlarla kullanabilir. Svg dosyasından birden fazla görüntüyü ayıklar ve harici png dosyalarına kaydeder. Svg ve png dosyaları 'svg' dizinindedir, ancak sabit 'SVG_DIR' biçiminde değiştirebilirsiniz.

<?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

Dosyanızı Inkscape'te açın ve dışa aktarmak istediğiniz bitmap'i seçin. Dosya-> Bitmap'i Dışa Aktar'ı (Ctrl + Shift + E) tıklatın; yalnızca seçilen bitmap'i dışa aktarmalıdır.


Bu çözümü sevmiyorum çünkü görüntüyü yeniden kodlayacak. Görüntüyü orijinal biçiminde ayıklayan bir çözümü tercih ederim.
Denilson Sá Maia

1
Evet, Inkscape'in görüntüyü yeniden kodladığı anlaşılıyor, ancak varsayılan olarak PNG görüntülerini kaydediyor. Bu yüzden yeniden kodlamanın en azından kayıpsız olduğunu varsayıyorum.
Chris

1
Pek değil. Gömülü görüntüde dönüşümler (ölçeklendirme, döndürme…) olabilir, kırpılmış olabilir, hatta farkında olmadığım başka bir şey de olabilir. Inkscape, tüm bu dönüşümleri uyguladıktan sonra seçilen nesneyi kesinlikle dışa aktaracaktır, bu da bu çözümün tamamen kayıpsız olmadığı anlamına gelir.
Denilson Sá Maia
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.