2025. 7. 27. 19:47ㆍ프로그램/PHP 중급
📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 04 이미지 리사이징 및 썸네일 생성 (GD 라이브러리)

이번 #PHP 중급 4주차에서는 #파일 업로드된 #이미지를 다루는 방법을 알아봅니다. 특히 #GD 라이브러리를 활용하여 이미지 #리사이징 및 #썸네일 생성하는 과정에 초점을 맞출 거예요. 웹 애플리케이션에서 사용자에게 다양한 크기의 이미지를 제공하거나, 페이지 로딩 속도를 최적화할 때 이미지 리사이징은 필수적인 기술이죠.
1. GD 라이브러리 이해하기

#GD 라이브러리는 PHP에서 이미지를 동적으로 생성하고 조작할 수 있도록 해주는 강력한 도구입니다. 서버에 #PHP와 함께 GD 라이브러리가 설치되어 있어야만 사용할 수 있어요. 대부분의 웹 호스팅 환경에는 기본적으로 설치되어 있지만, 혹시 작동하지 않는다면 서버 관리자에게 문의하거나 phpinfo() 함수를 통해 GD 라이브러리 활성화 여부를 확인할 수 있습니다.
GD 라이브러리는 다양한 이미지 형식을 지원하는데요, 주로 #JPEG, #PNG, #GIF 등의 형식을 다룰 수 있습니다. 각 형식에 맞는 함수를 사용하여 이미지를 읽고 쓸 수 있죠.
2. 이미지 리사이징 기본 원리

#이미지 리사이징은 원본 이미지의 크기를 변경하여 새로운 이미지를 생성하는 과정입니다. GD 라이브러리에서는 주로 다음과 같은 단계를 거쳐 이루어집니다.
- #원본 이미지 로드: imagecreatefromjpeg(), imagecreatefrompng(), imagecreatefromgif() 등 원본 이미지 형식에 맞는 함수를 사용하여 이미지를 메모리에 로드합니다. 이 함수들은 #이미지 리소스를 반환합니다.
- #새로운 캔버스 생성: imagecreatetruecolor() 함수를 사용하여 리사이징될 이미지의 새로운 폭과 높이를 가진 빈 캔버스를 생성합니다. 이 캔버스도 이미지 리소스 형태로 반환됩니다.
- #이미지 복사 및 리샘플링: imagecopyresampled() 함수를 사용하여 원본 이미지 리소스의 특정 부분을 새로운 캔버스에 복사하면서 동시에 크기를 조절합니다. 이 함수는 이미지 품질을 유지하면서 크기를 변경하는 데 매우 중요합니다.
- #새로운 이미지 저장: imagejpeg(), imagepng(), imagegif() 등 원하는 출력 형식에 맞는 함수를 사용하여 새로 생성된 이미지를 파일로 저장하거나 브라우저에 직접 출력합니다.
- #메모리 해제: imagedestroy() 함수를 사용하여 사용이 끝난 이미지 리소스를 메모리에서 해제합니다. 이는 서버 자원을 효율적으로 관리하는 데 중요합니다.
3. 이미지 리사이징 및 썸네일 생성 코드 구현

이제 실제 코드를 통해 이미지 #리사이징과 #썸네일 생성 과정을 살펴보겠습니다. 여기서는 간단한 파일 업로드 후 즉시 #썸네일을 생성하는 시나리오를 가정합니다.
<?php
// 업로드된 파일이 있는지 확인
if (isset($_FILES['uploadFile'])) {
$uploadDir = 'uploads/'; // 이미지가 저장될 디렉토리
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0777, true); // 디렉토리가 없으면 생성
}
$fileName = $_FILES['uploadFile']['name'];
$fileTmpName = $_FILES['uploadFile']['tmp_name'];
$fileSize = $_FILES['uploadFile']['size'];
$fileError = $_FILES['uploadFile']['error'];
$fileType = $_FILES['uploadFile']['type'];
$fileExt = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
$allowedExt = ['jpg', 'jpeg', 'png', 'gif'];
// 허용된 확장자인지 확인
if (in_array($fileExt, $allowedExt)) {
if ($fileError === 0) {
if ($fileSize < 5000000) { // 5MB 미만
$fileNewName = uniqid('', true) . '.' . $fileExt;
$fileDestination = $uploadDir . $fileNewName;
// 파일 업로드
if (move_uploaded_file($fileTmpName, $fileDestination)) {
echo "파일이 성공적으로 업로드되었습니다: " . $fileNewName . "<br>";
// --- 이미지 리사이징 및 썸네일 생성 시작 ---
$thumbDir = 'thumbnails/'; // 썸네일이 저장될 디렉토리
if (!is_dir($thumbDir)) {
mkdir($thumbDir, 0777, true); // 디렉토리가 없으면 생성
}
$thumbWidth = 200; // 썸네일 폭
$thumbHeight = 200; // 썸네일 높이
// 원본 이미지 로드
$sourceImage = null;
if ($fileExt == 'jpg' || $fileExt == 'jpeg') {
$sourceImage = imagecreatefromjpeg($fileDestination);
} elseif ($fileExt == 'png') {
$sourceImage = imagecreatefrompng($fileDestination);
} elseif ($fileExt == 'gif') {
$sourceImage = imagecreatefromgif($fileDestination);
}
if ($sourceImage) {
$sourceWidth = imagesx($sourceImage);
$sourceHeight = imagesy($sourceImage);
// 비율 유지하며 썸네일 크기 계산
$ratio = max($thumbWidth / $sourceWidth, $thumbHeight / $sourceHeight);
$newWidth = $sourceWidth * $ratio;
$newHeight = $sourceHeight * $ratio;
// 새로운 캔버스 생성
$thumbImage = imagecreatetruecolor($thumbWidth, $thumbHeight);
// 투명도 유지 (PNG, GIF의 경우)
if ($fileExt == 'png' || $fileExt == 'gif') {
imagealphablending($thumbImage, false);
imagesavealpha($thumbImage, true);
$transparent = imagecolorallocatealpha($thumbImage, 255, 255, 255, 127);
imagefilledrectangle($thumbImage, 0, 0, $thumbWidth, $thumbHeight, $transparent);
}
// 이미지 복사 및 리샘플링 (비율에 맞춰 중앙 크롭 또는 여백 추가)
// 여기서는 간단하게 비율에 맞춰 줄이고, 썸네일 크기에 맞춰 중앙을 잘라내는 방식으로 구현
$sourceX = ($newWidth - $thumbWidth) / 2 / $ratio;
$sourceY = ($newHeight - $thumbHeight) / 2 / $ratio;
imagecopyresampled(
$thumbImage, // 목적 이미지 (새로운 캔버스)
$sourceImage, // 원본 이미지
0, // 목적 X 좌표
0, // 목적 Y 좌표
$sourceX, // 원본 X 좌표
$sourceY, // 원본 Y 좌표 (크롭을 위한 계산)
$thumbWidth, // 목적 폭
$thumbHeight, // 목적 높이
$sourceWidth, // 원본 폭
$sourceHeight // 원본 높이
);
// 썸네일 저장
$thumbFileName = 'thumb_' . $fileNewName;
$thumbDestination = $thumbDir . $thumbFileName;
if ($fileExt == 'jpg' || $fileExt == 'jpeg') {
imagejpeg($thumbImage, $thumbDestination, 90); // 90은 품질 (0-100)
} elseif ($fileExt == 'png') {
imagepng($thumbImage, $thumbDestination, 9); // 9는 압축 레벨 (0-9)
} elseif ($fileExt == 'gif') {
imagegif($thumbImage, $thumbDestination);
}
echo "썸네일이 성공적으로 생성되었습니다: " . $thumbFileName . "<br>";
// 메모리 해제
imagedestroy($sourceImage);
imagedestroy($thumbImage);
} else {
echo "지원하지 않는 이미지 형식입니다.<br>";
}
// --- 이미지 리사이징 및 썸네일 생성 끝 ---
} else {
echo "파일 업로드에 실패했습니다.<br>";
}
} else {
echo "파일 크기가 너무 큽니다 (5MB 제한).<br>";
}
} else {
echo "파일 업로드 중 오류가 발생했습니다: " . $fileError . "<br>";
}
} else {
echo "허용되지 않는 파일 확장자입니다.<br>";
}
} else {
echo "파일을 업로드해주세요.<br>";
}
?>
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile">
<button type="submit">업로드</button>
</form>
4. 코드 설명 및 추가 고려사항

위 코드는 다음과 같은 단계를 거쳐 이미지 리사이징 및 썸네일 생성을 수행합니다.
- #파일 업로드 처리: $_FILES 전역 변수를 사용하여 업로드된 파일의 정보를 얻고, 지정된 디렉토리로 파일을 이동시킵니다.
- #이미지 형식 감지: pathinfo()와 in_array()를 사용하여 업로드된 파일의 확장자를 확인하고, GD 라이브러리가 지원하는 이미지 형식인지 판별합니다.
- #원본 이미지 로드: imagecreatefromjpeg(), imagecreatefrompng(), imagecreatefromgif() 중 적절한 함수를 사용하여 원본 이미지를 메모리에 로드합니다.
- #썸네일 크기 및 비율 계산: imagesx()와 imagesy()로 원본 이미지의 폭과 높이를 가져온 후, 원하는 썸네일 크기(thumbWidth, thumbHeight)에 맞게 #비율을 유지하며 새로운 폭과 높이를 계산합니다. 여기서는 썸네일 영역을 채우면서 원본 비율을 유지하기 위해 #중앙 크롭 방식을 사용하도록 imagecopyresampled의 원본 X/Y 좌표를 조절했습니다.
- #새로운 이미지 캔버스 생성: imagecreatetruecolor() 함수로 썸네일 크기의 빈 이미지를 생성합니다.
- #투명도 유지: PNG나 GIF와 같이 투명도를 지원하는 이미지의 경우, imagealphablending(false)와 imagesavealpha(true)를 설정하여 투명 배경이 손상되지 않도록 처리합니다.
- #이미지 복사 및 리샘플링: imagecopyresampled() 함수가 핵심입니다. 이 함수는 원본 이미지의 픽셀을 새로운 캔버스에 복사하면서 동시에 크기를 조절하고, 픽셀 보간(interpolation)을 통해 이미지 품질을 향상시킵니다.
- #썸네일 저장: imagejpeg(), imagepng(), imagegif() 함수를 사용하여 썸네일을 thumbnails/ 디렉토리에 저장합니다. JPEG의 경우 품질을, PNG의 경우 압축률을 지정할 수 있습니다.
- #메모리 해제: imagedestroy()를 통해 사용된 이미지 리소스를 반드시 해제하여 메모리 누수를 방지해야 합니다.
추가 고려사항:

- #보안: 파일 업로드 시에는 반드시 파일 확장자, MIME 타입 검사, 파일 크기 제한 등 #보안 검증을 철저히 해야 합니다. 악성 파일 업로드를 방지하기 위함입니다.
- #오류 처리: 파일 업로드 및 이미지 처리 과정에서 발생할 수 있는 다양한 #오류에 대한 예외 처리를 강화해야 합니다.
- #대용량 이미지 처리: 매우 큰 이미지를 처리할 때는 메모리 제한 문제를 고려해야 합니다. 필요에 따라 PHP의 memory_limit 설정을 조정하거나, 더 효율적인 이미지 처리 라이브러리(예: ImageMagick)를 검토할 수 있습니다.
- #비동기 처리: 대량의 이미지 업로드 및 리사이징이 필요한 경우, 사용자 경험을 위해 이미지 처리를 #백그라운드에서 비동기적으로 처리하는 방안을 고려할 수 있습니다.
이번 주차에서는 #GD 라이브러리를 활용한 이미지 #리사이징 및 #썸네일 생성의 기초를 다뤄봤습니다. 이 기술은 실제 웹 서비스에서 이미지 처리 기능을 구현하는 데 핵심적인 역할을 할 거예요.
'프로그램 > PHP 중급' 카테고리의 다른 글
| 📚 PHP 중급 - 5주차: PHP 객체 지향 프로그래밍 (OOP) 기초 - 02 생성자 (__construct) (0) | 2025.07.29 |
|---|---|
| 📚 PHP 중급 - 5주차: PHP 객체 지향 프로그래밍 (OOP) 기초 - 01 클래스, 객체, 속성, 메서드 (0) | 2025.07.28 |
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 03 업로드된 파일 유효성 검사 (확장자, 크기) (0) | 2025.07.26 |
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 02 $_FILES 슈퍼 글로벌 변수 (0) | 2025.07.25 |
| 📚 PHP 중급 - 4주차: 파일 업로드 및 이미지 처리 - 01 HTML 폼을 이용한 파일 업로드 (0) | 2025.07.24 |