Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Please add a feature that can keep ratio in free mode. (with kotlin code) #405

Open
ghost opened this issue Apr 9, 2018 · 5 comments
Open

Comments

@ghost
Copy link

ghost commented Apr 9, 2018

I looked the source, but there is no feature can keep ratio with setFreeStyleCropEnabled enabled.

So I wrote some code to do this, but it only works in Debug mode, I can't extend or override, no callbacks or protect method can let me hook it.

My Kotlin code:


    /**
     * @param corner mCurrentTouchCornerIndex
     * @param ratio mTargetAspectRatio, w/h
     * @param x original touchX
     * @param y original touchY
     * @param rect mCropViewRect
     *
     * @return newTouchX, newTouchY for OverlayView#updateCropViewRect
     */
    fun newPositionForUpdateCropViewRect(
            corner: Int,
            ratio: Float,
            x: Float,
            y: Float,
            rect: RectF
    ): Pair<Float, Float> {
        if (corner !in 0..3) return x to y
    
        var k = 1f / ratio
    
        if (corner == 1 || corner == 3) k = -k
    
        val w = if (corner == 0 || corner == 3) rect.left else rect.right
        val h = if (corner == 0 || corner == 1) rect.top else rect.bottom
    
        val kk1 = k * k + 1
        val tx = ((w * k + y - h) * k + x) / kk1
        val ty = ((y * k + x - w) * k + h) / kk1
    
        return tx to ty
    }

untitled

@ghost
Copy link
Author

ghost commented Apr 10, 2018

Currently OverlayView#mCurrentTouchCornerIndex and OverlayView#updateCropViewRect are private members. I have to using reflection and intercept touch event. If updateCropViewRect can be overrided, will be very nice.

My hack:


import android.os.Bundle
import android.view.MotionEvent
import com.yalantis.ucrop.UCropActivity
import com.yalantis.ucrop.view.OverlayView
import com.yalantis.ucrop.view.UCropView

class CropActivity : UCropActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val uc = findViewById<UCropView>(R.id.ucrop) ?: return

    var ratio = -1F
    var corner = -1

    val overlay = uc.overlayView
    val rect = overlay.cropViewRect
    val reflect = OverlayView::class.java
            .getDeclaredField("mCurrentTouchCornerIndex") //todo proguard
            .apply { isAccessible = true }

    uc.cropImageView.setCropBoundsChangeListener {
        overlay.setTargetAspectRatio(it)
        ratio = it
    }

    overlay.setOnTouchListener { _, event ->
        val action = event.action and MotionEvent.ACTION_MASK

        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
            overlay.onTouchEvent(event).also { corner = reflect.getInt(overlay) }
        } else {
            if (action == MotionEvent.ACTION_MOVE && corner in 0..3) {
                newPositionForUpdateCropViewRect(corner, ratio, event.x, event.y, rect)
                        .run { event.setLocation(first, second) }
            }
            overlay.onTouchEvent(event)
        }
    }
}

}


@Legementarion
Copy link
Contributor

@1001101 Hello! Thank you for your code and contribution! I guess we can implement your feature in next release. I think better to do this like FREESTYLE_CROP_MODE_WITH_ASPECT_RATIO

@ghost
Copy link
Author

ghost commented Apr 10, 2018

In my opinion, most fields should be protected, then we can do much.

For example, custom crop menu behavior:
UCropActivity#cropAndSaveImage is protected but mBlockingView mShowLoader are private, so not posible to unset the toolbar state, and BitmapCropTask will recycle cropImageView, so not posible to re-crop.

Another problems:
BitmapCropCallback#onBitmapCropped first argument is Uri.fromFile with outputPath but not File, cannot get file length directly. but outputPath is used as a file path in BitmapLoadTask#copyFile.

@ashishmahla
Copy link

Guys, its been 2 years already and this issue has not been resolved. Can we have a roadmap for when this will be released? This is a really important feature for the usability of the library for some of us. It is powerful to allow free style but we are tied down by this issue. When can we expect this to be released?

@tridhm-3108
Copy link

Thanks @ghost you save my day <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants