Skip to content

图像 ​

ui.Image 显示位图,或按自身颜色显示的 SVG,默认以其 DIP 尺寸显示; 给定其他尺寸时按比例缩放以适应。

go
//go:embed logo.png
var logoPNG []byte

var logo, _ = ui.DecodeBitmap(logoPNG)

ui.Image(c, logo).Size(64, 64).Fit(ui.Contain).Radius(12)

位图 ​

ui.NewBitmap 从 image.Image 创建位图,ui.DecodeBitmap 从 PNG、JPEG、 GIF(第一帧)、WebP 或 BMP 数据创建,并按相机 EXIF 方向把照片转正。位图要 创建一次,不要在视图里创建:只要你在使用,MyGo 就会把位图保留在 GPU 上。 远小于其像素尺寸显示的位图,比如缩略图里的照片,绘制时用的是一份一次性 生成的逐级减半副本,减半到再减就更小为止,从而显示出每个像素的部分, 而不是闪烁。

位图在 CPU 和 GPU 上都保留像素,照片很多的程序会明显感觉到这一点。 DecodeBitmap 创建的位图显示过一次之后,ReleasePixels 会释放它的 CPU 副本,包括原图和各级减半副本:它仍照常从 GPU 绘制;当再次需要像素时—— 比如 GPU 丢失了纹理,或连续几帧没用到而释放了它,CPU 渲染器,或为更小绘制 而需要的减半副本——像素会从 DecodeBitmap 当初接收的数据重新解码,位图 保留着这些数据,而且这些数据必须保持原样;而上传到 GPU 后又会再次释放。 这些数据的开销只是像素的一小部分。NewBitmap 创建的位图、画布的位图, 或被 Update 改过的位图,没有别的东西可以重新生成像素,因此会保留像素。 和绘制一样,在主线程调用 ReleasePixels:

go
cover, _ := ui.DecodeBitmap(fileData)
// … once the cover has shown:
cover.ReleasePixels()

Update 让位图显示另一张图,适用于像视频那样不断变化的图像。尺寸相同时, 它保留位图在 GPU 上的纹理并上传新像素,而每帧新建位图则会每帧新建一个 纹理。由 image.NewRGBA 创建的 *image.RGBA 无需复制即可使用:在下一次 Update 之前,保持它的像素不变。在 goroutine 上解码的帧通过 Window.Update 送达位图,由它重绘窗口:

go
go func() {
	for frame := range frames { // *image.RGBA, a new one each time
		win.Update(func() { app.video.Update(frame) })
	}
}()

ui.Video 正是这样播放视频帧的:提前解码,每个帧到点即显示, 开箱即支持动画 GIF。

Pixelated 把放大到超过其像素尺寸显示的位图,画成一个个像素颜色的方块, 就像像素画和游戏精灵那样,而不是平滑地混合相邻像素。在整数倍尺寸下,每个 像素是一整块完整的屏幕像素。在其他尺寸,比如 2.5 倍缩放时,方块保持同样 大小,边缘在单个屏幕像素上过渡,而不会出现有的方块比别的宽一个像素,并且 它们平滑移动而不是跳格,与 Ebitengine 的 FilterPixelated 的绘制方式相同。 缩小时则和任何图像一样平滑。

go
tiles, err := ui.DecodeBitmap(tilesPNG)
if err != nil {
	log.Fatal(err)
}
tiles.Pixelated()
ui.Image(c, tiles).Size(64, 64) // 16×16 pixels, each 4×4

适配 ​

Fit 决定图像如何填充它的盒子:Contain(默认)把它完整放进盒子, Cover 铺满盒子并裁掉多余部分,FillBox 拉伸填满,ScaleDown 按自身尺寸 显示(放不下时才缩小),NaturalSize 按自身尺寸显示并裁剪。Grayscale 用 灰度绘制,比如用于禁用状态。Radius 圆角,AspectRatio 在会增大的盒子里 保持宽高比。

go
ui.Image(c, photo).AspectRatio(16.0 / 9).Fit(ui.Cover).Radius(8)

SVG ​

ui.ParseSVG 解析 SVG,ui.MustParseSVG 用于作为程序一部分的 SVG,比如 嵌入的文件,出错时 panic。除非给定其他尺寸,Image 按 SVG 自身给出的尺寸 (width 和 height,或 viewBox 的尺寸)以它自己的颜色显示 SVG,其中 currentColor 用文本颜色:

go
ui.Image(c, illustration).Width(240)

要让 SVG 按文本颜色显示(比如作为图标),用图标。

MyGo 把 SVG 的形状按显示尺寸各一次绘制进 GPU 的图集,与绘制文字的方式 相同,GPU 从图集里绘制它们:移动图像、滚动或改变颜色都不需要重新绘制。 MyGo 支持路径与基本形状、分组、use 和 symbol 元素、变换、填充与描边 (含其连接、端点与虚线)的颜色、currentColor 以及线性与径向渐变、 不透明度、裁剪路径、遮罩,以及只用简单选择器(类型、类、id)的样式表。 不支持文字、嵌入图像、图案(pattern)、标记(marker)与滤镜:导出前请在 编辑器里把文字转成路径。

在 Draw 回调中,Painter.Image 同样可以绘制位图和 SVG。

任意格式的图片 ​

ui.DecodeImage 解码事先不知道格式的图片,比如从链接下载的:格式为 DecodeBitmap 所认识时得到位图,否则得到指定尺寸的 SVG。ui.ImageSize 给出 Image 默认显示位图或 SVG 的尺寸(以 DIP 计),以便按比例设置大小:

go
pic, err := ui.DecodeImage(data) // once, as it arrives, not in the view
if err != nil {
	return err
}
// … in the view:
if w, h := ui.ImageSize(pic); w > 0 && h > 0 {
	ui.Image(c, pic).MaxWidthPercent(100).AspectRatio(w / h)
}

无障碍 ​

图像是辅助技术看不到的装饰,除非用 Label 为它命名,比如一张重要的照片。