Làm cách nào để trích xuất một hình ảnh nhúng từ tệp SVG?


26

Tôi có một tệp SVG chứa ít nhất một hình ảnh JPG / PNG được nhúng bên trong. Tôi muốn trích xuất hình ảnh JPG / PNG từ tệp SVG đó và lưu chúng vào đĩa.

Tôi đang thêm inkscapethẻ vì đây là chương trình tôi sử dụng để chỉnh sửa các tệp SVG, nhưng tôi cũng chấp nhận các giải pháp sử dụng các công cụ khác.


1
Nếu không có gì khác, Python có thể làm điều đó với một số keo tùy chỉnh bằng cách sử dụng lxml và PIL (hoặc tương đương).
Keith

@Keith, thực sự, tôi vừa viết một kịch bản Python để giải quyết câu hỏi này. Nó sử dụng xml.etreethư viện tích hợp.
Denilson Sá Maia

Câu trả lời:


30

Giải pháp của riêng tôi (hoặc ... cách giải quyết):

  1. Chọn hình ảnh trong Inkscape
  2. Mở tích hợp XML Editor( Shift+ Ctrl+ X)
  3. Chọn xlink:hrefthuộc tính, sẽ chứa hình ảnh dưới dạng dữ liệu: URI
  4. Sao chép toàn bộ data:URI
  5. Dán data:URI đó vào trình duyệt và lưu nó từ đó.

Ngoài ra, tôi có thể mở tệp SVG trong bất kỳ trình soạn thảo văn bản nào, định vị data:URI và sao chép nó từ đó.

Mặc dù giải pháp này có hiệu quả, nhưng nó hơi cồng kềnh và tôi muốn học một thứ tốt hơn.


2
+1 - Tôi đã xuất hình ảnh 3,5 MB bằng phương pháp này mất một lúc nhưng vẫn hoạt động. Bằng cách nào đó, chức năng "Trích xuất hình ảnh" không hoạt động đối với tôi.
Martin

Vui lòng xem thêm tập lệnh Python dòng lệnh cho mục đích này.
Denilson Sá Maia

17

Thay vào đó là một giải pháp tốt hơn:

đi đến Extensions -> Images -> Extract Image...đó, bạn có thể lưu hình ảnh raster đã chọn dưới dạng tệp. Tuy nhiên phần mở rộng này hoạt động kỳ lạ và bằng cách nào đó hoạt động khá chậm (nhưng hoàn toàn tốt).

Một lưu ý khác: phần mở rộng này rất cồng kềnh và chết lặng trên các hình ảnh lớn khác nhau. Ngoài ra, với số lượng lớn hình ảnh raster, nó có thể tăng mức sử dụng bộ nhớ của inkscape lên mức khủng khiếp (như 3GB chỉ sau một số ít hình ảnh được trích xuất).

Bởi vì tôi đã có khoảng 20 tệp svg với khoảng 70 ảnh raster trong mỗi tệp, mỗi ảnh có kích thước tối thiểu 1MB, tôi cần một giải pháp khác nhau. Sau khi kiểm tra ngắn bằng cách sử dụng mẹo Denilson Sá, tôi đã nghĩ ra tập lệnh php sau, trích xuất hình ảnh từ các tập tin 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);

Bằng cách này tôi có thể có được tất cả các hình ảnh tôi muốn và md5 giúp tôi không bị lặp lại các hình ảnh.

Tôi cá là phải có một cách khác đơn giản hơn rất nhiều, nhưng phải đến các nhà phát triển inkscape để làm điều đó tốt hơn.


Lưu ý: Tập lệnh của bạn chỉ hỗ trợ một data:URL trên mỗi dòng và không hỗ trợ các dòng mới bên trong thuộc tính href (inkscape thêm chúng cho các URL dữ liệu và thông số cơ sở64 thậm chí bắt buộc các dòng không được dài hơn 76 ký tự ). Kịch bản hay cho một bản hack nhanh, nhưng nó không hoạt động với tất cả các loại SVG.
Denilson Sá Maia

@Johnny_Bit +1 cho việc sử dụng tổng md5 để ngăn ngừa trùng lặp tệp. Tôi viết kịch bản của bạn dưới đây .
Ivan Z

tốt, tháng ba năm 2019 và làm việc dễ dàng lớn với một hình ảnh hợp lý lớn. Và máy tính xách tay khá cũ / ubfox / inkscape 0.48.4. Cảm ơn!
gaoithe ngày

9

Cuối cùng, nhiều năm sau, tôi đã viết một tập lệnh để trích xuất chính xác tất cả các hình ảnh từ tệp SVG, sử dụng thư viện XML thích hợp để phân tích mã SVG.

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

Tập lệnh này được viết cho Python 2.7 nhưng khá dễ dàng để chuyển đổi sang Python 3. Thậm chí tốt hơn, khoảng 50 dòng có thể bị xóa sau khi chuyển đổi sang Python 3.4, do các tính năng mới được giới thiệu trong phiên bản đó.


Cảm ơn, vì nó hoạt động. Nhưng nó chậm hơn nhiều so với cách giải quyết PDF. Bạn đã nghĩ về xử lý song song? Ngay bây giờ, tập lệnh chỉ sử dụng một lõi / luồng CPU duy nhất.
DanMan

@DanMan Thật không may, làm cho nó song song không phải là một giải pháp kỳ diệu để tăng tốc bất cứ điều gì. Tôi cần phải lập hồ sơ mã để xác định nút cổ chai. Nếu nút cổ chai là phân tích cú pháp XML, tôi xin lỗi, phần đó không thể được thực hiện song song. Bạn có thể vui lòng gửi cho tôi qua e-mail các tệp SVG chính xác quá chậm không? Bất cứ khi nào tôi có thời gian, tôi có thể điều tra hiệu suất.
Denilson Sá Maia

Vâng, tôi đã thử tự làm và hóa ra phân tích cú pháp XML là phần chậm, không giải mã được hình ảnh. Điều đó nói rằng, cElementTreeđược cho là nhanh hơn. Nhưng có lẽ một cái gì đó như Sax hoạt động tốt hơn, quá.
DanMan

@DanMan cElementTreecó khả năng nhanh hơn. Tuy nhiên, trên Python 3.3, cả hai đều giống nhau . Tại một số điểm tôi có thể sẽ cập nhật tập lệnh đó lên Python 3.
Denilson Sá Maia

5

Như một cách giải quyết khác, bạn có thể lưu dưới dạng PDF, sau đó mở tài liệu đó bằng Inkscape.

Bỏ chọn "hình ảnh nhúng" và lô tô, tất cả các png / jpeg sẽ được đưa vào thư mục chính của bạn.

Lộn xộn, nhưng nhanh hơn so với việc sử dụng dữ liệu: URL.


Bạn đã tìm thấy tùy chọn "nhúng hình ảnh" ở đâu?
mik01aj

1
Khi bạn mở tài liệu PDF trong inkscape, nó sẽ ở hộp thoại tiếp theo.
Nicholas Wilson

Tôi đã có một bản PDF mà tôi đã cố trích xuất một hình ảnh bằng cách nhập nó trong Inkscape. Trong trường hợp đó, việc có thể thực hiện việc này khi nhập thay vì sau khi nhập trở nên tiện dụng hơn.
user149408

Tôi không chắc nhưng theo cách này, mọi cấu hình ICC nhúng dường như bị mất trong quá trình này. Các hình ảnh tôi trích xuất trực tiếp từ SVG thông qua tập lệnh Python có các cấu hình ICC được nhúng.
DanMan

1

Tôi cải thiện tập lệnh php của @Johnny_Bit . Bản phát hành mới của tập lệnh có thể sử dụng svg với các dòng mới. Nó trích xuất nhiều hình ảnh tập tin svg và lưu chúng trong tập tin png bên ngoài. Các tệp Svg và png nằm trong thư mục 'svg', nhưng bạn có thể thay đổi nó trong hằng số '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

Mở tệp của bạn trong Inkscape và chọn bitmap mà bạn muốn xuất. Bấm vào Tệp-> Xuất Bitmap (Ctrl + Shift + E) và nó sẽ chỉ xuất ra bitmap đã chọn.


Tôi không thích giải pháp này vì nó sẽ mã hóa lại hình ảnh. Tôi muốn một giải pháp trích xuất hình ảnh ở định dạng ban đầu của nó.
Denilson Sá Maia

1
Vâng, có vẻ như Inkscape mã hóa lại hình ảnh nhưng nó lưu hình ảnh PNG theo mặc định. Vì vậy, tôi giả định rằng việc mã hóa lại ít nhất là không mất mát.
Chris

1
Vâng, không thực sự. Hình ảnh nhúng có thể đã có các biến đổi (chia tỷ lệ, xoay vòng), có thể đã bị cắt bớt, hoặc thậm chí một cái gì đó khác mà tôi không biết. Inkscape chắc chắn sẽ xuất đối tượng được chọn sau khi áp dụng tất cả các biến đổi này, điều đó có nghĩa là giải pháp này không thực sự mất mát.
Denilson Sá Maia
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.