Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- bootstrap
- mod_security2 설치
- 윈도우 환경 아파치 mod_security2 설치
- usb efi 시스템 파티션 삭제
- 아파치 웹 서버의 정보 숨기기
- sha-2 root
- thumbnail 클래스
- 유튜브 플레이 리스트 저장
- postfix 설치
- PHP 정규식 예제
- PHP 구글 OTP 연동
- group_concat 구분자
- httpd.conf 보안 설정
- (using password: YES)" when trying to connect
- mariadb upgrade
- bootstrap modal
- 비밀번호정규식
- 파라미터 & 오류
- javascript
- apple push notification service (apns) is changing
- 비밀번호검증정규식
- mysqldump: Got error: 1045
- html pdf 변환
- wsl2 우분투에 docker 설치
- php 배열제거
- 윈도우 mod_security2
- modsecurity 설치
- 숫자 3자리(천단위) 마다 콤마 찍기
- php 이미지 url 검증 함수
- 자바스크립트비밀번호검증
Archives
- Today
- Total
투덜이 개발자
이미지 변환 Thumbnail 클래스 본문
반응형
이미지 변환 Thumbnail 클래스
<?php
class Thumbnail {
/**
* HEIC 파일을 JPEG로 변환
*
* ※ 주의: 서버에 ImageMagick 및 libheif 라이브러리가 설치되어 있어야 함
*
* @param string $heicFile 원본 HEIC 파일 경로
* @return string|false 변환된 JPEG 파일 경로 또는 실패 시 false
*/
public static function convertHeicToJpeg($heicFile) {
$jpgFile = preg_replace('/\.heic$/i', '.jpg', $heicFile);
$cmd = "convert " . escapeshellarg($heicFile) . " " . escapeshellarg($jpgFile);
exec($cmd, $output, $return_var);
if ($return_var === 0 && file_exists($jpgFile)) {
return $jpgFile;
} else {
error_log("[HEIC 변환 실패] 파일: $heicFile");
return false;
}
}
/**
* 썸네일 이미지 생성
*
* @param string $srcFile 원본 이미지 경로
* @param string $destFile 썸네일 저장 경로 (비우면 자동 생성)
* @param int $thumbWidth 썸네일 너비
* @param int|null $thumbHeight 썸네일 높이 (null이면 비율 유지)
* @param int $quality 저장 품질 (기본 JPEG용)
* @param bool $cropSquare 정사각형으로 크롭 여부
* @param array $watermark 워터마크 설정 [file, text, font_path, font_size, text_color, position]
* @return array|false 썸네일 정보 배열 또는 실패 시 false
*/
public static function generate(
$srcFile,
$destFile = '',
$thumbWidth = 600,
$thumbHeight = null,
$quality = 90,
$cropSquare = false,
$watermark = array()
) {
if (!file_exists($srcFile)) {
error_log("[Thumbnail Error] Source file not found: $srcFile");
error_log("[Thumbnail Error] Failed to create thumbnail for: $srcFile");
return false;
}
$size = @getimagesize($srcFile);
// HEIC 확장자 또는 MIME 검사 시 변환 시도
$ext = strtolower(pathinfo($srcFile, PATHINFO_EXTENSION));
$mime = function_exists('mime_content_type') ? mime_content_type($srcFile) : '';
if ($ext === 'heic' || $mime === 'image/heic') {
$converted = self::convertHeicToJpeg($srcFile);
if (!$converted) {
error_log("[Thumbnail Error] HEIC 변환 실패: $srcFile");
return false;
}
$srcFile = $converted;
}
$size = @getimagesize($srcFile);
if ($size === false) {
error_log("[Thumbnail Error] Invalid image size for: $srcFile");
return false;
}
$imageType = $size[2];
$orientation = 1;
$srcImage = false;
switch ($imageType) {
case IMAGETYPE_JPEG:
$srcImage = @imagecreatefromjpeg($srcFile);
if (function_exists('exif_read_data')) {
$exif = @exif_read_data($srcFile);
if (!empty($exif['Orientation'])) {
$orientation = $exif['Orientation'];
}
}
break;
case IMAGETYPE_PNG:
$srcImage = @imagecreatefrompng($srcFile);
break;
case IMAGETYPE_GIF:
$srcImage = @imagecreatefromgif($srcFile);
break;
default:
error_log("[Thumbnail Error] Unsupported image type for: $srcFile");
return false;
}
if (!$srcImage) {
error_log("[Thumbnail Error] Failed to create image resource from: $srcFile");
return false;
}
switch ($orientation) {
case 3: $srcImage = imagerotate($srcImage, 180, 0); break;
case 6: $srcImage = imagerotate($srcImage, -90, 0); break;
case 8: $srcImage = imagerotate($srcImage, 90, 0); break;
}
$width = imagesx($srcImage);
$height = imagesy($srcImage);
$targetWidth = $thumbWidth;
$targetHeight = $thumbHeight !== null ? $thumbHeight : $thumbWidth / ($width / $height);
$hasWatermark = !empty($watermark['file']) || !empty($watermark['text']);
$isRotated = ($orientation !== 1);
if ($width <= $targetWidth && $height <= $targetHeight && !$hasWatermark && !$isRotated) {
return array(
'path' => $srcFile,
'size' => filesize($srcFile),
'width' => $width,
'height' => $height
);
}
if ($cropSquare) {
$cropSize = min($width, $height);
$srcX = ($width - $cropSize) / 2;
$srcY = ($height - $cropSize) / 2;
$newWidth = $newHeight = $thumbWidth;
} else {
$srcX = 0; $srcY = 0; $cropSize = 0;
if ($width <= $targetWidth && $height <= $targetHeight) {
$newWidth = $width;
$newHeight = $height;
} else if ($thumbHeight === null) {
$newWidth = $thumbWidth;
$newHeight = $thumbWidth / ($width / $height);
} else {
$ratio = $width / $height;
if ($thumbWidth / $thumbHeight > $ratio) {
$newHeight = $thumbHeight;
$newWidth = $thumbHeight * $ratio;
} else {
$newWidth = $thumbWidth;
$newHeight = $thumbWidth / $ratio;
}
}
}
$srcW = $cropSize ? $cropSize : $width;
$srcH = $cropSize ? $cropSize : $height;
$dstImg = imagecreatetruecolor($newWidth, $newHeight);
if ($imageType == IMAGETYPE_PNG || $imageType == IMAGETYPE_GIF) {
imagecolortransparent($dstImg, imagecolorallocatealpha($dstImg, 0, 0, 0, 127));
imagealphablending($dstImg, false);
imagesavealpha($dstImg, true);
}
imagecopyresampled($dstImg, $srcImage, 0, 0, $srcX, $srcY, $newWidth, $newHeight, $srcW, $srcH);
self::applyWatermark($dstImg, $newWidth, $newHeight, $watermark);
if (empty($destFile)) {
$destFile = self::getDestFile($srcFile, $newWidth, $newHeight);
}
$success = false;
switch ($imageType) {
case IMAGETYPE_JPEG: $success = imagejpeg($dstImg, $destFile, $quality); break;
case IMAGETYPE_PNG: $success = imagepng($dstImg, $destFile); break;
case IMAGETYPE_GIF: $success = imagegif($dstImg, $destFile); break;
}
if (is_resource($srcImage)) imagedestroy($srcImage);
if (is_resource($dstImg)) imagedestroy($dstImg);
if ($success && file_exists($destFile)) {
$info = @getimagesize($destFile);
return array(
'path' => $destFile,
'size' => filesize($destFile),
'width' => $info[0],
'height' => $info[1]
);
}
return false;
}
// 워터마크 이미지 및 텍스트를 지정된 위치에 적용
/**
* 이미지에 워터마크 이미지 또는 텍스트 삽입
*
* @param resource $img GD 이미지 리소스
* @param int $imgW 이미지 너비
* @param int $imgH 이미지 높이
* @param array $watermark 워터마크 설정값
*/
private static function applyWatermark(&$img, $imgW, $imgH, $watermark) {
$position = isset($watermark['position']) ? $watermark['position'] : 'bottom-right';
$fontSize = isset($watermark['font_size']) ? $watermark['font_size'] : 12;
$textColor = isset($watermark['text_color']) ? $watermark['text_color'] : array(255,255,255);
if (!empty($watermark['file']) && file_exists($watermark['file'])) {
$wmImg = @imagecreatefrompng($watermark['file']);
if ($wmImg) {
$wmW = imagesx($wmImg);
$wmH = imagesy($wmImg);
list($x, $y) = self::getWatermarkPosition($position, $imgW, $imgH, $wmW, $wmH);
imagecopy($img, $wmImg, $x, $y, 0, 0, $wmW, $wmH);
imagedestroy($wmImg);
}
}
if (!empty($watermark['text']) && !empty($watermark['font_path']) && file_exists($watermark['font_path'])) {
$color = imagecolorallocate($img, $textColor[0], $textColor[1], $textColor[2]);
$bbox = imagettfbbox($fontSize, 0, $watermark['font_path'], $watermark['text']);
$textW = abs($bbox[2] - $bbox[0]);
$textH = abs($bbox[7] - $bbox[1]);
list($x, $y) = self::getWatermarkPosition($position, $imgW, $imgH, $textW, $textH);
$y += $textH;
imagettftext($img, $fontSize, 0, $x, $y, $color, $watermark['font_path'], $watermark['text']);
}
}
// 워터마크 위치 계산
/**
* 워터마크 삽입 위치 계산
*
* @param string $position 위치 (top-left, top-right, center, bottom-left, bottom-right)
* @param int $imgW 이미지 너비
* @param int $imgH 이미지 높이
* @param int $markW 워터마크 너비
* @param int $markH 워터마크 높이
* @return array [x, y] 좌표값
*/
private static function getWatermarkPosition($position, $imgW, $imgH, $markW, $markH) {
switch (strtolower($position)) {
case 'top-left': return array(10, 10);
case 'top-right': return array($imgW - $markW - 10, 10);
case 'center': return array(($imgW - $markW) / 2, ($imgH - $markH) / 2);
case 'bottom-left': return array(10, $imgH - $markH - 10);
case 'bottom-right':
default: return array($imgW - $markW - 10, $imgH - $markH - 10);
}
}
// 썸네일 저장 경로 자동 생성
/**
* 썸네일 저장 파일 경로 자동 생성
*
* @param string $srcFile 원본 이미지 경로
* @param int $w 최종 저장될 이미지 너비
* @param int $h 최종 저장될 이미지 높이
* @return string 저장될 썸네일 경로
*/
private static function getDestFile($srcFile, $w, $h) {
$srcDir = dirname($srcFile);
$srcName = pathinfo($srcFile, PATHINFO_FILENAME);
$srcExt = pathinfo($srcFile, PATHINFO_EXTENSION);
$thumbDir = $srcDir . '/thumb';
if (!is_dir($thumbDir)) @mkdir($thumbDir, 0755, true);
return "$thumbDir/{$srcName}_" . intval($w) . "x" . intval($h) . ".{$srcExt}";
}
}
/*
사용 예시:
1. 기본 썸네일 생성 (600px 너비 기준)
$result = Thumbnail::generate('/upload/photo.jpg');
2. 썸네일 너비 지정 + 크롭
$result = Thumbnail::generate('/upload/photo.jpg', '', 300, null, 90, true);
3. 워터마크 이미지 또는 텍스트 삽입
$result = Thumbnail::generate('/upload/photo.jpg', '', 300, null, 90, false, array(
'file' => '/upload/logo.png',
'text' => '엠투',
'font_path' => '/fonts/NotoSansKR-Regular.ttf',
'font_size' => 14,
'text_color' => array(255,255,255),
'position' => 'bottom-right'
));
리턴값 예시:
Array
(
[path] => /upload/thumb/photo_300x200.jpg
[size] => 21503
[width] => 300
[height] => 200
)
*/
?>
반응형
'Program Language > PHP' 카테고리의 다른 글
WSL(우분투) 환경에 Laravel(라라벨) 11 설치 (1) | 2025.05.19 |
---|---|
[php] 라라벨 설치 (0) | 2025.04.25 |
[PHP] 파일 다운로드 함수 (0) | 2025.03.27 |
PHP 5.3.27 구버전 에디터 내 base64 인코딩 이미지 파일로 저장하기 (0) | 2025.02.07 |
preg_match_all 길이 문제 (0) | 2025.02.07 |