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<RectTransform>().SetPivot(PivotPresets.TopLeft);
        ima.GetComponent<RectTransform>().SetAnchor(AnchorPresets.TopLeft, 0, 0);
#elif UNITY_ANDROID   //安卓位于左下
        ima.GetComponent<RectTransform>().SetPivot(PivotPresets.BottomLeft);
        ima.GetComponent<RectTransform>().SetAnchor(AnchorPresets.BottomLeft, 0, 0);
#endif

        Rect rect = ima.GetComponent<RectTransform>().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
    }


    /// <summary>
    /// </summary>
    /// <param name="backTextrue">背景图</param>
    /// <param name="path">需要覆盖上的图</param>
    /// <param name="w">添加的位置</param>
    /// <param name="dis">dis 为图片的对应conrner 与 conrner的距离 若WaterMarkConrner 选的是lowerright 
 则是地板图的右下角距离覆盖图的右下角的像素距离</param>
    /// <returns></returns>
    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;
    }


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351