Cómo representar un mapa de bits fuera de la pantalla y luego pasar a la pantalla con Core Graphics
-
03-07-2019 - |
Pregunta
Me gustaría renderizar a un mapa de bits fuera de pantalla (o una matriz de valores RGBA) y luego combinarlos en una UIView
durante la función drawRect
de la vista. Preferiría realizar la representación completa de 32 bits (incluido el canal alfa), pero también estaría contento con la representación de 24 bits.
¿A alguien le importaría apuntarme en la dirección correcta con algunos fragmentos de código o API relevantes?
Además, sé exactamente cómo hacerlo utilizando OpenGL. Preferiría hacer este trabajo en Core Graphics.
Solución
Para renderizar en un contexto fuera de la pantalla y guardarlo como CGImageRef:
void *bitmapData = calloc(height, bytesPerLine);
CGContextRef offscreen = CGBitmapContextCreate(..., bitmapData, ...)
// draw stuff into offscreen
CGImageRef image = CGBitmapContextCreateImage(offscreen);
CFRelease(offscreen);
free(bitmapData);
Para dibujarlo en la pantalla:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, rect, image);
}
También puede simplemente guardar la imagen en la propiedad de contenido de la capa de la vista ( view.layer.contents = image
), o usar un UIImageView.
Otros consejos
Puede usar un CGBitmapContext . Puede generar una imagen desde un CGBitmapContext y dibujarla durante su drawRect.
Use CGDataProviderCreateWithData
y CGImageCreate
si no necesita el contexto de mapa de bits y solo quiere el CGImageRef
.
Para referencias futuras, aquí hay un ejemplo completo en Swift 2.1 de renderizar a un mapa de bits fuera de la pantalla y mostrarlo en la pantalla.
Tenga en cuenta que una vez que haya creado el contexto de mapa de bits, puede seguir dibujando más contenido en él y actualizar la vista cuando lo desee. Esto es excelente si desea realizar una larga operación de dibujo en un hilo de fondo y mostrar periódicamente el progreso al usuario.
Ver controlador:
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
}
}
Subclase de 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)
}
}