Making Intervention Image Ignore SVGs

I recently started seeing a recurring exception pop up on one of my sites related to resizing and caching of images, after a bit of digging I realized what the underlying issue ended up being and figured I should document how I went about fixing it.

This particular site is built with Laravel using Intervention Image, Intervention Image Cache, and utilizing Intervention’s URL based image manipulation. Your mileage may vary if you’re using some other PHP framework but you should still be able to copy the solution _somewhere_ if not in the exact file I’m referencing. If you do I’d love to hear about it!

The Problem

The problem ended up being that some of the images I was trying to resize using Intervention were SVGs, and the default image manipulation Intervention uses is the GD library which only supports JPG, PNG, GIF, BMP or WebP files. When it encounters an SVG (or any other unsupported format) it fails.

Here’s the relevant part of the stack trace (emphasis added to the first line):

Intervention\Image\Exception\NotReadableException: Unsupported image type image/svg+xml. GD driver is only able to decode JPG, PNG, GIF, BMP or WebP files.
#48 /vendor/intervention/image/src/Intervention/Image/Gd/Decoder.php(75): Intervention\Image\Gd\Decoder::initFromPath
#47 /vendor/intervention/image/src/Intervention/Image/AbstractDecoder.php(344): Intervention\Image\AbstractDecoder::init
#46 /vendor/intervention/image/src/Intervention/Image/AbstractDriver.php(66): Intervention\Image\AbstractDriver::init
#45 /vendor/intervention/image/src/Intervention/Image/ImageManager.php(54): Intervention\Image\ImageManager::make
#44 [internal](0): call_user_func_array
#43 /vendor/intervention/imagecache/src/Intervention/Image/ImageCache.php(257): Intervention\Image\ImageCache::processCall
#42 /vendor/intervention/imagecache/src/Intervention/Image/ImageCache.php(273): Intervention\Image\ImageCache::process
#41 /vendor/intervention/imagecache/src/Intervention/Image/ImageCache.php(315): Intervention\Image\ImageCache::get
#40 /vendor/intervention/image/src/Intervention/Image/ImageManager.php(92): Intervention\Image\ImageManager::cache
#39 /vendor/intervention/imagecache/src/Intervention/Image/ImageCacheController.php(58): Intervention\Image\ImageCacheController::getImage
#38 /vendor/intervention/imagecache/src/Intervention/Image/ImageCacheController.php(31): Intervention\Image\ImageCacheController::getResponse

I can’t check for this Intervention\Image\Exception\NotReadableException exception using a try/catch because I’m using URL-based image manipulation. For example, attempting to load mysite.com/imagecache/small/logo.svg was what was throwing this NotReadableException error. There’s no code under my control triggering these image manipulations, it’s all vendor code through Intervention that handles these URLs.

The biggest reason I implemented resizing and caching was for performance reasons. So in my case, its okay for SVG images to not be programmatically resized because they’re already vector and (generally) are already way smaller in filesize.

So, how do I get Intervention Image to ignore SVGs?

The Solution

I’m sure many of you are gonna scroll to this section pretty quickly (I know I would’ve too if it was documented while I was searching) so I’m going to cut to the chase.

In Laravel there’s a global exception handler defined at app/Exceptions/Handler.php, it’s where all uncaught exceptions flow through. You may have had to add some code to this handler for app monitoring service integrations, I’m glad I did because otherwise I wouldn’t have even known about this error in the first place!

Here’s my addition to the render method in that app/Exceptions/Handler.php file:

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable   $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Throwable $exception)
    {
        /**
         * If the error class is `Intervention\Image\Exception\NotReadableException`, 
         * redirect the image URL to the original instead to avoid 500 errors on
         * the frontend. In particular, it has trouble with SVG images as the GD 
         * Library doesn't support anything other than JPG, PNG, GIF, BMP or WebP files.
         * 
         * This RegEx handles all Intervention Image filters defined ('/small/',
         * '/medium/', '/large/', for example) by isolating the URL path after
         * the configured Intervention URL Manipulation route (`imagecache` in 
         * this case) and replaces it with `/original/` which is a built in 
         * Intervention route that sends am HTTP response with the original image file.
         * 
         * @see https://image.intervention.io/v2/usage/url-manipulation
         */
        if ( get_class($exception) == "Intervention\Image\Exception\NotReadableException" ) {
            header('Location: '. preg_replace('/(imagecache\/[^\/]*\/)+/i', 'imagecache/original/', $request->getUri()) );
            exit();
        }

        return parent::render($request, $exception);
    }

The whole description of what this is doing is in the comment block, be sure to change imagecache in there to whatever you defined as your route in config/imagecache.php!

Have some thoughts or feedback about this blog post?

Get a conversation started on LinkedIn or Twitter