0
0
mirror of https://github.com/markusfisch/BinaryEye.git synced 2024-09-20 12:02:17 +02:00

Convert ROI handle positions to integer points

Because they're always discrete values and can never be inbetween.

Also, calling `drawBitmap()` with float values can lead to slightly
distorted renderings because the image is interpolated between
pixels then.

So let's just avoid this by using integers.
This commit is contained in:
Markus Fisch 2020-06-01 23:27:39 +02:00
parent d34fceb48f
commit 221cf11576

View File

@ -34,15 +34,15 @@ class DetectorView : View {
)
private val handleXRadius = handleBitmap.width / 2
private val handleYRadius = handleBitmap.height / 2
private val handleHome = PointF()
private val handlePos = PointF(-1f, -1f)
private val center = PointF()
private val touchDown = PointF()
private val distToFull: Float
private val minMoveThresholdSq: Float
private val cornerRadius: Float
private val fabHeight: Float
private val padding: Float
private val handleHome = Point()
private val handlePos = Point(-1, -1)
private val center = Point()
private val touchDown = Point()
private val distToFull: Int
private val minMoveThresholdSq: Int
private val cornerRadius: Int
private val fabHeight: Int
private val padding: Int
private var marks: List<Point>? = null
private var orientation = resources.configuration.orientation
@ -52,12 +52,12 @@ class DetectorView : View {
init {
val dp = context.resources.displayMetrics.density
distToFull = 24f * dp
val minMoveThreshold = 8f * dp
distToFull = (24f * dp).roundToInt()
val minMoveThreshold = (8f * dp).roundToInt()
minMoveThresholdSq = minMoveThreshold * minMoveThreshold
cornerRadius = 8f * dp
fabHeight = (72f + 20f) * dp
padding = 20f * dp
cornerRadius = (8f * dp).roundToInt()
fabHeight = (92f * dp).roundToInt()
padding = (20f * dp).roundToInt()
isSaveEnabled = true
}
@ -79,20 +79,20 @@ class DetectorView : View {
return super.onSaveInstanceState()
}
return SavedState(super.onSaveInstanceState()).apply {
handlePos.set(this@DetectorView.handlePos)
orientation = this@DetectorView.orientation
savedHandlePos.set(handlePos)
savedOrientation = orientation
}
}
override fun onRestoreInstanceState(state: Parcelable) {
super.onRestoreInstanceState(
if (state is SavedState) {
if (state.orientation == orientation) {
handlePos.set(state.handlePos)
if (state.savedOrientation == orientation) {
handlePos.set(state.savedHandlePos)
} else {
handlePos.set(
state.handlePos.y,
state.handlePos.x
state.savedHandlePos.y,
state.savedHandlePos.x
)
}
handleMoved = true
@ -106,12 +106,14 @@ class DetectorView : View {
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
event ?: return super.onTouchEvent(event)
val x = event.x.roundToInt()
val y = event.y.roundToInt()
return when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
if (prefs.showCropHandle) {
touchDown.set(event.x, event.y)
handleGrabbed = abs(event.x - handlePos.x) < handleXRadius &&
abs(event.y - handlePos.y) < handleYRadius
touchDown.set(x, y)
handleGrabbed = abs(x - handlePos.x) < handleXRadius &&
abs(y - handlePos.y) < handleYRadius
handleGrabbed
} else {
false
@ -119,7 +121,7 @@ class DetectorView : View {
}
MotionEvent.ACTION_MOVE -> {
if (handleGrabbed) {
handlePos.set(event.x, event.y)
handlePos.set(x, y)
if (distSq(handlePos, touchDown) > minMoveThresholdSq) {
handleMoved = true
}
@ -131,7 +133,7 @@ class DetectorView : View {
}
MotionEvent.ACTION_CANCEL -> {
if (handleGrabbed) {
snap(event.x, event.y)
snap(x, y)
handleGrabbed = false
}
false
@ -139,11 +141,14 @@ class DetectorView : View {
MotionEvent.ACTION_UP -> {
if (handleGrabbed) {
if (!handleMoved) {
handlePos.set(center.x * 1.5f, center.y * 1.25f)
handlePos.set(
(center.x * 1.5f).roundToInt(),
(center.y * 1.25f).roundToInt()
)
handleMoved = true
invalidate()
} else {
snap(event.x, event.y)
snap(x, y)
}
updateRoi?.invoke()
handleGrabbed = false
@ -154,11 +159,11 @@ class DetectorView : View {
}
}
private fun snap(x: Float, y: Float) {
private fun snap(x: Int, y: Int) {
if (abs(x - center.x) < distToFull ||
abs(y - center.y) < distToFull
) {
handlePos.set(handleHome.x, handleHome.y)
handlePos.set(handleHome)
handleMoved = false
invalidate()
}
@ -169,15 +174,15 @@ class DetectorView : View {
val width = right - left
val height = bottom - top
center.set(
(left + (width / 2)).toFloat(),
(top + (height / 2)).toFloat()
left + (width / 2),
top + (height / 2)
)
handleHome.set(
width - handleXRadius - paddingRight - padding,
height - handleYRadius - paddingBottom - fabHeight
)
if (handlePos.x < 0) {
handlePos.set(handleHome.x, handleHome.y)
handlePos.set(handleHome)
}
}
@ -192,8 +197,8 @@ class DetectorView : View {
if (prefs.showCropHandle) {
canvas.drawBitmap(
handleBitmap,
handlePos.x - handleXRadius,
handlePos.y - handleYRadius,
(handlePos.x - handleXRadius).toFloat(),
(handlePos.y - handleYRadius).toFloat(),
null
)
}
@ -201,12 +206,12 @@ class DetectorView : View {
private fun drawClip(canvas: Canvas) {
val minDist = updateClipRect()
if (minDist < 1f) {
if (minDist < 1) {
return
}
// canvas.clipRect() doesn't work reliably below KITKAT
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
val radius = min(minDist * .5f, cornerRadius)
val radius = min(minDist / 2, cornerRadius).toFloat()
canvas.save()
canvas.clipOutPathCompat(
calculateRoundedRectPath(
@ -225,40 +230,43 @@ class DetectorView : View {
}
}
private fun updateClipRect(): Float {
private fun updateClipRect(): Int {
val dx = abs(handlePos.x - center.x)
val dy = abs(handlePos.y - center.y)
val d = min(dx, dy)
shadeColor = (min(1f, d / distToFull) * 128f).toInt() shl 24
shadeColor = (min(
1f,
d.toFloat() / distToFull.toFloat()
) * 128f).toInt() shl 24
roi.set(
(center.x - dx).roundToInt(),
(center.y - dy).roundToInt(),
(center.x + dx).roundToInt(),
(center.y + dy).roundToInt()
center.x - dx,
center.y - dy,
center.x + dx,
center.y + dy
)
return d
}
internal class SavedState : BaseSavedState {
val handlePos = PointF()
val savedHandlePos = Point()
var orientation = 0
var savedOrientation = 0
constructor(superState: Parcelable?) : super(superState)
private constructor(parcel: Parcel) : super(parcel) {
handlePos.set(
parcel.readFloat(),
parcel.readFloat()
savedHandlePos.set(
parcel.readInt(),
parcel.readInt()
)
orientation = parcel.readInt()
savedOrientation = parcel.readInt()
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeFloat(handlePos.x)
out.writeFloat(handlePos.y)
out.writeInt(orientation)
out.writeInt(savedHandlePos.x)
out.writeInt(savedHandlePos.y)
out.writeInt(savedOrientation)
}
companion object {
@ -271,12 +279,17 @@ class DetectorView : View {
}
}
private fun distSq(a: PointF, b: PointF): Float {
private fun distSq(a: Point, b: Point): Int {
val dx = a.x - b.x
val dy = a.y - b.y
return dx * dx + dy * dy
}
private fun Point.set(point: Point) {
x = point.x
y = point.y
}
private fun Canvas.clipOutPathCompat(path: Path) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
clipOutPath(path)