一种可以对超出屏幕的坐标(x,y任意一个为负或者x,y超出屏幕宽度)的Path截成一幅图的办法

设有如下情况:

canvas是一个刚好可以覆盖屏幕大小的画布,其中有3条path因为translate或scale被部分或全部移动到屏幕外面。如何把超出屏幕的部分(Path上有负坐标或超过屏幕宽高的x,y值)和屏幕中的一起合成一个位图?并且已知所有的path子类均有dx,dy值记录了偏移的位置,这些path在刚写入屏幕canvas中时x,y坐标数组均为正值


方法如下:


首先,要算出一个刚好可以覆盖所有Path的面积的Range,一种方法是直接遍历出左上角的点和最右下角的点,但android本身就有range之间union成一个大range的方法,并求出总面积的宽高所以只需这样即可(使用kotlin编写):

        var totalRectF = SerRectF()

        Log.i("layerSize", "sum:" + getLayerUtil().sum)
        Log.i("curLayer.allList.size", getLayerUtil().curLayer.allList.size.toString())
        //计算所有path合成的总面积
        getLayerUtil().curLayer.allList?.forEach {
            if (it != null) {
                if (it.mPath != null && it.mPath.pathPoints != null) {
                    var itRange: SerRectF = SerRectF()
                    it.mPath.computeBounds(itRange, false)
                    Log.i("itRange", itRange.toString())
                    totalRectF.union(itRange)
                }
            }
        }
        width  = totalRectF.width()
        height = totalRectF.height()

然后,我们需要在新的画布上,算出负值最大的x值,取绝对值后使其成为一个虚假的x的0点(虚拟x轴)。

加入现在原画布有两个点:

点1的x点原本值为10,偏移了-30(dx=-30),现在值变为-20。

点2的x点原本值为40,偏移了-30(dx=-30),现在值为10的点。

那么画布x最负值就是-20。而我们设-20的绝对值20为模拟的x的0点。

那么写入的时候基于新画布的点1值就是      现在值 + 虚拟0点 = 虚拟现在值,也就是-20 + 20 = 0,

点2基于新画布的值就是     现在值 + 虚拟0点 = 虚拟现在值,也就是10 + 20 = 30,保持了相对距离的同时,他们的值也都变为了正。


等效的算法就是 dx = dx + 20 = -10,原本值 + 新的dx =新的现在值,例如10 +(-10) = 0,      40 + (-10)= 30 。


写入path的时候,先把画布移到虚假的新dx=-10的反向位置x=-(-10)=10,然后此时写入点10,它再被新dx偏移-10,就刚好写在了画布的x=0的应属位置上(因为计算机总面积时是以这个最小的点确定画布左边界的,所以它是最靠左边的点,理应是0)。

同样,先把画布移到虚假的新dx=-10的反向位置x=-(-10)=10,写入点40,被新dx偏移-10,写在了画布x=30的该点该在的x轴的位置上。


同样的方法,也可以用于构建虚拟的y轴,使得一切负坐标都可以通过对虚拟的x,y轴进行加减运算成为正坐标,从而可以写入只可以看见正数的画布中。


        // 虚拟画布的0点
        var canvasVirtualZeroXPoint: Float = 0f
        var canvasVirtualZeroYPoint: Float = 0f

        if (totalRectF.left >= 0f) canvasVirtualZeroXPoint = 0f
        else canvasVirtualZeroXPoint = Math.abs(totalRectF.left)

        if (totalRectF.top >= 0f) canvasVirtualZeroYPoint = 0f
        else canvasVirtualZeroYPoint = Math.abs(totalRectF.top)

示意图:


具体完整实现:

    /** 漫游拿全景  */
    fun getBitmap(): Bitmap {
        var totalRectF = SerRectF()
        //计算所有path合成的总面积
        getLayerUtil().curLayer.allList?.forEach {
            if (it != null) {
                if (it.mPath != null && it.mPath.pathPoints != null) {
                    var itRange: SerRectF = SerRectF()
                    it.mPath.computeBounds(itRange, false)
                    Log.i("itRange", itRange.toString())
                    totalRectF.union(itRange)
                }
            }
        }
        var width: Float = 1f
        var height: Float = 1f
        /****用范围值Rectf来得到宽度高度Start***/
        width = totalRectF.width()
        height = totalRectF.height()


        // 虚拟画布的0点
        var canvasVirtualZeroXPoint: Float = 0f
        var canvasVirtualZeroYPoint: Float = 0f

        if (totalRectF.left >= 0f) canvasVirtualZeroXPoint = 0f
        else canvasVirtualZeroXPoint = Math.abs(totalRectF.left)

        if (totalRectF.top >= 0f) canvasVirtualZeroYPoint = 0f
        else canvasVirtualZeroYPoint = Math.abs(totalRectF.top)

        Log.i("虚拟0线", String.format("虚拟0线x:%f, 虚拟0线y:%f", canvasVirtualZeroXPoint, canvasVirtualZeroYPoint))

        var bitmap = Bitmap.createBitmap(width.toInt(), height.toInt(), Bitmap.Config.ARGB_4444)  //统计该用多大的位图
        var can: Canvas = Canvas(bitmap)
        getLayerUtil().curLayer?.allList?.forEach {
            ///
            var fixPath: SerPath = SerPath()
            var dx: Float = 0f
            var dy: Float = 0f
            dx = it.dx
            dy = it.dy
           
            if (it.mPath != null) {
                Log.i("qrcodeMaking", String.format("dx:%f, dy:%f", dx, dy))
                fixPath.addPath(it.mPath, canvasVirtualZeroXPoint + dx, canvasVirtualZeroYPoint + dy) //取消原来的偏移值,改写偏移值
                can.translate(-dx, -dy)   //画布对偏移值反向偏移使得相对0点真正起到0点的效果
                can.drawPath(fixPath, it.cPaint)
                can.translate(dx, dy)    //取消画布偏移
            } 
            //
//            Log.i("画图记录",  String.format("start_x:%f, start_y:%f, current_x:%f, current_y:%f, dx:%f, dy:%f",
//                    it.start.x, it.start.y, it.current.x, it.current.y, dx, dy))
            if (it != null) {
                if (it.mPath != null && it.mPath.pathPoints != null) {
                    if (it.mPath.pathPoints.isNotEmpty()) {
                        Log.i("画图记录", String.format("x:%f, y:%f, dx:%f, dy:%f", it.mPath.pathPoints.get(0)[0] + dx, it.mPath.pathPoints.get(0)[1] + dy, dx, dy))
                    }
                }
            }
        }

        try {
            var bgBitmap: Bitmap
            if (getBgColor() == 0) {  //如果背景色为空
                if (getBgBitmap() == null) {  //而且背景图为空则使用默认背景图填充后再绘制
                    bgBitmap = BitmapFactory.decodeResource(resources, R.drawable.background)  //背景位图
                } else {   //否则使用自定义背景图填充后再绘制内容
                    bgBitmap = getBgBitmap()
                }
                var resultBitmap: Bitmap = Tool.getPPBitmap(bitmap, bgBitmap)
                Log.i("resultBitmapSize", String.format("width:%d,height:%d", bitmap.width, bitmap.height))
                return resultBitmap
            } else {  //否则使用背景色先填充再绘制图形
                var resultBitmap: Bitmap = Tool.getPPBitmap(bitmap, getBgColor())
                Log.i("resultBitmapSize", String.format("width:%d,height:%d", bitmap.width, bitmap.height))
                return resultBitmap
            }
        } catch (exception: Exception) {
            exception.printStackTrace()
            return Tool.getPPBitmap(mLayerUtil.getCurLayer().toBitmap(), bgBitmap)
        }
    }

实际效果

原图是这样:



①被拖上了左上角,加了一个③,被拖到右下角



然后开启截屏功能


顺利得到大幅的全景图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值