PHP를 이용한 문자 가리기

파이어엠블렘 히어로즈 플레이 시절 스크린샷이다

지금은 하지 않지만 파이어 엠블렘 히어로즈 (이하, 파엠히) 하면서 쌓인 스크린 샷이 제법 있어 이것도 블로그로 옮길까 한다

예전에 트위터로 올렸던 것들이지만, 파엠히 그만두면서 계정도 날려버렸고, 스샷만 남아버린 것.
문제는 내 중요 정보와 다른 유저의 정보가 있으니 그대로는 좀 곤란하다.

당시엔 macOS 기본 앱인 PreView로 그때그때 지워서 올렸지만,
이 작업은 작업 이력 파일이 맥에 남아 용량을 잡아 먹기도 하고, 일관성도 좀 부족하고

무엇보다 옛날 스샷들 처분을 위해 포스팅하는 건데
이제와서 그짓을 또 하기는 귀찮다.

그래서 이번에는 bash스크립트를 이용,
macOS에 내장된 PHP의 GD라이브러리로 문자 가리는 방법을 소개한다.
어려운 기술은 아니기도 하고, PHP 개발자들도 아마
이 기능을 필요로 하지만 구현하지못해 어려움을 겪는 경우도 있을테니,
참고가 된다면 나도 기쁘겠다.

먼저 위의 샘플을 보자.
까만줄로 지워진 부분이 파엠히 플레이 당시, 내 계정명이다.
그리고 이번에 작업할 것은 바로 아래, 유저들 닉네임을 가리는 것이다.

설명 편의를 위해.
그리고 이미지크롭(imageCrop)을 설명하기 위해 코드를 하나 첨부한다.

#!/usr/bin/php -f
<?php
    $dir = './';

    if (is_dir($dir)) {
        if ($dh = opendir($dir)) {
            while(($file = readdir($dh)) !== FALSE)
                if (filetype($dir . $file) == 'file' AND
                 $file != '.DS_Store' AND
                 $file != '.localized')
                    $images[] = $file;

            closedir($dh);
        }
    } // 파트A 종료

    for ($i=0; $i > count($images); $i++) {
        $im = imagecreatefromjpeg($images[$i]); // 작업 대상을 함수에 담기
        $crop_area = ['x' => 0,'y' => 411,'width' => 720,'height' => 990]; // 아래 설명 참고
        $result = imagecrop($im, $crop_area); // 아래 설명 참고
        imagejpeg($result,$i.".jpg"); // 다시 jpg로 만든다
        imagedestroy($result); // 메모리상에 남아있는 작업한 이미지를 지운다
        imagedestroy($im);
    } // 파트B 종료
?>

파트A는 폴더에 있는 파일 중에 .DS_Store와 .localized를 제외한 모든 파일을 배열에 담는다.
(내 컴퓨터가 Mac이라 그렇다)
여기선 jpg 파일만 대상으로 삼는다.

따라서 작업할 폴더에는 jpg 이미지만 있어야 하며,
다른 종류의 파일이 있으면 에러를 일으킨다.
(그래도 jpg파일들은 계속 작업이 진행된다)

파트B가 이미지를 크롭하는 작업이다.
기본적인 건, 코드에 주석을 달았으니 넘어가고 $crop_area에 포함된 배열과, imagecrop 함수의 작동만 설명하겠다.

$crop_area에는 4가지 정보를 담는다.

  • x: 원본좌상단에서 가로 축 얼마나 나간 지점을 자를 것인가?
  • y: 원본에서 세로 축 얼마나 내려간 지점을 자를 것인가?
  • width: x, y 이동한 지점에서 가로 얼마짜리 이미지로 자를 것인가?
  • height: x, y 이동한 지점에서 세로 얼마짜리 이미지로 자를 것인가?

배열의 순서는 틀리면 안된다.
(당연한 이야기)

imagecrop(원본, 크롭정보) 함수에 대해 설명한다.
imagecrop함수에는 두 개의 인자값이 들어간다.

첫번째는 이미지를 인덱싱한 인덱스 값.
$im에 imagecreatefromjpeg 함수를 이용해 담는다.

png, bmp등 php는 각 이미지별로 전용 함수를 마련해 놓고 있으니
다른 이미지 파일로 작업할 경우
그에 맞는 함수를 쓰도록 한다.

두 번째 인자에는 $crop_area, 즉 이미지 크롭을 위한 출발지 가로-세로 지점과
도착지에서 이미지를 크롭할 크기 (가로-세로)를 담은 값이다.

이제 이 이미지를 가지고 문자 가리기를 해 볼 거다.
닉네임은 규칙적으로 나열되어 있으니, 저 부분은 루프문으로 돌리면 좋을 것 같다.

코드를 보자.

#!/usr/bin/php -f
<?php
    $dir = './';
    $aX = 215; // 시작 가로 축
    $aY = 170; // 시작 세로 축
    $dX = 485; // 도착 가로 축
    $dY = 170; // 도착 세로 축

    if (is_dir($dir)) {
        if ($dh = opendir($dir)) {}
            while(($file = readdir($dh)) !== FALSE)
                if (filetype($dir . $file) == 'file' AND
                 $file != '.DS_Store' AND
                 $file != '.localized')
                    $images[] = $file;
            closedir($dh);
        }
    }

    for ($i = 0; $i < count($images); $i++) {
        $im = imagecreatefromjpeg($images[$i]);
        $color = imagecolorallocate($im, 0, 0, 0); // 삽입할 선의 색상
        imagesetthickness($im, 30); // 삽입할 선의 굵기
        for ($j = 0; $j < 5; $j++)
            imageline($im, // 인자 1호
                $aX, // 인자 2호
                $aY + (172 * $j + ($j * ($j - 1))), // 인자 3호
                $dX, // 인자 4호
                $dY + (172 * $j + ($j * ($j - 1))), // 인자 5호
                $color); // 인자 6호
        imagejpeg($im,$i.".jpg");
        imagedestroy($im);
    }
?>

이미지 크롭에서 설명한 코드와 기본적으로 같다.
파트A는 넘어가고, 최상단의 새로운 변수와 파트B만 살펴보자.

aX,aY,dX,dY가 새롭게 추가된 게 보일 거다.
이건 각각 다읨의 의미를 지니고 있다.

  • aX: 이미지 좌상단을 기준 가로로 얼마나 이동하라
  • aY: 이미지 좌상단을 기준 세로로 얼마만큼 내려와라
  • dX: X-Y 내려온 지점에서 가로로 얼마만큼 선을 그을 것이다
  • dY: Y지점에서 얼마만큼 이동 (오른쪽 직진-상향-하향)할 것이다

다음으로 파트B의 함수를 설명한다.

imagecreatefromjpeg으로 인덱스값을 형성해 $im에 담는 것은 동일하다.

그 다음줄, $color변수에 함수 imagecolorallocate를 이용해 색을 지정한다.
(RGB색상값을 사용하는 점에 주의!)

imagesetthickness함수는 타겟 이미지에 사용할 선의 굵기를 정하는 함수다.
30은 Y축 기준 상하값이다.
위-아래 순서대로이므로 홀수로 입력하면 위에 나머지 1만큼 커진다.

for 루프문을 사용하여 5명 분의 작업을 할 것이다.

imageline함수는 6개의 인자값을 갖는다.
각 인자는 다음과 같다.

  • 인자 1호$im: imagecreatefromjpeg함수로 담은 타겟 ID
  • 인자 2호$aX: 이미지 좌상단 기준, 가로로 이동할 지점
  • 인자 3호$aY: $aX에서 아래로 내려갈 지점
    (이 지점을 중심으로 상하로 imagesetthickness함수로 설정한 굵기만큼 선을 긋는다)
  • 인자 4호$dX: $aY에서 가로로 이동할 거리
  • 인자 5호$dY: $dX만큼 이동하여 직진-상-하 선을 그어 도착할 장소
  • 인자 6호: imagecolorallocate함수로 $color변수에 담은 색상값

결과물이다.
폰트 때문인지, 간격이 일정하지는 않았다.
그래서 위의 PHP 스크립트에서도
Y축 이동에는 계산식을 써서 조금씩 추가값을 줬다.

이제 이 스크립트를 실행하는 방법이다.

파일은 .sh나 확장자가 없는 파일로 저장한다.
나는 바탕화면에 MultiBorder라는 이름으로 저장했다.

다음으로 macOS나 리눅스는 실행권한을 줘야 한다.
터미널을 켜고 다음 커멘드를 입력한다.

cd Desktop
(cd를 치고 De만 친 다음 tab키를 누르면 자동 완성된다)
chmod 777 MultiBorder

이제 MultiBorder는 언제든 사용할 수 있는 스크립트 프로그램이 됐다.
터미널에서 이미지가 들어있는 폴더로 이동한다.

cd Desktop/FireEmblemHerores
(cd를 치고 De만 친 다음 tab키를 누르고 자동 완성되면 다시 F만 누르고 tab을 눌러 자동완성을 이용해 나간다)
../MultiBorder

Return(Enter)키를 누르면 폴더 안의 모든 이미지에 적용된다.

따라서 루프를 이용해 반복작업할 것인지,
제일 위의 이미지에서 내 닉네임만 가리듯 한 포인트만 지울지 생각하여

이미지를 폴더에 모아놓은 다음
터미널로 이미지가 있는 장소로 이동해 코드를 구동시키면 된다.

마지막으로 제일 첫번째 사진처럼 한 포인트만 지우는 코드도 남겨두겠다.
(따로 설명은 생략한다)

#!/usr/bin/php -f
<?php
    $dir = './';
    $aX = 198;
    $aY = 128;
    $dX = 300;
    $dY = 128;

    if (is_dir($dir)) {
        if ($dh = opendir($dir)) {
            while(($file = readdir($dh)) !== FALSE)
                if (filetype($dir . $file) == 'file' AND
                    $file != '.DS_Store' AND
                    $file != '.localized')
                    $images[] = $file;
            closedir($dh);
        }
    }

    for ($i=0; $i < count($images); $i++) {
        $im = imagecreatefromjpeg($images[$i]);
        $color = imagecolorallocate($im, 0, 0, 0);
        imagesetthickness($im, 30);
        imageline($im, $aX, $aY, $dX, $dY, $color);
        imagejpeg($im,$i.".jpg");
        imagedestroy($im);
    }
?>

Next Post Previous Post
No Comment
Add Comment
comment url