qr code生成二维码并且logo设置为圆角

2020-11-19  本文已影响0人  fly_侠

本篇介绍的是php如何创建一个带圆角logo的二维码。

前言
目前的二维码生成的库有很多,我用的是qr-code,里面有生成带logo的二维码功能,美中不足的是logo不能设置圆角,于是我就自己修改代码实现。


下载qr-code库,引入项目,qr-code的目录结构如下:


image.png

我这里修改的是PngWriter.php文件,这个文件是生成png格式的二维码,logo的添加也在里面。我们找到addLogo这个方法,添加如下代码:

// 1: 白底
        if ($imgBorderType == '1') {
            $px = 4;
            $logoImage = $this->addBorder($logoImage, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight, $px);
            $logoSourceWidth = $logoWidth + $px * 2;
            $logoSourceHeight = $logoHeight + $px * 2;
            $logoWidth = $logoWidth + $px * 2;
            $logoHeight = $logoHeight + $px * 2;
        }
        // 2: 圆角
        else if($imgBorderType == '2') {
            $radius = intval(imagesx($sourceImage) * 0.3 * 0.2);
            $logoImage = $this->addBorder($logoImage, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight);
            $logoSourceWidth = $logoWidth;
            $logoSourceHeight = $logoHeight;
            $logoImage  = $this->addRadius($logoImage, $logoWidth, $logoHeight, $radius);
        }
        // 3: 圆角白底
        else if($imgBorderType == '3') {
            $radius = intval(imagesx($sourceImage) * 0.3 * 0.2);
            $logoImage = $this->addBorder($logoImage, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight);
            $logoSourceWidth = $logoWidth;
            $logoSourceHeight = $logoHeight;
            $logoImage  = $this->addRadius($logoImage, $logoWidth, $logoHeight, $radius);
            $px = 4;
            $logoImage = $this->addBorder($logoImage, $logoWidth, $logoHeight, $logoSourceWidth, $logoSourceHeight, $px);
            $logoSourceWidth = $logoWidth + $px * 2;
            $logoSourceHeight = $logoHeight + $px * 2;
            $logoWidth = $logoWidth + $px * 2;
            $logoHeight = $logoHeight + $px * 2;
            $logoImage  = $this->addRadius($logoImage, $logoWidth, $logoHeight, $radius + $px);
        }

addBorder是添加白色边框方法:

function addBorder($img, $imgWidth, $imgHeight, $imgSourceWidth, $imgSourceHeight, $px = 0) {
        $im = imagecreatetruecolor(($imgWidth + $px * 2), ($imgHeight + $px * 2));
        if (!is_resource($im)) {
            throw new GenerateImageException('Unable to generate image: check your GD installation');
        }
        $color = imagecolorallocate($im, 255, 255, 255);
        imagefill($im, 0, 0, $color);
        imageColorTransparent($im, $color);
        imagecopyresampled($im, $img, intval($px), intval($px), 0, 0, $imgWidth, $imgHeight, $imgSourceWidth, $imgSourceHeight);
        imagedestroy($img);
        return $im;
    }

addRadius是设置圆角方法:

function addRadius($img, $imgWidth, $imgHeight, $radius = 20) {
        $im = imagecreatetruecolor($imgWidth, $imgHeight);
        //这一句一定要有
        imagesavealpha($im, true);
        $bg = imagecolorallocatealpha($im, 255, 255, 255, 127);
        imagefill($im, 0, 0, $bg);
        $widthX = $imgWidth - $radius * 2;
        $heightY = $imgHeight - $radius * 2;
        $limitX = $radius;
        $limitY = $radius;
        if ($widthX > 0) {
            imagecopyresampled($im, $img, intval($radius), intval(0), intval($radius), intval(0), $widthX, $imgHeight, $widthX, $imgHeight);
            if ($heightY > 0) {
                imagecopyresampled($im, $img, intval(0), intval($radius), intval(0), intval($radius), $radius, $heightY, $radius, $heightY);
                imagecopyresampled($im, $img, intval($imgWidth - $radius), intval($radius), intval($imgWidth - $radius), intval($radius), $radius, $heightY, $radius, $heightY);
            }
            else {
                $limitY = $imgHeight / 2;
            }
        }
        else {
            $limitX = $imgWidth / 2;
            if ($heightY > 0) {
                imagecopyresampled($im, $img, intval(0), intval($radius), intval(0), intval($radius), $imgWidth, $heightY, $imgWidth, $heightY);
            }
            else {
                $limitY = $imgHeight / 2;
            }
        }
        // 左上
        for ($x = 0; $x < $limitX; $x++) {
            for ($y = 0; $y < $limitY; $y++) {
                $y_x = $radius; //圆心X坐标
                $y_y = $radius; //圆心Y坐标
                $this->setRadius($img, $im, $x, $y, $y_x, $y_y, $radius);
            }
        }
        // 右上
        for ($x = $imgWidth - $limitX; $x < $imgWidth; $x++) {
            for ($y = 0; $y < $limitY; $y++) {
                $y_x = $imgWidth - $radius; //圆心X坐标
                $y_y = $radius; //圆心Y坐标
                $this->setRadius($img, $im, $x, $y, $y_x, $y_y, $radius);
            }
        }
        // 左下
        for ($x = 0; $x < $limitX; $x++) {
            for ($y = $imgHeight - $limitY; $y < $imgHeight; $y++) {
                $y_x = $radius; //圆心X坐标
                $y_y = $imgHeight - $radius; //圆心Y坐标
                $this->setRadius($img, $im, $x, $y, $y_x, $y_y, $radius);
            }
        }
        // 右下
        for ($x = $imgWidth - $limitX; $x < $imgWidth; $x++) {
            for ($y = $imgHeight - $limitY; $y < $imgHeight; $y++) {
                $y_x = $imgWidth -$radius; //圆心X坐标
                $y_y = $imgHeight - $radius; //圆心Y坐标
                $this->setRadius($img, $im, $x, $y, $y_x, $y_y, $radius);
            }
        }
        return $im;
    }

首页先创建一个透明的背景图,然后把logo中的像素点复制到背景图中,四个圆角部分的处理在用setRadius方法处理。

function setRadius($img, $im, $x, $y, $circleX, $circleY, $radius) {
        $val1 = ($x - $circleX) * ($x - $circleX) + ($y - $circleY) * ($y - $circleY);
        $val2 = $radius * $radius;
        $rgbColor = imagecolorat($img, $x, $y);
        if ($val1 <= $val2) {
            imagesetpixel($im, $x, $y, $rgbColor);

        }
        // 除锯齿
        if($val1 > $val2 && $val1 <= ($radius + 0.3) * ($radius + 0.3)) {
            $rgbColor = imagecolorat($img, $x, $y);
            $img_pix_array = imagecolorsforindex($im, $rgbColor);
            imagesetpixel($im, $x, $y, imagecolorallocatealpha($img, $img_pix_array['red'], $img_pix_array['green'], $img_pix_array['blue'], intval((127 - $img_pix_array['alpha']) * 0.3)));
        }
        if($val1 > ($radius + 0.3) * ($radius + 0.3) && $val1 <= ($radius + 0.7) * ($radius + 0.7)) {
            $rgbColor = imagecolorat($img, $x, $y);
            $img_pix_array = imagecolorsforindex($im, $rgbColor);
            imagesetpixel($im, $x, $y, imagecolorallocatealpha($img, $img_pix_array['red'], $img_pix_array['green'], $img_pix_array['blue'], intval((127 - $img_pix_array['alpha']) * 0.6)));
        }
        if($val1 > ($radius + 0.7) * ($radius + 0.7) && $val1 <= ($radius + 0.98) * ($radius + 0.98)) {
            $rgbColor = imagecolorat($img, $x, $y);
            $img_pix_array = imagecolorsforindex($im, $rgbColor);
            imagesetpixel($im, $x, $y, imagecolorallocatealpha($img, $img_pix_array['red'], $img_pix_array['green'], $img_pix_array['blue'], intval((127 - $img_pix_array['alpha']) * 0.8)));
        }
    }

利用圆的公式x2 + y2 <= r2判断需要绘制的像素点。如果只是绘制满足在圆上的像素点,会有很明显的锯齿效果,这里我做了一些处理,当点在圆边上的点我使用透明之后的像素点来绘制。

上一篇下一篇

猜你喜欢

热点阅读