Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resize SVG with PHP?

I am trying to resize (increase size) a SVG inside a PHP script and save it as a new SVG. Given SVG is generated by another script. It contains image and texts.

I have tried with imagick, but the generated svg is broken, and doesn't include any of the contents.

This is how I have done:

$image = new Imagick();
$image->setResolution(2000,2000);
$image->readImage('/pathe/to/my/svg.svg');
$image->scaleImage(1000,1000);
file_put_contents('/pathe/to/my/new.svg', $image->getImageBlob());
like image 400
тнє Sufi Avatar asked Feb 16 '18 05:02

тнє Sufi


People also ask

How do I resize an SVG file?

❓ How can I resize a SVG image? First, you need to add a SVG image file: drag & drop your SVG image file or click inside the white area to choose a file. Then adjust resize settings, and click the "Resize" button. After the process completes, you can download your result file.

How do I change the size of an SVG icon in CSS?

Approach: You can simply customize the class of SVG by changing the height and width of the icons or by changing the values of viewBox attributes of SVG. Note: The viewBox attribute defines the position and dimension of an SVG viewport.

How do I scale SVG viewport?

What we have to do is remove the viewBox and the preserveAspectRatio and just set the width of the SVG to 100% and the height to the height of our <path> ( 711px ). That way the SVG viewport fills the width of the page and keeps it's height at the size we want.

Can SVG images be scaled?

We use viewBox to make the SVG image scalable. viewBox = “0 0 100 100”: defines a coordinate system having x=0, y=0, width=100 units and height=100 units. Thus, the SVG containing a rectangle having width=50px and height=50px will fill up the height and width of the SVG image, and all the dimensions get scaled equally.


2 Answers

Consider that "SVG" stands for "Scalable Vector Grafics".

  1. Imagick is a library for manipulating pixel-oriented grafics and as such unfit for vector grafic formats like SVG.

  2. SVGs are by their nature scalable. In most cases you will not need to rewrite them to change their size. If you display SVGs inside a webpage (via <img> or <object> tags, or as a CSS background-image, it will be displayed at the size defined for these elements, and if there is size information stored in the SVG file, that will be simply ignored. (Note that a lot of SVG files contain no display size information at all.)

  3. The only case you may need to set size information in the SVG file is if you display it as a standalone file (for example if you have a link pointing to the .svg itself).

    In this case, you can take advantage of the fact that SVG is a XML file:

    $dom = new DOMDocument('1.0', 'utf-8');
    $dom->load('/pathe/to/my/svg.svg');
    $svg = $dom->documentElement;
    
    if ( ! $svg->hasAttribute('viewBox') ) { // viewBox is needed to establish
                                             // userspace coordinates
         $pattern = '/^(\d*\.\d+|\d+)(px)?$/'; // positive number, px unit optional
    
         $interpretable =  preg_match( $pattern, $svg->getAttribute('width'), $width ) &&
                           preg_match( $pattern, $svg->getAttribute('height'), $height );
    
         if ( $interpretable ) {
            $view_box = implode(' ', [0, 0, $width[0], $height[0]]);
            $svg->setAttribute('viewBox', $view_box);
        } else { // this gets sticky
             throw new Exception("viewBox is dependent on environment");
        }
    }
    
    $svg->setAttribute('width', '1000');
    $svg->setAttribute('height', '1000');
    $dom->save('/pathe/to/my/new.svg');
    

    There are some tricky cases if the element has no viewBox attribute and the width and height have non-px units. Handling them requires a deeper understanding of SVG. It would be best to assure that the SVG files produced by the "other script" always have a viewBox. Then the conditional section can be left out.

    The term "resolution" is inapplicable for vector grafics. Width and height can be dimensionless numbers (representing pixel for the purpose of rendering into an output device, for example the screen), or any valid CSS length unit: em, ex, px, pt, pc, cm, mm, in, and percentages.

like image 166
ccprog Avatar answered Oct 19 '22 19:10

ccprog


Imagick uses the viewbox to generate a pixelbased image at the size of the viewbox upon importing an svg into imagick. Thus should you need a higher resolution than the viewbox implies you need to read the svg stream in a cache, change the viewBox size parameters to multiplied values and only import into imagick afterwards.

Or you could exactly as you did. Worked like a charm for me...

I had the following problems that lead to a blank image:

Fix missing xml intro

if (substr($svgContent,0,5) != '<?xml') {
    $svgContent = '<?xml version="1.0" encoding="utf-8"?>' . $svgContent;
}

Other mistakes I made and stuff that might not work properly

  • tried importing an invalid svg
  • tried calculating new height values for scaleImage based on former svg image height attributes (makes no sense of cause)
  • used something different than COMPOSITE_DEFAULT in $bg->compositeImage($im, \Imagick::COMPOSITE_DEFAULT, $marginHorizontal, $marginVertical ); which lead to the imported image being nearly invisible in my case
like image 27
Hafenkranich Avatar answered Oct 19 '22 20:10

Hafenkranich