Class it:

/**
 * Convert an image to a given size and type (ensures input is an image)
 * @param $p['in']        Input filename (mandatory)
 * @param $p['out']        Output filename (mandatory)
 * @param $p['size']        Width x height of resulting image, e.g. "160x60"
 * @param $p['type']        Output file type, e.g. "jpg"
 * @param $p['types']        Comma separated list of accepted input types, default "bmp,eps,gif,jp2,jpg,png,svg,tif"
 * @param $p['quality']        JPEG quality (0-100), default is 75
 * @param $p['keepalpha']    Don't add option --flatten to preserve alpha channel
 * @param $p['pngcrush']  Use pngcrush for sm
 * @param $p['-opts']        Custom command line options to ImageMagick convert
 * @return Success of convert as true/false
 */
static function imageconvert($p)
{
    if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false))))
    {
        if (get_class((object)it_xml::create(it::fopen($p['in'], "r"), array('prefix' => "_imageconvert_", 'safety' => 0))) == "_imageconvert_svg")
            $type = "svg"; # Accept SVG files if they are valid XML and root tag is svg
        else
            list(, $type) = explode(' ', strtolower(it::exec('identify 2>/dev/null {in}', $p))); # for things like eps
    }

    # emulate -auto-orient which is not supported by GM
    if ($p['-opts']['-auto-orient'])
    {
        $exif = @exif_read_data($p['in'], 'IFD0');
        switch ($exif['Orientation'])
        {
            case 2: $p['-opts']['-flop'] = true;  break;
            case 3: $p['-opts']['-rotate'] = 180; break;
            case 4: $p['-opts']['-flip'] = true;  break;
            case 6: $p['-opts']['-rotate'] = 90;  break;
            case 8: $p['-opts']['-rotate'] = 270; break;
        }

        unset($p['-opts']['-auto-orient']);
    }

    $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
    $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
    $p['-opts'] = array('-thumbnail' => $p['size'], '-quality' => $p['quality']) + (array)$p['-opts'];

    if (!$p['keepalpha'])
        $p['-opts'] = array_merge(array('-flatten' => true), $p['-opts']);    # Option -flatten must be first

    if (in_array($type, explode(',', $p['types'])))    # Valid type?
        $cmdoutput = it::exec('( timeout 30s gm convert -limit threads 2 +profile "*" 2>&1 {-opts} {in} {type}:{out} || echo "SHELL ERROR $?" ) | grep -Ev "( iCCP: | Invalid SOS parameters for sequential JPEG | profile matches .* but writing .* instead | inconsistent chromacities )"', $p);

    if ($p['pngcrush'] && $p['type'] == "png")
        it::exec('pngcrush.sh 2>/dev/null {out} {out}.tmp && mv {out}.tmp {out} || rm {out}.tmp', $p);

    return $cmdoutput === "";
}