php 图片压缩类

 PHP图片压缩类,部分来源于网络(侵则删),部分自己改写拼凑成一个类。该类封装了了PHP7没有的imagecreatefrombmp等的相关方法(7.2有提供这个方法)


compressImg($dst_img);       //调用示例
 */
Class ImageCompressService{

    private $src;
    public $image;
    private $imageinfo;
    private $percent = 0.5;
    /**
     * 图片压缩
     * @param $src 源图
     * @param float $percent  压缩比例
     */
    public function __construct($src, $percent=1)
    {
        $this->src = $src;
        $this->percent = $percent;
    }


    /** 高清压缩图片
     * @param string $saveName  提供图片名(可不带扩展名,用源图扩展名)用于保存。或不提供文件名直接显示
     */
    public function compressImg($saveName='')
    {
        $this->_openImage();
        if(!empty($saveName)) $this->_saveImage($saveName);  //保存
        else $this->_showImage();
    }

    /**
     * 内部:打开图片
     */
    private function _openImage()
    {
        list($width, $height, $type, $attr) = getimagesize($this->src);
        $this->imageinfo = array(
            'width'=>$width,
            'height'=>$height,
            'type'=>image_type_to_extension($type,false),
            'attr'=>$attr
        );
        if($this->imageinfo['type'] == 'bmp'){
            $this->image = $this->imagecreatefrombmp($this->src);  //  自己编写的bmp处理方法
        }else{
            $fun = "imagecreatefrom".$this->imageinfo['type'];  //调用php方法
            $this->image = $fun($this->src);
        }
        $this->_thumpImage();
    }
    /**
     * 内部:操作图片
     */
    private function _thumpImage()
    {
        $new_width = $this->imageinfo['width'] * $this->percent;
        $new_height = $this->imageinfo['height'] * $this->percent;
        $image_thump = imagecreatetruecolor($new_width,$new_height);
        //将原图复制带图片载体上面,并且按照一定比例压缩,极大的保持了清晰度
        imagecopyresampled($image_thump,$this->image,0,0,0,0,$new_width,$new_height,$this->imageinfo['width'],$this->imageinfo['height']);
        imagedestroy($this->image);
        $this->image = $image_thump;
    }

    /**
     * 输出图片:保存图片则用saveImage()
     */
    private function _showImage()
    {
        header('Content-Type: image/'.$this->imageinfo['type']);
        $funcs = "image".$this->imageinfo['type'];
        $funcs($this->image);
    }
    /**
     * 保存图片到硬盘:
     * @param  string $dstImgName  1、可指定字符串不带后缀的名称,使用源图扩展名 。2、直接指定目标图片名带扩展名。
     */
    private function _saveImage($dstImgName)
    {
        if(empty($dstImgName)) return false;
        $allowImgs = ['.jpg', '.jpeg', '.png', '.bmp', '.wbmp','.gif'];   //如果目标图片名有后缀就用目标图片扩展名 后缀,如果没有,则用源图的扩展名
        $dstExt =  strrchr($dstImgName ,".");
        $sourseExt = strrchr($this->src ,".");
        if(!empty($dstExt)) $dstExt =strtolower($dstExt);
        if(!empty($sourseExt)) $sourseExt =strtolower($sourseExt);

        //有指定目标名扩展名
        if(!empty($dstExt) && in_array($dstExt,$allowImgs)){
            $dstName = $dstImgName;
        }elseif(!empty($sourseExt) && in_array($sourseExt,$allowImgs)){
            $dstName = $dstImgName.$sourseExt;
        }else{
            $dstName = $dstImgName.$this->imageinfo['type'];
        }

        if($this->imageinfo['type'] == 'bmp'){
            $this->imagebmp($this->image,$dstName);     //调用外部方法
        }else{
            $funcs = "image".$this->imageinfo['type'];
            $funcs($this->image,$dstName);
        }
    }

    /**
     * 销毁图片
     */
    public function __destruct(){
        if(is_resource($this->image)){
            imagedestroy($this->image);
        }
    }


    /**
     * 补全bmp相关的方法(函数)
     */
    function imagecreatefrombmp($file)
    {
        global $CurrentBit, $echoMode;
        $f=fopen($file,"r");
        $Header=fread($f,2);
        if($Header=="BM")
        {
            $Size=$this->freaddword($f);
            $Reserved1=$this->freadword($f);
            $Reserved2=$this->freadword($f);
            $FirstByteOfImage=$this->freaddword($f);
            $SizeBITMAPINFOHEADER=$this->freaddword($f);
            $Width=$this->freaddword($f);
            $Height=$this->freaddword($f);
            $biPlanes=$this->freadword($f);
            $biBitCount=$this->freadword($f);
            $RLECompression=$this->freaddword($f);
            $WidthxHeight=$this->freaddword($f);
            $biXPelsPerMeter=$this->freaddword($f);
            $biYPelsPerMeter=$this->freaddword($f);
            $NumberOfPalettesUsed=$this->freaddword($f);
            $NumberOfImportantColors=$this->freaddword($f);
            if($biBitCount<24)
            {
                $img=imagecreate($Width,$Height);
                $Colors=pow(2,$biBitCount);
                for($p=0;$p<$Colors;$p++)
                {
                    $B=$this->freadbyte($f);
                    $G=$this->freadbyte($f);
                    $R=$this->freadbyte($f);
                    $Reserved=$this->freadbyte($f);
                    $Palette[]=imagecolorallocate($img,$R,$G,$B);
                }
                if($RLECompression==0)
                {
                    $Zbytek=(4-ceil(($Width/(8/$biBitCount)))%4)%4;
                    for($y=$Height-1;$y>=0;$y--)
                    {
                        $CurrentBit=0;
                        for($x=0;$x<$Width;$x++)
                        {
                            $C=$this->freadbits($f,$biBitCount);
                            imagesetpixel($img,$x,$y,$Palette[$C]);
                        }
                        if($CurrentBit!=0) {$this->freadbyte($f);}
                        for($g=0;$g<$Zbytek;$g++)
                            $this->freadbyte($f);
                    }
                }
            }
            if($RLECompression==1) //$BI_RLE8
            {
                $y=$Height;
                $pocetb=0;
                while(true)
                {
                    $y--;
                    $prefix=$this->freadbyte($f);
                    $suffix=$this->freadbyte($f);
                    $pocetb+=2;
                    $echoit=false;
                    if($echoit)echo "Prefix: $prefix Suffix: $suffix
"; if(($prefix==0)and($suffix==1)) break; if(feof($f)) break; while(!(($prefix==0)and($suffix==0))) { if($prefix==0) { $pocet=$suffix; $Data.=fread($f,$pocet); $pocetb+=$pocet; if($pocetb%2==1) {$this->freadbyte($f); $pocetb++;} } if($prefix>0) { $pocet=$prefix; for($r=0;$r<$pocet;$r++) $Data.=chr($suffix); } $prefix=$this->freadbyte($f); $suffix=$this->freadbyte($f); $pocetb+=2; if($echoit) echo "Prefix: $prefix Suffix: $suffix
"; } for($x=0;$x";*/ while(true) { //break; $y--; $prefix=$this->freadbyte($f); $suffix=$this->freadbyte($f); $pocetb+=2; $echoit=false; if($echoit)echo "Prefix: $prefix Suffix: $suffix
"; if(($prefix==0)and($suffix==1)) break; if(feof($f)) break; while(!(($prefix==0)and($suffix==0))) { if($prefix==0) { $pocet=$suffix; $CurrentBit=0; for($h=0;$h<$pocet;$h++) $Data.=chr($this->freadbits($f,4)); if($CurrentBit!=0) $this->freadbits($f,4); $pocetb+=ceil(($pocet/2)); if($pocetb%2==1) {$this->freadbyte($f); $pocetb++;} } if($prefix>0) { $pocet=$prefix; $i=0; for($r=0;$r<$pocet;$r++) { if($i%2==0) { $Data.=chr($suffix%16); } else { $Data.=chr(floor($suffix/16)); } $i++; } } $prefix=$this->freadbyte($f); $suffix=$this->freadbyte($f); $pocetb+=2; if($echoit) echo "Prefix: $prefix Suffix: $suffix
"; } for($x=0;$x=0;$y--) { for($x=0;$x<$Width;$x++) { $B=$this->freadbyte($f); $G=$this->freadbyte($f); $R=$this->freadbyte($f); $color=imagecolorexact($img,$R,$G,$B); if($color==-1) $color=imagecolorallocate($img,$R,$G,$B); imagesetpixel($img,$x,$y,$color); } for($z=0;$z<$Zbytek;$z++) $this->freadbyte($f); } } return $img; } fclose($f); } function freadbits($f, $biBitCount,&$echoMode='') { $str=''; if($biBitCount==4){ if($echoMode==false){ $echoMode=true; $str = $this->freadbyte($f); fseek($f, -1,SEEK_CUR); $str = $str >> 4; return $str & 0x0f; }else{ $str = $this->freadbyte($f); $echoMode = false; return $str & 0x0f; } } if($biBitCount == 8){ $str=$this->freadbyte($f); return $str & 0xff; } } function freadbyte($f) { return ord(fread($f,1)); } function freadword($f) { $b1=$this->freadbyte($f); $b2=$this->freadbyte($f); return $b2*256+$b1; } function freaddword($f) { $b1=$this->freadword($f); $b2=$this->freadword($f); return $b2*65536+$b1; } /*格式组成典型的BMP图像文件由四部分组成: 1:位图头文件数据结构,它包含BMP图像文件的类型、显示内容等信息; 2:位图信息数据结构,它包含有BMP图像的宽、高、压缩方法,以及定义颜色等信息; 3:调色板,这个部分是可选的,有些位图需要调色板,有些位图,比如真彩色图(24位的BMP)就不需要调色板; 4:位图数据,这部分的内容根据BMP位图使用的位数不同而不同,在24位图中直接使用RGB,而其他的小于24位的使用调色板中颜色索引值。 */ function imagebmp(&$im, $filename = '', $bit = 8, $compression = 0) { if (!in_array($bit, array(1, 4, 8, 16, 24, 32))) { $bit = 8; //记录每个像素所占计算机字节的位数,默认为8位 } else if ($bit == 32) // todo:32 bit { $bit = 24; } $bits = pow(2, $bit); //表示待创建的图像一共由$bits种颜色组成 // 将图像调整为调色板图像,便于以后绘图,如果是24位BMP位图,那么就不需要这一步 /*调色板是被保存在一个RGBQUAD结构的数组中,该结构指出了每一种颜色的红、绿、蓝的分量值。 *位数组中的每一个索引都对应于一个调色板项(即一个RGBQUAD结构),应用程序将根据这种对 *应关系,将像素索引值转换为像素RGB值(真实的像素颜色) * */ imagetruecolortopalette($im, true, $bits); $width = imagesx($im); $height = imagesy($im); $colors_num = imagecolorstotal($im); //返回的一般都是256 // 颜色索引 $rgb_quad = ''; if ($bit <= 8)//仅针对1,4,8位BMP位图建立颜色索引 { for ($i = 0; $i < $colors_num; $i ++) { $colors = imagecolorsforindex($im, $i);//每一幅图的索引表都是不一样的! $rgb_quad .= chr($colors['blue']) . chr($colors['green']) . chr($colors['red']) . "\0"; } // 位图数据 $bmp_data = ''; // 非压缩,即对RGB值不进行压缩,读取时顺序为BGR,高位在前,低位在后 if ($compression == 0 || $bit < 8) { $compression = 0; // 每行字节数必须为4的倍数,补齐。 $extra = ''; $padding = 32 - ( $width * $bit ) % 32 ; if ($padding % 32 != 0) { $extra = str_repeat("\0", $padding); } for ($j = $height - 1; $j >= 0; $j --) { $i = 0; while ($i < $width) { $bin = 0; $limit = $width - $i < 8 / $bit ? (8 / $bit - $width + $i) * $bit : 0; for ($k = 8 - $bit; $k >= $limit; $k -= $bit) { $index = imagecolorat($im, $i, $j); $bin |= $index << $k; $i ++; } $bmp_data .= chr($bin); } $bmp_data .= $extra; } } // RLE8 压缩 else if ($compression == 1 && $bit == 8) { for ($j = $height - 1; $j >= 0; $j --) { $last_index = "\0"; $same_num = 0; for ($i = 0; $i <= $width; $i ++) { $index = imagecolorat($im, $i, $j); if ($index !== $last_index || $same_num > 255) { if ($same_num != 0) { $bmp_data .= chr($same_num) . chr($last_index); } $last_index = $index; $same_num = 1; } else { $same_num ++; } } $bmp_data .= "\0\0"; } $bmp_data .= "\0\1"; } $size_quad = strlen($rgb_quad); $size_data = strlen($bmp_data); } else { // 每行字节数必须为4的倍数,补齐。 $extra = ''; $padding = 4 - ($width * ($bit / 8)) % 4; if ($padding % 4 != 0) { $extra = str_repeat("\0", $padding); } // 位图数据 $bmp_data = ''; for ($j = $height - 1; $j >= 0; $j --) { for ($i = 0; $i < $width; $i ++) { $index = imagecolorat($im, $i, $j); $colors = imagecolorsforindex($im, $index); if ($bit == 16) { $bin = 0 << $bit; $bin |= ($colors['red'] >> 3) << 10; $bin |= ($colors['green'] >> 3) << 5; $bin |= $colors['blue'] >> 3; $bmp_data .= pack("v", $bin); } else { $bmp_data .= pack("c*", $colors['blue'], $colors['green'], $colors['red']); } // todo: 32bit; } $bmp_data .= $extra; } $size_quad = 0; $size_data = strlen($bmp_data); $colors_num = 0; } // 位图文件头 $file_header = "BM" . pack("V3", 54 + $size_quad + $size_data, 0, 54 + $size_quad); // 位图信息头 $info_header = pack("V3v2V*", 0x28, $width, $height, 1, $bit, $compression, $size_data, 0, 0, $colors_num, 0); // 写入文件 if ($filename != '') { $fp = fopen($filename, "wb"); fwrite($fp, $file_header); fwrite($fp, $info_header); if($rgb_quad!=='') fwrite($fp, $rgb_quad); fwrite($fp, $bmp_data); fclose($fp); return true; } // 浏览器输出 header("Content-Type: image/bmp"); echo $file_header . $info_header; echo $rgb_quad; echo $bmp_data; return true; } }

 

你可能感兴趣的:(PHP,图片压缩,图片压缩)