Unity 截屏 分享和保存图片 与各个机型分辨率的适配问题

最近有一个需求,是分享图片。之前做过一次类似的功能,但是使用setPixels来做的。在这里由于需要动态设置的信息过多,不便于使用此方法,此方法在文章最后列出。

1 通过camera渲染

大概是 玩家在游戏中达成某些要求后会解锁成就,游戏内部已经有成就的显示界面,需要把成就的信息分享出去。但是问题主要在于分享出去的图并非游戏内显示的图,并且尺寸不是游戏内设置的分辨率。而且由于在PC、安卓和IOS等各个平台不同以及市面上各种机型分辨率的原因 ,导致分享出去的图片不是有多余空白部分 就是显示不完全只发送出了一部分。
最后解决成功,先说下思路。

由于需要有分享功能的界面在游戏内的很多场景都要用到,所以在游戏内新建了一个canvas和用于渲染他的camera 并在游戏过程中让他保持不销毁,设置相机渲染层级为最低,并将canvas scaler设置如下


canvas的设置

将需要分享的信息先按照规则显示在此隐藏的canvas上,在此canvas上得到要分享出的图片,再将图片保存到本地并进行分享。

然后是具体实现的代码

首先要的得到运行设备的分辨率,与正常显示的分辨率相比的缩放比例 m_multiplyNum 防止出现在720P、全面屏 或者宽屏手机上出现截取的图片出现上面的问题

float m_multiplyNum = 1;
void Awake()
{
        float standardPhoneNum = 1080f / 1920f; //16:9 尺寸
        float phoneNum = (float)Screen.width / (float)Screen.height;

        m_canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.Expand;
        //宽屏,pad等
        if (phoneNum > standardPhoneNum)
        {
            m_multiplyNum = m_camera.pixelHeight/ 1920f;
        }
        else  //全面屏 mix p20 iphonex等
        {
            m_multiplyNum = m_camera.pixelWidth / 1080f;
        }
}

在拿到要显示的信息并在你的canvas内对要现实的信息处理完成之后 执行以下代码
这里我是用背板image作为父物体,可以根据自己的实际需求修改

    public Camera m_camera;
    private RenderTexture m_renderTexture;

//ima为要分享的图片,分享时要保证此canvas下只打开要分享的相关物体
    private string StartRender(Image ima)
    {
        m_camera.enabled = true;
//分局平台的不同设置分享图片显示的位置
//pc或者iphone的起始点位于坐上
#if UNITY_EDITOR || UNITY_IPHONE
        ima.GetComponent().SetPivot(PivotPresets.TopLeft);
        ima.GetComponent().SetAnchor(AnchorPresets.TopLeft, 0, 0);
#elif UNITY_ANDROID   //安卓位于左下
        ima.GetComponent().SetPivot(PivotPresets.BottomLeft);
        ima.GetComponent().SetAnchor(AnchorPresets.BottomLeft, 0, 0);
#endif

        Rect rect = ima.GetComponent().rect;
        rect.width = rect.width ;
        rect.height = rect.height;
        //首次执行创建renderTexture,大小为相机渲染出的canvas的像素,并设置相机targetTexture
        if (m_renderTexture == null)
        {
            m_renderTexture = new RenderTexture(m_camera.pixelWidth, m_camera.pixelHeight, 24);
            m_renderTexture.Create();
            m_camera.targetTexture = m_renderTexture;
        }
        
        m_camera.Render();
        RenderTexture.active = m_renderTexture;
        //创建要分享出的texture2d 大小为ima的rect的宽、高乘之前计算的缩放比例
        Texture2D t = new Texture2D((int)(rect.width * m_multiplyNum), (int)(rect.height * m_multiplyNum), TextureFormat.ARGB32, true);
        //读取renderTexture内贴图大小的像素内保存在贴图内
        t.ReadPixels(new Rect(0, 0, t.width, t.height), 0, 0);
        //图片的名称,命名为分享的时间
        string name = System.DateTime.Now.ToString().Replace("/", "_");
        name = name.Replace(" ", "_");
        name = name.Replace(":", "_");
        //获取图片保存的路径
        string path = Application.persistentDataPath + "/sharePic/" + name + ".png";
        string directoryPath = Application.persistentDataPath + "/sharePic";
        //如果 com.xxx.xxx  下不存在 sharePic路径 创建该文件夹
        if (!Directory.Exists(directoryPath))
        {
            System.IO.Directory.CreateDirectory(directoryPath);
        }
        if (!File.Exists(path))
        {
            var bytes = t.EncodeToPNG();
            File.WriteAllBytes(path, bytes);
        }

#if !UNITY_EDITOR
        //防止全面屏手机穿透看到  如果不关闭会导致屏幕最下方出现此图片
        m_camera.enabled = false;
#endif
         //返回保存图片的路径
        return path;
    }

代码比较简单并且注释写的比较详细,就不再过多解释了 主要麻烦在适配的测试上
如果在使用过程中适配遇到了问题,可以留言遇到问题的平台 设备 以及对应型号的屏幕分辨率

图上的代码设置UGUI锚点的点这里 代码设置UGUI锚点

2 SetPixels

这个方法是之前做的一个 简单的功能,只是单纯用来在给固定图片在固定位置添加游戏水印和二维码
代码如下:

    public enum WaterMarkConrner
    {
        uperLeft,
        uperRight,
        lowerLeft,
        lowerRight
    }


    /// 
    /// 
    /// 背景图
    /// 需要覆盖上的图
    /// 添加的位置
    /// dis 为图片的对应conrner 与 conrner的距离 若WaterMarkConrner 选的是lowerright 
 则是地板图的右下角距离覆盖图的右下角的像素距离
    /// 
    public static Texture2D TextureOverlay(Texture2D backTextrue, Texture2D upTeture, WaterMarkConrner w, Vector2 dis)
    {
        Color[] colors = upTeture.GetPixels();
        int startX = 0, starty = 0;
        switch (w)
        {
            case WaterMarkConrner.lowerLeft:
                startX = 0 + (int)dis.x; starty = 0 + (int)dis.y;
                break;
            case WaterMarkConrner.lowerRight:
                startX = backTextrue.width - upTeture.width - (int)dis.x; starty = 0 + (int)dis.y;
                break;
            case WaterMarkConrner.uperLeft:
                startX = 0 + (int)dis.x; starty = backTextrue.height - upTeture.height - (int)dis.y;
                break;
            case WaterMarkConrner.uperRight:
                startX = backTextrue.width - upTeture.width - (int)dis.x; starty = backTextrue.height - upTeture.height - (int)dis.y;
                break;
        }

        for (int i = 0; i < upTeture.width; i++)
        {
            for (int j = 0; j < upTeture.height; j++)
            {
                int x = i + startX, y = j + starty;

                if (upTeture.GetPixel(i, j).a == 0)
                {
                    Color c = backTextrue.GetPixel(x, y);
                    colors[upTeture.width * j + i] = c;
                }

                // 透明通道添加
                else if (upTeture.GetPixel(i, j).a < 0.5)
                {
                    Color c = backTextrue.GetPixel(x, y);
                    colors[upTeture.width * j + i] = (c * c.a + upTeture.GetPixel(i, j) * (1 - (upTeture.GetPixel(i, j).a))) / 2;
                }
            }
        }
        backTextrue.SetPixels(startX, starty, upTeture.width, upTeture.height, colors);
        backTextrue.Apply();
        return backTextrue;
    }


你可能感兴趣的:(Unity 截屏 分享和保存图片 与各个机型分辨率的适配问题)