Как визуализировать растровое изображение вне экрана, а затем blit на экран с использованием Core Graphics
Я хотел бы отобразить на offscreen растровое изображение (или массив значений RGBA), а затем разбить их на UIView
во время просмотра функции drawRect
. Я бы предпочел сделать полный 32-битный рендеринг (включая альфа-канал), но также будет доволен 24-битным рендерингом.
Кто-нибудь может указать мне в правильном направлении с некоторыми фрагментами кода или соответствующими API-интерфейсами?
Кроме того, я точно знаю, как это сделать с помощью OpenGL - я бы просто предпочел сделать эту работу в самой основной графике.
Ответы
Ответ 1
Вынести в контекст вне экрана и сохранить его как CGImageRef:
void *bitmapData = calloc(height, bytesPerLine);
CGContextRef offscreen = CGBitmapContextCreate(..., bitmapData, ...)
// draw stuff into offscreen
CGImageRef image = CGBitmapContextCreateImage(offscreen);
CFRelease(offscreen);
free(bitmapData);
Чтобы нарисовать его на экране:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, rect, image);
}
Вы также можете просто сохранить изображение в свойстве содержимого слоя представления (view.layer.contents = image
) или использовать UIImageView.
Ответ 2
Вы можете использовать CGBitmapContext. Вы можете сгенерировать изображение из CGBitmapContext и нарисовать его во время drawRect.
Ответ 3
Используйте CGDataProviderCreateWithData
и CGImageCreate
если вам не нужен растровый контекст и вы просто хотите CGImageRef
.
Ответ 4
В дальнейшем для справки здесь приведен полный пример в Swift 2.1 рендеринга на экранное растровое изображение и его отображение на экране.
Обратите внимание, что как только вы создали контекст растрового изображения, вы можете продолжать рисовать в него больше контента и обновлять представление, когда захотите. Это здорово, если вы хотите сделать длинную операцию рисования в фоновом потоке и периодически показывать прогресс пользователю.
Контроллер просмотра:
import UIKit
class ViewController: UIViewController {
@IBOutlet var myView: MyView!
var bitmapContext: CGContext?
override func viewDidLoad() {
super.viewDidLoad()
createBitmapContext()
drawContentIntoBitmap()
myView.update(from: bitmapContext)
releaseBitmapContext()
}
func createBitmapContext() {
bitmapContext = CGBitmapContextCreate(
nil, // auto-assign memory for the bitmap
Int (myView.bounds.width * UIScreen.mainScreen().scale), // width of the view in pixels
Int (myView.bounds.height * UIScreen.mainScreen().scale), // height of the view in pixels
8, // 8 bits per colour component
0, // auto-calculate bytes per row
CGColorSpaceCreateDeviceRGB(), // create a suitable colour space
CGImageAlphaInfo.PremultipliedFirst.rawValue) // use quartz-friendly byte ordering
}
func drawContentIntoBitmap() {
CGContextScaleCTM(bitmapContext, UIScreen.mainScreen().scale, UIScreen.mainScreen().scale) // convert to points dimensions
CGContextSetStrokeColorWithColor (bitmapContext, UIColor.redColor().CGColor)
CGContextSetLineWidth (bitmapContext, 5.0)
CGContextStrokeEllipseInRect (bitmapContext, CGRectMake(50, 50, 100, 100))
}
func releaseBitmapContext() {
bitmapContext = nil // in Swift, CGContext and CGColorSpace objects are memory managed by automatic reference counting
}
}
Подкласс UIView:
import UIKit
class MyView: UIView {
var cgImage: CGImage?
func update(from bitmapContext: CGContext?) {
cgImage = CGBitmapContextCreateImage(bitmapContext)
setNeedsDisplay()
}
override func drawRect(rect: CGRect) {
let displayContext = UIGraphicsGetCurrentContext()
CGContextDrawImage(displayContext, bounds, cgImage)
}
}