如何在 Gtk3 中在开罗上下文中使用 Skia 绘制
Posted
技术标签:
【中文标题】如何在 Gtk3 中在开罗上下文中使用 Skia 绘制【英文标题】:How to draw with Skia on Cairo context in Gtk3 【发布时间】:2016-02-29 14:14:34 【问题描述】:我希望得到彩色矩形,但得到的是垃圾矩形。到目前为止,我有以下代码:
using System;
using GLib;
using SkiaSharp;
using Gtk;
namespace SkiaSharpExample
class CCDrawingArea : DrawingArea
protected override bool OnDrawn (Cairo.Context cr)
using (var skSurface = SKSurface.Create (100, 100, SKColorType.N_32, SKAlphaType.Premul))
var canvas = skSurface.Canvas;
var paint = new SKPaint
StrokeWidth = 4,
Color = new SKColor (255, 255, 255, 255)
;
var rect = new SKRect (10, 10, 50, 50);
canvas.DrawRect (rect, paint);
var image = skSurface.Snapshot ();
Cairo.Surface surface = new Cairo.ImageSurface (
image.Encode ().Data,
Cairo.Format.Argb32,
image.Width, image.Height,
4 * image.Width * image.Height);
surface.MarkDirty ();
cr.SetSourceSurface (surface, 0, 0);
cr.Paint ();
return true;
class MainClass
public static void Main (string[] args)
ExceptionManager.UnhandledException += delegate(UnhandledExceptionArgs expArgs)
Console.WriteLine (expArgs.ExceptionObject.ToString ());
expArgs.ExitApplication = true;
;
Gtk.Application.Init ();
var window = new Window ("Hello World");
window.SetDefaultSize (1024, 800);
window.SetPosition (WindowPosition.Center);
window.DeleteEvent += delegate
Gtk.Application.Quit ();
;
var darea = new CCDrawingArea ();
window.Add (darea);
window.ShowAll ();
Gtk.Application.Run ();
【问题讨论】:
【参考方案1】:我对 Skia 毫无头绪,也找不到任何有关其图像格式的文档,但这里的最后一个参数应该是步幅。 自然步幅为4*image.Width
。这也是Skia使用的吗? (步幅是一个像素的开头和该像素下面的像素之间的字节数)
Cairo.Surface surface = new Cairo.ImageSurface (
image.Encode ().Data,
Cairo.Format.Argb32,
image.Width, image.Height,
4 * image.Width * image.Height);
【讨论】:
是的,这是问题的一部分,我应该使用 4 * image.Width【参考方案2】:我找到了在创建 SKSurface 和 SKCanvas 之前我应该使用 SKBitmap 的解决方案。要获取像素数据,我应该使用 SKBitmap.GetPixels 方法。以下是工作示例的源代码:
using System;
using GLib;
using SkiaSharp;
using Gtk;
namespace SkiaSharpExample
class CCDrawingArea : DrawingArea
protected override bool OnDrawn(Cairo.Context cr)
const int width = 100;
const int height = 100;
using (var bitmap = new SKBitmap(width, height, SKColorType.N_32, SKAlphaType.Premul))
IntPtr len;
using (var skSurface = SKSurface.Create(bitmap.Info.Width, bitmap.Info.Height, SKColorType.N_32, SKAlphaType.Premul, bitmap.GetPixels(out len), bitmap.Info.RowBytes))
var canvas = skSurface.Canvas;
canvas.Clear(SKColors.White);
using (var paint = new SKPaint())
paint.StrokeWidth = 4;
paint.Color = new SKColor(0x2c, 0x3e, 0x50);
var rect = new SKRect(10, 10, 50, 50);
canvas.DrawRect(rect, paint);
Cairo.Surface surface = new Cairo.ImageSurface(
bitmap.GetPixels(out len),
Cairo.Format.Argb32,
bitmap.Width, bitmap.Height,
bitmap.Width * 4);
surface.MarkDirty();
cr.SetSourceSurface(surface, 0, 0);
cr.Paint();
return true;
class MainClass
public static void Main(string[] args)
ExceptionManager.UnhandledException += delegate(UnhandledExceptionArgs expArgs)
Console.WriteLine(expArgs.ExceptionObject.ToString());
expArgs.ExitApplication = true;
;
Gtk.Application.Init();
var window = new Window("Hello Skia World");
window.SetDefaultSize(1024, 800);
window.SetPosition(WindowPosition.Center);
window.DeleteEvent += delegate
Gtk.Application.Quit();
;
var darea = new CCDrawingArea();
window.Add(darea);
window.ShowAll();
Gtk.Application.Run();
void OnException(object o, UnhandledExceptionArgs args)
【讨论】:
此代码仅适用于Cairo.Format.Argb32
和 SKColorType.N_32
定义相同 A-R-G-B 顺序的 Windows。在 Linux 和 Mac 上,SKColorType.N_32
改为 A-B-G-R
。以上是关于如何在 Gtk3 中在开罗上下文中使用 Skia 绘制的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Cairo 和 Gtk3 在 GtkDrawingArea 中绘制一条线
如何在Haskell gtk2hs中将Cairo绘图渲染到打印机