使用下面的代码,我可以绘制徒手绘制的路径并可以裁剪图像,但是我遇到了一个问题,我总是得到具有某些透明度的位图,这是我所不希望的。
这是我从图像中选择部分的课程,我已经尝试了几乎所有搜索过的解决方案,或者已经在解决方案中找到了解决方案,但是我没有达到自己的目标
class MyCanvasView(context: Context?, attributeSet: AttributeSet) : View(context, attributeSet) {
private var mCanvas: Canvas? = null
private var mPath: Path? = null
private var mPaint: Paint? = null
private val paths = ArrayList<Pair<Path, Paint>>()
private val undonePaths = ArrayList<Pair<Path, Paint>>()
var startingOfTouchX: Float? = null
var startingOfTouchY: Float? = null
var mBitmap: Bitmap? = null
var shader: Shader? = null
var shaderPaint: Paint? = null
var mMatrix: Matrix? = null
private var scaleGestureDetector: ScaleGestureDetector? = null
var scale: Float = 5.0f
var imageView: ImageView? = null
var stroke: Float = 6f
init {
isFocusable = true
isFocusableInTouchMode = true
mPaint = Paint()
mPaint?.isAntiAlias = true
mPaint?.isDither = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
mPaint!!.color = context!!.getColor(R.color.colorPrimaryTranparent)
else
mPaint!!.color = -0x1
mPaint?.style = Paint.Style.STROKE
mPaint?.strokeJoin = Paint.Join.ROUND
mPaint?.strokeCap = Paint.Cap.ROUND
mPaint?.strokeWidth = stroke
mCanvas = Canvas()
mPath = Path()
shaderPaint = Paint()
mMatrix = Matrix()
scaleGestureDetector = ScaleGestureDetector(context, ScaleListener())
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
mCanvas = Canvas(mBitmap!!)
shader = BitmapShader(mBitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
shaderPaint?.shader = shader
mMatrix?.reset()
mMatrix?.postScale(2f, 2f, mX, mY)
shaderPaint?.shader?.setLocalMatrix(matrix)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
for (p in paths) {
canvas?.drawPath(p.first, p.second)
}
}
var mX: Float = 0.toFloat()
var mY: Float = 0.toFloat()
private val TOUCH_TOLERANCE = 4f
private fun touchStart(x: Float, y: Float) {
undonePaths.clear()
mY = y
startingOfTouchX = x
startingOfTouchY = y
val p = Paint()
p.isAntiAlias = true
p.isDither = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
p.color = context.getColor(R.color.colorPrimaryTranparent)
else
p.color = -0x1
p.style = Paint.Style.STROKE
p.strokeJoin = Paint.Join.ROUND
p.strokeCap = Paint.Cap.ROUND
p.strokeWidth = stroke
val pa = Path()
pa.moveTo(x, y)
paths.add(Pair(pa, p))
shaderPaint?.shader = shader
mMatrix?.reset()
mMatrix?.postScale(20f, 20f, 100f, 100f)
shaderPaint?.shader?.setLocalMatrix(matrix)
}
fun setSeekStroke(diameter: Float) {
stroke = diameter
}
private fun touchMove(x: Float, y: Float) {
val dx = Math.abs(x - mX)
val dy = Math.abs(y - mY)
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mX = x
mY = y
paths[paths.size - 1].first.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2)
}
}
private fun touchUp() {
paths[paths.size - 1].first.lineTo(mX, mY)
paths[paths.size - 1].second.style = Paint.Style.FILL
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
var x = event!!.x
var y = event.y
x += stroke
y += stroke
// Invalidate() is inside the case statements because there are many
// other types of motion events passed into this listener,
// and we don't want to invalidate the view for those.
when (event.action) {
MotionEvent.ACTION_DOWN -> {
touchStart(x, y)
invalidate()
}
MotionEvent.ACTION_MOVE -> {
touchMove(x, y)
invalidate()
}
MotionEvent.ACTION_UP -> {
touchUp()
invalidate()
}
}
scaleGestureDetector!!.onTouchEvent(event)
return true
}
fun onClickUndo() {
if (paths.size > 0) {
undonePaths.add(paths.removeAt(paths.size - 1))
invalidate()
} else {
Toast.makeText(context, "Nothing to undo !!!", Toast.LENGTH_SHORT).show()
}
}
fun onClickRedo() {
if (undonePaths.size > 0) {
paths.add(undonePaths.removeAt(undonePaths.size - 1))
invalidate()
} else {
Toast.makeText(context, "Nothing to redo !!!", Toast.LENGTH_SHORT).show()
}
}
private inner class ScaleListener : ScaleGestureDetector.SimpleOnScaleGestureListener() {
override fun onScale(detector: ScaleGestureDetector?): Boolean {
scale *= detector!!.scaleFactor
scale = Math.max(0.1f, Math.min(scale, 5f))
mMatrix!!.setScale(scale, scale)
imageView!!.imageMatrix = matrix
return true
}
}
}
这是我用于从imageview的选定部分进行裁剪的代码
ib_selection_done.setOnClickListener {
val bitmap = cropBitmap()
Glide.with(this).load(BitmapHelper.getInstance().bitmap).into(iv_croped)
}
private fun cropBitmap(): Bitmap {
val bmp2 = screenShot(iv_background_image)
val bmOverlay = Bitmap.createBitmap(my_canvas_view.width, my_canvas_view.height, Bitmap.Config.ARGB_8888)
val paint = Paint()
val p = Paint()
paint.color = resources.getColor(R.color.colorBlack)
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
paint.isAntiAlias = true
val canvas = Canvas(bmOverlay)
canvas.drawBitmap(bmp2, 0f, 0f, p)
val b = screenShot(my_canvas_view) // custom view for selection
canvas.drawBitmap(b, 0f, 0f, paint)
return bmOverlay
}
private fun screenShot(view: View): Bitmap {
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.draw(canvas)
return bitmap
}
我的XML在这里,
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<photoblender.kotlin.thetamobile.com.photoblender.Classes.MyCanvasView
android:id="@+id/my_canvas_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/ib_selection_done"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="8dp"
android:background="@drawable/btn_white_round_background"
android:src="@drawable/next_arrow"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />