本篇介绍的是php如何创建一个带圆角logo的二维码。
前言
目前的二维码生成的库有很多,我用的是qr-code,里面有生成带logo的二维码功能,美中不足的是logo不能设置圆角,于是我就自己修改代码实现。
下载qr-code库,引入项目,qr-code的目录结构如下:
我这里修改的是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判断需要绘制的像素点。如果只是绘制满足在圆上的像素点,会有很明显的锯齿效果,这里我做了一些处理,当点在圆边上的点我使用透明之后的像素点来绘制。