[PHP] 샤픈 효과를 적용한 썸네일 생성함수
이전에 만들었던 썸네일 관련 함수의 기능도 문제지만 썸네일의 품질이 너무 마음에 들지 않아 또 삽질을 시작!!
이번 함수의 가장 큰 특징은 썸네일에 샤픈 효과를 적용해 이미지 품질이 많이 좋아졌다는 것이다. 다만 적용된
일부 함수때문에 PHP4에서는 사용할 수 없다. 제대로 사용하기 위해서는 PHP 5.2 이상이어야 할 것이다.
<?php
$source_file = ‘./DSC_4180.jpg’;
$target_file = ‘./resize_DSC_4180.jpg’;
$target_file2 = ‘./resize2_DSC_4180.jpg’;
$result = pl_resizer($source_file, $target_file, 100, 100, true, ‘center’, true);
$result2 = pl_resizer($source_file, $target_file2, 100, 100, true, ‘center’);
?>
<!doctype html>
<html lang=”ko”>
<head>
<meta charset=”utf-8″>
<title>리사이징 테스트</title>
</head>
<body>
<table cellpadding=”10″ cellspacing=”0″ align=”center”>
<tr>
<td><img src=”<?php echo $result; ?>” /></td>
<td><img src=”<?php echo $result2; ?>” /></td>
</tr>
</table>
</body>
</html>
<?php
function pl_resizer($source_file, $target_file, $width=0, $height=0, $is_crop=false, $crop_mode=’center’, $step_resize=false)
{
$size = @getimagesize($source_file);
// gif, jpg, png 에 대해서만 적용
if($size[2] < 1 || $size[2] > 3)
return;
// Animated GIF 체크
if($size[2] == 1) {
if(is_animated_gif($source_file))
return;
}
if($width) {
if($height) {
if($size[0] < $width || $size[1] < $height)
return;
} else {
$height = round(($width * $size[1]) / $size[0]);
}
} else {
if($height) {
$width = round(($height * $size[0]) / $size[1]);
} else {
return;
}
}
$src = null;
if ($size[2] == 1) {
$src = imagecreatefromgif($source_file);
} else if ($size[2] == 2) {
$src = imagecreatefromjpeg($source_file);
} else if ($size[2] == 3) {
$src = imagecreatefrompng($source_file);
} else {
return;
}
$dst_x = 0;
$dst_y = 0;
$src_x = 0;
$src_y = 0;
$dst_w = $width;
$dst_h = $height;
$src_w = $size[0];
$src_h = $size[1];
$ratio = $dst_h / $dst_w;
// 크롭처리
if($is_crop) {
switch($crop_mode)
{
case ‘center’:
if($size[1] / $size[0] >= $ratio) {
$src_h = round($src_w * $ratio);
$src_y = round(($size[1] – $src_h) / 2);
} else {
$src_w = round($size[1] / $ratio);
$src_x = round(($size[0] – $src_w) / 2);
}
break;
default:
if($size[1] / $size[0] >= $ratio) {
$src_h = round($src_w * $ratio);
} else {
$src_w = round($size[1] / $ratio);
}
break;
}
} else {
if($size[1] / $size[0] >= $ratio) {
$src_h = round($src_w * $ratio);
} else {
$src_w = round($size[1] / $ratio);
}
}
/* sharpen 설정 */
$sharpenMatrix = array
(
array(-1.2, -1, -1.2),
array(-1, 20, -1),
array(-1.2, -1, -1.2)
);
// calculate the sharpen divisor
$divisor = array_sum(array_map(‘array_sum’, $sharpenMatrix));
$offset = 0;
/* sharpen 설정 */
/* 다단계 리사이즈 시작 */
if($step_resize)
{
$w = $dst_w;
$w_count = 0;
while(1) {
$w = $w * 2;
if($w >= $src_w)
break;
$w_count++;
}
$h = $dst_h;
$h_count = 0;
while(1) {
$h = $h * 2;
if($h >= $src_h)
break;
$h_count++;
}
$resize_count = min($w_count, $h_count);
if($resize_count > 1) {
$dst_w = round($src_w / 2);
$dst_h = round($src_h / 2);
} else {
$dst_w = $width;
$dst_h = $height;
}
$count = 0;
while($count<=$resize_count)
{
$dst = imagecreatetruecolor($dst_w, $dst_h);
imagecopyresampled($dst, $src, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
$src = $dst;
$src_x = 0;
$src_y = 0;
$src_w = $dst_w;
$src_h = $dst_h;
$dst_w = round($src_w / 2);
$dst_h = round($src_h / 2);
if($dst_w <= $width || $dst_h <= $height) {
$dst_w = $width;
$dst_h = $height;
}
$count++;
}
}
/* 다단계 리사이즈 끝 */
else
{
$dst = imagecreatetruecolor($dst_w, $dst_h);
imagecopyresampled($dst, $src, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
}
/* sharpen 적용 */
imageconvolution($dst, $sharpenMatrix, $divisor, $offset);
imagejpeg($dst, $target_file, 90);
return $target_file;
}
function is_animated_gif($filename) {
if(!($fh = @fopen($filename, ‘rb’)))
return false;
$count = 0;
// 출처 : http://www.php.net/manual/en/function.imagecreatefromgif.php#104473
// an animated gif contains multiple “frames”, with each frame having a
// header made up of:
// * a static 4-byte sequence (x00x21xF9x04)
// * 4 variable bytes
// * a static 2-byte sequence (x00x2C) (some variants may use x00x21 ?)
// We read through the file til we reach the end of the file, or we’ve found
// at least 2 frame headers
while(!feof($fh) && $count < 2) {
$chunk = fread($fh, 1024 * 100); //read 100kb at a time
$count += preg_match_all(‘#x00x21xF9x04.{4}x00(x2C|x21)#s’, $chunk, $matches);
}
fclose($fh);
return $count > 1;
}
//include this file whenever you have to use imageconvolution…
//you can use in your project, but keep the comment below 🙂
//great for any image manipulation library
//Made by Chao Xu(Mgccl) 2/28/07
//www.webdevlogs.com
//V 1.0
if(!function_exists(‘imageconvolution’)){
function imageconvolution($src, $filter, $filter_div, $offset){
if ($src==NULL) {
return 0;
}
$sx = imagesx($src);
$sy = imagesy($src);
$srcback = ImageCreateTrueColor ($sx, $sy);
ImageCopy($srcback, $src,0,0,0,0,$sx,$sy);
if($srcback==NULL){
return 0;
}
#FIX HERE
#$pxl array was the problem so simply set it with very low values
$pxl = array(1,1);
#this little fix worked for me as the undefined array threw out errors
for ($y=0; $y<$sy; ++$y){
for($x=0; $x<$sx; ++$x){
$new_r = $new_g = $new_b = 0;
$alpha = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_a = $alpha >> 24;
for ($j=0; $j<3; ++$j) {
$yv = min(max($y – 1 + $j, 0), $sy – 1);
for ($i=0; $i<3; ++$i) {
$pxl = array(min(max($x – 1 + $i, 0), $sx – 1), $yv);
$rgb = imagecolorat($srcback, $pxl[0], $pxl[1]);
$new_r += (($rgb >> 16) & 0xFF) * $filter[$j][$i];
$new_g += (($rgb >> 8) & 0xFF) * $filter[$j][$i];
$new_b += ($rgb & 0xFF) * $filter[$j][$i];
}
}
$new_r = ($new_r/$filter_div)+$offset;
$new_g = ($new_g/$filter_div)+$offset;
$new_b = ($new_b/$filter_div)+$offset;
$new_r = ($new_r > 255)? 255 : (($new_r < 0)? 0:$new_r);
$new_g = ($new_g > 255)? 255 : (($new_g < 0)? 0:$new_g);
$new_b = ($new_b > 255)? 255 : (($new_b < 0)? 0:$new_b);
$new_pxl = ImageColorAllocateAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
if ($new_pxl == -1) {
$new_pxl = ImageColorClosestAlpha($src, (int)$new_r, (int)$new_g, (int)$new_b, $new_a);
}
if (($y >= 0) && ($y < $sy)) {
imagesetpixel($src, $x, $y, $new_pxl);
}
}
}
imagedestroy($srcback);
return 1;
}
}
?>
아직 완성된 함수는 아니다. 예외처리 등의 코드를 더 추가해야하는데.. 간단히 테스트해볼 정도는 된다. 샤픈 효과에
더불어 다단계 리사이즈 기능을 구현해보려고 삽질을 했는데.. 제대로 된 것인지는 모르겠다. 작동은 하는데.. 뭔가
이미지 품질에서 차이가 없다고 해야할까? 결과물만 보면 굳이 다단계 리사이즈라는 게 필요할까 싶은 생각도 든다.
암튼 좀 더 함수를 다듬어야 한다. 근데.. 이건 또 언제할지.. ㅋ 퇴근 후에 해야하는 것이라 여유가 많지 않다.