支持横向和纵向的图片拼接,可以选择将拼接好的图片输出到文件或输出到用户浏览器,并且可以设置允许的最大宽度或最大高度,程序将自动进行缩放。

值得注意的是,程序中包含了一个重写了的file_get_contents函数。phper都知道,普通的file_get_contentsfsockopen功能的简单打包,如果网速很慢或下载这个页面需要很长的时间,会卡在那,持续占用资源,具体分析可以看张宴 - PHP-CGI 进程 CPU 100% 与 file_get_contents 函数的关系。所以此处的file_get_contents重写了一下,避免出现上述情况。

<?php
/**
 * Created by IntelliJ IDEA.
 * User: chenzhidong
 * Date: 13-11-19
 * Time: 下午2:55
 */
class ImageCombiner {
    const COMBINE_HORIZONTAL = 1;
    const COMBINE_VERTICAL = 2;
 
    private $srcs;
    private $src_infos;
    private $dest_type = IMAGETYPE_JPEG;
    private $dest_width = 0;
    private $dest_height = 0;
    private $combine_mode = self::COMBINE_VERTICAL;
 
    private $canvas;
    private $done = false;
 
    public function __construct($srcs, $mode = self::COMBINE_VERTICAL, $dest_width = 0, $dest_height = 0) {
        $this->srcs = $srcs;
        $this->combine_mode = $mode;
        $this->dest_width = $dest_width;
        $this->dest_height = $dest_height;
        $this->canvas = null;
    }
 
    private function sys_get_temp_dir() {
        if (function_exists('sys_get_temp_dir')) {
            return sys_get_temp_dir();
        }
        if ($temp = getenv('TMP')) {
            return $temp;
        }
        if ($temp = getenv('TEMP')) {
            return $temp;
        }
        if ($temp = getenv('TMPDIR')) {
            return $temp;
        }
        $temp = tempnam(__FILE__, '');
        if (file_exists($temp)) {
            unlink($temp);
            return dirname($temp);
        }
        return null;
    }
 
    private function file_get_contents($url, $use_include_path = false, $stream_context = null, $curl_timeout = 8) {
        if ($stream_context == null && preg_match('/^https?:\/\//', $url))
            $stream_context = @stream_context_create(array('http' => array('timeout' => $curl_timeout)));
        if (in_array(ini_get('allow_url_fopen'), array('On', 'on', '1')) || !preg_match('/^https?:\/\//', $url))
            return @file_get_contents($url, $use_include_path, $stream_context);
        elseif (function_exists('curl_init')) {
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
            curl_setopt($curl, CURLOPT_TIMEOUT, $curl_timeout);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
            $opts = stream_context_get_options($stream_context);
            if (isset($opts['http']['method']) && strtolower($opts['http']['method']) == 'post') {
                curl_setopt($curl, CURLOPT_POST, true);
                if (isset($opts['http']['content'])) {
                    parse_str($opts['http']['content'], $datas);
                    curl_setopt($curl, CURLOPT_POSTFIELDS, $datas);
                }
            }
            $content = curl_exec($curl);
            curl_close($curl);
            return $content;
        }
        else
            return false;
    }
 
    private function saveFile($url, $filepath) {
        if ($url && $filepath) {
            $file = $this->file_get_contents($url);
            $fp = @fopen($filepath, 'w');
            if ($fp) {
                @fwrite($fp, $file);
                @fclose($fp);
                return $filepath;
            }
        }
        return false;
    }
 
    private function writeImage($type, $resource, $filename) {
        switch ($type) {
            case IMAGETYPE_GIF:
                $success = imagegif($resource, $filename);
                break;
            case IMAGETYPE_PNG:
                $success = imagepng($resource, $filename);
                break;
            case IMAGETYPE_BMP:
                $success = imagewbmp($resource, $filename);
                break;
            case IMAGETYPE_JPEG:
            default:
                $success = imagejpeg($resource, $filename, 100);
                break;
        }
        @chmod($filename, 0664);
        return $success;
    }
 
    private function checkSrcs() {
        foreach ($this->srcs as $key => $src) {
            $tmp = tempnam($this->sys_get_temp_dir(), 'img_');
            if ($this->saveFile($src, $tmp)) {
                list($src_width, $src_height, $type) = @getimagesize($tmp);
                if ($src_width && $src_height && $type && in_array($type, array(IMAGETYPE_BMP, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_GIF))) {
                    $image = array('width' => $src_width, 'height' => $src_height, 'type' => $type, 'image' => $tmp);
                    $this->src_infos[$key] = $image;
                }
                else {
                    unset($this->srcs[$key]);
                }
            }
            else {
                unset($this->srcs[$key]);
            }
        }
    }
 
    private function checkSizes() {
        switch ($this->combine_mode) {
            case self::COMBINE_VERTICAL:
                if (!$this->dest_width) {
                    foreach ($this->src_infos as $src) {
                        $this->dest_width = max($this->dest_width, $src['width']);
                    }
                }
                foreach ($this->src_infos as $src) {
                    $this->dest_height += round($this->dest_width * $src['height'] / $src['width']);
                }
                break;
            case self::COMBINE_HORIZONTAL:
                if (!$this->dest_height) {
                    foreach ($this->src_infos as $src) {
                        $this->dest_height = max($this->dest_height, $src['height']);
                    }
                }
                foreach ($this->src_infos as $src) {
                    $this->dest_width += round($this->dest_height * $src['width'] / $src['height']);
                }
                break;
        }
    }
 
    private function createTransImage($width, $height) {
        $image = imagecreatetruecolor($width, $height);
        $white = imagecolorallocate($image, 255, 255, 255);
        imagefill($image, 0, 0, $white);
        imagecolortransparent($image, $white);
        return $image;
    }
 
    private function combineVertical() {
        $destX = 0;
        $destY = 0;
        foreach ($this->src_infos as $key => $src) {
            if ($this->dest_width != $src['width']) {
                $dest_height = round($src['height'] * ($this->dest_width / $src['width']));
            }
            else
                $dest_height = $src['height'];
            switch ($src['type']) {
                case IMAGETYPE_PNG:
                    $image = @imagecreatefrompng($src['image']);
                    break;
                case IMAGETYPE_BMP:
                    $image = @imagecreatefromwbmp($src['image']);
                    break;
                case IMAGETYPE_GIF:
                    $image = @imagecreatefromgif($src['image']);
                    break;
                case IMAGETYPE_JPEG:
                default:
                    $image = @imagecreatefromjpeg($src['image']);
                    break;
            }
            if ($image && !imagecopyresampled($this->canvas, $image, $destX, $destY, 0, 0, $this->dest_width, $dest_height, $src['width'], $src['height']))
                return false;
            if ($image)
                imagedestroy($image);
            unlink($src['image']);
            $destY += $dest_height;
        }
        return $this->canvas;
    }
 
    private function combineHorizontal() {
        $destX = 0;
        $destY = 0;
        foreach ($this->src_infos as $key => $src) {
            if ($this->dest_height != $src['height']) {
                $dest_width = round($src['width'] * ($this->dest_height / $src['height']));
            }
            else
                $dest_width = $src['width'];
            switch ($src['type']) {
                case IMAGETYPE_PNG:
                    $image = @imagecreatefrompng($src['image']);
                    break;
                case IMAGETYPE_BMP:
                    $image = @imagecreatefromwbmp($src['image']);
                    break;
                case IMAGETYPE_GIF:
                    $image = @imagecreatefromgif($src['image']);
                    break;
                case IMAGETYPE_JPEG:
                default:
                    $image = @imagecreatefromjpeg($src['image']);
                    break;
            }
            if ($image && !imagecopyresampled($this->canvas, $image, $destX, $destY, 0, 0, $dest_width, $this->dest_height, $src['width'], $src['height']))
                return false;
            if ($image)
                imagedestroy($image);
            unlink($src['image']);
            $destX += $dest_width;
        }
        return true;
    }
 
    public function setDestType($type) {
        $this->dest_type = $type;
    }
 
    public function getDestType() {
        return $this->dest_type;
    }
 
    private function combine() {
        if (!$this->done) {
            if (PHP_VERSION_ID < 50300)
                clearstatcache();
 
            $this->checkSrcs();
            $this->checkSizes();
 
            if (!empty($this->src_infos)) {
                $this->canvas = $this->createTransImage($this->dest_width, $this->dest_height);
                switch ($this->combine_mode) {
                    case self::COMBINE_HORIZONTAL:
                        $this->done = $this->combineHorizontal();
                        break;
                    case self::COMBINE_VERTICAL:
                        $this->done = $this->combineVertical();
                        break;
                }
            }
        }
        return $this->done;
    }
 
    public function getCombination() {
        $image = $this->combine();
        if ($image)
            return $this->canvas;
        return false;
    }
 
    public function showCombination() {
        $image = $this->combine();
        if ($image) {
            switch ($this->getDestType()) {
                case IMAGETYPE_GIF:
                    header("Content-type: image/gif");
                    imagegif($this->canvas);
                    break;
                case IMAGETYPE_BMP:
                    header("Content-type: image/bmp");
                    imagewbmp($this->canvas);
                    break;
                case IMAGETYPE_JPEG:
                    header("Content-type: image/jpeg");
                    imagejpeg($this->canvas);
                    break;
                case IMAGETYPE_PNG:
                    header("Content-type: image/png");
                    imagepng($this->canvas);
                    break;
            }
        }
        imagedestroy($this->canvas);
    }
 
    public function saveCombination($dest_file) {
        $image = $this->combine();
        if ($image) {
            if ($this->writeImage($this->dest_type, $this->canvas, $dest_file)) {
                imagedestroy($this->canvas);
                return true;
            }
        }
        return false;
    }
}