에루샤
erusya
Back-end Developer
Web Geek
Anime Otaku
에루샤
개발
Dev: Back-end

php 이미지 검열 구현

74 views as of December 20, 2024.
우리가 웹사이트를 운영하다가보면 필요에 따라 이미지를 검열할 방법이 필요하다.

일반적으로 문제가 되는 이미지면 안보이게하거나 감추면 그만인데, 사이트 성향에 따라서는 직접적으로 노출만안되면 되는 경우도 존재한다.

이럴때 이미지를 강제로 열화시켜서 원본을 기반한 검열 이미지를 만들어야 하는 경우가 있다.
이 포스팅에선 그 방법에 대해 간략하게 기록하고자 한다.


이미지 가져오기

일단 백단에서 처리해야할 이미지를 가져오는 방법이다.

나같은 경우는 아마존 S3를 통해서 이미지를 서비스하고있기 때문에 아래와 같이 이미지를 가져와 사용했다.

// 원본 파일 가져오기
$originalFile = Storage::disk('s3')->get($originalFilePath);
$tmpFilePath = tempnam(sys_get_temp_dir(), 'original_image');
file_put_contents($tmpFilePath, $originalFile);

// 이미지 정보 가져오기
$imageInfo = getimagesize($tmpFilePath);
$mime = $imageInfo['mime'];
$width = $imageInfo[0];
$height = $imageInfo[1];Copy



만약에 앞단에서 POST 방식으로 파일로 이미지를 가져올 경우엔 이렇게 이미지를 가져올 수도 있겠다.

$file = $request->file('file');
$fileSize = $file->getSize(); // 파일 크기 (바이트 단위)
$imagePath = $file->getPathname();
$imageInfo = getimagesize($imagePath);
$mime = $imageInfo['mime'];
$width = $imageInfo[0]; // 이미지의 가로 길이 (픽셀 단위)
...Copy



이미지 검열 처리

이미지를 검열하는 과정은 단순하다.

1. 이미지의 원형을 뭉개기위해 원본 이미지를 특정 크기로 다운스케일링한다.
2. 다운스케일링된 이미지에 블러를 적용한다.
3. 이미지를 원형사이즈로 업스케일링을 한다.
4. 필요에 따라 필터를 추가한다. (나는 흑백필터 추가)

이 과정이 녹아있는 코드는 아래와 같다.

// 이미지 생성
$image = imagecreatefromstring(file_get_contents($tmpFilePath));
unlink($tmpFilePath); // 임시 파일 삭제

$tmpLowResImage = $image; // 기본적으로 원본 이미지를 유지

// 다운스케일링 조건: 가로 크기가 500px 이상일 때만 실행
if ($width > 500) {
    // 다운스케일링 (500px로 축소)
    $downscaleWidth = 500; // 다운스케일링 가로 크기
    $downscaleHeight = floor($height * ($downscaleWidth / $width));

    $tmpLowResImage = imagecreatetruecolor($downscaleWidth, $downscaleHeight);
    imagecopyresampled($tmpLowResImage, $image, 0, 0, 0, 0, $downscaleWidth, $downscaleHeight, $width, $height);
}

// 블러 처리 (다운스케일된 이미지에 적용)
for ($i = 0; $i < 10; $i++) {
    imagefilter($tmpLowResImage, IMG_FILTER_GAUSSIAN_BLUR);
}

// 다시 업스케일링 (730px 또는 원본 크기)
$finalWidth = $width > 730 ? 730 : $width; // 최대 730px로 제한
$finalHeight = floor($height * ($finalWidth / $width));

$tmpFinalImage = imagecreatetruecolor($finalWidth, $finalHeight);
imagecopyresampled($tmpFinalImage, $tmpLowResImage, 0, 0, 0, 0, $finalWidth, $finalHeight, $downscaleWidth, $downscaleHeight);

// 흑백 처리 (최종 이미지에 적용)
imagefilter($tmpFinalImage, IMG_FILTER_GRAYSCALE);

// 품질 최적화
ob_start();
if ($mime == 'image/webp') {
    imagewebp($tmpFinalImage, null, 50); // 품질 50
} else {
    imagejpeg($tmpFinalImage, null, 50); // 품질 50
}
$censoredImage = ob_get_clean();

// 메모리 해제
imagedestroy($image);
imagedestroy($tmpLowResImage);
imagedestroy($tmpFinalImage);Copy


이 코드를 통과하는 이미지는 총 아래의 3가지 경우로 구분된다.

1) 이미지 사이즈가 500px 보다 작은경우

다운스케일링 X, 블러처리 O, 업스케일링 X, 흑백처리 O
원본 사이즈가 작기때문에 블러만먹여도 이미 흐려질대로 흐려지는 작은 이미지의 경우이다.

2) 이미지 사이즈가 500px ~ 730px 일경우

다운스케일링 O, 블러처리 O, 업스케일링 O(원래 원본 크기까지), 흑백처리 O
원본 사이즈가 애매한 경우이다.
이경우엔 최종 결과물의 이미지 사이즈가 원본 사이즈와 같게 나온다.

3) 이미지 사이즈가 730px 보다 큰 경우

다운스케일링 O, 블러처리 O, 업스케일링 O(730px), 흑백처리 O
원본 사이즈가 큰 경우이다.
이 경우가 가장 블러와 다운스케일링의 영향이 크게 적용된다.
결과물은 무조건 가로 730 픽셀에 해당하는 사이즈로 조정된다.


검색엔진의 성인 콘텐츠 처리

이 부분은 정확히 어떤 기준으로 페이지의 성인 콘텐츠를 결정하는지 정확히 나온 사항이 없다.

GPT에게 물어보니 성적인 외형, 묘사등이 자세하게 표현된 리소스를 기준으로 판단한다고하고, 이미지에 피부색이 많을수록 그렇게 판단한다는 경향이 있다고한다.

이를 회피하기위해서는 적당한 블러처리와 다운스케일링으로 이미지를 열화시켜야하며 추가로 흑백처리하는것도 좋다고 했다.

그래서 나도 마지막 단계에서 이미지를 흑백처리하는 파트도 넣었다.


결과물

아래는 실제 위 코드를 기반으로 검열처리된 이미지이다.




이 결과를 바탕으로 블러가 더필요하다면 아래 블러처리를 더 많이 해주면된다.

// 블러 처리 (다운스케일된 이미지에 적용)
for ($i = 0; $i < 10; $i++) {
    imagefilter($tmpLowResImage, IMG_FILTER_GAUSSIAN_BLUR);
}Copy

근데 생각보다 이 블러처리를 여러번하면 연산하는데 시간이 꽤 걸려서...
블러를 여러번하기보다 다운스케일링처리를 더 낮게하면 쉽다.

위 코드에서는 내가 다운스케일링 기준을 500px로 잡았는데, 이를 200px까지 낮추면 아래와 같은 결과가 도출된다.

500px
200px


그리고 흑백필터의 유무는 아래와 같다.



이외에 사진을 열화시키는 방법은 어둡게 하는 방법이라던지, 대비를 증가시켜서 색간의 차이를 줄이는 방법등이 있다.

// 어둡게 처리
imagefilter($image, IMG_FILTER_BRIGHTNESS, -30);

// 대비 처리
imagefilter($image, IMG_FILTER_CONTRAST, 50);Copy



결론

나는 이 기능을 플로라 에디터의 퀵 툴바에 연동해서 아래와 같이 사용하고 있다.


그리고 또 검열된 이미지를 클릭할경우 아래와 같이 컨펌창 동의를 한 이후에 원본이미지가 보이는 장치도 해놓았다.


우리나라는 진짜 성인 컨텐츠를 보려면 본인인증 절차를 거쳐야하지만, 불쾌감을 주는 이미지나 1차적인 검열이 필요한 이미지는 임의로 블러처리하고 동의 이후에 보게하는 장치도 나쁘진 않을것이다.

실제로 옆나라인 일본은 성인 컨텐츠에 대해서 이런식으로 처리하고있는 사이트가 대부분이다.
끝!

#php
0 개의 댓글
Dev: Back-end 콜렉션의 다른 글
×