API-Referenz: Surface
Die Surface-Klasse ist das Ziel für alle Zeichenbefehle. Sie verwaltet den Pixelspeicher (auf CPU oder GPU) und stellt das Canvas bereit, das Sie zum Zeichnen verwenden.
Überblick
Eine Surface ist verantwortlich für:
- Das Halten der Pixeldaten (oder das Verwalten der GPU-Textur).
- Das Bereitstellen einer
Canvas-Schnittstelle, um in diese Daten zu zeichnen. - Das Erstellen eines Schnappschusses (
Image) des aktuellen Inhalts.
Erstellen einer Surface
1. Raster-Surface (CPU)
Die einfachste Surface. Pixel befinden sich im Standardsystemspeicher (RAM). Am besten geeignet zum Generieren von Bildern, serverseitigem Rendern oder zum Testen.
// Standard 32-bit RGBA-Surface
Surface raster = Surface.makeRasterN32Premul(800, 600);
// Mit benutzerdefinierter ImageInfo (z.B. F16-Farbe für HDR)
ImageInfo info = new ImageInfo(800, 600, ColorType.RGBA_F16, AlphaType.PREMUL);
Surface hdrSurface = Surface.makeRaster(info);2. GPU-Surface (Renderziel)
Wird für hardwarebeschleunigtes Rendern verwendet. Sie benötigen einen DirectContext (OpenGL/Metal/Vulkan-Kontext).
DirectContext context = ...; // Ihr GPU-Kontext
// Erstellt eine neue Textur auf der GPU, die von Skia verwaltet wird
Surface gpuSurface = Surface.makeRenderTarget(
context,
false, // Budgeted? (Sollte Skia dies gegen sein Cache-Limit zählen?)
ImageInfo.makeN32Premul(800, 600)
);3. Einbinden bestehender OpenGL/Metal-Texturen
Wenn Sie Skija in eine bestehende Game-Engine oder ein Fenstersystem (wie LWJGL oder JWM) integrieren, stellt das Fenster normalerweise eine "Framebuffer"- oder "Textur"-ID bereit. Diese binden Sie ein, damit Skija direkt auf den Bildschirm zeichnen kann.
// OpenGL-Beispiel
int framebufferId = 0; // Standard-Bildschirmpuffer
BackendRenderTarget renderTarget = BackendRenderTarget.makeGL(
800, 600, // Breite, Höhe
0, // Sample-Anzahl (0 für kein MSAA)
8, // Stencil-Bits
framebufferId,
BackendRenderTarget.FRAMEBUFFER_FORMAT_GR_GL_RGBA8
);
Surface screenSurface = Surface.wrapBackendRenderTarget(
context,
renderTarget,
SurfaceOrigin.BOTTOM_LEFT, // OpenGL-Koordinaten beginnen unten links
ColorType.RGBA_8888,
ColorSpace.getSRGB(),
null // SurfaceProps
);4. Einbinden von Raster-Pixeln (Interop)
Wenn Sie einen ByteBuffer oder Zeiger von einer anderen Bibliothek haben (z.B. von einem Videoframe-Decoder), können Sie ihn direkt einbinden, ohne ihn zu kopieren.
long pixelPtr = ...; // Nativer Zeiger auf den Speicher
int rowBytes = width * 4; // Bytes pro Zeile
Surface wrap = Surface.wrapPixels(
ImageInfo.makeN32Premul(width, height),
pixelPtr,
rowBytes
);5. Null-Surface
Erstellt eine Surface, die nichts tut. Nützlich zum Messen oder Testen ohne Speicherzuweisung.
Surface nullSurface = Surface.makeNull(100, 100);Erstellen von Schnappschüssen (Image)
Das Erstellen eines unveränderlichen Image aus einer Surface ist eine kostengünstige Operation (Copy-on-Write).
// Dies kopiert die Pixel nicht sofort!
// Es "verzweigt" effektiv die Surface. Zukünftige Zeichenoperationen auf 'surface' beeinflussen 'snapshot' nicht.
Image snapshot = surface.makeImageSnapshot();
// Sie können 'snapshot' jetzt verwenden, um auf eine andere Surface zu zeichnen oder auf die Festplatte zu speichern.Interaktion mit dem Inhalt
// Holt das Canvas zum Zeichnen
Canvas canvas = surface.getCanvas();
canvas.drawCircle(50, 50, 20, paint);
// Liest Pixel zurück in eine Bitmap
Bitmap bitmap = new Bitmap();
bitmap.allocPixels(ImageInfo.makeN32Premul(100, 100));
if (surface.readPixels(bitmap, 0, 0)) {
// Pixel erfolgreich gelesen
}
// Schreibt Pixel von einer Bitmap auf die Surface
surface.writePixels(bitmap, 10, 10);
// Sendet Befehle an die GPU (wichtig für GPU-Surfaces)
surface.flush();getCanvas(): Gibt das Canvas zum Zeichnen zurück.readPixels(bitmap, x, y): Liest Pixel von der GPU/CPU zurück in eine Bitmap.writePixels(bitmap, x, y): Schreibt Pixel von einer Bitmap auf die Surface.flush(): Stellt sicher, dass alle ausstehenden GPU-Befehle an den Treiber gesendet werden.notifyContentWillChange(): Rufen Sie dies auf, wenn Sie den zugrundeliegenden Pixelspeicher direkt ändern (unter Umgehung des Canvas).getRecordingContext(): Gibt denDirectContextzurück, der diese Surface unterstützt (falls vorhanden).