Files
gio-patched/widget/image_test.go
T
Dominik Honnef 51b11486c5 widget: [API] correct default scaling of images
When no scale factor is set, scale by 1.0, mapping one image pixel to
one device-independent pixel. This matches the behavior of CSS and other
frameworks.

The old code attempted to convert to Dp while taking the image's DPI
into account. This was wrong in two ways:

- It assumed that the default display DPI is 160, but this is only true
  for Android. Other platforms use 96, 162, or leave it undefined. Thus
  image.Layout's idea of a dp didn't match that of Gio on most
  platforms.

- It tried to account for image DPI, and assumed a default of 72. This
  was wrong in that DPI in images is merely metadata meant for printing,
  not display. The vast majority of software such as image viewers and
  image editors do not take DPI into account, mapping one image pixel
  either to one physical pixel or to one device-independent pixel. That
  is, users would expect their images to either display 1 to 1, or scaled
  based on PxPerDp, but not scaled based on the image's DPI.

We default to a scale of 1 to stay consistent with other parts of Gio
that scale by default. Users who don't want any scaling can continue to
set the scale to the inverse of PxPerDp.

While we're here we clarify the documentation of the Scale field.

This change is backwards incompatible for users that relied on the
default scale.

Signed-off-by: Dominik Honnef <dominik@honnef.co>
2023-03-23 17:06:43 -06:00

67 lines
2.1 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package widget
import (
"image"
"testing"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/op/paint"
)
func TestImageScale(t *testing.T) {
var ops op.Ops
gtx := layout.Context{
Ops: &ops,
Constraints: layout.Constraints{
Max: image.Pt(50, 50),
},
}
imgSize := image.Pt(10, 10)
img := image.NewNRGBA(image.Rectangle{Max: imgSize})
imgOp := paint.NewImageOp(img)
// Ensure the default scales correctly.
dims := Image{Src: imgOp}.Layout(gtx)
expectedSize := imgSize
expectedSize.X = int(float32(expectedSize.X))
expectedSize.Y = int(float32(expectedSize.Y))
if dims.Size != expectedSize {
t.Fatalf("non-scaled image is wrong size, expected %v, got %v", expectedSize, dims.Size)
}
// Ensure scaling the image via the Scale field works.
currentScale := float32(0.5)
dims = Image{Src: imgOp, Scale: float32(currentScale)}.Layout(gtx)
expectedSize = imgSize
expectedSize.X = int(float32(expectedSize.X) * currentScale)
expectedSize.Y = int(float32(expectedSize.Y) * currentScale)
if dims.Size != expectedSize {
t.Fatalf(".5 scale image is wrong size, expected %v, got %v", expectedSize, dims.Size)
}
// Ensure the image responds to changes in DPI.
currentScale = float32(1)
gtx.Metric.PxPerDp = 2
dims = Image{Src: imgOp, Scale: float32(currentScale)}.Layout(gtx)
expectedSize = imgSize
expectedSize.X = int(float32(expectedSize.X) * currentScale * gtx.Metric.PxPerDp)
expectedSize.Y = int(float32(expectedSize.Y) * currentScale * gtx.Metric.PxPerDp)
if dims.Size != expectedSize {
t.Fatalf("HiDPI non-scaled image is wrong size, expected %v, got %v", expectedSize, dims.Size)
}
// Ensure scaling the image responds to changes in DPI.
currentScale = float32(.5)
gtx.Metric.PxPerDp = 2
dims = Image{Src: imgOp, Scale: float32(currentScale)}.Layout(gtx)
expectedSize = imgSize
expectedSize.X = int(float32(expectedSize.X) * currentScale * gtx.Metric.PxPerDp)
expectedSize.Y = int(float32(expectedSize.Y) * currentScale * gtx.Metric.PxPerDp)
if dims.Size != expectedSize {
t.Fatalf("HiDPI .5 scale image is wrong size, expected %v, got %v", expectedSize, dims.Size)
}
}