PHP二维码类库phpqrcode改造面向对象风格

保留输出到前端、写入文件,去掉了写入文件同时输出到前端,增加贴Logo并且可以设置横向比例,增加返回GdImage对象可直接用于海报生成等场景,完善了jpg格式的输出。

调用示例 :

$logoUri='./path/to/logo.png'; //支持本地和网络资源,如需支持其他图片格式需要在相应位置作调整
$qr=new QRcode('这里是二维码内容');
$qr->png(NULL,$logoUri,20); //第一个参数是要写入的文件名(不含后缀),第三个参数是logo宽占二维码宽的比例
exit;

注意事项:

  • 如果可以,请使用PHP8,否则请删掉png和jpg方法的返回值类型约束
  • 建议PHP7以上,否则你将不能在png和jpg方法中使用??运算,需要改成三目运算
  • 实例化对象时只有一个必要参数$text-二维码内容
  • 获得结果的方法有三个:image、png、jpg
  • image方法返回GdImage对象,可以直接用于GD库生成海报等场景
  • png和jpg方法通过类的path属性和方法的filename参数区分输出到前端还是写入文件
  • 只有当path为空字符串且filename为NULL时才会输出到前端
  • filename不要传入空字符串,除非你想用空字符串取代NULL判断是否需要写入文件,这样的话你将不能使用??运算
  • 否则都会写入文件并返回文件名
  • 如果filename为NULL,将用微秒时间戳代替之;filename不要后缀(传了也没用)
  • 然后会把path属性和filename拼接起来并补上后缀,将数据写入文件
  • 需要注意的是,此时的返回值是完整路径而非文件名

使用方法:找到phpqrcode.php源码,删除QRcode、QRencode和QRtools三个类,替换为下面的带码段。
当然如果你愿意支持一下博主,也可以直接去用C币下载成品:面向对象风格的phpqrcode

class QRcode {
    private bool $casesensitive = true;
    private bool $eightbit = false;
    private int $hint = QR_MODE_8;
    private int $size; //设置单点像素数
    private int $margin; //设置边框点数
    private int $level; //设置纠错等级,1/2/3/4
    private string $path=''; //设置写入文件夹,空字符串时不写入
    private string $text; //设置内容
    private $version = 0;
    public int $points; //结果横边点数
    public int $w; //结果像素宽
    public int $h; //结果像素高
    public $data;
    public function __construct(string $text,int $level=1,int $size=5,int $margin=4,string $path='')
    {
        $this->setLevel($level);
        $this->setText($text); //setText应当在setLevel之后调用,否则$level属性不会生效
        $this->setSize($size);
        $this->setMargin($margin);
        $this->setPath($path);
    }
    public function image(string $logo=NULL,int $ratio=5) : \GdImage
    {
        $h = count($this->data);
        $w = strlen($this->data[0]);
        $imgW = $w + 2*$this->margin;
        $imgH = $h + 2*$this->margin;
        $base =ImageCreate($imgW, $imgH);
        $col[0] = ImageColorAllocate($base,255,255,255);
        $col[1] = ImageColorAllocate($base,0,0,0);
        imagefill($base, 0, 0, $col[0]);
        for($y=0; $y<$h; $y++) {
            for($x=0; $x<$w; $x++) {
                if($this->data[$y][$x]=='1') ImageSetPixel($base,$x+$this->margin,$y+$this->margin,$col[1]);
            }
        }
        $pixelPerPoint=min($this->size,intval(QR_PNG_MAXIMUM_SIZE/(count($this->data)+2*$this->margin)));
        $this->w=$imgW*$pixelPerPoint;
        $this->h=$imgH*$pixelPerPoint;
        $target=ImageCreate($this->w,$this->h);
        ImageCopyResized($target,$base,0,0,0,0,$this->w,$this->h,$imgW,$imgH);
        ImageDestroy($base);
        if(isset($logo)&&$ratio>1&&file_exists($logo)){
            // 因为可以用透明色使边角圆润,所以我的logo都是PNG格式的,因此这里就懒得判断了,如果想支持其他格式可以在这里判断文件类型
            $lg=imagecreatefrompng($logo);
            // 一般情况下二维码和logo都是正方形的,但为保证兼容和美观,这里只有宽度是按输入比例调整的,高度则是根据logo原比例自适应
            $lgSize=getimagesize($logo);
            $lgW=(int)round($this->w*$ratio/100);
            $lgH=$lgSize[1]*$lgW/$lgSize[0];
            imagecopyresampled($target,$lg,intval(($this->w-$lgW)/2),intval(($this->h-$lgH)/2),0,0,$lgW,$lgH,$lgSize[0],$lgSize[1]);
        }
        return $target;
    }
    /*下面两个方法用到了php8的联合类型约束,不重要,低版本删掉约束即可*/
    public function png(string $filename = NULL,string $logo=NULL,int $ratio=20) : NULL|string
    {
        $resource=$this->image($logo,$ratio);
        if($this->path===''&&!isset($filename)) Header("Content-type: image/png");
        else $filename=$this->path.($filename??microtime(TRUE)).'.png';
        ImagePng($resource,$filename);
        ImageDestroy($resource);
        $resource=NULL;
        return $filename;
    }
    public function jpg(int $q=85,string $filename = NULL,string $logo=NULL,int $ratio=20) : NULL|string
    {
        $resource=$this->image($logo,$ratio);
        if($this->path===''&&!isset($filename)) Header("Content-type: image/jpeg");
        else $filename=$this->path.($filename??microtime(TRUE)).'.jpeg';
        ImageJpeg($resource, $filename, $q);
        ImageDestroy($resource);
        $resource=NULL;
        return $filename;
    }
    public function setText(string $text) : self
    {
        $input = new QRinput($this->version, $this->level);
        if($input == NULL) return $this;
        if($this->eightbit) {
            if($text == NULL) throw new \Exception('empty string!');
            $ret = $input->append($input,QR_MODE_8,strlen($text),str_split($text));
        } else {
            if($this->hint!==QR_MODE_8&&$this->hint!=QR_MODE_KANJI) throw new \Exception('bad hint');
            $ret = QRsplit::splitStringToQRinput($text,$input,$this->hint,$this->casesensitive);
        }
        if($ret<0){
            unset($input);
            return $this;
        }
        $mask=-1;
        if($input->getVersion()<0||$input->getVersion()>QRSPEC_VERSION_MAX) throw new \Exception('wrong version');
        if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) throw new \Exception('wrong level');
        $raw = new QRrawcode($input);
        $version = $raw->version;
        $width = QRspec::getWidth($version);
        $frame = QRspec::newFrame($version);
        $filler = new FrameFiller($width, $frame);
        if(is_null($filler)) {
            return $this;
        }
        // inteleaved data and ecc codes
        for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
            $code = $raw->getCode();
            $bit = 0x80;
            for($j=0; $j<8; $j++) {
                $addr = $filler->next();
                $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
                $bit = $bit >> 1;
            }
        }
        unset($raw);
        // remainder bits
        $j = QRspec::getRemainder($version);
        for($i=0; $i<$j; $i++) {
            $addr = $filler->next();
            $filler->setFrameAt($addr, 0x02);
        }
        $frame = $filler->frame;
        unset($filler);
        // masking
        $maskObj = new QRmask();
        if($mask < 0) {
            if (QR_FIND_BEST_MASK) {
                $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
            } else {
                $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
            }
        } else {
            $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
        }
        if($masked == NULL) return $this;
        // 原本有个raw方法,返回的是此时的$masked值
        $this->version = $version;
        $this->points = $width;
        $len = count($masked);
        foreach ($masked as &$frameLine) {
            for($i=0; $i<$len; $i++) {
                $frameLine[$i] = (ord($frameLine[$i])&1)?'1':'0';
            }
        }
        // 原本有个text方法,传入$text和$outfile参数
        // 如果$outfile值有效,返回值是这里的$masked值
        // 否则则写入文件file_put_contents($outfile,join("\n",$masked));
        // 现在$text已经拆到setText方法中了
        $this->data = $masked;
        return $this;
    }
    public function setPath(string $path) : self
    {
        if($this->path===$path) return $this;
        if(!file_exists($path)) mkdir($path,0777,TRUE);
        $this->path=$path;
        return $this;
    }
    public function setLevel(int $level) : self
    {
        if($level<QR_ECLEVEL_L) $this->level=QR_ECLEVEL_L;
        elseif($level>QR_ECLEVEL_H) $this->level=QR_ECLEVEL_H;
        else $this->level=$level;
        return $this;
    }
    public function setSize(int $size) : self
    {
        $this->size=$size>1?$size:1;
        return $this;
    }
    public function setMargin(int $margin) : self
    {
        $this->margin=$margin>0?($margin<10?$margin:10):0;
        return $this;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值