Come eseguire il rendering su bitmap fuori schermo, quindi eseguire il blit sullo schermo utilizzando Core Graphics
-
03-07-2019 - |
Domanda
Vorrei eseguire il rendering su una bitmap fuori schermo (o array di valori RGBA) e poi trasferirli su un UIView
durante la funzione drawRect
della vista. Preferirei eseguire il rendering completo a 32 bit (incluso il canale alfa), ma sarei anche contento del rendering a 24 bit.
Qualcuno potrebbe dispiacermi indicarmi la giusta direzione con alcuni frammenti di codice o API pertinenti?
Inoltre, so esattamente come farlo usando OpenGL - Preferirei semplicemente fare questo lavoro nella Core Graphics stessa.
Soluzione
Per eseguire il rendering in un contesto fuori schermo e salvarlo come CGImageRef:
void *bitmapData = calloc(height, bytesPerLine);
CGContextRef offscreen = CGBitmapContextCreate(..., bitmapData, ...)
// draw stuff into offscreen
CGImageRef image = CGBitmapContextCreateImage(offscreen);
CFRelease(offscreen);
free(bitmapData);
Per disegnarlo sullo schermo:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, rect, image);
}
Potresti anche salvare l'immagine nella proprietà dei contenuti del layer della vista ( view.layer.contents = image
) o usare un UIImageView.
Altri suggerimenti
Puoi utilizzare un CGBitmapContext . Puoi generare un'immagine da un CGBitmapContext e disegnarla durante drawRect.
Usa CGDataProviderCreateWithData
e CGImageCreate
se non hai bisogno del contesto bitmap e vuoi solo CGImageRef
.
Per riferimento futuro, ecco un esempio completo in Swift 2.1 di rendering su una bitmap fuori schermo e visualizzazione sullo schermo.
Notare che una volta creato il contesto bitmap è possibile continuare a disegnare più contenuto e aggiornare la vista quando si desidera. Questo è fantastico se vuoi fare una lunga operazione di disegno su un thread in background e mostrare periodicamente i progressi all'utente.
Visualizza controller:
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
}
}
Sottoclasse di 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)
}
}