[코어그래픽] 비트맵 그래픽 컨텍스트

비트맵 그래픽 컨텍스트는 비트맵 이미지를 담는 그래픽 컨텍스트이다. CGImage를 바탕으로 새로운 레이어를 생성하거나, 혹은 레이어에 그려진 그래픽을 CGImage 구조체로 만들 때 사용한다.

쉽게 말해, 터치 드로잉 앱을 만든다고 하면, 캔버스가 되는 뷰는 비트맵 컨텍스트를 하나 준비해서, 손가락의 움직임을 따라 레이어에 선을 그린다. 그려진 내용을 이 비트맵 컨텍스트에 저장한 다음 뷰의 현재 컨텍스트에는 비트맵이미지를 그려준다. 그러면 여태까지 그린 내용을 전부 하나의 비트맵 이미지에 기록하여 그림을 실시간으로 그려줄 수 있다. (레이어를 그리고, 이를 바로 뷰에 그리면, 이전에 그렸던 내용이 보존되지 않는다.)

비트맵 컨텍스트 만들기

비트맵 컨텍스트를 만들기 위해서는 몇 가지 정보가 필요하다. 비트맵은 고정된 영역의 크기와, 각 픽셀의 정보값의 크기(몇 비트인지), 그리고 비트맵에 컬러를 표시할 때 사용하는 색공간은 무엇인지 등의 정보가 필요하다.

CGColorSpaceRef colorSpace = CGColorSpaceDeviceRGB();
CGContextRef *bitmapCTX = CGBitmapContextCreate(NULL,
                    self.frame.size.width,
                    self.frame.size.height,
                    8,
                    4 * 8 * self.frame.size.width,
                    colorspace,
                    kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);

각 파라미터를 순서대로 살펴보자

  1. NULL – 첫번째 인자는 사용할 메모리 영역이다. 이는 NULL을 넣어주면 쿼츠에서 적당한 영역을 자동으로 잡아준다.
  2. width – 비트맵 영역의 폭을 픽셀 단위로 잡아준다.
  3. height – 비트맵 영역의 높이를 픽셀 단위로 잡아준다.
  4. 8 – 컴포넌트 당 비트이다. 통상 8을 준다. 즉 RGB 각 채널당 8비트(256)의 단계를 표현한다.
  5. 1줄을 표현하는데 사용하는 정보의 크기이다. 8비트 * 4개컴포언트(RGBA) * 1줄당 픽셀 수를 곱한 값이 된다.
  6. colorSpace – CGColorSpace의 참조를 전달한다.
  7. kCGImageAlphaPremultipliedLast – 알파 인덱스가 어떻게 처리되는지를 결정하는 값이다. 이는 CGImage Reference를 참조한다.

이렇게 만들어진 비트맵 그래픽 컨텍스트에 그림을 그리면 쉽게 CGImage를 얻을 수 있다. 또한 CGImage는 다시 쉽게 UIImage로 변환이 가능하다.

[추가]

비트맵 컨텍스트를 고려해볼 상황

뷰에 어떤 그림을 패스로 그리고자 할 때는 UIGraphicsGetCurrentContext 함수를 사용해서 현재 컨텍스트를 얻고, 이 컨텍스트에 그림을 그리면 된다. 문제는 이 메소드를 통해 컨텍스트를 얻을 수 있는 상황이 self 가 UIView 일때만 가능하다는 것이다. 만약 뷰 컨트롤러 등의 객체에서 이 메소드를 호출한다면 nil을 돌려받을 뿐이다.

이 때는 비트맵 컨텍스트를 생성해서, 이 컨텍스트에 그림을 그릴 수 있다. 다시 이 컨텍스트의 내용으로 이미지를 만들어서 원하는 View에 그려넣으면 UIView를 커스터마이징하지 않고 해결할 수 있다.

UIKit은 비트맵 그래픽 컨텍스트를 생성하여 이를 현재 그래픽 컨텍스트로 만드는 함수를 제공한다. UIGraphicsBeginImageContext() 함수가 그것이다. 그래픽 컨텍스트를 여러 개 생성하여 사용하는 것은 스택에 컨텍스트들을 쌓아두고 사용하는 것이므로, 이 함수를 사용하여 비트맵 컨텍스트를 시작하였다면 반드시 UIGraphicsEndImageContext() 함수를 호출해서 컨텍스트를 종료해주도록 한다.

참고로 UIGraphicsBeginImageContextWithOption() 함수는 사이즈와 투명픽셀여부 및 스케일 팩터를 인수로 받아 좀 더 최적화된 비트맵 컨텍스트를 생성할 수 있다. 스케일 팩터 값은 0으로 주면 기본적으로 UIScreen의 스케일팩터와 동일한 값을 갖는다. 스케일 팩터는 ‘해상도’와 비슷한 개념인데 실제 물리적인 길이 단위인 pt 를 몇 개의 픽셀로 표현하는가를 정하는 개념이다.