Swift에서 텍스트를 이미지로 렌더링하는 방법: UIGraphicsImageRenderer 활용하기

[진행] {BE} Python 3.1x / naver.how/f / 2020. 7. 1. 00:04

  • 수정
  • (공개)→비공개로 변경
  • 관련글(트랙백)
  • 삭제

iOS 애플리케이션 개발 과정에서 텍스트를 이미지로 변환해야 하는 상황이 종종 발생합니다. 특히 복잡한 레이아웃이나 사용자 정의 텍스트 스타일을 적용할 때, 텍스트를 이미지로 렌더링하면 더 일관된 표현이 가능합니다. 이번 포스팅에서는 Swift에서 UIGraphicsImageRenderer를 사용하여 텍스트를 이미지로 렌더링하는 방법을 알아보겠습니다.

UIGraphicsImageRenderer란?

UIGraphicsImageRenderer는 iOS 10부터 도입된 클래스로, 이미지 생성 및 렌더링 작업을 더 효율적으로 수행할 수 있게 해줍니다. 기존의 UIGraphicsBeginImageContextWithOptionsUIGraphicsEndImageContext 방식보다 메모리 사용량이 적고 성능이 우수합니다.

텍스트를 이미지로 변환하는 예제 코드

다음은 문자열을 이미지로 변환하는 함수의 예제 코드입니다. 이 코드는 러프한 코드 뭉치이지만, 실제 개발 상황에서 유용하게 활용할 수 있습니다.

private func drawText(str: String, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, txtSize: CGFloat) -> CALayer {
    let commonWidth = width + (txtSize / 4)
    let renderer = UIGraphicsImageRenderer(size: CGSize(width: commonWidth, height: height))
    let img = renderer.image { soraforever in
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center
        let attrs = [NSAttributedStringKey.font: UIFont(name: "".font1(), size: txtSize)!, NSAttributedStringKey.paragraphStyle: paragraphStyle]
        let string = str
        string.draw(with: CGRect(x: 0, y: 0, width: commonWidth, height: height), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)
    }
    
    // 여기서 CALayer를 생성하고 이미지를 설정하는 코드가 누락되어 있습니다.
    // 아래와 같이 구현할 수 있습니다.
    let layer = CALayer()
    layer.contents = img.cgImage
    layer.frame = CGRect(x: x, y: y, width: commonWidth, height: height)
    return layer
}

이 함수의 호출 예시는 다음과 같습니다:

self.addSublayer(drawText(str: String(l), x: xlocation-(GS.s.jhATextPanelSize*3), y: jhDraw.ARQ-mMargin, width: GS.s.jhATextPanelSize, height: GS.s.jhATextPanelSize, txtSize: GS.s.jhATextSize))

self.addSublayer(drawText(str: mUnit, x: 50, y: 50, width: GS.s.jhATextPanelSize+10, height: GS.s.jhATextPanelSize, txtSize: 7))

self.addSublayer(drawText(str: label, x: 100, y: fx2 - 600, width: GS.s.jhATextPanelSize, height: GS.s.jhATextPanelSize, txtSize: GS.s.jhATextSize))

코드 분석 및 개선점

위 코드를 자세히 살펴보겠습니다.

1. 함수 매개변수

private func drawText(str: String, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, txtSize: CGFloat) -> CALayer

이 함수는 6개의 매개변수를 받습니다:

  • str: 이미지로 변환할 문자열
  • x, y: 레이어의 위치 좌표
  • width, height: 텍스트 영역의 크기
  • txtSize: 텍스트 크기

2. UIGraphicsImageRenderer 사용

let commonWidth = width + (txtSize / 4)
let renderer = UIGraphicsImageRenderer(size: CGSize(width: commonWidth, height: height))

여기서 commonWidth는 텍스트 영역의 너비에 텍스트 크기의 1/4을 더한 값으로, 텍스트가 잘리지 않도록 여유 공간을 확보합니다. UIGraphicsImageRenderer는 이 크기로 이미지를 생성합니다.

3. 텍스트 스타일 설정

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let attrs = [NSAttributedStringKey.font: UIFont(name: "".font1(), size: txtSize)!, NSAttributedStringKey.paragraphStyle: paragraphStyle]

여기서는 텍스트의 스타일을 설정합니다:

  • 단락 스타일을 생성하고 텍스트 정렬을 가운데로 설정합니다.
  • 폰트는 "".font1()을 사용하는데, 이는 확장 메서드로 특정 폰트를 반환하는 것으로 보입니다.
  • NSAttributedStringKey를 사용하여 폰트와 단락 스타일을 설정합니다.

4. 텍스트 그리기

let string = str
string.draw(with: CGRect(x: 0, y: 0, width: commonWidth, height: height), options: .usesLineFragmentOrigin, attributes: attrs, context: nil)

draw(with:options:attributes:context:) 메서드를 사용하여 지정된 사각형 영역에 텍스트를 그립니다. .usesLineFragmentOrigin 옵션은 텍스트 라인이 지정된 사각형의 원점에서 시작하도록 합니다.

5. CALayer 반환 (누락된 부분)

원본 코드에서는 이미지로부터 CALayer를 생성하는 부분이 누락되어 있습니다. 완전한 구현은 다음과 같을 수 있습니다:

let layer = CALayer()
layer.contents = img.cgImage
layer.frame = CGRect(x: x, y: y, width: commonWidth, height: height)
return layer

개선된 코드

원본 코드의 몇 가지 문제점을 개선한 버전을 제안합니다:

private func drawText(str: String, x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, txtSize: CGFloat, alignment: NSTextAlignment = .center, fontName: String = "Helvetica") -> CALayer {
    // 텍스트 크기에 따른 여유 공간 계산
    let commonWidth = width + (txtSize / 4)
    
    // 이미지 렌더러 생성
    let renderer = UIGraphicsImageRenderer(size: CGSize(width: commonWidth, height: height))
    
    // 이미지 생성
    let img = renderer.image { context in
        // 단락 스타일 설정
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = alignment
        
        // 폰트 및 속성 설정
        let font = UIFont(name: fontName, size: txtSize) ?? UIFont.systemFont(ofSize: txtSize)
        let attrs: [NSAttributedString.Key: Any] = [
            .font: font,
            .paragraphStyle: paragraphStyle,
            .foregroundColor: UIColor.black
        ]
        
        // 텍스트 그리기
        str.draw(with: CGRect(x: 0, y: 0, width: commonWidth, height: height),
                options: .usesLineFragmentOrigin,
                attributes: attrs,
                context: nil)
    }
    
    // CALayer 생성 및 설정
    let layer = CALayer()
    layer.contents = img.cgImage
    layer.frame = CGRect(x: x, y: y, width: commonWidth, height: height)
    
    return layer
}

개선 사항:

  1. 기본값이 있는 매개변수 추가 (텍스트 정렬, 폰트 이름)
  2. 명확한 변수명 사용
  3. 폰트가 없을 경우를 대비한 예외 처리
  4. NSAttributedString.Key 사용 (최신 API)
  5. 텍스트 색상 추가

실제 사용 사례

이 함수는 다양한 상황에서 활용할 수 있습니다:

  1. 동적 차트나 그래프 레이블: let yAxisLabel = drawText(str: "\(value)°C", x: 10, y: yPosition, width: 50, height: 20, txtSize: 12) chartView.layer.addSublayer(yAxisLabel)
  2. 워터마크: let watermark = drawText(str: "© Company Name", x: view.bounds.width - 150, y: view.bounds.height - 30, width: 140, height: 20, txtSize: 10, alignment: .right) view.layer.addSublayer(watermark)
  3. 커스텀 배지나 알림: let notificationBadge = drawText(str: "\(count)", x: iconView.frame.maxX - 10, y: iconView.frame.minY - 5, width: 20, height: 20, txtSize: 10) notificationBadge.cornerRadius = 10 notificationBadge.backgroundColor = UIColor.red.cgColor view.layer.addSublayer(notificationBadge)

성능 고려사항

텍스트를 이미지로 렌더링하는 작업은 CPU 리소스를 사용하기 때문에, 이 기법을 과도하게 사용하면 앱 성능에 영향을 줄 수 있습니다. 다음 상황에서는 이 방법을 사용하는 것이 좋습니다:

  1. 자주 변경되지 않는 텍스트
  2. 표준 UILabel로 구현하기 어려운 복잡한 레이아웃
  3. 애니메이션이나 변환을 적용해야 하는 텍스트

반면, 자주 업데이트되는 텍스트나 대량의 텍스트 요소가 있는 경우에는 표준 UIKit 컴포넌트를 사용하는 것이 더 효율적일 수 있습니다.

결론

Swift에서 UIGraphicsImageRenderer를 사용하여 텍스트를 이미지로 렌더링하는 방법을 살펴보았습니다. 이 기법은 특히 커스텀 UI 요소를 만들거나 표준 텍스트 컴포넌트로 구현하기 어려운 레이아웃을 구현할 때 유용합니다.

제공된 코드를 기반으로 자신의 요구사항에 맞게 수정하여 사용하면, 더 풍부하고 다양한 텍스트 표현이 가능합니다. 성능 최적화를 위해 필요한 경우에만 이 방법을 사용하고, 가능하면 캐싱을 적용하는 것이 좋습니다.

러프한 코드 뭉치에서 출발했지만, 이를 분석하고 개선하여 실제 개발에 활용할 수 있는 유용한 도구로 만들 수 있었습니다. iOS 개발에서 텍스트를 이미지로 변환하는 작업이 필요하다면, 이 포스팅이 도움이 되길 바랍니다.

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다