本篇介紹的是php如何創(chuàng)建一個(gè)帶圓角logo的二維碼。
前言
目前的二維碼生成的庫有很多,我用的是qr-code,里面有生成帶logo的二維碼功能,美中不足的是logo不能設(shè)置圓角,于是我就自己修改代碼實(shí)現(xiàn)。
下載qr-code庫,引入項(xiàng)目,qr-code的目錄結(jié)構(gòu)如下:

image.png
我這里修改的是PngWriter.php文件,這個(gè)文件是生成png格式的二維碼,logo的添加也在里面。我們找到addLogo這個(gè)方法,添加如下代碼:
// 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是設(shè)置圓角方法:
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坐標(biāo)
$y_y = $radius; //圓心Y坐標(biāo)
$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坐標(biāo)
$y_y = $radius; //圓心Y坐標(biāo)
$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坐標(biāo)
$y_y = $imgHeight - $radius; //圓心Y坐標(biāo)
$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坐標(biāo)
$y_y = $imgHeight - $radius; //圓心Y坐標(biāo)
$this->setRadius($img, $im, $x, $y, $y_x, $y_y, $radius);
}
}
return $im;
}
首頁先創(chuàng)建一個(gè)透明的背景圖,然后把logo中的像素點(diǎn)復(fù)制到背景圖中,四個(gè)圓角部分的處理在用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判斷需要繪制的像素點(diǎn)。如果只是繪制滿足在圓上的像素點(diǎn),會(huì)有很明顯的鋸齒效果,這里我做了一些處理,當(dāng)點(diǎn)在圓邊上的點(diǎn)我使用透明之后的像素點(diǎn)來繪制。