php > 내가 만들어 쓰는 함수 > 기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기2

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

강좌는 php 5. 대를 기준으로 하며, 기본적으로 GD 나 FREETYPE 등의
기본적인 라이브러리는 연동되었다는 가정하에 진행합니다.

예전 개발 환경에서는 GD 나 FREETYPE 등의 연동여부나 php버젼들을 따졌지만,
요새 개발 환경에서는 대부분 기본적으로 다 제공하기 때문에 그렇습니다.



php > 내가 만들어 쓰는 함수 > 기준점에 따른 이미지 크롭(이미지의 특정 부분만 복사) 처리하기2

이전에는 이미지 크롭 처리하는 것의 일부분을 다루어 보았습니다.
이번에는 이번에는 원본과 썸네일의 크기만 가지고 자동으로 크롭하고 리사이즈처리하는 부분을 다루어 보도록 하겠습니다.

문제1> 너비가 1280이고 높이가 960인 test.jpg라는 원본 이미지가 있습니다.이 이미지로 다음 세개의 썸네일 이미지를 만드세요.
128 X 96 ==> test_crop_128X96.jpg
128 X 86 ==> test_crop_128X86.jpg
128 X 106 ==> test_crop_128X106.jpg
단 정비율로서 만들되 남는 부분이나 큰부분을 중앙을 기준으로 크롭하여 생성하세요.

처리힌트>
문제가 좀 어렵게 느껴질수 있습니다.
첫번째 썸네일은 10분의 1로 축소한 이미지 입니다.
두번째 이미지는 10분의 1로 축소하되 높이가 96보다 작으므로 높이 중앙을 기준으로 크롭을 해야 합니다.
세번째 이미지는 10분의 1로 축소해서 보면 높이가 96보다 크기 때문에 복사해오면 여백이 남으므로 다시 높이를 기준으로 비율을 계산하여 너비 중앙을 기준으로 크롭을 해야 합니다.

 

처리과정>
1. 먼저 원본이미지로 부터 get_image_resource_from_file 함수를 통해 이미지 리소스를 가져온다.

2. 최종 생성될 이미지(썸네일이미지)의 리소스를 imagecreatetruecolor 함수를 통해 세개 (128 X 96 , 128 X 86, 128 X 106) 생성합니다.

3. 각 썸네일의 너비를 기준으로 크롭할지 여부와 크롭 기준점, 크롭영역을 계산합니다.

4. 원본이미지로 부터 각 기준점과 크롭영역으로 크롭 및 리사이즈를 합니다.

5. 처리된 썸네일 이미지의 리소스들을 각 test_crop_128X96.jpg, test_crop_128X86.jpg, test_crop_128X106.jpg test_crop.jpg 로 저장합니다.


다른건 크게 문제 될것이 없다고 보이고 3번이 좀 문제가 되리라고 봅니다.
편의상 128 X 96 을 1번, 128 X 86 을 2번, 128 X 106 을 3번 이미지라고 부르겠습니다.
일단, 세개의 이미지가 모두 너비가 128 이므로 너비를 기준으로 계산을 하겠습니다.

원본 1280 X 960 의 이미지를 128 의 정비율 썸네일로 만든다고 생각합니다. 그러면 자동으로 썸네일의 높이가 결정됩니다.
그 높이(96) 로 만들어야할 세개의 썸네일의 높이와 비교합니다.

1번은 동일하므로 크롭없이 리사이즈하면 됩니다.

2번은 96보다 작으므로 높이를 기준으로 크롭후 리사이즈 해야합니다.
따라서 원본에서 크롭을 해야할 기준점과 영역을 구해야 합니다.
너비는 비율대로 이고 높이가 문제이므로 크롭할 영역은 1280  X 860 입니다.
이유는 0.1 비율로 너비가 축소되기 때문에 높이는 반대의 경우로 86 * 10 이기 때문입니다.
너비는 동일하고 높이가 다르므로, 중앙을 기준으로 크롭한다고 했으니까......
크롭할 기준점은 0, 50 입니다.
이유는 이전 내용에서도 설명했지만 왼쪽 꼭지점에서 높이만 아래로 내려오는 것이기 때문에 X좌표는 0 이고 Y좌표는 (960 - 860 ) / 2 입니다. 물론 소숫점이 나올수 있으므로 ceil을 사용합니다.

3번은 96보다 크므로 정상적으로 복사를 해오게 되면 썸네일의 높이부분에 남는 영역 생깁니다.
그러므로 기존 가로 기준에서 높이 기준으로 바꿔야 합니다.
기존에는 너비기준이었기 때문에 비율이 0.1 이엇지만 높이 기준으로 바꾸게 되면 0.114..... 가 됩니다.
이것을 기준으로 썸네일의 너비를 새로 구하게 되면 142 가 됩니다. 물론 소숫점은 올림으로 처리하였습니다.
높이는 비율대로 이고 너비가 문제이므로 크롭할 영역은 1160 X 960 입니다.
이유는 약 0.11XX 비율로 너비가 축소되기 때문에 높이는 반대의 경우로 128 * 9.05XX 이기 때문입니다.
높이는 동일하고 너비가 다르므로, 중앙을 기준으로 크롭한다고 했으니까......
크롭할 기준점은 60, 0 입니다.
이유는 이전 내용에서도 설명했지만 왼쪽 꼭지점에서 너비만 오른쪽으로 이동하는것이기 때문에 Y좌표는 0 이고 X좌표는 (1280 - 1160 ) / 2 입니다. 물론 소숫점이 나올수 있으므로 ceil을 사용합니다.


테스트를 하기 이전에 기존 함수 수정과 새로운 함수 두개를 추가해야 합니다.

아래 get_size_by_rule 을 조금 수정해야 합니다. 이전에는 예제에서 소숫점이 나올경우가 없었기 때문에 리턴값을 계산후 그냥 반환하였습니다. 하지만, 정확하게는 소숫점도 나올수 있으므로 ceil 함수를 사용하여 리턴값을 반환해야 합니다. 따라서 기존 함수를 아래와 같이 수정합니다.

예제2 : lib/image_proc.function.php 의 get_size_by_rule 수정

//원본의 너비, 원본의 높이, 리사이즈 너비나 높이, 기준값을 받아 기준값을 토대로 정비율의 값을 구함
//성공시 정비율의 값을 반환, 실패시 false를 반환
//기준값은 width 나 height, 기준값은 생략 가능하며 생략시 자동으로 width가 된다.
function get_size_by_rule($src_w, $src_h, $dst_size, $rule='width'){

  if (!is_int($src_w) || $src_w < 1 || !is_int($src_h) || $src_h < 1){//원본의 너비와 높이가 둘중에 하나라도 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "원본의 너비와 높이가 0보다 큰 정수가 아닙니다. ($src_w, $src_h)";
    return false;
  }

  if (!is_int($dst_size) || $dst_size < 1){//리사이즈 될 사이즈가 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "리사이즈될 사이즈가 0보다 큰 정수가 아닙니다. ($dst_size)";
    return false;
  }

  if ($rule != 'height') {//기준값이 너비일 경우

    return ceil($dst_size / $src_w * $src_h);
  }
  else {//기준값이 높이일 경우

    return ceil($dst_size / $src_h * $src_w);
  }
}




예제2 : lib/image_proc.function.php 에 추가

//원본의 너비나 높이, 썸네일 너비, 썸네일 높이, 기준값을 받아 기준값을 토대로 정비율의 값을 구함
//성공시 정비율의 값을 반환, 실패시 false를 반환
//기준값은 width 나 height, 기준값은 생략 가능하며 생략시 자동으로 width가 된다.
function get_bigsize_by_rule($src_size, $dst_w, $dst_h, $rule='width'){

  if (!is_int($src_size) || $src_size < 1){//원본의 사이즈가 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "원본의 사이즈가 0보다 큰 정수가 아닙니다. ($src_size)";
    return false;
  }

  if (!is_int($dst_w) || $dst_w < 1 || !is_int($dst_h) || $dst_h < 1){//썸네일의 너비와 높이가 둘중에 하나라도 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "썸네일의 너비와 높이가 0보다 큰 정수가 아닙니다. ($dst_w, $dst_h)";
    return false;
  }

  if ($rule != 'height') {//기준값이 너비일 경우

    return ceil($src_size / $dst_w * $dst_h);
  }
  else {//기준값이 높이일 경우

    return ceil($src_size / $dst_h * $dst_w);
  }
}


lib/image_proc.function.php 파일에 위 함수 get_bigsize_by_rule 를 추가 합니다.
기존 get_size_by_rule 는 큰 너비와 큰 높이를 알때 정비율의 작은 값을 구하는 것이었다면 get_bigsize_by_rule 은 작은 너비와 작은 높이를 알때 정비율의 큰 값을 구하는 것입니다.

get_bigsize_by_rule($src_size, $dst_w, $dst_h, $rule='width')
용도 : 썸네일 크기에 대해 원본 이미지의 정비율 크기를 구할때 사용, 성공시 0보다 큰 정수를 반환, 실패시 false를 반환합니다.

인자 :
$src_size ==> 원본의 너비나 높이, 0보다 큰 정수를 사용합니다
$dst_w ==> 썸네일의 너비, 0보다 큰 정수를 사용합니다.
$dst_h ==> 썸네일의 높비, 0보다 큰 정수를 사용합니다.
$rule ==> 너비를 기준으로 값을 생성할지, 높이를 기준으로 값을 생성할지 결정하는 구분자. 너비를 기준으로 할때는 width, 높이를 기준으로 할때는 height, $rule이 생략되거나, $rule 이 height 가 아닌경우에는 모두 width 로 인식합니다.



예제3 : lib/image_proc.function.php 에 추가

//원본의 리소스, 원본의 너비, 원본의 높이, 크롭리사이즈 너비, 높이를 받아 이미지 크롭 후 리사이즈 처리
//성공시 리사이즈된 이미지의 리소스를 반환, 실패시 false를 반환
function get_image_cropresize($src, $src_w, $src_h, $dst_w, $dst_h=0){

  if (empty($src))  {//원본의 리소스가 빈값일 경우

    $GLOBALS['errormsg'] = '원본 리소스가 없습니다.';
    return false;
  }

  //정수형이 아니라면 정수형으로 강제 형변환
  if (!is_int($src_w)) settype($src_w, 'int');
  if (!is_int($src_h)) settype($src_h, 'int');
  if (!is_int($dst_w)) settype($dst_w, 'int');
  if (!is_int($dst_h)) settype($dst_h, 'int');

  if ($src_w < 1 || $src_h < 1){//원본의 너비와 높이가 둘중에 하나라도 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "원본의 너비와 높이가 0보다 큰 정수가 아닙니다. ($src_w, $src_h)";
    return false;
  }

  if (empty($dst_w) && empty($dst_h)) {//리사이즈될 너비와 높이 둘다 없을 경우

    $GLOBALS['errormsg'] = '리사이즈될 너비와 높이는 둘중에 하나는 반듯이 있어야 합니다.';
    return false;
  }

  if (!empty($dst_w) && $dst_w < 1){//리사이즈 될 너비가 존재하는데 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "리사이즈될 너비가 0보다 큰 정수가 아닙니다. ($dst_w)";
    return false;
  }

  if (!empty($dst_h) && $dst_h < 1){//리사이즈 될 높이가 존재하는데 0보다 큰 정수가 아닐경우

    $GLOBALS['errormsg'] = "리사이즈될 높이가 0보다 큰 정수가 아닙니다. ($dst_h)";
    return false;
  }

  //리사이즈 될 너비와 높이가 둘중에 하나가 없는 경우에는 정비율을 의미하며, 비율데로 너비와 높이를 결정한다.
  if (empty($dst_w) || empty($dst_h)) {

    if (empty($dst_h)) $dst_h = get_size_by_rule($src_w, $src_h, $dst_w, 'width');
    else $dst_w = get_size_by_rule($src_w, $src_h, $dst_h, 'height');
  }

  //만드어질 $dst_w , $dst_h 크기의 이미지 리소스를 생성한다.
  $dst = @imagecreatetruecolor ($dst_w , $dst_h);
  if ($dst === false) {

    $GLOBALS['errormsg'] = "$dst_w , $dst_h 크기의 썸네일 이미지의 리소스를 생성하지 못했습니다.";
    return false;
  }

  //먼저 리사이즈 너비를 기준으로 정비율 리사이즈 높이를 계산한다.
  $s_w = $dst_w;
  $s_h = get_size_by_rule($src_w, $src_h, $s_w, 'width');

  if ($dst_h == $s_h) {//높이가 같을 경우, 즉 정비율 리사이즈일경우

    $result_resize = imagecopyresampled ($dst , $src , 0 , 0 , 0 , 0 , $dst_w , $dst_h , $src_w , $src_h );
    if ($result_resize === false) {

      $GLOBALS['errormsg'] = "$dst_w , $dst_h 크기로 리사이즈에 실패하였습니다.";
      return false;
    }
  }
  else if ($dst_h < $s_h) {//지정된 높이가 정비율 높이 보다 작을경우, 높이를 기준으로 가운데를 크롭

    //썸네일의 높이를 기준으로 정비율의 원본 높이를 구한다.
    $src_nh = get_bigsize_by_rule($src_w, $dst_w, $dst_h, 'width');

    $src_x = 0;
    $src_y = ceil(($src_h - $src_nh) / 2);

    $result_resize = imagecopyresampled ($dst , $src , 0 , 0 , $src_x , $src_y , $dst_w , $dst_h , $src_w , $src_nh );
    if ($result_resize === false) {

      $GLOBALS['errormsg'] = "$dst_w , $dst_h 크기로 리사이즈에 실패하였습니다.";
      return false;
    }
  }
  else {//지정된 높이가 정비율 높이 보다 큰경우, 너비를 기준으로 가운데를 크롭

    //썸네일의 너비를 기준으로 정비율의 원본 너비를 구한다.
    $src_nw = get_bigsize_by_rule($src_h, $dst_w, $dst_h, 'height');

    $src_x = ceil(($src_w - $src_nw) / 2);
    $src_y = 0;

    $result_resize = imagecopyresampled ($dst , $src , 0 , 0 , $src_x , $src_y , $dst_w , $dst_h , $src_nw , $src_h );
    if ($result_resize === false) {

      $GLOBALS['errormsg'] = "$dst_w , $dst_h 크기로 리사이즈에 실패하였습니다.";
      return false;
    }
  }

  return $dst;
}


lib/image_proc.function.php 파일에 위 함수 get_image_cropresize 를 추가 합니다.
기존 get_image_resize 은 단순 이미지 리사이즈만을 위한 함수라면get_image_cropresize 어느 한쪽 부분이 비율보다 클 경우, 비율대로 계산하여 중앙을 기준으로 크롭후 리사이즈 해주는 함수입니다.

get_image_resize($src, $src_w, $src_h, $dst_w, $dst_h=0)
용도 :
원본 이미지의 리소스를 받아 새로운 크기의 썸네일 이미지를 생성하여 그 이미지의 리소스를 반환합니다. 성공시에는 이미지 리소스를 반환하고, 실패시에는 false를 반환합니다. get_image_resize 와 다른 점은 중앙을 기준으로 크롭후 리사이즈 합니다.

인자 :
$src ==> 원본의 이미지 리소스
$src_w ==> 원본의 너비, 0보다 큰 정수를 사용합니다.
$src_h ==> 원본의 높이, 0보다 큰 정수를 사용합니다.
$dst_w ==> 새로 만들 이미지의 너비를 지정합니다. 0이상의 정수를 사용합니다. 0을 사용할때는 $dst_h 에는 반듯이 0보다 큰 정수를 사용해야 합니다.
$dst_h ==> 새로 만들 이미지의 높이를 지정합니다. 0이상의 정수를 사용합니다. 0을 사용할때는 $dst_w 에는 반듯이 0보다 큰 정수를 사용해야 합니다.

처리순서 :
1. 원본 리소스의 값이 있는지 체크
2. 정수형으로 사용되어져야할 변수들이 정수가 아니면 정수로 강제 변환
3. 원본의 너비와 높이가 0보다 큰 정수인지 체크
4. 리사이즈 이미지의 너비 높이 둘다 값이 없는지 체크
5. 리사이즈 이미지의 너비나 높이에 값이 있을때 0보다 큰 정수인지 체크
6. 리사이즈 이미지의 너비나 높이, 둘중 하나가 없을때 정비율로 나머지 값을 구하는 부분
7. 리사이즈 이미지 리소스 생성
8. 이미지 크롭 및 리사이즈 처리
9. 생성된 이미지 리소스 반환

아래의 예제를 통해 위 문제1을 처리해 가는 과정을 확인합니다.
예제4 : test9.php

<?php

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

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

$path_crop_128X96_file = 'sample_image/test_crop_128X96.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_128X86_file = 'sample_image/test_crop_128X86.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로
$path_crop_128X106_file = 'sample_image/test_crop_128X106.jpg';//크롭 및 리사이즈 처리되어 저장될 파일 경로

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

//128 X 96 처리
$dst_w = 128;
$dst_h = 96;
$dst_128X96 = get_image_cropresize($src, $src_w, $src_h, $dst_w, $dst_h);
if ($dst_128X96 === false) die($GLOBALS['errormsg'] . "<br />\n");

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

@imagedestroy($dst_128X96);

//128 X 86 처리
$dst_w = 128;
$dst_h = 86;
$dst_128X86 = get_image_cropresize($src, $src_w, $src_h, $dst_w, $dst_h);
if ($dst_128X86 === false) die($GLOBALS['errormsg'] . "<br />\n");

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

@imagedestroy($dst_128X86);

//128 X 106 처리
$dst_w = 128;
$dst_h = 106;
$dst_128X106 = get_image_cropresize($src, $src_w, $src_h, $dst_w, $dst_h);
if ($dst_128X106 === false) die($GLOBALS['errormsg'] . "<br />\n");

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

@imagedestroy($dst_128X106);


@imagedestroy($src);

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

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

썸네일 이미지 - 크롭 및 리사이즈 128px X 96px <br />
<img src='<?=$path_crop_128X96_file?>'> <br />

썸네일 이미지 - 크롭 및 리사이즈 128px X 86px <br />
<img src='<?=$path_crop_128X86_file?>'> <br />

썸네일 이미지 - 크롭 및 리사이즈 128px X 106px <br />
<img src='<?=$path_crop_128X106_file?>'> <br />



오늘 예제에서는 크롭을 너비 기준으로 하였지만, 실전에서는 높이 기준으로 처리해야 할때와 여러 기준점을 줄때도 있습니다.
하지만 그러한 것들은 다 응용이 가능한 부분들이고 강좌 특성상 이정도로 크롭은 마무리 짓도록 하겠습니다.
다음 시간에는 워터마크에 대해 다뤄볼까 합니다.

[이 게시물은 관리자님에 의해 2011-10-31 17:16:08 PHP & HTML에서 이동 됨]
|
댓글을 작성하시려면 로그인이 필요합니다.

프로그램

태그 필터 (최대 3개) 전체 개발자 소스 기타 mysql 팁자료실 javascript php linux flash 정규표현식 jquery node.js mobile 웹서버 os 프로그램 강좌 썸네일 이미지관련 도로명주소 그누보드5 기획자 견적서 계약서 기획서 마케팅 제안서 seo 통계 서식 통계자료 퍼블리셔 html css 반응형 웹접근성 퍼블리싱 표준화 반응형웹 홈페이지기초 부트스트랩 angularjs 포럼 스크린리더 센스리더 개발자톡 개발자팁 퍼블리셔톡 퍼블리셔팁 기획자톡 기획자팁 프로그램강좌 퍼블리싱강좌
+
제목 글쓴이 날짜 조회
15년 전 조회 1,532
15년 전 조회 1,445
15년 전 조회 2,163
15년 전 조회 1,312
15년 전 조회 1,372
15년 전 조회 917
15년 전 조회 1,022
15년 전 조회 996
15년 전 조회 947
15년 전 조회 900
15년 전 조회 962
15년 전 조회 1,107
15년 전 조회 1,121
15년 전 조회 2,643
15년 전 조회 971
15년 전 조회 1,628
15년 전 조회 1,495
15년 전 조회 1,621
15년 전 조회 1,321
15년 전 조회 1,816
15년 전 조회 632
15년 전 조회 1,120
15년 전 조회 1,087
15년 전 조회 2,870
15년 전 조회 3,196
15년 전 조회 1,868
15년 전 조회 1,380
15년 전 조회 1,995
15년 전 조회 1,502
15년 전 조회 1,093
15년 전 조회 3,790
15년 전 조회 1,444
15년 전 조회 1,536
15년 전 조회 2,771
15년 전 조회 1,462
15년 전 조회 4,190
15년 전 조회 2,400
15년 전 조회 3,183
15년 전 조회 1,788
15년 전 조회 2,019
15년 전 조회 1,323
15년 전 조회 4,402
15년 전 조회 3,983
15년 전 조회 3,802
15년 전 조회 5,227
15년 전 조회 3,438
15년 전 조회 1,828
15년 전 조회 1,778
15년 전 조회 1,927
15년 전 조회 1,617
15년 전 조회 4,016
15년 전 조회 2,941
15년 전 조회 2,111
15년 전 조회 1,696
15년 전 조회 1,932
15년 전 조회 2,417
16년 전 조회 1,490
16년 전 조회 2,423
16년 전 조회 1,756
16년 전 조회 1,856
16년 전 조회 1,511
16년 전 조회 2,203
16년 전 조회 1,534
16년 전 조회 1,948
16년 전 조회 2,133
16년 전 조회 1,205
16년 전 조회 1,275
16년 전 조회 1,925
16년 전 조회 5,364
16년 전 조회 1,667
16년 전 조회 2,180
16년 전 조회 2,370
16년 전 조회 1,527
16년 전 조회 1,330
16년 전 조회 2,247
16년 전 조회 4,962
16년 전 조회 2,235
16년 전 조회 2,892
16년 전 조회 1,772
16년 전 조회 3,624
16년 전 조회 4,462
16년 전 조회 3,126
16년 전 조회 2,372
16년 전 조회 2,463
16년 전 조회 2,703
16년 전 조회 2,199
16년 전 조회 5,534
16년 전 조회 3,391
16년 전 조회 1,384
16년 전 조회 1,728
16년 전 조회 5,099
16년 전 조회 2,336
16년 전 조회 3,430
16년 전 조회 2,673
16년 전 조회 1,585
16년 전 조회 5,386
16년 전 조회 2,500
16년 전 조회 5,991
16년 전 조회 1,966
16년 전 조회 4,044