기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기1 > 개발강좌

개발강좌

프로그램 강좌 :
1. 유창화님의 썸네일, 정규표현식, 이미지관련 강좌
2. Sphinx 검색엔진을 이용한 도로명 주소 검색 시스템 구축

기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기1 정보

썸네일 기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기1

본문

대단할것은 없는 강좌이지만,
제 강좌를 출처를 밝히고 외부로 퍼가는 것은 허용하지만,
다른 강좌의 자료나 책의 자료로 사용되거나 부분적인 인용은 허용하지 않습니다.

강좌는 php 5. 대를 기준으로 하며, 기본적으로 GD 나 FREETYPE 등의 기본적인 라이브러리는 연동되었다는 가정하에 진행합니다.
예전 개발 환경에서는 GD 나 FREETYPE 등의 연동여부나 php버젼들을 따졌지만, 요새 개발 환경에서는 대부분 기본적으로 다 제공하기 때문에 그렇습니다.

기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기1

이전에는 리사이즈 처리에 필요한 함수를 만들어 보았습니다.
이번에는 기준점에 따른 이미지 크롭을 처리해보도록 하겠습니다.

이미지 크롭은 활용하기에 따라 다양한 것이 있겠지만, 주로 사용되는 것에는 원본이미지에 대한 썸네일을 만들때 원본이미지의 너비에 대한 높이의 비율과 썸네일의 너비와 높이의 비율이 다를때 강제로 리사이즈 해서 보여주지 않고 가운데를 중심으로 잘라서 보여주던지 상단이나 하단, 왼쪽, 오른쪽 을 기준으로 잘라서 리사이즈 해서 보여줄때 사용됩니다.

이미지 크롭을 처리하기 위해서는 별다른 추가의 함수가 필요한것이 아니라 기존에 다루었던 내용만으로 가능합니다.

이번것을 읽기 이전에 이전내용들은 한번 더 읽어보는것이 이번 내용을 이해하는데 도움이 되리라 생각합니다.

아래의 문제를 보고 그것을 해결해나가는 과정을 통해 이미지 크롭에 대해 부분적으로 이해하고자 합니다.

문제1>  너비가 1280이고 높이가 960인 test.jpg라는 원본 이미지가 있습니다.
이 이미지를 상단 왼쪽 꼭지점 부터 800 에 800 만큼을 잘라내서, 이것을 300에 300 짜리로 리사이즈 하여 test_crop.jpg로 저장하세요.

처리과정>
1. 먼저 원본이미지로 부터 get_image_resource_from_file 함수를 통해 이미지 리소스를 가져온다.
  ==> 함수내부에서 원본이미지가 존재하는지, 파일인지, 이미지 파일인지, 지원하는 이미지타입인지 체크하므로 별도의 체크는 필요없습니다.

2. 최종 생성될 이미지(썸네일이미지)의 리소스를 imagecreatetruecolor 함수를 통해 생성합니다.

3. 원본이미지의 특정부분(왼쪽 꼭지점부터 800 X 800)을 원하는 크기(300 X 300) 로 리사이즈 하여 복사합니다.

4. 복사된 썸네일 이미지의 리소스를 test_crop.jpg 로 저장합니다.

처리과정에서 살펴보았듯이 위 문제를 처리하기위해선 1번 부터 4번까지의 과정이 필요합니다.
모두 이전에 익힌 내용이지만, 3번은 좀 더 이해가 필요하리라 생각됩니다.

이전 내용의 함수 설명에서 나온것을 다시 인용한다면
imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
설명 : 원본을 복사하여 크기를 리사이즈 한후에 GD 라이브러리가 이미지를 재구성하여 복사본을 만듭니다. 성공시에는 true, 실패시에는 false 를 반환합니다.

인자 :
  $dst_image -> 복사본으로 만들어질 이미지의 리소스
  $src_image -> 원본 이미지의 리소스
  $dst_x -> 복사본에 복사할 시작점의 x좌표
  $dst_y -> 복사본에 복사할 시작점의 y좌표
  $src_x -> 원본에서 복사되어질 부분의 시작점의 x좌표
  $src_y -> 원본에서 복사되어질 부분의 시작점의 y좌표
  $dst_w -> 복사본 이미지의 너비
  $dst_h -> 복사본 이미지의 높이
  $src_w -> 원본 이미지의 너비
  $src_h -> 원본 이미지의 높이

와 같습니다.

이전 내용에서는 리사이즈처리의 이해를 쉽게 하기 위해서 인자설명을
$dst_w -> 복사본 이미지의 너비
$dst_h -> 복사본 이미지의 높이
$src_w -> 원본 이미지의 너비
$src_h -> 원본 이미지의 높이

와 같이 했지만 정확한 설명은

$dst_w -> 복사본 이미지의 복사될 너비
$dst_h -> 복사본 이미지의 복사될 높이
$src_w -> 원본 이미지의 복사할 너비
$src_h -> 원본 이미지의 복사할 높이입니다.

이전 리사이즈에서는 모든 영역을 다 복사하고 복사받기 때문에 전체 크기로 설명하였습니다.

$dst_x, $dst_y 은 위의 설명에서도 나와있듯이 썸네일의 복사되는 시작점의 좌표를 나타냅니다. 썸네일 이미지의 전체 영역에 복사되는 것이므로 당연히 0, 0입니다.

$src_x, $src_y 은 위의 설명에서도 나와있듯이 원본에서 복사할 시작점의 좌표를 나타냅니다. 문제에서 상단 왼쪽 꼭지점부터 라는 말이 있으므로 당연히 0, 0 입니다.

아래 예제는 이전 test6.php에 이미지 크롭하는 부분만을 추가하여 비교 테스트 한것입니다.

예제1> test7.php
<?php

//이미지 처리 함수 인클루드
include_once 'lib/image_proc.function.php';

$path_file = 'sample_image/test.jpg';//원본파일

$path_resizefile1 = 'sample_image/test_resize_4.jpg';//리사이즈되어 저장될 파일 경로, 크롭 리사이즈 이미지와 비교를 위함
$path_resizefile2 = 'sample_image/test_resize_5.jpg';//리사이즈되어 저장될 파일 경로, 크롭 리사이즈 이미지와 비교를 위함
$path_resizefile3 = 'sample_image/test_resize_6.jpg';//리사이즈되어 저장될 파일 경로, 크롭 리사이즈 이미지와 비교를 위함
$path_cropfile = 'sample_image/test_crop.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로



$src_x = 0;//원본의 복사 시작점 x좌표
$src_y = 0;//원본의 복사 시작점 y좌표

$src_crop_w = 800;//원본의 복사될 너비
$src_crop_h = 800;//원본의 복사될 높이

$dst_w = 300;//만들어질 이미지의 너비 지정, 픽셀단위의 0이상의 정수를 지정
$dst_h = 300;//만들어질 이미지의 높이 지정, 픽셀단위의 0이상의 정수를 지정



//이미지 리소스를 받아온다.
list($src, $src_w, $src_h) = get_image_resource_from_file ($path_file);
if (empty($src)) die($GLOBALS['errormsg'] . "<br />\n");

//너비를 기준으로 정비율 생성
$dst1 = get_image_resize($src, $src_w, $src_h, $dst_w);
if ($dst1 === false) die($GLOBALS['errormsg'] . "<br />\n");

$result_save1 = save_image_from_resource ($dst1, $path_resizefile1);//저장
if ($result_save1 === false) die($GLOBALS['errormsg'] . "<br />\n");

//높이를 기준으로 정비율 생성
$dst2 = get_image_resize($src, $src_w, $src_h, 0, $dst_h);
if ($dst2 === false) die($GLOBALS['errormsg'] . "<br />\n");

$result_save2 = save_image_from_resource ($dst2, $path_resizefile2);//저장
if ($result_save2 === false) die($GLOBALS['errormsg'] . "<br />\n");

//강제 생성
$dst3 = get_image_resize($src, $src_w, $src_h, $dst_w, $dst_h);
if ($dst3 === false) die($GLOBALS['errormsg'] . "<br />\n");

$result_save3 = save_image_from_resource ($dst3, $path_resizefile3);//저장
if ($result_save3 === false) die($GLOBALS['errormsg'] . "<br />\n");

//이미지 크롭후 리사이즈
$dst = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");

$result_crop = imagecopyresampled ($dst , $src , 0 , 0 , $src_x , $src_y , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save = save_image_from_resource ($dst, $path_cropfile);//저장
if ($result_save === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($src);
@imagedestroy($dst);
@imagedestroy($dst1);
@imagedestroy($dst2);
@imagedestroy($dst3);

//성공하였다면 이미지 출력

?>
원본 이미지 <br />
<img src='<?=$path_file?>'> <br />

썸네일 이미지 - 너비기준 정비율 <?=$dst_w?>px <br />
<img src='<?=$path_resizefile1?>'> <br />

썸네일 이미지 - 높이기준 정비율 <?=$dst_h?>px <br />
<img src='<?=$path_resizefile2?>'> <br />

썸네일 이미지 - 강제지정 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_resizefile3?>'> <br />

썸네일 이미지 - 크롭후 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_cropfile?>'> <br />


문제2>  너비가 1280이고 높이가 960인 test.jpg라는 원본 이미지가 있습니다.
이 이미지를 왼쪽 상단, 오른쪽 상단, 왼쪽 하단, 오른쪽 하단, 정중앙을 기준으로 각각 500 에 500 만큼을 잘라내서, 이것을 300에 300 짜리로 리사이즈 하여 test_crop_left_top.jpg,  test_crop_right_top.jpg,  test_crop_left_bottom.jpg,  test_crop_right_bottom.jpg,  test_crop_center_middle.jpg로 저장하세요.

처리힌트>
이문제의 핵심은 다른 처리과정은 문제1과 동일한데, 어떻게 기준점의 좌표를 찾는가가 관건입니다.

처리과정>
1. 왼쪽상단 기준점은 생각할 필요도 없이 0, 0
오른쪽 상단 기준점은 y좌표는 상단이므로 자동으로 0이고, x좌표는 너비 - 500 즉, 780, 0
왼쪽 하단 기준점은 x좌표는 왼쪽이므로 자동으로 0이고, y좌표는 높이 - 500 즉, 0, 460
오른쪽 하단 기준점은 x좌표는 너비 - 500, y좌표는 높이 - 500 즉 780, 460
중앙 기준점은 x좌표는 (너비 - 500) / 2, y좌표는 (높이 -500) / 2 즉 340, 260 입니다.

2. 나머지 과정은 문제1과 동일합니다.


위 문제의 풀이 과정을 예제에서 처리해보았습니다.

예제2>  test8.php

<?php

//이미지 처리 함수 인클루드
include_once 'lib/image_proc.function.php';

$path_file = 'sample_image/test.jpg';//원본파일

$path_crop_left_top_file = 'sample_image/test_crop_left_top.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_left_bottom_file = 'sample_image/test_crop_left_bottom.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_right_top_file = 'sample_image/test_crop_right_top.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_right_bottom_file = 'sample_image/test_crop_right_bottom.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_center_middle_file = 'sample_image/test_crop_center_middle.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로



$src_crop_w = 800;//원본의 복사될 너비
$src_crop_h = 800;//원본의 복사될 높이

$dst_w = 300;//만들어질 이미지의 너비 지정, 픽셀단위의 0이상의 정수를 지정
$dst_h = 300;//만들어질 이미지의 높이 지정, 픽셀단위의 0이상의 정수를 지정



//이미지 리소스를 받아온다.
list($src, $src_w, $src_h) = get_image_resource_from_file ($path_file);
if (empty($src)) die($GLOBALS['errormsg'] . "<br />\n");

//이미지 크롭후 리사이즈 left_top
$dst_left_top = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst_left_top === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");

//시작점 좌표를 구한다.
$src_x_left_top = 0;//원본의 복사 시작점 x좌표
$src_y_left_top = 0;//원본의 복사 시작점 y좌표

$result_crop_left_top = imagecopyresampled ($dst_left_top , $src , 0 , 0 , $src_x_left_top , $src_y_left_top , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop_left_top === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save_left_top = save_image_from_resource ($dst_left_top, $path_crop_left_top_file);//저장
if ($result_save_left_top === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($dst_left_top);



//이미지 크롭후 리사이즈 left_bottom
$dst_left_bottom = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst_left_bottom === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");

//시작점 좌표를 구한다.
$src_x_left_bottom = 0;//원본의 복사 시작점 x좌표
$src_y_left_bottom = $src_h - $src_crop_h;//원본의 복사 시작점 y좌표

$result_crop_left_bottom = imagecopyresampled ($dst_left_bottom , $src , 0 , 0 , $src_x_left_bottom , $src_y_left_bottom , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop_left_bottom === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save_left_bottom = save_image_from_resource ($dst_left_bottom, $path_crop_left_bottom_file);//저장
if ($result_save_left_bottom === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($dst_left_bottom);



//이미지 크롭후 리사이즈 right_top
$dst_right_top = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst_right_top === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");
//시작점 좌표를 구한다.
$src_x_right_top = $src_w - $src_crop_w;//원본의 복사 시작점 x좌표
$src_y_right_top = 0;//원본의 복사 시작점 y좌표

$result_crop_right_top = imagecopyresampled ($dst_right_top , $src , 0 , 0 , $src_x_right_top , $src_y_right_top , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop_right_top === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save_right_top = save_image_from_resource ($dst_right_top, $path_crop_right_top_file);//저장
if ($result_save_right_top === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($dst_right_top);



//이미지 크롭후 리사이즈 right_bottom
$dst_right_bottom = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst_right_bottom === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");

//시작점 좌표를 구한다.
$src_x_right_bottom = $src_w - $src_crop_w;//원본의 복사 시작점 x좌표
$src_y_right_bottom = $src_h - $src_crop_h;//원본의 복사 시작점 y좌표

$result_crop_right_bottom = imagecopyresampled ($dst_right_bottom , $src , 0 , 0 , $src_x_right_bottom , $src_y_right_bottom , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop_right_bottom === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save_right_bottom = save_image_from_resource ($dst_right_bottom, $path_crop_right_bottom_file);//저장
if ($result_save_right_bottom === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($dst_right_bottom);



//이미지 크롭후 리사이즈 center_middle
$dst_center_middle = @imagecreatetruecolor ($dst_w , $dst_h);//만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
if ($dst_center_middle === false) die("$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.<br />\n");

//시작점 좌표를 구한다.
$src_x_center_middle = ceil(($src_w - $src_crop_w) / 2);//원본의 복사 시작점 x좌표
$src_y_center_middle = ceil(($src_h - $src_crop_h) / 2);//원본의 복사 시작점 y좌표

$result_crop_center_middle = imagecopyresampled ($dst_center_middle , $src , 0 , 0 , $src_x_center_middle , $src_y_center_middle , $dst_w , $dst_h , $src_crop_w , $src_crop_h );
if ($result_crop_center_middle === false)die("$dst_w , $dst_h 크기로 크롭 및 리사이즈에 실패하였습니다.<br />\n");

$result_save_center_middle = save_image_from_resource ($dst_center_middle, $path_crop_center_middle_file);//저장
if ($result_save_center_middle === false) die($GLOBALS['errormsg'] . "<br />\n");

@imagedestroy($dst_center_middle);


@imagedestroy($src);

//성공하였다면 이미지 출력

?>
원본 이미지 <br />
<img src='<?=$path_file?>'> <br />

썸네일 이미지 - 왼쪽 상단 기준점 크롭 및 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_crop_left_top_file?>'> <br />

썸네일 이미지 - 왼쪽 하단 기준점 크롭 및 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_crop_left_bottom_file?>'> <br />

썸네일 이미지 - 오른쪽 상단 기준점 크롭 및 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_crop_right_top_file?>'> <br />

썸네일 이미지 - 오른쪽 하단 기준점 크롭 및 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_crop_right_bottom_file?>'> <br />

썸네일 이미지 - 가운데 중간 기준점 크롭 및 리사이즈 <?=$dst_w?>px X <?=$dst_h?>px <br />
<img src='<?=$path_crop_center_middle_file?>'> <br />

위 예제에서 다른건 설명이 필요없을 것 같고
$src_x_center_middle = ceil(($src_w - $src_crop_w) / 2);//원본의 복사 시작점 x좌표
$src_y_center_middle = ceil(($src_h - $src_crop_h) / 2);//원본의 복사 시작점 y좌표
이부분만 설명하자면, 2로 나누기 때문에 소숫점이 발생할 소지가 있어서 ceil 을 사용하여 소숫점이하 올림을 하였습니다.
추천
4

댓글 6개

원본보다 큰사이즈로 크롭이 걸리면 원본+검정영역으로 잡히나요?
원본사이즈를 비교해서 원본사이즈보다 크게 크롭되지 않게 하면 될까요?
네 원본 보다 큰 크롭은
원하는데로 결과가 나오기 어렵죠?

용도에 따라 조금씩 다르겠지만
크게 두가지 방향을 제시할수 있습니다.

한가지는 크롭 사이즈가 원본보다 너비나 높이 모두 크다면
원본을 크롭사이즈로 리사이즈 해주는 방향과

다른 한가지는 크롭사이즈가 원본보다 너비나 높이 둘중 하나만 크다면
큰 쪽을 원본 쪽과 맞추어서
크롭하는 방향이 있습니다.
크게 잡으면 아래 두가지 방식이고 그 방식중 마지막에 말씀하신것처럼 처리하면되는군요.

1, 조건으로 원본보다 큰 크롭은 원본을 출력
2. 원본보다 큰경우 크롭사이즈로 원본 리사이징

답변 감사합니다.



--------------------------------------
2013-01-31 14:04
전체 103
개발강좌 내용 검색

회원로그인

(주)에스아이알소프트 / 대표:홍석명 / (06211) 서울특별시 강남구 역삼동 707-34 한신인터밸리24 서관 1404호 / E-Mail: admin@sir.kr
사업자등록번호: 217-81-36347 / 통신판매업신고번호:2014-서울강남-02098호 / 개인정보보호책임자:김민섭(minsup@sir.kr)
© SIRSOFT