Comment rendre en bitmap hors écran puis en écran à l’aide de Core Graphics
-
03-07-2019 - |
Question
Je souhaite rendre un bitmap hors écran (ou un tableau de valeurs RGBA), puis les convertir en un UIView
au cours de la fonction drawRect
de la vue. Je préférerais effectuer un rendu complet sur 32 bits (y compris le canal alpha), mais je me contenterais également d'un rendu sur 24 bits.
Quelqu'un voudrait-il m'indiquer la bonne direction avec des extraits de code ou des API pertinentes?
De plus, je sais exactement comment faire cela avec OpenGL - je préférerais simplement faire ce travail dans Core Graphics lui-même.
La solution
Pour effectuer le rendu dans un contexte hors écran et l'enregistrer en tant que CGImageRef:
void *bitmapData = calloc(height, bytesPerLine);
CGContextRef offscreen = CGBitmapContextCreate(..., bitmapData, ...)
// draw stuff into offscreen
CGImageRef image = CGBitmapContextCreateImage(offscreen);
CFRelease(offscreen);
free(bitmapData);
Pour le dessiner à l'écran:
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, rect, image);
}
Vous pouvez également simplement enregistrer l'image dans la propriété de contenu de la couche ( view.layer.contents = image
) ou utiliser un UIImageView.
Autres conseils
Vous pouvez utiliser un CGBitmapContext . Vous pouvez générer une image à partir d'un CGBitmapContext et la dessiner lors de votre drawRect.
Utilisez CGDataProviderCreateWithData ??code> et
CGImageCreate
si vous n'avez pas besoin du contexte bitmap et souhaitez simplement le CGImageRef
.
Pour référence future, voici un exemple complet dans Swift 2.1 de rendu en bitmap hors écran et de son affichage à l'écran.
Notez qu'une fois que vous avez créé le contexte bitmap, vous pouvez continuer à y dessiner plus de contenu et à mettre à jour la vue quand vous le souhaitez. C’est génial si vous souhaitez effectuer une longue opération de dessin sur un fil d’arrière-plan et afficher périodiquement les progrès à l’utilisateur.
Contrôleur de vue:
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
}
}
Sous-classe d'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)
}
}