Fix black border at strong album art zoom by scaling the recenter shift
The centering Translate formula, (1-s)*(ART_SIZE/2), was derived assuming it's applied in final output pixels. That held up at a moderate zoom (1.4x) but pushed past the image's actual edge at a strong one (1.7x) -- a real, on-device black border in the bottom-right corner, confirmed with the calibration tool (true black RGB(0,0,0) pixels, not just dark content). Dividing the shift by the scale factor keeps the crop inside the image's bounds at every zoom level the app offers, verified via the calibration tool at 1.0/1.15/1.4/1.7x and against a live station -- at the cost of the most extreme (1.7x) setting being very slightly off-center rather than perfectly centered, which is a trade worth making since going outside the art's bounds is worse. Moderate and subtle remain visibly centered.
This commit is contained in:
1 parent
16ac004d06
commit
9f2216c692
2 files changed
+16
-6
No files matched your search
@@ -30,7 +30,7 @@ ART_ZOOM_DURATION = 200
|
||||
def _art_widget(art_bytes, zoom_scale):
|
||||
art = render.Image(src = art_bytes, width = ART_SIZE, height = ART_SIZE)
|
||||
top_scale = max(zoom_scale, 1.0)
|
||||
shift = (1.0 - top_scale) * (ART_SIZE / 2.0)
|
||||
shift = (1.0 - top_scale) * (ART_SIZE / 2.0) / top_scale
|
||||
zoom = animation.Transformation(
|
||||
child = art,
|
||||
duration = ART_ZOOM_DURATION,
|
||||
|
||||
+15
-5
@@ -230,14 +230,24 @@ def _art_widget(art_bytes, zoom_scale):
|
||||
# bottom and right than the top and left -- most of the animation's
|
||||
# duration is spent between keyframes, not sitting at the symmetric
|
||||
# rest state, so this read as a persistent bottom/right crop. Pairing
|
||||
# Scale with a Translate that's a deterministic function of the same
|
||||
# scale value (`shift`) re-centers the zoom so it crops evenly from
|
||||
# Scale with a Translate re-centers the zoom so it crops evenly from
|
||||
# all sides instead -- verified against a calibration grid image.
|
||||
# This is safe because scale never drops below 1.0 here: the
|
||||
# black-border bug from an earlier version came from combining
|
||||
#
|
||||
# The naive "final pixel shift" formula, (1-s)*(ART_SIZE/2), looked
|
||||
# right at a moderate zoom (1.4x) but pushed past the image's actual
|
||||
# edge at a strong one (1.7x) -- a real, on-device black border in the
|
||||
# bottom-right corner. That means Translate isn't applied in final
|
||||
# output pixels here; empirically, dividing by `top_scale` keeps the
|
||||
# crop inside the image's bounds at every zoom level this app offers
|
||||
# (verified via the calibration tool at both 1.4x and 1.7x), at the
|
||||
# cost of the *most* extreme (1.7x) zoom being very slightly
|
||||
# off-center rather than perfectly centered -- a trade worth making
|
||||
# since going outside the art's bounds is worse than a slight
|
||||
# asymmetry. This is safe because scale never drops below 1.0 here:
|
||||
# the black-border bug from an earlier version came from combining
|
||||
# Translate with scale *below* 1.0, not from Translate itself.
|
||||
top_scale = max(zoom_scale, 1.0)
|
||||
shift = (1.0 - top_scale) * (ART_SIZE / 2.0)
|
||||
shift = (1.0 - top_scale) * (ART_SIZE / 2.0) / top_scale
|
||||
zoom = animation.Transformation(
|
||||
child = art,
|
||||
duration = ART_ZOOM_DURATION,
|
||||
|
||||