PHP QR Code 改变颜色

2022年4月23日

在 php 中,我们可以通过 phpqrcode 这个库来快速生成二维码。

QRcode::png ($text, $outfile=false, $level=QR_ECLEVEL_L, $size=3, $margin=4, $saveandprint=false)

但是,官方却没有暴露出设置二维码颜色和背景颜色的方法。

查看源码

于是,我们在 phpqrcode.php 中找到 QRcode::png() 这个方法

class QRcode {
    // ...省略

    public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false) 
    {
        $enc = QRencode::factory($level, $size, $margin);
        return $enc->encodePNG($text, $outfile, $saveandprint=false);
    }

    // ...省略
}

可以看到其实调用的是 QRencode->encodePNG() 方法

class QRencode {
        // ...省略

        public function encodePNG($intext, $outfile = false,$saveandprint=false) 
        {
            try {
            
                ob_start();
                $tab = $this->encode($intext);
                $err = ob_get_contents();
                ob_end_clean();
                
                if ($err != '')
                    QRtools::log($outfile, $err);
                
                $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));

                // 找到这个位置
                QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint);
            
            } catch (Exception $e) {
            
                QRtools::log($outfile, $e->getMessage());
            
            }
        }

    // ...省略
    }

继续找到 QRimage::png()

 class QRimage {
        // ...省略

        public static function png($frame, $filename = false, $pixelPerPoint = 4, $outerFrame = 4, $saveandprint=FALSE) 
        {
            // 找到这个位置
            $image = self::image($frame, $pixelPerPoint, $outerFrame);
            if ($filename === false) {
                Header("Content-type: image/png");
                ImagePng($image);
            } else {
                if($saveandprint===TRUE){
                    ImagePng($image, $filename);
                    header("Content-type: image/png");
                    ImagePng($image);
                }else{
                    ImagePng($image, $filename);
                }
            }
            
            ImageDestroy($image);
        }

        // ...省略

        private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4) 
        {
            $h = count($frame);
            $w = strlen($frame[0]);
            
            $imgW = $w + 2*$outerFrame;
            $imgH = $h + 2*$outerFrame;
            
            $base_image =ImageCreate($imgW, $imgH);
            
            // 我们看到这里
            $col[0] = ImageColorAllocate($base_image,255,255,255); // 设置白色背景
            $col[1] = ImageColorAllocate($base_image,0,0,0); // 设置黑色内容

            imagefill($base_image, 0, 0, $col[0]);

            for($y=0; $y<$h; $y++) {
                for($x=0; $x<$w; $x++) {
                    if ($frame[$y][$x] == '1') {
                        ImageSetPixel($base_image,$x+$outerFrame,$y+$outerFrame,$col[1]); 
                    }
                }
            }
            
            $target_image =ImageCreate($imgW * $pixelPerPoint, $imgH * $pixelPerPoint);
            ImageCopyResized($target_image, $base_image, 0, 0, 0, 0, $imgW * $pixelPerPoint, $imgH * $pixelPerPoint, $imgW, $imgH);
            ImageDestroy($base_image);
            
            return $target_image;
       }
  }

解决方法

我们发现最后调用的是 QRimage::image() ,这里面就有关于二维码颜色的设置,只是官方默认设置成了“白纸黑字”,所以,我们只需修改 QRimage::image(),并添加一个设置背景颜色的参数即可,其之上的方法也添加同样的参数

// 修改 QRimage::image() 
private static function image($frame, $pixelPerPoint = 4, $outerFrame = 4, $cols = [[255,255,255],[0,0,0]]) 
 {
     // ...省略

     // 注释掉原来的
     // $col[0] = ImageColorAllocate($base_image,255,255,255); // 设置白色背景
     // $col[1] = ImageColorAllocate($base_image,0,0,0); // 设置黑色内容

     // 设置我们自己传入的颜色
     $col[0] = ImageColorAllocate($base_image,$cols[0][0],$cols[0][1],$cols[0][2]); // 设置自定义背景颜色
     $col[1] = ImageColorAllocate($base_image,$cols[1][0],$cols[1][1],$cols[1][2]); // 设置自定义内容颜色

     // ...省略
 }

// ...省略 修改 QRencode::encodePNG()
QRencode::encodePNG($intext, $outfile = false,$saveandprint=false,$cols=[]) {}

// 修改 QRcode::png()
public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $cols=[], $saveandprint=false) 
{
     $enc = QRencode::factory($level, $size, $margin);
     return $enc->encodePNG($text, $outfile, $saveandprint=false, $cols);
}

最后,我们通过生成可以变换颜色的二维码

$cols = [
    [255,255,0], // 背景颜色
    [255,0,255]  // 二维码颜色
];
// 生成二维码图片
QRcode::png($value, $qrFilePath, $errorCorrectionLevel, $matrixPointSize, $margin, $cols);

小鑫

写写代码, 掉掉头发。

文章评论