Konvertieren Sie das SVG-Bild mit PHP in PNG

111

Ich arbeite an einem Webprojekt, bei dem eine dynamisch generierte Karte der USA verschiedene Staaten basierend auf einem Datensatz färbt.

Diese SVG-Datei gibt mir eine gute leere Karte der USA und ist sehr einfach, die Farbe jedes Staates zu ändern. Die Schwierigkeit besteht darin, dass IE-Browser SVG nicht unterstützen. Damit ich die praktische Syntax des SVG verwenden kann, muss ich sie in ein JPG konvertieren.

Idealerweise möchte ich dies nur mit der GD2-Bibliothek tun, könnte aber auch ImageMagick verwenden. Ich habe absolut keine Ahnung, wie das geht.

Jede Lösung, die es mir ermöglicht, die Farben von Staaten auf einer Karte der USA dynamisch zu ändern, wird in Betracht gezogen. Der Schlüssel ist, dass es einfach ist, die Farben im laufenden Betrieb zu ändern, und dass es sich um einen Cross-Browser handelt. Bitte nur PHP / Apache-Lösungen.

Michael Berkompas
quelle
Gibt es Klassen, die SVG auf VML portieren sollen? Auf diese Weise könnten Sie immer noch eine Lösung vom Typ 'HTML5' haben
Patrick
Schau dir meine Antwort an. genau das, was Sie brauchen

Antworten:

142

Das ist lustig, dass du das gefragt hast. Ich habe das erst kürzlich für die Website meiner Arbeit gemacht und dachte, ich sollte ein Tutorial schreiben ... So geht's mit PHP / Imagick, das ImageMagick verwendet:

$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();

Die Schritte zum Ersetzen von Regex-Farben können abhängig vom SVG-Pfad xml und der Art und Weise, wie Ihre ID- und Farbwerte gespeichert werden, variieren. Wenn Sie keine Datei auf dem Server speichern möchten, können Sie das Image als Basis 64 ausgeben

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

(bevor Sie clear / destroy verwenden), hat aber Probleme mit PNG als base64, sodass Sie base64 wahrscheinlich als JPEG ausgeben müssten

Sie können hier ein Beispiel sehen, das ich für die Verkaufsgebietskarte eines ehemaligen Arbeitgebers gemacht habe:

Start: https://upload.wikimedia.org/wikipedia/commons/1/1a/Blank_US_Map_(states_only).svg

Fertig: Geben Sie hier die Bildbeschreibung ein

Bearbeiten

Seit ich das Obige geschrieben habe, habe ich mir zwei verbesserte Techniken ausgedacht:

1) Verwenden Sie anstelle einer Regex-Schleife, um den Füllstatus zu ändern, CSS, um Stilregeln wie zu erstellen

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

und dann können Sie einen einzelnen Text ersetzen, um Ihre CSS-Regeln in das SVG einzufügen, bevor Sie mit der Erstellung des Imagick-JPEG / PNG fortfahren. Wenn sich die Farben nicht ändern, stellen Sie sicher, dass Ihre Pfad-Tags keine Inline-Füllstile enthalten, die das CSS überschreiben.

2) Wenn Sie keine JPEG- / PNG-Bilddatei erstellen müssen (und keine veralteten Browser unterstützen müssen), können Sie das SVG direkt mit jQuery bearbeiten. Sie können nicht auf die SVG-Pfade zugreifen, wenn Sie die SVG mithilfe von IMG- oder Objekt-Tags einbetten. Daher müssen Sie die SVG-XML direkt in Ihre HTML-Webseite aufnehmen, z.

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

Dann ist das Ändern der Farben so einfach wie:

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
    $('#CA').css('fill', 'blue');
    $('#NY').css('fill', '#ff0000');
</script>
WebChemist
quelle
1
Vielen Dank für das sehr genaue und nützliche Tutorial dazu. Ich werde Ihre Lösung auf jeden Fall als Backup verwenden, bin aber sehr bemüht, die SVG-Kompatibilität für alle gängigen Browser zu erreichen.
Michael Berkompas
1
SVG wird in IE8 oder niedriger nicht unterstützt, ohne dass der Benutzer ein SVG-Viewer-Plugin installieren muss - von der SVG-Wikipedia-Seite: "Alle gängigen modernen Webbrowser unterstützen und rendern SVG-Markups direkt mit Ausnahme von Microsoft Internet Explorer (IE) [ 3] Die Beta-Version von Internet Explorer 9 unterstützt die grundlegenden SVG-Funktionen. [4] Derzeit ist die Unterstützung für Browser, die unter Android ausgeführt werden, ebenfalls eingeschränkt. "
WebChemist
1
Ja, aber svgweb scheint alle Inkompatibilitäten mit ein wenig js und flash auszubügeln. Das ist die Lösung, mit der ich gegangen bin.
Michael Berkompas
2
Ich mag deine saubere und schnelle Lösung. Persönlich bevorzuge ich bei der Interaktion mit XML-Dateien die Verwendung eines Dom-Parsers, um mich sicherer zu fühlen als mit Regex. Etwas wie:$dom = new DOMDocument(); $dom->loadXML( $svg ); $dom->getElementsByTagName('image')->item(0)->setAttribute('id', $state); $svg = $dom->saveXML();
Tapper
Ein XML-Parser wäre eine sicherere, wenn auch etwas langsamere Lösung mit jedem anderen SVG. In diesem Fall ist der reguläre Ausdruck sicher, da ich sichergestellt habe, dass die Attribute jedes Status genau wie folgt formatiert sind: (id = "XX" style = "fill: # XXXXXX ").
WebChemist
11

Sie erwähnen, dass Sie dies tun, weil der IE SVG nicht unterstützt.

Die gute Nachricht ist , dass der IE tut Support - Vektor - Grafiken. Okay, es ist in Form einer Sprache namens VML, die nur vom IE unterstützt wird, anstatt von SVG, aber es ist da und Sie können es verwenden.

Google Maps erkennt unter anderem die Browserfunktionen, um festzustellen, ob SVG oder VML bereitgestellt werden sollen.

Dann gibt es die Raphael-Bibliothek , eine auf Javascript-Browsern basierende Grafikbibliothek, die je nach Browser entweder SVG oder VML unterstützt.

Eine andere, die helfen kann: SVGWeb .

All dies bedeutet, dass Sie Ihre IE-Benutzer unterstützen können, ohne auf Bitmap-Grafiken zurückgreifen zu müssen.

Siehe auch die Top-Antwort auf diese Frage, zum Beispiel: XSL Transform SVG to VML

Spudley
quelle
+1 für die Erwähnung von Raphael, das definitiv eine gute Lösung ist und es wert ist, auf seine hervorragende Implementierung von browserübergreifenden Vektorgrafiken untersucht zu werden.
dmp
10

Vergessen Sie bei der Konvertierung von SVG in transparentes PNG Folgendes $imagick->readImageBlob():

$imagick->setBackgroundColor(new ImagickPixel('transparent'));
psycho brm
quelle
Wie ist es möglich, diese Methode vor dem Lesen des Bildes aufzurufen? Ich erhalte die Fehlermeldung "Leeres Imagick-Objekt kann nicht verarbeitet werden". Und ja, meine Imagick-Erweiterung ist installiert, da sie funktioniert und Bilder konvertiert.
Denis2310
6

Das ist sehr einfach, ich habe in den letzten Wochen daran gearbeitet.

Sie benötigen das Batik SVG Toolkit . Laden Sie die Dateien herunter und legen Sie sie im selben Verzeichnis ab wie das SVG, das Sie in ein JPEG konvertieren möchten. Stellen Sie außerdem sicher, dass Sie es zuerst entpacken.

Öffnen Sie das Terminal und führen Sie den folgenden Befehl aus:

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

Das sollte ein JPEG der SVG-Datei ausgeben. Wirklich einfach. Sie können es sogar einfach in eine Schleife einfügen und viele SVGs konvertieren.

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')
Willi Mentzel
quelle
Das ist toll. Danke für den Tipp. Ich werde es in Verbindung mit Perl verwenden, um viele SVG-Dateien, die ich aus einer Vorlage erstellt habe, stapelweise zu verarbeiten.
Simbabque
2

Ich kenne keine eigenständige PHP / Apache-Lösung, da hierfür eine PHP-Bibliothek erforderlich wäre, die SVG-Bilder lesen und rendern kann. Ich bin mir nicht sicher, ob es eine solche Bibliothek gibt - ich kenne keine.

ImageMagick ist in der Lage, SVG-Dateien entweder über die Befehlszeile oder die PHP-Bindung IMagick zu rasteren , scheint jedoch eine Reihe von Macken und externen Abhängigkeiten zu haben, wie z. B. in diesem Forenthread gezeigt . Ich denke, es ist immer noch der vielversprechendste Weg, es ist das erste, was ich untersuchen würde, wenn ich du wäre.

Pekka
quelle
2

Dies ist eine Methode zum Konvertieren eines SVG-Bildes in ein GIF unter Verwendung von Standard-PHP-GD-Tools

1) Sie fügen das Bild in ein Canvas-Element im Browser ein:

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

Konvertieren Sie es dann auf dem Server (ProcessPicture.php) von (Standard) png in gif und speichern Sie es. (Sie hätten auch als PNG speichern können und dann imagepng anstelle von image gif verwenden können):

//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);
Oleviolin
quelle
-1

Sie können Raphaël - JavaScript Library verwenden und es einfach erreichen. Es wird auch im IE funktionieren.

Lokesh Kumar Ravi
quelle
2
Fügen Sie im Link vorhandene Details hinzu. Link kann jederzeit brechen
Sagar Jain
-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);

oder mit: potrace demo: Tool4dev.com

Thành NV
quelle