SVG görüntüsünü PHP ile PNG'ye dönüştürün


111

ABD'nin dinamik olarak oluşturulmuş bir haritasını bir dizi veriye dayalı olarak farklı durumları renklendiren bir web projesi üzerinde çalışıyorum.

Bu SVG dosyası bana ABD'nin iyi bir boş haritasını veriyor ve her eyaletin rengini değiştirmek çok kolay. Zorluk, IE tarayıcılarının SVG'yi desteklememesidir, bu yüzden svg'nin sunduğu kullanışlı sözdizimini kullanmam için, onu bir JPG'ye dönüştürmem gerekecek.

İdeal olarak, bunu yalnızca GD2 kitaplığı ile yapmak isterdim, ancak ImageMagick'i de kullanabilirdim. Bunu nasıl yapacağım konusunda kesinlikle hiçbir fikrim yok.

ABD haritasındaki eyaletlerin renklerini dinamik olarak değiştirmeme izin verecek herhangi bir çözüm dikkate alınacaktır. Anahtar, renkleri anında değiştirmenin kolay olması ve çapraz tarayıcı olmasıdır. Yalnızca PHP / Apache çözümleri lütfen.


SVG'yi VML'ye taşımak için tasarlanmış herhangi bir sınıf var mı? bu şekilde hala 'HTML5' türü bir çözüme sahip olabilirsiniz
Patrick

cevabıma bir bak. tam olarak ihtiyacınız olan şey

Yanıtlar:


142

Bunu sordunuz komik, bunu yakın zamanda işimin sitesi için yaptım ve bir eğitim yazmam gerektiğini düşünüyordum ... İşte ImageMagick kullanan PHP / Imagick ile nasıl yapılacağı:

$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 renk değiştirme adımları, svg yolu xml'ye ve id ve renk değerlerinin nasıl saklandığına bağlı olarak değişebilir. Sunucuda bir dosya depolamak istemiyorsanız, görüntüyü 64 temelde çıktısını alabilirsiniz.

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

(temizle / yok et kullanmadan önce) ancak örneğin PNG ile base64 olarak sorunları var, bu nedenle muhtemelen base64'ü jpeg olarak çıktılamanız gerekir.

Burada eski bir işverenin satış bölge haritası için yaptığım bir örneği görebilirsiniz:

Başlangıç: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

Bitiş: görüntü açıklamasını buraya girin

Düzenle

Yukarıdakileri yazdığımdan beri, 2 gelişmiş teknik buldum:

1) doldurma durumunu değiştirmek için bir normal ifade döngüsü yerine, stil kuralları oluşturmak için CSS kullanın.

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

ve sonra, imagick jpeg / png oluşturmaya geçmeden önce css kurallarınızı svg'ye eklemek için tek bir metin değişikliği yapabilirsiniz. Renkler değişmezse, yol etiketlerinizde css'yi geçersiz kılan herhangi bir satır içi dolgu stiliniz olmadığından emin olun.

2) Gerçekten bir jpeg / png resim dosyası oluşturmanız gerekmiyorsa (ve eski tarayıcıları desteklemeniz gerekmiyorsa), svg'yi doğrudan jQuery ile değiştirebilirsiniz. Svg'yi img veya nesne etiketlerini kullanarak katıştırırken svg yollarına erişemezsiniz, bu nedenle svg xml'yi web sayfanızın html'sine doğrudan dahil etmeniz gerekir:

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

sonra renkleri değiştirmek şu kadar kolaydır:

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

1
Bunun nasıl yapılacağına dair çok kesin ve faydalı eğitim için teşekkürler. Çözümünüzü kesinlikle bir yedek olarak kullanacağım, ancak tüm büyük tarayıcılarda svg uyumluluğunu denemeye ve almaya hevesliyim.
Michael Berkompas

1
SVG, kullanıcının bir svg görüntüleyici eklentisi yüklemesini gerektirmeden ie8 veya daha düşük sürümlerde desteklenmez - SVG Wikipedia sayfasından: "Tüm büyük modern web tarayıcıları, SVG işaretlemesini Microsoft Internet Explorer'ın (IE) çok dikkate değer istisnasıyla doğrudan destekler ve işletir [ 3] Internet Explorer 9 beta, temel SVG özellik setini destekler. [4] Şu anda, Android altında çalışan tarayıcılar için destek de sınırlıdır. "
WebChemist

1
Evet, ancak svgweb biraz js ve flash kullanarak tüm uyumsuzlukları gideriyor gibi görünüyor. Benim kullandığım çözüm bu.
Michael Berkompas

2
Temiz ve hızlı çözümünüzü beğendim. Kişisel olarak xml dosyalarıyla etkileşim kurarken, regex'ten daha güvende hissetmek için bir dom ayrıştırıcısı kullanmayı tercih ederim. Sth gibi:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper

bir xml ayrıştırıcısı, diğer svg'ler için biraz daha yavaş olsa da daha güvenli bir çözüm olabilir ... bu durumda normal ifade güvenlidir çünkü her bir durumun özniteliklerinin tam olarak (id = "XX" style = "fill: # XXXXXX ").
WebChemist

11

IE, SVG'yi desteklemediği için bunu yaptığınızı söylüyorsunuz.

İyi haber IE olmasıdır yapar destek vektör grafikleri. Tamam, yani SVG yerine sadece IE'nin desteklediği VML adında bir dil biçiminde, ama orada ve onu kullanabilirsiniz.

Google Haritalar, diğerlerinin yanı sıra, SVG veya VML sunup sunmayacağını belirlemek için tarayıcı özelliklerini tespit edecektir.

Ardından , tarayıcıya bağlı olarak SVG veya VML'yi destekleyen Javascript tarayıcı tabanlı bir grafik kitaplığı olan Raphael kitaplığı var .

Yardımcı olabilecek bir tane daha: SVGWeb .

Tüm bunlar, IE kullanıcılarınızı bitmap grafiklerine başvurmak zorunda kalmadan destekleyebileceğiniz anlamına gelir.

Ayrıca bu sorunun en iyi cevabına bakın, örneğin: XSL SVG'yi VML'ye Dönüştür


Kesinlikle iyi bir çözüm olan ve çapraz tarayıcı vektör grafiklerinin mükemmel uygulaması için araştırmaya değer olan Raphael'den bahsetmek için +1.
dmp

10

SVG'yi şeffaf PNG'ye dönüştürürken bunu ÖNCE koymayı unutmayın $imagick->readImageBlob():

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

Görüntüyü okumadan önce bu yöntemi çağırmak nasıl mümkün oluyor, "Boş Imagick nesnesi işlenemiyor" hatası alıyorum. Ve evet, imagick uzantım, çalışırken ve görüntüleri dönüştürürken yüklendi.
Denis2310

6

Bu çok kolay, son birkaç haftadır bunun üzerinde çalışıyoruz.

Batik SVG Toolkit'e ihtiyacınız var . Dosyaları indirin ve JPEG formatına dönüştürmek istediğiniz SVG ile aynı dizine yerleştirin , ayrıca önce sıkıştırmayı açtığınızdan emin olun.

Terminali açın ve şu komutu çalıştırın:

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

Bu, SVG dosyasının bir JPEG çıktısını almalıdır. Gerçekten kolay. Hatta bir döngüye yerleştirebilir ve çok sayıda SVG'yi dönüştürebilirsiniz,

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

Bu harika. Bahşiş için teşekkürler. Bunu bir şablondan oluşturduğum SVG dosyalarının toplu işlemesi için perl ile birlikte kullanacağım.
simbabque

2

Bağımsız bir PHP / Apache çözümü bilmiyorum çünkü bu, SVG resimlerini okuyabilen ve işleyebilen bir PHP kitaplığı gerektirecektir. Böyle bir kitaplığın var olduğundan emin değilim - hiç bilmiyorum.

ImageMagick , SVG dosyalarını komut satırı veya PHP bağlama, IMagick aracılığıyla rasterleştirebilir , ancak bu forum başlığında gösterildiği gibi bir takım tuhaflıklar ve harici bağımlılıklar var gibi görünüyor . Sanırım hala gidilecek en umut verici yol, senin yerinde olsam ilk bakacağım şey buydu.


2

Bu, standart php GD araçlarını kullanarak bir svg resmini gif'e dönüştürmek için bir yöntemdir.

1) Görüntüyü tarayıcıdaki bir tuval öğesine koyarsınız:

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

Ve sonra bunu sunucuda (ProcessPicture.php) (varsayılan) png'den gif'e dönüştürün ve kaydedin. (png olarak da kaydedebilirdiniz, sonra image gif yerine imagepng kullanabilirsiniz):

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

veya kullanarak: potrace demo: Tool4dev.com

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.