반응형
이 글은 php 구현에 대해 QR코드 클래스 생성, 치수 설정 지원, LOGO 추가, 선, 필렛, 투명도 등의 처리를 소개한다.전체 코드, 데모 인스턴스 및 상세 파라미터 설명이 제공되어 학습에 편리합니다.
구현 기능은 다음과 같습니다.
1.QR코드 만들기
2.QR코드에 로고 추가
3.로고는 그릴 수 있다.
4.로고 라운드 가능
5.logo 투명도 설정 가능
6.logo 이미지 및 출력 이미지 유형은 png, jpg, gif 포맷을 지원합니다.
7.출력 이미지 품질 설정 가능
설정 매개 변수 설명:
ecc
QR 품질 L-smallest, M, Q, H-best
size
QR사이즈1-50
dest_filE
생성된 QR코드 이미지경로
quality
생성된 그림의 품질
로고
logo 경로:빈칸은 logo에 가입하지 않음을 나타냅니다.
로고_sizE
로고 사이즈, null은 QR코드 사이즈 비율에 따라 자동으로 계산됨을 나타냅니다.
logo_outline_size
로고 스트로크기null은 logo 사이즈에 비례하여 자동으로 계산됨을 나타냅니다.
logo_outline_color
로고 선 컬러
logo_opacity
로고 불투명도 0-100
로고_라디우스
로고 라운드 각도 0-30
코드는 다음과 같습니다.
PHPQRCode.class.php
<?php
require_once dirname(__FILE__)."/qrcode/qrlib.php";
/**
* PHP QR코드 클래스 만들기
* Date: 2018-03-18
* Author: fdipzone
* Version: 1.0
*
* Description:
* PHP 구현 QR코드 클래스 생성, 치수 설정 지원, 로고 추가, 필렛, 투명도 등 처리 지원。
*
* Func:
* public set_config 설정
* public generate QR코드 만들기
* private create_qrcode 순수 QR코드 그림 만들기
* private add_logo 퓨어 QR 이미지와 로고 이미지를 합쳐서
* private image_outline 그림 오브젝트에 테두리를 그리다
* private image_fillet 객체를 둥글게 처리하다
* private imagecopymerge_alpha 그림을 합쳐서 투명도를 유지하다
* private create_dirs 디렉터리 만들기
* private hex2rgb 헥스 색상 rgb 색상 변환
* private get_file_ext 그림 종류 가져오기
*/
class PHPQRCode{ // class start
/** 默认设定 */
private $_config = array(
'ecc' => 'H', // 차원 품질 L-smallest, M, Q, H-best
'size' => 15, // QR사이즈 1-50
'dest_file' => 'qrcode.png', // 만든 QR코드 경로
'quality' => 100, // 이미지 품질
'logo' => '', // logo 경로, 비어 있으면 logo가 없음을 나타냅니다
'logo_size' => null, // 로고 사이즈, null은 QR코드 사이즈 비율로 자동 계산됨을 나타냅니다
'logo_outline_size' => null, // 로고 스트로크 사이즈, null은 로고 사이즈 비례 자동 계산
'logo_outline_color' => '#FFFFFF', // 로고 선 컬러
'logo_opacity' => 100, // 로고 불투명도 0-100
'logo_radius' => 0, // 로고 라운드 각도 0-30
);
/**
* 설정
* @param Array $config 내용 설정
*/
public function set_config($config){
// 설정 허용 설정
$config_keys = array_keys($this->_config);
//들어오는 설정 가져오기, 쓰기 설정
foreach($config_keys as $k=>$v){
if(isset($config[$v])){
$this->_config[$v] = $config[$v];
}
}
}
/**
* QR코드 만들기
* @param String $data QR코드 내용
* @return String
*/
public function generate($data){
// 임시 QR코드 그림 만들기
$tmp_qrcode_file = $this->create_qrcode($data);
// 임시 QR코드 이미지와 로고 이미지를 합쳐서
$this->add_logo($tmp_qrcode_file);
// 임시 QR코드 이미지 삭제
if($tmp_qrcode_file!='' && file_exists($tmp_qrcode_file)){
unlink($tmp_qrcode_file);
}
return file_exists($this->_config['dest_file'])? $this->_config['dest_file'] : '';
}
/**
* 임시 QR코드 그림 만들기
* @param String $data QR코드 내
* @return String
*/
private function create_qrcode($data){
// 임시 QR코드 이미지
$tmp_qrcode_file = dirname(__FILE__).'/tmp_qrcode_'.time().mt_rand(100,999).'.png';
// 임시 QR코드 만들기
QRcode::png($data, $tmp_qrcode_file, $this->_config['ecc'], $this->_config['size'], 2);
// 임시 QR코드 경로 되돌리기
return file_exists($tmp_qrcode_file)? $tmp_qrcode_file : '';
}
/**
* 임시 QR코드 이미지와 로고 이미지를 합쳐서
* @param String $tmp_qrcode_file 임시 QR코드 이미지
*/
private function add_logo($tmp_qrcode_file){
// 대상 폴더 만들기
$this->create_dirs(dirname($this->_config['dest_file']));
// 대상 그림 종류 가져오기
$dest_ext = $this->get_file_ext($this->_config['dest_file']);
// 로고 가입이 필요함
if(file_exists($this->_config['logo'])){
// 임시 QR코드 그림 개체 만들기
$tmp_qrcode_img = imagecreatefrompng($tmp_qrcode_file);
//임시 QR코드 그림 크기 가져오기
list($qrcode_w, $qrcode_h, $qrcode_type) = getimagesize($tmp_qrcode_file);
// 로고 이미지 크기 및 종류 가져오기
list($logo_w, $logo_h, $logo_type) = getimagesize($this->_config['logo']);
// 로고 그림 개체 만들기
switch($logo_type){
case 1: $logo_img = imagecreatefromgif($this->_config['logo']); break;
case 2: $logo_img = imagecreatefromjpeg($this->_config['logo']); break;
case 3: $logo_img = imagecreatefrompng($this->_config['logo']); break;
default: return '';
}
// 로고 이미지 맞춤 사이즈 설정, 미설정 시 비례 자동 계산
$new_logo_w = isset($this->_config['logo_size'])? $this->_config['logo_size'] : (int)($qrcode_w/5);
$new_logo_h = isset($this->_config['logo_size'])? $this->_config['logo_size'] : (int)($qrcode_h/5);
// 설정 사이즈에 따라 로고 이미지 조정
$new_logo_img = imagecreatetruecolor($new_logo_w, $new_logo_h);
imagecopyresampled($new_logo_img, $logo_img, 0, 0, 0, 0, $new_logo_w, $new_logo_h, $logo_w, $logo_h);
// 선화가 필요한지 여부를 판단하다
if(!isset($this->_config['logo_outline_size']) || $this->_config['logo_outline_size']>0){
list($new_logo_img, $new_logo_w, $new_logo_h) = $this->image_outline($new_logo_img);
}
// 필렛 처리가 필요한지 여부를 판단하다
if($this->_config['logo_radius']>0){
$new_logo_img = $this->image_fillet($new_logo_img);
}
// 스펠링 로고와 임시 QR코드
$pos_x = ($qrcode_w-$new_logo_w)/2;
$pos_y = ($qrcode_h-$new_logo_h)/2;
imagealphablending($tmp_qrcode_img, true);
// 그림을 합쳐서 투명도를 유지하다
$dest_img = $this->imagecopymerge_alpha($tmp_qrcode_img, $new_logo_img, $pos_x, $pos_y, 0, 0, $new_logo_w, $new_logo_h, $this->_config['logo_opacity']);
// 그림 생성
switch($dest_ext){
case 1: imagegif($dest_img, $this->_config['dest_file'], $this->_config['quality']); break;
case 2: imagejpeg($dest_img, $this->_config['dest_file'], $this->_config['quality']); break;
case 3: imagepng($dest_img, $this->_config['dest_file'], (int)(($this->_config['quality']-1)/10)); break;
}
// 로고 가입 필요 없음
}else{
$dest_img = imagecreatefrompng($tmp_qrcode_file);
// 그림 생성
switch($dest_ext){
case 1: imagegif($dest_img, $this->_config['dest_file'], $this->_config['quality']); break;
case 2: imagejpeg($dest_img, $this->_config['dest_file'], $this->_config['quality']); break;
case 3: imagepng($dest_img, $this->_config['dest_file'], (int)(($this->_config['quality']-1)/10)); break;
}
}
}
/**
* 그림 오브젝트에 테두리를 그리다
* @param Obj $img 그림 객체
* @return Array
*/
private function image_outline($img){
// 그림 너비 가져오기
$img_w = imagesx($img);
$img_h = imagesy($img);
// 선 치수를 계산하고, 설정이 없으면 비례로 자동 계산
$bg_w = isset($this->_config['logo_outline_size'])? intval($img_w + $this->_config['logo_outline_size']) : $img_w + (int)($img_w/5);
$bg_h = isset($this->_config['logo_outline_size'])? intval($img_h + $this->_config['logo_outline_size']) : $img_h + (int)($img_h/5);
//밑그림 개체 만들기
$bg_img = imagecreatetruecolor($bg_w, $bg_h);
// 밑그림 색상 설정
$rgb = $this->hex2rgb($this->_config['logo_outline_color']);
$bgcolor = imagecolorallocate($bg_img, $rgb['r'], $rgb['g'], $rgb['b']);
// 밑그림 색 채우기
imagefill($bg_img, 0, 0, $bgcolor);
// 그림과 밑그림을 합쳐서 선명한 효과를 실현하다
imagecopy($bg_img, $img, (int)(($bg_w-$img_w)/2), (int)(($bg_h-$img_h)/2), 0, 0, $img_w, $img_h);
$img = $bg_img;
return array($img, $bg_w, $bg_h);
}
/**
* 그림 객체를 둥글게 처리하다
* @param Obj $img 그림 객체
* @return Obj
*/
private function image_fillet($img){
// 그림 너비 가져오기
$img_w = imagesx($img);
$img_h = imagesy($img);
// 둥근 모서리 그림 개체 만들기
$new_img = imagecreatetruecolor($img_w, $img_h);
//투명 채널 저장
imagesavealpha($new_img, true);
// 필렛 그림
$bg = imagecolorallocatealpha($new_img, 255, 255, 255, 127);
imagefill($new_img, 0, 0, $bg);
// 필렛 반경
$r = $this->_config['logo_radius'];
// 필렛 처리를 하다
for($x=0; $x<$img_w; $x++){
for($y=0; $y<$img_h; $y++){
$rgb = imagecolorat($img, $x, $y);
// 이미지 사각 범위 없이 직접 그림 그리기
if(($x>=$r && $x<=($img_w-$r)) || ($y>=$r && $y<=($img_h-$r))){
imagesetpixel($new_img, $x, $y, $rgb);
// 이미지 사각 범위에서 그림 선택
}else{
// 상좌
$ox = $r; // 원심 x 좌표
$oy = $r; // 원심 y 좌표
if( ( ($x-$ox)*($x-$ox) + ($y-$oy)*($y-$oy) ) <= ($r*$r) ){
imagesetpixel($new_img, $x, $y, $rgb);
}
// 상우
$ox = $img_w-$r; // 원심 x 좌표
$oy = $r; // 원심 y 좌표
if( ( ($x-$ox)*($x-$ox) + ($y-$oy)*($y-$oy) ) <= ($r*$r) ){
imagesetpixel($new_img, $x, $y, $rgb);
}
// 아래쪽 왼쪽
$ox = $r; // 원심 x 좌표
$oy = $img_h-$r; // 원심 y 좌표
if( ( ($x-$ox)*($x-$ox) + ($y-$oy)*($y-$oy) ) <= ($r*$r) ){
imagesetpixel($new_img, $x, $y, $rgb);
}
// 아래쪽 오른쪽
$ox = $img_w-$r; // 원심 x 좌표
$oy = $img_h-$r; //원심 y 좌표
if( ( ($x-$ox)*($x-$ox) + ($y-$oy)*($y-$oy) ) <= ($r*$r) ){
imagesetpixel($new_img, $x, $y, $rgb);
}
}
}
}
return $new_img;
}
// 그림을 합쳐서 투명도를 유지하다
private function imagecopymerge_alpha($dest_img, $src_img, $pos_x, $pos_y, $src_x, $src_y, $src_w, $src_h, $opacity){
$w = imagesx($src_img);
$h = imagesy($src_img);
$tmp_img = imagecreatetruecolor($src_w, $src_h);
imagecopy($tmp_img, $dest_img, 0, 0, $pos_x, $pos_y, $src_w, $src_h);
imagecopy($tmp_img, $src_img, 0, 0, $src_x, $src_y, $src_w, $src_h);
imagecopymerge($dest_img, $tmp_img, $pos_x, $pos_y, $src_x, $src_y, $src_w, $src_h, $opacity);
return $dest_img;
}
/**
* 디렉터리 만들기
* @param String $path
* @return Boolean
*/
private function create_dirs($path){
if(!is_dir($path)){
return mkdir($path, 0777, true);
}
return true;
}
/** 헥스 색상 rgb 색상 변환
* @param String $color hex색깔
* @return Array
*/
private function hex2rgb($hexcolor){
$color = str_replace('#', '', $hexcolor);
if (strlen($color) > 3) {
$rgb = array(
'r' => hexdec(substr($color, 0, 2)),
'g' => hexdec(substr($color, 2, 2)),
'b' => hexdec(substr($color, 4, 2))
);
} else {
$r = substr($color, 0, 1) . substr($color, 0, 1);
$g = substr($color, 1, 1) . substr($color, 1, 1);
$b = substr($color, 2, 1) . substr($color, 2, 1);
$rgb = array(
'r' => hexdec($r),
'g' => hexdec($g),
'b' => hexdec($b)
);
}
return $rgb;
}
/** 그림 종류 가져오기
* @param String $file 그림 경로
* @return int
*/
private function get_file_ext($file){
$filename = basename($file);
list($name, $ext)= explode('.', $filename);
$ext_type = 0;
switch(strtolower($ext)){
case 'jpg':
case 'jpeg':
$ext_type = 2;
break;
case 'gif':
$ext_type = 1;
break;
case 'png':
$ext_type = 3;
break;
}
return $ext_type;
}
} // class end
?>
demo.php
<?php
require 'PHPQRCode.class.php';
$config = array(
'ecc' => 'H', // L-smallest, M, Q, H-best
'size' => 12, // 1-50
'dest_file' => 'qrcode.png',
'quality' => 90,
'logo' => 'logo.jpg',
'logo_size' => 100,
'logo_outline_size' => 20,
'logo_outline_color' => '#FFFF00',
'logo_radius' => 15,
'logo_opacity' => 100,
);
// QR코드 내용
$data = 'http://weibo.com/fdipzone';
// QR코드 클래스 만들기
$oPHPQRCode = new PHPQRCode();
// 설정
$oPHPQRCode->set_config($config);
//QR코드 만들기
$qrcode = $oPHPQRCode->generate($data);
// QR코드 보이기
echo '<img src="'.$qrcode.'?t='.time().'">';
?>
반응형
'개발 꿀팁 > PHP' 카테고리의 다른 글
php redis 잠금을 사용하여 동시 액세스 제한 (0) | 2022.08.17 |
---|---|
php redis 카운터 기반 (0) | 2022.08.17 |
php XML 파일 해석 클래스 (0) | 2022.08.16 |
php 광고 로딩 클래스 (0) | 2022.08.15 |
PHP 생성 유일한 RequestID 클래스 (0) | 2022.08.15 |