Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现马赛克效果,Kotlin(3)

Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现马赛克效果,Kotlin(3)

Kotlin 复制代码
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.util.AttributeSet
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatImageView


class MyView : AppCompatImageView {
    private var WIDTH = 0
    private var HEIGHT = 0

    private var mPaint: Paint = Paint()
    private var mBmpMosaic: Bitmap
    private var mBmpDst: Bitmap
    private var mBmpSrc: Bitmap
    private var mPath: Path
    private var mPreX = 0f
    private var mPreY = 0f
    private var mPorterDuffXfermode: PorterDuffXfermode

    private val mResId = R.mipmap.p
    private val mScaleFator = 20f

    constructor(ctx: Context, attributeSet: AttributeSet) : super(ctx, attributeSet) {
        mPaint.style = Paint.Style.STROKE
        mPaint.strokeWidth = 30f

        //和一张原图大小相同的马赛克图
        mBmpMosaic = getMosaicBmp()

        //原图。
        mBmpSrc = BitmapFactory.decodeResource(resources, mResId, null)

        WIDTH = mBmpSrc.width
        HEIGHT = mBmpSrc.height

        //空的Bitmap
        mBmpDst = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888)

        mPath = Path()

        /**
         *
         * SRC_OUT
         *
         * 当目标图像有图像时合成结果为空白像素;
         * 当目标图像没有图像时,合成结果显示源图像;
         * 如果把手指Path做为目标图像,在与源图像合成时,有手指轨迹的地方就变为空白像素,效果就是擦除。
         *
         */
        mPorterDuffXfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)
    }

    override fun onDraw(canvas: Canvas) {
        //super.onDraw(canvas)
        //第一层,一张固定的马赛克底图。
        canvas.drawBitmap(mBmpMosaic, 0f, 0f, null)


        val layerId = canvas.saveLayer(0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat(), null)

        //第二层,原图。
        canvas.drawBitmap(mBmpSrc, 0f, 0f, null)

        //第三层,绘制空的目标图像,和原图大小一致
        canvas.drawBitmap(mBmpDst, 0f, 0f, null)

        //合成图像
        mPaint.setXfermode(mPorterDuffXfermode)
        //空的mBmpDst绘制Path
        canvas.drawPath(mPath, mPaint) //擦除第二层的原图,使得第一层的马赛克底图露出来。


        mPaint.setXfermode(null)
        canvas.restoreToCount(layerId)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                mPath.moveTo(event.x, event.y)
                mPreX = event.x
                mPreY = event.y

                return true
            }

            MotionEvent.ACTION_MOVE -> {
                val endX = (mPreX + event.x) / 2
                val endY = (mPreY + event.y) / 2
                mPath.quadTo(mPreX, mPreY, endX, endY)
                mPreX = event.x
                mPreY = event.y
            }

            MotionEvent.ACTION_UP -> {

            }
        }

        postInvalidate()

        return super.onTouchEvent(event)
    }


    private fun getMosaicBmp(): Bitmap {
        val bmpSrc = BitmapFactory.decodeResource(resources, mResId, null)
        val w = bmpSrc.width
        val h = bmpSrc.height

        //原Bitmap的1/mScaleFator
        val smallBmp = Bitmap.createBitmap((w / mScaleFator).toInt(), (h / mScaleFator).toInt(), Bitmap.Config.ARGB_8888)
        val cDst = Canvas(smallBmp)
        val mtx = Matrix()
        mtx.setScale(1 / mScaleFator, 1 / mScaleFator)
        cDst.drawBitmap(bmpSrc, mtx, null)

        mtx.reset()

        val resultBmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(resultBmp)
        mtx.setScale(mScaleFator, mScaleFator)
        canvas.drawBitmap(smallBmp, mtx, null)

        //此时的resultBmp为原图大小的马赛克图。
        return resultBmp
    }
}

当手指在图像上划过后,划过的轨迹变成马赛克。

Android使用PorterDuffXfermode模式PorterDuff.Mode.SRC_OUT橡皮擦实现"刮刮乐"效果,Kotlin(2)-CSDN博客文章浏览阅读589次,点赞21次,收藏12次。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。Android Bitmap保存成至手机图片文件,Kotlin_android bitmap保存图片-CSDN博客。Android拼接合并图片生成长图代码实现合并两张图片,以第一张图片的宽度为标准,如果被合并的第二张图片宽度和第一张不同,那么就以第一张图片的宽度为准线,对第二张图片进行缩放。https://blog.csdn.net/zhangphil/article/details/144536192

相关推荐
遇见你的那天13 分钟前
反编译查看源码
android
明飞198718 分钟前
isSuperclassOf 与is 与 ==的区别
kotlin
用户20187928316729 分钟前
SIGABRT+GL errors Native Crash 问题分析
android
Nathan2024061630 分钟前
Kotlin-Sealed与Open的使用
android·前端·面试
2501_9160137432 分钟前
iOS 26 设备文件管理实战指南,文件访问、沙盒导出、系统变更与 uni-app 项目适配
android·ios·小程序·uni-app·cocoa·iphone·webview
2501_9159214339 分钟前
前端用什么开发工具?常用前端开发工具推荐与不同阶段的选择指南
android·前端·ios·小程序·uni-app·iphone·webview
2501_916007471 小时前
iOS 26 能耗检测实战指南,升级后电池掉速是否正常 + KeyMob + Instruments 实时监控 + 优化策略
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_916013741 小时前
苹果上架 App 全流程详解,iOS 应用发布步骤、ipa 文件上传工具、TestFlight 测试与 App Store 审核经验
android·ios·小程序·https·uni-app·iphone·webview
2501_915909061 小时前
HTML 开发工具有哪些?常用 HTML 开发工具推荐、学习路线与实战经验分享
android·小程序·https·uni-app·iphone·webview
wei8440678722 小时前
Android实现RecyclerView粘性头部效果,模拟微信账单列表的月份标题平移
android·java·微信·gitee