แปลงภาพ SVG เป็น PNG ด้วย PHP


111

ฉันกำลังทำโปรเจ็กต์เว็บที่เกี่ยวข้องกับแผนที่ที่สร้างขึ้นแบบไดนามิกของสหรัฐอเมริกาโดยระบายสีสถานะต่างๆตามชุดข้อมูล

ไฟล์ SVG นี้ให้แผนที่ว่างเปล่าของสหรัฐอเมริกาและเปลี่ยนสีของแต่ละรัฐได้ง่ายมาก ปัญหาคือเบราว์เซอร์ IE ไม่รองรับ SVG ดังนั้นเพื่อให้ฉันใช้ไวยากรณ์ที่มีประโยชน์ที่ svg เสนอฉันจะต้องแปลงเป็น JPG

ตามหลักการแล้วฉันต้องการทำสิ่งนี้กับไลบรารี GD2 เท่านั้น แต่สามารถใช้ ImageMagick ได้ด้วย ฉันไม่รู้ว่าต้องทำอย่างไร

วิธีการแก้ปัญหาใด ๆ ที่ทำให้ฉันสามารถเปลี่ยนสีของรัฐบนแผนที่ของสหรัฐอเมริกาได้แบบไดนามิกจะได้รับการพิจารณา ที่สำคัญคือมันง่ายที่จะเปลี่ยนสีได้ทันทีและเป็นเบราว์เซอร์ข้าม โปรดใช้โซลูชัน PHP / Apache เท่านั้น


มีคลาสใดบ้างที่ออกแบบมาเพื่อพอร์ต SVG ไปยัง VML? ด้วยวิธีนี้คุณยังสามารถใช้โซลูชันประเภท 'HTML5' ได้
Patrick

ลองดูคำตอบของฉัน สิ่งที่คุณต้องการ

คำตอบ:


142

เป็นเรื่องตลกที่คุณถามสิ่งนี้ฉันเพิ่งทำสิ่งนี้เมื่อเร็ว ๆ นี้สำหรับไซต์งานของฉันและฉันคิดว่าฉันควรจะเขียนบทช่วยสอน ... นี่คือวิธีดำเนินการกับ PHP / Imagick ซึ่งใช้ 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();

ขั้นตอนการเปลี่ยนสี regex อาจแตกต่างกันไปขึ้นอยู่กับเส้นทาง svg xml และวิธีการจัดเก็บค่า id และสีของคุณ หากคุณไม่ต้องการจัดเก็บไฟล์บนเซิร์ฟเวอร์คุณสามารถส่งออกรูปภาพเป็นฐาน 64 เช่น

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

(ก่อนที่คุณจะใช้ clear / destroy) แต่เช่นมีปัญหากับ PNG เป็น base64 ดังนั้นคุณอาจต้องส่งออก base64 เป็น jpeg

คุณสามารถดูตัวอย่างได้ที่นี่สำหรับแผนที่พื้นที่ขายของนายจ้างในอดีต:

เริ่มต้น: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

เสร็จสิ้น: ใส่คำอธิบายภาพที่นี่

แก้ไข

ตั้งแต่เขียนข้อความข้างต้นฉันได้พบกับ 2 เทคนิคที่ปรับปรุงแล้ว:

1) แทนที่จะใช้ regex loop เพื่อเปลี่ยนสถานะการเติมให้ใช้ CSS เพื่อสร้างกฎสไตล์เช่น

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

จากนั้นคุณสามารถแทนที่ข้อความเดียวเพื่อแทรกกฎ css ของคุณลงใน svg ก่อนที่จะดำเนินการสร้าง Imagick jpeg / png หากสีไม่เปลี่ยนให้ตรวจสอบให้แน่ใจว่าคุณไม่มีรูปแบบการเติมแบบอินไลน์ในแท็กพา ธ ของคุณที่ทับ css

2) หากคุณไม่จำเป็นต้องสร้างไฟล์รูปภาพ jpeg / png (และไม่จำเป็นต้องรองรับเบราว์เซอร์ที่ล้าสมัย) คุณสามารถจัดการ svg ได้โดยตรงด้วย jQuery คุณไม่สามารถเข้าถึงพา ธ svg เมื่อฝัง svg โดยใช้ img หรือแท็กอ็อบเจ็กต์ดังนั้นคุณจะต้องรวม svg xml ไว้ใน html ของหน้าเว็บโดยตรงเช่น:

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

จากนั้นการเปลี่ยนสีทำได้ง่ายเหมือน:

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

1
ขอบคุณสำหรับบทแนะนำที่แน่นอนและมีประโยชน์เกี่ยวกับวิธีการทำ ฉันจะใช้โซลูชันของคุณเป็นข้อมูลสำรองอย่างแน่นอน แต่ฉันกระตือรือร้นที่จะลองและเพียงแค่รับความเข้ากันได้ของ svg ในเบราว์เซอร์หลักทั้งหมด
Michael Berkompas

1
SVG ไม่ได้รับการสนับสนุนใน IE8 หรือต่ำกว่าโดยไม่ต้องให้ผู้ใช้ติดตั้งปลั๊กอิน svg viewer - จากหน้า SVG Wikipedia: "เว็บเบราว์เซอร์สมัยใหม่ที่สำคัญทั้งหมดรองรับและแสดงผลมาร์กอัป SVG โดยตรงโดยมีข้อยกเว้นที่โดดเด่นมากของ Microsoft Internet Explorer (IE) [ 3] Internet Explorer 9 เบต้ารองรับชุดคุณลักษณะพื้นฐานของ SVG [4] ปัจจุบันการรองรับเบราว์เซอร์ที่ทำงานภายใต้ Android ยังมีข้อ จำกัด ด้วย "
WebChemist

1
ใช่ แต่ดูเหมือนว่า svgweb จะรีดความเข้ากันไม่ได้ทั้งหมดโดยใช้ js และ flash เล็กน้อย นั่นเป็นวิธีแก้ปัญหาที่ฉันใช้
Michael Berkompas

2
ฉันชอบโซลูชันที่สะอาดและรวดเร็วของคุณ โดยส่วนตัวเมื่อโต้ตอบกับไฟล์ xml ฉันชอบใช้ dom parser เพื่อให้รู้สึกปลอดภัยกว่า regex Sth like:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper

ตัวแยกวิเคราะห์ xml จะปลอดภัยกว่าแม้ว่าจะช้ากว่าเล็กน้อยวิธีแก้ปัญหากับ svg อื่น ๆ ... ในกรณีนี้ regex ปลอดภัยเพราะฉันตรวจสอบให้แน่ใจว่าแอตทริบิวต์ของแต่ละรัฐได้รับการจัดรูปแบบตรงตาม (id = "XX" style = "fill: # XXXXXX ")
WebChemist

11

คุณระบุว่าคุณกำลังทำสิ่งนี้เนื่องจาก IE ไม่รองรับ SVG

ข่าวดีก็คือว่า IE ไม่สนับสนุนกราฟิกแบบเวกเตอร์ โอเคมันอยู่ในรูปแบบของภาษาที่เรียกว่า VML ซึ่งมีเพียง IE เท่านั้นที่รองรับแทนที่จะเป็น SVG แต่อยู่ที่นั่นและคุณสามารถใช้งานได้

Google Maps จะตรวจจับความสามารถของเบราว์เซอร์เพื่อพิจารณาว่าจะให้บริการ SVG หรือ VML

จากนั้นก็มีไลบรารี Raphaelซึ่งเป็นไลบรารีกราฟิกบนเบราว์เซอร์ Javascript ซึ่งรองรับ SVG หรือ VML อีกครั้งขึ้นอยู่กับเบราว์เซอร์

อีกคนหนึ่งที่อาจช่วยให้: SVGWeb

ซึ่งทั้งหมดนี้หมายความว่าคุณสามารถรองรับผู้ใช้ IE ของคุณได้โดยไม่ต้องใช้กราฟิกบิตแมป

ดูคำตอบยอดนิยมสำหรับคำถามนี้เช่นXSL แปลง SVG เป็น VML


+1 สำหรับการกล่าวถึงราฟาเอลซึ่งเป็นทางออกที่ดีและคุ้มค่าที่จะตรวจสอบการใช้งานกราฟิกเวกเตอร์ข้ามเบราว์เซอร์ที่ยอดเยี่ยม
dmp

10

เมื่อแปลง SVG เป็น PNG โปร่งใสอย่าลืมใส่สิ่งนี้ก่อน$imagick->readImageBlob():

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

เป็นไปได้อย่างไรที่จะเรียกวิธีนั้นก่อนอ่านภาพฉันได้รับข้อผิดพลาด "ไม่สามารถประมวลผลวัตถุ Imagick ที่ว่างเปล่า" และใช่ส่วนขยาย Imagick ของฉันได้รับการติดตั้งในขณะที่ทำงานและแปลงรูปภาพ
Denis2310

6

นี่คือ v. ง่ายได้รับการดำเนินการนี้ในช่วงสองสามสัปดาห์ที่ผ่านมา

คุณจำเป็นต้องมีผ้าบาติก SVG Toolkit ดาวน์โหลดและวางไฟล์ไว้ในไดเร็กทอรีเดียวกับ SVG ที่คุณต้องการแปลงเป็น JPEGและอย่าลืมเปิดเครื่องรูดก่อน

เปิดเทอร์มินัลและเรียกใช้คำสั่งนี้:

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

ซึ่งควรส่งออกเป็น JPEG ของไฟล์ SVG ง่ายมาก คุณสามารถวางไว้ในลูปและแปลงไฟล์ 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')

นี่มันเยี่ยมมาก ขอบคุณสำหรับทิป. ฉันจะใช้มันร่วมกับ perl ในการประมวลผลชุดไฟล์ SVG ที่ฉันสร้างจากเทมเพลต
simbabque

2

ฉันไม่รู้จักโซลูชัน PHP / Apache แบบสแตนด์อโลนเนื่องจากต้องใช้ไลบรารี PHP ที่สามารถอ่านและแสดงภาพ SVG ได้ ฉันไม่แน่ใจว่ามีห้องสมุดอยู่ - ฉันไม่รู้เลย

ImageMagickสามารถแรสเตอร์ไฟล์ SVG ได้ไม่ว่าจะผ่านทางบรรทัดคำสั่งหรือการรวม PHP, IMagickแต่ดูเหมือนว่าจะมีนิสัยแปลกๆ และการอ้างอิงภายนอกตามที่แสดงเช่นในฟอรัมนี้ ฉันคิดว่ามันยังคงเป็นหนทางที่ดีที่สุดที่จะไปมันเป็นสิ่งแรกที่ฉันจะพิจารณาว่าฉันเป็นคุณ


2

นี่เป็นวิธีการแปลงรูปภาพ svg เป็น gif โดยใช้เครื่องมือ php GD มาตรฐาน

1) คุณใส่รูปภาพลงในองค์ประกอบผ้าใบในเบราว์เซอร์:

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

จากนั้นแปลงที่เซิร์ฟเวอร์ (ProcessPicture.php) จาก (ค่าเริ่มต้น) png เป็น gif และบันทึก (คุณสามารถบันทึกเป็น png ได้เช่นกันจากนั้นใช้ imagepng แทนรูปภาพ 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);

หรือใช้: potrace demo: Tool4dev.com

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.