Asked  7 Months ago    Answers:  5   Viewed   47 times

I'm working on a web project that involves a dynamically generated map of the US coloring different states based on a set of data.

This SVG file gives me a good blank map of the US and is very easy to change the color of each state. The difficulty is that IE browsers don't support SVG so in order for me to use the handy syntax the svg offers, I'll need to convert it to a JPG.

Ideally, I'd like to do this with only the GD2 library but could also use ImageMagick. I have absolutely no clue how to do this.

Any solution that would allow me to dynamically change the colors of states on a map of the US will be considered. The key is that it is easy to change the colors on the fly and that it is cross browser. PHP/Apache solutions only, please.

 Answers

36

That's funny you asked this, I just did this recently for my work's site and I was thinking I should write a tutorial... Here is how to do it with PHP/Imagick, which uses 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();

the steps regex color replacement may vary depending on the svg path xml and how you id & color values are stored. If you don't want to store a file on the server, you can output the image as base 64 like

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

(before you use clear/destroy) but ie has issues with PNG as base64 so you'd probably have to output base64 as jpeg

you can see an example here I did for a former employer's sales territory map:

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

Finish: enter image description here

Edit

Since writing the above, I've come up with 2 improved techniques:

1) instead of a regex loop to change the fill on state , use CSS to make style rules like

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

and then you can do a single text replace to inject your css rules into the svg before proceeding with the imagick jpeg/png creation. If the colors don't change, check to make sure you don't have any inline fill styles in your path tags overriding the css.

2) If you don't have to actually create a jpeg/png image file (and don't need to support outdated browsers), you can manipulate the svg directly with jQuery. You can't access the svg paths when embedding the svg using img or object tags, so you'll have to directly include the svg xml in your webpage html like:

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

then changing the colors is as easy as:

<script type="text/javascript" src="/path/to/jquery.js"></script>
<script type="text/javascript">
    $('#CA').css('fill', 'blue');
    $('#NY').css('fill', '#ff0000');
</script>
Wednesday, March 31, 2021
 
Exoon
answered 7 Months ago
93

Given all your data downloaded to my computer, I can convert it to png using ImageMagick 6.9.10.82 Q16 Mac OSX Sierra that calls Inkscape 0.92.4 as the SVG renderer.

convert right.inside.svg x.png


enter image description here

You have not shown the correct result. So I do not know if this is correct or not. But it does appear to be correct given the images in the assets folder.

However, the mask and other image needs to be accessible from whomever is trying to view the svg file. So either the data needs to be downloaded or perhaps you need to provide the URL to those files on some server that has the svg file.

Saturday, May 29, 2021
 
kwichz
answered 5 Months ago
46

You just need imagepng() then. In fact it almost becomes a one-liner:

 imagepng(imagecreatefromstring(file_get_contents($filename)), "output.png");

You would use $_FILES["id"]["tmp_name"] for the filename, and a different output filename obviously. But the image format probing itself would become redundant.

Saturday, June 12, 2021
 
fhonics
answered 5 Months ago
47

Inkscape will do this:

inkscape 
    --export-png=out.png --export-dpi=200 
    --export-background-opacity=0 --without-gui in.svg

Update

The terminology has changed: all the export params suppress gui, and the output parameter is now simply based on the file type. For example, a type of png will cause a file in /path/to/picture.svg to be exported as /path/to/picture.png (caution: this overwrites output).

inkscape 
    --export-type=png --export-dpi=200 
    --export-background-opacity=0 picture.svg

Note cited wiki has quotes on --export-type=png, which is incorrect.

Also if don't have Inkscape command line, MacOS can access via bash directly:

/Applications/Inkscape.app/Contents/MacOS/inkscape
Tuesday, July 27, 2021
 
Asher
answered 3 Months ago
42

On a site we convert hundreds of PDF's on a daily basis where we need to create JPGs and we found it only reliable to convert the PDF's to postscript first.

We use the "pdftops" command, try

pdftops baby_aRCWTU.pdf baby_aRCWTU.ps

then your convert command above, but on the ps. Works for me, the image is then included.

Monday, August 30, 2021
 
Abdul Rehman
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :