Chuyển đổi hình ảnh SVG sang PNG bằng PHP


111

Tôi đang thực hiện một dự án web liên quan đến một bản đồ được tạo động của Hoa Kỳ tô màu các tiểu bang khác nhau dựa trên một tập hợp dữ liệu.

Tệp SVG này cung cấp cho tôi một bản đồ trống tốt của Hoa Kỳ và rất dễ thay đổi màu sắc của từng tiểu bang. Khó khăn là các trình duyệt IE không hỗ trợ SVG, vì vậy để tôi sử dụng cú pháp tiện dụng mà svg cung cấp, tôi sẽ cần chuyển nó sang JPG.

Lý tưởng nhất là tôi chỉ muốn làm điều này với thư viện GD2 nhưng cũng có thể sử dụng ImageMagick. Tôi hoàn toàn không biết làm thế nào để làm điều này.

Bất kỳ giải pháp nào cho phép tôi tự động thay đổi màu sắc của các tiểu bang trên bản đồ của Hoa Kỳ sẽ được xem xét. Điều quan trọng là có thể dễ dàng thay đổi màu sắc một cách nhanh chóng và nó là trình duyệt chéo. Vui lòng chỉ giải pháp PHP / Apache.


có lớp nào được thiết kế để chuyển SVG sang VML không? bằng cách đó, bạn vẫn có thể có giải pháp kiểu 'HTML5'
Patrick

hãy xem câu trả lời của tôi. chính xác những gì bạn cần

Câu trả lời:


142

Thật là buồn cười khi bạn hỏi điều này, tôi vừa mới làm điều này gần đây cho trang web công việc của mình và tôi đang nghĩ mình nên viết một hướng dẫn ... Đây là cách thực hiện với PHP / Imagick, sử dụng ImageMagick:

$usmap = '/path/to/blank/us-map.svg';
$im = new Imagick();
$svg = file_get_contents($usmap);

/*loop to color each state as needed, something like*/ 
$idColorArray = array(
     "AL" => "339966"
    ,"AK" => "0099FF"
    ...
    ,"WI" => "FF4B00"
    ,"WY" => "A3609B"
);

foreach($idColorArray as $state => $color){
//Where $color is a RRGGBB hex value
    $svg = preg_replace(
         '/id="'.$state.'" style="fill:#([0-9a-f]{6})/'
        , 'id="'.$state.'" style="fill:#'.$color
        , $svg
    );
}

$im->readImageBlob($svg);

/*png settings*/
$im->setImageFormat("png24");
$im->resizeImage(720, 445, imagick::FILTER_LANCZOS, 1);  /*Optional, if you need to resize*/

/*jpeg*/
$im->setImageFormat("jpeg");
$im->adaptiveResizeImage(720, 445); /*Optional, if you need to resize*/

$im->writeImage('/path/to/colored/us-map.png');/*(or .jpg)*/
$im->clear();
$im->destroy();

các bước thay thế màu regex có thể khác nhau tùy thuộc vào đường dẫn svg xml và cách bạn lưu trữ các giá trị id và màu sắc. Nếu bạn không muốn lưu trữ tệp trên máy chủ, bạn có thể xuất hình ảnh dưới dạng cơ sở 64 như

<?php echo '<img src="data:image/jpg;base64,' . base64_encode($im) . '"  />';?>

(trước khi bạn sử dụng xóa / hủy) nhưng có vấn đề với PNG dưới dạng base64, vì vậy bạn có thể phải xuất base64 dưới dạng jpeg

bạn có thể xem một ví dụ ở đây mà tôi đã làm cho bản đồ lãnh thổ bán hàng của một nhà tuyển dụng cũ:

Bắt đầu: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

Hoàn thành: nhập mô tả hình ảnh ở đây

Biên tập

Kể từ khi viết phần trên, tôi đã nghĩ ra 2 kỹ thuật cải tiến:

1) thay vì vòng lặp regex để thay đổi trạng thái điền vào, hãy sử dụng CSS để tạo các quy tắc kiểu như

<style type="text/css">
#CA,#FL,HI{
    fill:blue;
}
#Al, #NY, #NM{
    fill:#cc6699;
}
/*etc..*/
</style>

và sau đó, bạn có thể thực hiện một thay thế văn bản duy nhất để đưa các quy tắc css của bạn vào svg trước khi tiếp tục tạo ảnh jpeg / png. Nếu màu không thay đổi, hãy kiểm tra để đảm bảo rằng bạn không có bất kỳ kiểu tô nội dòng nào trong thẻ đường dẫn của bạn ghi đè css.

2) Nếu bạn không thực sự phải tạo tệp hình ảnh jpeg / png (và không cần hỗ trợ các trình duyệt lỗi thời), bạn có thể thao tác trực tiếp với svg với jQuery. Bạn không thể truy cập các đường dẫn svg khi nhúng svg bằng thẻ img hoặc thẻ đối tượng, vì vậy bạn sẽ phải bao gồm trực tiếp xml svg trong html trang web của mình như:

<div>
<?php echo file_get_contents('/path/to/blank/us-map.svg');?>
</div>

sau đó thay đổi màu sắc dễ dàng như:

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
    $('#CA').css('fill', 'blue');
    $('#NY').css('fill', '#ff0000');
</script>

1
Cảm ơn vì hướng dẫn rất chính xác và hữu ích về cách thực hiện việc này. Tôi chắc chắn sẽ sử dụng giải pháp của bạn như một bản sao lưu nhưng tôi rất muốn thử và chỉ cần có được khả năng tương thích svg trên tất cả các trình duyệt chính.
Michael Berkompas

1
SVG không được hỗ trợ trong ie8 hoặc thấp hơn mà không yêu cầu người dùng cài đặt plugin trình xem svg - từ trang Wikipedia của SVG: "Tất cả các trình duyệt web hiện đại chính, hỗ trợ và hiển thị đánh dấu SVG trực tiếp, ngoại trừ Microsoft Internet Explorer (IE) [ 3] Internet Explorer 9 beta hỗ trợ bộ tính năng SVG cơ bản. [4] Hiện tại, hỗ trợ cho các trình duyệt chạy dưới Android cũng bị hạn chế. "
WebChemist

1
Có, nhưng svgweb dường như loại bỏ tất cả các điểm không tương thích bằng cách sử dụng một chút js và flash. Đó là giải pháp tôi đã đi với.
Michael Berkompas

2
Tôi thích giải pháp sạch sẽ và nhanh chóng của bạn. Cá nhân khi tương tác với các tệp xml, tôi thích sử dụng trình phân tích cú pháp dom để cảm thấy an toàn hơn so với regex. Sth như:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper

trình phân tích cú pháp xml sẽ là giải pháp an toàn hơn, mặc dù hơi chậm hơn, với bất kỳ svg nào khác ... trong trường hợp này, regex an toàn vì tôi đã đảm bảo các thuộc tính của mỗi trạng thái được định dạng chính xác là (id = "XX" style = "fill: # XXXXXX ").
WebChemist 16/10/12

11

Bạn đề cập rằng bạn đang làm điều này vì IE không hỗ trợ SVG.

Các tin tốt là IE không đồ họa hỗ trợ vector. Được rồi, nó ở dạng một ngôn ngữ gọi là VML mà chỉ IE hỗ trợ, chứ không phải SVG, nhưng nó ở đó và bạn có thể sử dụng nó.

Google Maps, trong số những người khác, sẽ phát hiện các khả năng của trình duyệt để xác định xem có phân phát SVG hay VML hay không.

Sau đó, có thư viện Raphael , là một thư viện đồ họa dựa trên trình duyệt Javascript, hỗ trợ SVG hoặc VML, một lần nữa tùy thuộc vào trình duyệt.

Một cái khác có thể hữu ích: SVGWeb .

Tất cả điều đó có nghĩa là bạn có thể hỗ trợ người dùng IE của mình mà không cần dùng đến đồ họa bitmap.

Xem thêm câu trả lời hàng đầu cho câu hỏi này, ví dụ: XSL Chuyển đổi SVG thành VML


+1 khi đề cập đến raphael, đây chắc chắn là một giải pháp tốt và đáng để điều tra vì khả năng triển khai đồ họa vector trình duyệt chéo tuyệt vời.
dmp

10

Khi chuyển đổi SVG sang PNG trong suốt, đừng quên đặt điều này TRƯỚC $imagick->readImageBlob():

$imagick->setBackgroundColor(new ImagickPixel('transparent'));

Làm thế nào mà có thể gọi phương thức đó trước khi đọc hình ảnh, tôi đang nhận được lỗi "Không thể xử lý đối tượng Imagick trống". Và có, tiện ích mở rộng hình ảnh của tôi đã được cài đặt vì nó đang hoạt động và chuyển đổi hình ảnh.
Denis2310

6

Điều này thật dễ dàng, tôi đã thực hiện công việc này trong vài tuần qua.

Bạn cần Bộ công cụ Batik SVG . Tải xuống và đặt các tệp trong cùng thư mục với SVG mà bạn muốn chuyển đổi thành JPEG , đồng thời đảm bảo rằng bạn đã giải nén nó trước.

Mở thiết bị đầu cuối và chạy lệnh này:

java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 NAME_OF_SVG_FILE.svg

Điều đó sẽ xuất ra một JPEG của tệp SVG. Thật sự dễ dàng. Bạn thậm chí có thể chỉ cần đặt nó trong một vòng lặp và chuyển đổi vô số SVG,

import os

svgs = ('test1.svg', 'test2.svg', 'etc.svg') 
for svg in svgs:
    os.system('java -jar batik-rasterizer.jar -m image/jpeg -q 0.8 '+str(svg)+'.svg')

Điều đó thật tuyệt. Cảm ơn vì tiền hỗ trợ. Tôi sẽ sử dụng nó kết hợp với perl để xử lý hàng loạt các tệp SVG mà tôi đã tạo từ một mẫu.
simbabque

2

Tôi không biết về một giải pháp PHP / Apache độc ​​lập, vì điều này sẽ yêu cầu một thư viện PHP có thể đọc và hiển thị hình ảnh SVG. Tôi không chắc một thư viện như vậy tồn tại - tôi không biết cái nào.

ImageMagick có thể mã hóa các tệp SVG, thông qua dòng lệnh hoặc liên kết PHP, IMagick , nhưng dường như có một số điều kỳ quặc và phụ thuộc bên ngoài như được hiển thị ví dụ như trong chuỗi diễn đàn này . Tôi nghĩ rằng đó vẫn là con đường hứa hẹn nhất để đi, đó là điều đầu tiên tôi sẽ xem xét nếu tôi là bạn.


2

Đây là một phương pháp để chuyển đổi ảnh svg sang ảnh gif bằng các công cụ GD php tiêu chuẩn

1) Bạn đặt hình ảnh vào phần tử canvas trong trình duyệt:

<canvas id=myCanvas></canvas>

<script>
var Key='picturename'
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
base_image = new Image();
base_image.src = myimage.svg;
base_image.onload = function(){

    //get the image info as base64 text string

    var dataURL = canvas.toDataURL();
    //Post the image (dataURL) to the server using jQuery post method
    $.post('ProcessPicture.php',{'TheKey':Key,'image': dataURL ,'h': canvas.height,'w':canvas.width,"stemme":stemme } ,function(data,status){ alert(data+' '+status) });
}
</script>    

Và sau đó chuyển đổi nó tại máy chủ (ProcessPicture.php) từ (mặc định) png sang gif và lưu nó. (bạn cũng có thể lưu dưới dạng png sau đó sử dụng imagepng thay vì ảnh gif):

//receive the posted data in php
$pic=$_POST['image'];
$Key=$_POST['TheKey'];
$height=$_POST['h'];
$width=$_POST['w'];
$dir='../gif/'
$gifName=$dir.$Key.'.gif';
 $pngName=$dir.$Key.'.png';

//split the generated base64 string before the comma. to remove the 'data:image/png;base64, header  created by and get the image data
$data = explode(',', $pic);
$base64img = base64_decode($data[1]);
$dimg=imagecreatefromstring($base64img); 

//in order to avoid copying a black figure into a (default) black background you must create a white background

$im_out = ImageCreateTrueColor($width,$height);
$bgfill = imagecolorallocate( $im_out, 255, 255, 255 );
imagefill( $im_out, 0,0, $bgfill );

//Copy the uploaded picture in on the white background
ImageCopyResampled($im_out, $dimg ,0, 0, 0, 0, $width, $height,$width, $height);

//Make the gif and png file 
imagegif($im_out, $gifName);
imagepng($im_out, $pngName);


-1
$command = 'convert -density 300 ';
                        if(Input::Post('height')!='' && Input::Post('width')!=''){
                            $command.='-resize '.Input::Post('width').'x'.Input::Post('height').' ';
                        }
                        $command.=$svg.' '.$source;
                        exec($command);
                        @unlink($svg);

hoặc sử dụng: bản demo potrace : Tool4dev.com

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.