从图库中选择一张图片作为 Canvas 背景 [Android]
Choose an image from gallery as Canvas background [Android]
我在 canvas 完成绘图后已成功保存到画廊,但现在我需要从画廊打开图像(例如我的旧画)并将其用作背景,经过一些在那里搜索没有可以帮助我的答案。我已经开始尝试这样做,但是任何我如何实现它的建议或解决方案都会很棒。
我的自定义视图 Canvas:
(READ 和 WRITE 权限已在另一个 class 中授予和处理)
var drawingColor: Int = ResourcesCompat.getColor(resources, R.color.colorBlack, null)
var strokeDrawWidth: Float = 12f
private var path = Path()
private val paths = ArrayList<Triple<Path, Int, Float>>()
private val undonePaths = ArrayList<Triple<Path, Int, Float>>()
private val extraCanvas: Canvas? = null
private var bitmapBackground: Bitmap? = null
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
private var currentX = 0f
private var currentY = 0f
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop
private val paint = Paint().apply {
color = drawingColor
isAntiAlias = true
isDither = true
style = Paint.Style.STROKE
strokeJoin = Paint.Join.ROUND
strokeCap = Paint.Cap.ROUND
strokeWidth = strokeDrawWidth
}
fun loadCanvasBackground(bitmap: Bitmap) {
bitmapBackground = bitmap
invalidate()
}
fun saveCanvasDrawing() {
canvasCustomView.isDrawingCacheEnabled = true
val extraBitmap: Bitmap = canvasCustomView.drawingCache
MediaStore.Images.Media.insertImage(context.contentResolver, extraBitmap, "drawing", "Paint R")
}
fun resetCanvasDrawing() {
path.reset()
paths.clear()
invalidate()
}
fun undoCanvasDrawing() {
if (paths.size > 0) {
undonePaths.add(paths.removeAt(paths.size - 1))
invalidate()
} else {
Log.d("UNDO_ERROR", "Something went wrong with UNDO action")
}
}
fun redoCanvasDrawing() {
if (undonePaths.size > 0) {
paths.add(undonePaths.removeAt(undonePaths.size - 1))
invalidate()
} else {
Log.d("REDO_ERROR", "Something went wrong with REDO action")
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (bitmapBackground != null) {
extraCanvas?.drawBitmap(bitmapBackground!!, 0f, 0f, paint)
}
for (p in paths) {
paint.strokeWidth = p.third
paint.color = p.second
canvas?.drawPath(p.first, paint)
}
paint.color = drawingColor
paint.strokeWidth = strokeDrawWidth
canvas?.drawPath(path, paint)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
if (event == null)
return false
motionTouchEventX = event.x
motionTouchEventY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> {
undonePaths.clear()
path.reset()
path.moveTo(motionTouchEventX, motionTouchEventY)
currentX = motionTouchEventX
currentY = motionTouchEventY
invalidate()
}
MotionEvent.ACTION_MOVE -> {
val distanceX = abs(motionTouchEventX - currentX)
val distanceY = abs(motionTouchEventY - currentY)
if (distanceX >= touchTolerance || distanceY >= touchTolerance) {
path.quadTo(
currentX,
currentY,
(motionTouchEventX + currentX) / 2,
(currentY + motionTouchEventY) / 2
)
currentX = motionTouchEventX
currentY = motionTouchEventY
}
invalidate()
}
MotionEvent.ACTION_UP -> {
path.lineTo(currentX, currentY)
extraCanvas?.drawPath(path, paint)
paths.add(Triple(path, drawingColor, strokeDrawWidth))
path = Path()
}
}
return true
}
override fun isSaveEnabled(): Boolean {
return true
}
所以没有人回答,经过一些搜索和实验,我找到了可行的解决方案,如果您遇到相同的情况,请使用它或根据您的需要进行调整
(答案基于我问题中的代码 - 所以如果您遗漏了一些依赖项,请检查它)
- 在您的 ACTIVITY
中使用图库操作的请求代码初始化伴随对象
companion object {
private const val GALLERY_REQUEST_CODE = 102
}
- 创建一个从图库中选择图像的方法(您需要接收 Uri)
private fun pickFromGallery() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
val imageTypes = arrayOf("image/jpeg", "image/png")
intent.putExtra(Intent.EXTRA_MIME_TYPES, imageTypes)
startActivityForResult(intent, GALLERY_REQUEST_CODE)
}
- 您需要覆盖 onActivityResult() 方法来接收您的 Uri 并将其发送到自定义视图
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == GALLERY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
val uri: Uri? = data?.data
if (uri != null) {
val bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, uri)
canvasCustomView.loadCanvasBackground(bitmap)
}
}
}
}
- 现在在 onDraw() 方法 (在您的自定义视图中) 您需要使用 .drawBitmap 来设置您收到的 Uri 也就是位图作为您 canvas
的背景
override fun onDraw(canvas: Canvas?) {
if (bitmapBackground != null) {
canvas?.drawBitmap(bitmapBackground!!, 0f, 0f, paint)
}
我在 canvas 完成绘图后已成功保存到画廊,但现在我需要从画廊打开图像(例如我的旧画)并将其用作背景,经过一些在那里搜索没有可以帮助我的答案。我已经开始尝试这样做,但是任何我如何实现它的建议或解决方案都会很棒。
我的自定义视图 Canvas:
(READ 和 WRITE 权限已在另一个 class 中授予和处理)
var drawingColor: Int = ResourcesCompat.getColor(resources, R.color.colorBlack, null)
var strokeDrawWidth: Float = 12f
private var path = Path()
private val paths = ArrayList<Triple<Path, Int, Float>>()
private val undonePaths = ArrayList<Triple<Path, Int, Float>>()
private val extraCanvas: Canvas? = null
private var bitmapBackground: Bitmap? = null
private var motionTouchEventX = 0f
private var motionTouchEventY = 0f
private var currentX = 0f
private var currentY = 0f
private val touchTolerance = ViewConfiguration.get(context).scaledTouchSlop
private val paint = Paint().apply {
color = drawingColor
isAntiAlias = true
isDither = true
style = Paint.Style.STROKE
strokeJoin = Paint.Join.ROUND
strokeCap = Paint.Cap.ROUND
strokeWidth = strokeDrawWidth
}
fun loadCanvasBackground(bitmap: Bitmap) {
bitmapBackground = bitmap
invalidate()
}
fun saveCanvasDrawing() {
canvasCustomView.isDrawingCacheEnabled = true
val extraBitmap: Bitmap = canvasCustomView.drawingCache
MediaStore.Images.Media.insertImage(context.contentResolver, extraBitmap, "drawing", "Paint R")
}
fun resetCanvasDrawing() {
path.reset()
paths.clear()
invalidate()
}
fun undoCanvasDrawing() {
if (paths.size > 0) {
undonePaths.add(paths.removeAt(paths.size - 1))
invalidate()
} else {
Log.d("UNDO_ERROR", "Something went wrong with UNDO action")
}
}
fun redoCanvasDrawing() {
if (undonePaths.size > 0) {
paths.add(undonePaths.removeAt(undonePaths.size - 1))
invalidate()
} else {
Log.d("REDO_ERROR", "Something went wrong with REDO action")
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (bitmapBackground != null) {
extraCanvas?.drawBitmap(bitmapBackground!!, 0f, 0f, paint)
}
for (p in paths) {
paint.strokeWidth = p.third
paint.color = p.second
canvas?.drawPath(p.first, paint)
}
paint.color = drawingColor
paint.strokeWidth = strokeDrawWidth
canvas?.drawPath(path, paint)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
if (event == null)
return false
motionTouchEventX = event.x
motionTouchEventY = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> {
undonePaths.clear()
path.reset()
path.moveTo(motionTouchEventX, motionTouchEventY)
currentX = motionTouchEventX
currentY = motionTouchEventY
invalidate()
}
MotionEvent.ACTION_MOVE -> {
val distanceX = abs(motionTouchEventX - currentX)
val distanceY = abs(motionTouchEventY - currentY)
if (distanceX >= touchTolerance || distanceY >= touchTolerance) {
path.quadTo(
currentX,
currentY,
(motionTouchEventX + currentX) / 2,
(currentY + motionTouchEventY) / 2
)
currentX = motionTouchEventX
currentY = motionTouchEventY
}
invalidate()
}
MotionEvent.ACTION_UP -> {
path.lineTo(currentX, currentY)
extraCanvas?.drawPath(path, paint)
paths.add(Triple(path, drawingColor, strokeDrawWidth))
path = Path()
}
}
return true
}
override fun isSaveEnabled(): Boolean {
return true
}
所以没有人回答,经过一些搜索和实验,我找到了可行的解决方案,如果您遇到相同的情况,请使用它或根据您的需要进行调整
(答案基于我问题中的代码 - 所以如果您遗漏了一些依赖项,请检查它)
- 在您的 ACTIVITY 中使用图库操作的请求代码初始化伴随对象
companion object {
private const val GALLERY_REQUEST_CODE = 102
}
- 创建一个从图库中选择图像的方法(您需要接收 Uri)
private fun pickFromGallery() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
val imageTypes = arrayOf("image/jpeg", "image/png")
intent.putExtra(Intent.EXTRA_MIME_TYPES, imageTypes)
startActivityForResult(intent, GALLERY_REQUEST_CODE)
}
- 您需要覆盖 onActivityResult() 方法来接收您的 Uri 并将其发送到自定义视图
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == GALLERY_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
val uri: Uri? = data?.data
if (uri != null) {
val bitmap = MediaStore.Images.Media.getBitmap(this.contentResolver, uri)
canvasCustomView.loadCanvasBackground(bitmap)
}
}
}
}
- 现在在 onDraw() 方法 (在您的自定义视图中) 您需要使用 .drawBitmap 来设置您收到的 Uri 也就是位图作为您 canvas 的背景
override fun onDraw(canvas: Canvas?) {
if (bitmapBackground != null) {
canvas?.drawBitmap(bitmapBackground!!, 0f, 0f, paint)
}