본문 바로가기
iOS 한번 개발해보자/related to UIKit

[iOS][UIKit]Watermark 적용하기

by 임간디 2022. 7. 25.

필자의 회사에서 App.의 보안을 강화하라는 지시가 내려왔다.

문제가 되는 것은 Screen Capture였다.

필자가 알기로 iOS는 Screen Recording은 막을 수 있지만 Screen Capture는 현 상황 못 막는 것으로 알고 있다.

그래서 고안해낸 것이 Watermark!

사용자의 ID를 watermark로 화면에 찍어내면 추후 유출되도 누가 유출했는지 알 수 있을 것이다.

개발자의 바이블 구글을 켜고 시작해보자.

 

역시 훌륭하신 선배님들이 사전에 개발을 해두셨다.

그 중 내가 참고한 선배님의 게시물은 아래와 같다.

https://github.com/hyuni/Blog-Swift/blob/master/Content/watermark.md

 

GitHub - hyuni/Blog-Swift

Contribute to hyuni/Blog-Swift development by creating an account on GitHub.

github.com

Watermark는 UIGraphicsImageRenderer 클래스를 이용하여 그린다.

https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer

 

Apple Developer Documentation

 

developer.apple.com

UIGraphicsImageRenderer는 쉽게 생각하면 그림을 그려주는 클래스라고 보면될 것 같다.

(기회 되면 심층분석 들어가겠다.)

 

기본 컨셉은 WatermarkView를 현재뷰의 Subview로 추가해주면 된다.

 

WatermarkView는 UIImageView로 생성하여 UIImage로 그림을 그려주면 된다.

굉장히 간단(?)한 작업이다.

 

이제 소스를 리뷰해보자

필자는 watermark 적용 버튼을 만들어 아래와 같이 IBAction을 추가했다.

해당 함수는 watermarkView를 생성하여 Image를 입히고 Subview에 추가하고 있다.

@IBAction func touchWatermarkBtn(button: UIButton) {
	if button.isSelected == false {
    		//watermarkView를 정의해준다.
		watermarkView = UIImageView(frame: .zero)
        	//1.watermarkView의 크기를 잡아준다.
		watermarkView.frame = CGRect(x: 0, y: 0, width: self.view.frame.height * 2, height: self.view.frame.height * 2)
        	//background는 투명한 색으로 설정해야 subview로 추가해도 상위view를 가리지 않는다.
		watermarkView.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 0)
        
        	//watermarkImage를 그려서 watermarkView에 image로 적용한다.
		let watermarkImage = watermark(watermarkView.bounds, text: "WaterMark Adopted!!", device_width: self.view.frame.width)
		watermarkView.image = watermarkImage

		//생성한 wartermarkView를 subview로 추가한다.
		self.view.addSubview(watermarkView)
	}
	else{
		//watermarkView를 지워준다.
		watermarkView.removeFromSuperview()
	}
	button.isSelected.toggle()
}

1. watermarkView의 크기를 잡아준다.

모자람보다 남는게 낫다고 했다. 한 변이 (모바일 뷰의 세로길이) X 2 인 정사각형으로 충분하게 정의했다.

이렇게 충분히 정의하지 않는 경우 watermarkView를 기울였을 때

아래와 같이 모두 커버하지 못하는 불상사가 발생한다.

 

다음은 watermark image를 그려볼 시간이다.

이 영역은 오랜만에 고등수학이 쓸모있음을 느끼게해준다.

func watermark(_ rect: CGRect, text: String, device_width: CGFloat) -> UIImage {
    let renderer = UIGraphicsImageRenderer(bounds: rect)
    
    let image = renderer.image{ (context) in
        //1.Image기준 좌표를 view의 모든 부분을 커버할 수 있도록 이동하고 45도 기울여준다.
        context.cgContext.translateBy(x: (device_width / 2) - (sqrt(2) / 2 * rect.width), y: rect.height/4)
        let angle = CGFloat(-45) * .pi / 180
        context.cgContext.rotate(by: angle)
    
    	//Font를 설정한다.
        let font = UIFont.systemFont(ofSize:20)
        let attrs:[NSAttributedString.Key: Any] = [
            .foregroundColor: #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1),
            .font: font,
        ]
        let size = (text as NSString).size(withAttributes: attrs)
        
        //2.watermark text를 찍어낸다.
        var x = CGFloat(0)
        var y = CGFloat(0)
        var i = 1
        repeat {
            (text as NSString).draw(at: CGPoint(x: x, y: y), withAttributes : attrs)
            x += 2 * size.width
            if(x >= rect.width){
                x = size.width * CGFloat(i)
                y += 100
                i = ( i == 0 ) ? 1 : 0
            }
            
        }while x < rect.width && y < rect.height
        
    }
    
    return image
}

필자는 아래와 같이 Current View의 중심점과 Watermark의 중심점을 맞추고 45도 기울이도록 세팅할 예정이다.

 

1.Image기준 좌표를 view의 모든 부분을 커버할 수 있도록 이동해준다.

1) Image의 기준점은 왼쪽 상단 꼭지점이다.

    이 점을 기준으로 이동하고 회전한다.

 

2) Y축으로 Current View의 절반만큼 움직인다.

 

3) X축으로 요만큼(???) 이동한다.

    기울였을때 WatermarkView의 중앙이 Current View의 중앙이 되도록 계산했다.

    물론 뇌피셜이다.

    (여기서 오랜만의 피타고라스의 유산을 사용해본다.)

 

4) 마지막으로 45도 기울여 세련됨(?)을 추가하면 끝.

 

2.watermark text를 찍어낸다.

repeat-while문을 사용하여 아래와 같이 듬성듬성 찍어냈다.

이 것도 좌표를 이용해 찍었는데 기울인 각도가 아닌

정방향의 정사각형에 찍어낸다고 생각하면 더 쉬웠던 것 같다.

 

작동화면을 끝으로 포스트를 마무리한다.

댓글