Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?

news2025/2/28 21:22:09

JPG还是PNG?

JPG和PNG是两种常见的图片文件格式,在压缩方式、图像质量、透明效果和可编辑性等方面存在显著差异。

  • 压缩方式:JPG是一种有损压缩格式,通过丢弃图像数据来减小文件大小,因此可能会损失一些图像细节和质量。而PNG使用的是无损压缩格式,它不会丢失任何原始图像数据,从而保持了图像的完整性和质量。
  • 图像质量:由于压缩方式的不同,JPG在压缩后会牺牲一部分图像数据,因此在图像质量上可能存在损失,例如可能会出现锯齿状边缘或颜色失真。相比之下,PNG的无损压缩可以保证原图像数据的完整性,其256个透明层次的设定可以使图片边缘平滑融合,从而消除图片锯齿边缘。
  • 透明效果:PNG支持透明度,可以用作背景透明的图片,而JPG则不支持透明效果。因此,如果你需要制作半透明的图像或者需要背景透明的图片,PNG是一个更好的选择。
  • 可编辑性:JPG是一种不可编辑的图片格式,一旦被保存为JPG格式,就无法进行修改。而PNG是一种可编辑的图片格式,可以通过图像编辑软件(如Photoshop)进行修改、编辑和重新保存。例如,你可以改变PNG图片中的文字样式、线条等元素。

Android推流端的截图设计

大牛直播SDK早期在做Android平台RTMP推流和轻量级RTSP服务模块的时候,截图考虑到PNG的特性,直接保存png图片,随着GB28181-2022规范的实施,规范里面有明确要求,需要支持JPG编码,为此我们针对截图这块,做了如下的调整(对应:实时快照):

原接口:

	 /**
	  * 请使用新的CaptureImage接口, 这个接口只能保存PNG图片, 不推荐使用
	  * Save current image during publishing stream(实时快照)
	  *
	  * @param imageName: image name, which including fully path, "/sdcard/daniuliveimage/daniu.png", etc.
	  *
	  * @return {0} if successful
	  */
	 public native int SmartPublisherSaveCurImage(long handle,  String imageName);

值得注意的是,原接口如果需要截图,还需要调用SmartPublisherSaveImageFlag()。

新的接口,我们设计如下:

	/**
	 * 新的截图接口, 支持JPEG和PNG两种格式
	 * @param compress_format: 压缩格式, 0:JPEG格式, 1:PNG格式, 其他返回错误
	 * @param quality: 取值范围:[0, 100], 值越大图像质量越好, 仅对JPEG格式有效, 若是PNG格式,请填100
	 * @param file_name: 图像文件名, 例如:/dirxxx/test20231113100739.jpeg, /dirxxx/test20231113100739.png
	 * @param user_data_string: 用户自定义字符串
	 * @return {0} if successful
	 */
	 public native int CaptureImage(long handle, int compress_format, int quality, String file_name, String user_data_string);

如何调用?

废话不多说,直接上代码:

    private SimpleDateFormat capture_image_date_format_;

    class ButtonCaptureImageListener implements OnClickListener {
        @SuppressLint("SimpleDateFormat")
        public void onClick(View v) {
            if(isPushingRtmp || isRecording || isRTSPPublisherRunning || isPushingRtsp)
            {
                if (null == capture_image_date_format_)
                    capture_image_date_format_ = new SimpleDateFormat("yyyyMMddHHmmssSSS");

                String timeStamp = capture_image_date_format_.format(new Date());
                String imageFileName = timeStamp;    //创建以时间命名的文件名称

                String imagePath = imageSavePath + "/" + imageFileName;

                int quality;
                boolean is_jpeg = true;
                if (is_jpeg) {
                    imagePath += ".jpeg";
                    quality = 100;
                }
                else {
                    imagePath += ".png";
                    quality = 100;
                }

                int capture_ret = libPublisher.CaptureImage(publisherHandle,is_jpeg?0:1, quality, imagePath, "test_user_data");
                Log.i(TAG, "capture_image ret:" + capture_ret + ", file:" + imagePath);
            }
            else
            {
                Log.e(TAG, "快照失败,请确保在推送、录像或内置RTSP服务发布状态..");
            }
        }
    }

截图成功,对应的event回调如下:

    class EventHandeV2 implements NTSmartEventCallbackV2 {
        @Override
        public void onNTSmartEventCallbackV2(long handle, int id, long param1, long param2, String param3, String param4, Object param5) {

            Log.i(TAG, "EventHandeV2: handle=" + handle + " id:" + id);

            String publisher_event = "";

            switch (id) {
                .....

                case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_CAPTURE_IMAGE:
                    publisher_event = "快照: " + param1 + " 路径:" + param3;
                    if (0 == param1) {
                        rename_image_file_name(param3, param2);
                        publisher_event = publisher_event + "截取快照成功.." + ", 用户数据:" + param4;
                    } else
                        publisher_event = publisher_event + "截取快照失败..";

                    break;
                    ....
        }
    }

如果需要对截图后的文件重命名(比如gb28181,我们会把截图时间返上来),便于统一管理,参考代码如下:

    private void rename_image_file_name(String file_name, long file_date_time_ms) {
        if (null == file_name || file_name.isEmpty()
                || file_date_time_ms < 1 || null == capture_image_date_format_)
            return;

        try {
            java.io.File file = new File(file_name);
            if (!file.exists() || !file.isFile() || !file.canRead() || file.length() < 1)
                return;

            String file_name_extension = null;
            int index = file_name.lastIndexOf('.');
            if (index > -1)
                file_name_extension = file_name.substring(index + 1);

            Date file_date = new Date(file_date_time_ms);
            String new_file_name = capture_image_date_format_.format(file_date);
            if (file_name_extension != null && !file_name_extension.isEmpty())
                new_file_name += "." + file_name_extension;

            java.io.File new_file = new java.io.File(file.getParent(), new_file_name);
            if (file.renameTo(new_file))
                Log.i(TAG, "rename image file name ok, file_name:" + file_name + ", new:"+ new_file_name);
             else
                Log.e(TAG, "rename image file name failed, file_name:" + file_name);

        } catch (Exception e) {
            Log.e(TAG, "rename_image_file_name Exception:", e);
        }
    }

总结

Android平台RTMP推送、轻量级RTSP还是GB28181设备对接模块,选择哪种图片格式主要取决于具体的使用需求。如果你需要压缩图像文件并且不关心原始图像的完整性,JPG可能是一个更好的选择。而如果你需要保持原始图像的完整性和质量,或者需要制作背景透明的图片,那么PNG可能是更好的选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1382483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

将图片添加到 PDF 的 5 种方法

需要一种称为 PDF 编辑器的特定工具才能将图片添加到 PDF。尽管大多数浏览器在查看和注释 PDF 文件方面都非常出色&#xff0c;但如果您使用图像到 PDF 技术&#xff0c;则只能将照片放入 PDF 中。无需修改即可将 PDF 文件恢复为原始格式的能力是使用此类软件程序甚至在线服务的…

故障诊断全家桶,看这一篇就够了,精品力荐!

本期推出故障诊断全家桶&#xff0c;包含传统的分析时频诊断方法&#xff0c;依靠数据分解方法的诊断方法&#xff0c;依靠机器学习的诊断方法。还包含了6种适应度函数随意切换的VMD优化方法&#xff0c;16种数据分解方法&#xff0c;包络谱&#xff0c;包络熵等代码。以及作者…

计算机硬件 5.1机箱与电源

第五章 其他设备 第一节 机箱与电源 一、认识电源 1.功能&#xff1a;将普通交流电转换为直流电&#xff0c;再控制电压分别输出给不同部件。 2.分类&#xff1a; 3.供电插头&#xff1a; ①8Pin插头&#xff1a;为高档PCI-E显卡供电&#xff0c;或为较新的CPU供电&#xff…

2023 我的编程之旅——路人贾‘ω‘

哈喽&#xff01;大家好&#xff0c;我是路人贾&#x1f601;~今天不读论文也不讲算法&#xff0c;来聊点有意思的&#xff01; 这是我第100篇博文&#xff0c;我翻了几遍草稿箱的库存&#xff0c;正纠结选哪篇时&#xff0c;一抬头看见了这个活动&#xff0c;眼前瞬间一亮——…

学习Java API(一):基础知识点一文通✅

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读API文档注释String类创建字符串拼接字符串格式化字符串String方法substring(…

网络安全工具:通过监控分析日志数据保护企业网络

由于混合工作模式的兴起以及业务运营向云环境的迁移&#xff0c;企业网络变得更加分散和复杂&#xff0c;仅安装外围安全解决方案只会创建一个基本的防御层&#xff0c;系统、服务器和其他网络实体会生成记录所有网络活动的日志。集中式日志管理系统可以帮助管理员自动监控网络…

探寻编程深渊:那些你无法想象的‘最差程序员’

在IT行业&#xff0c;有一类人让其他程序员闻风丧胆&#xff1a;那些最差的程序员。 他们的代码可能是漏洞百出&#xff0c;效率低下&#xff0c;甚至难以运行。他们可能对基本的编程概念一无所知&#xff0c;却自认为是个编程天才。那么&#xff0c;这些最差的程序员到底是什…

定时任务-理论基础

什么是小顶堆 小顶堆&#xff08;Min Heap&#xff09;是一种特殊的二叉堆&#xff0c;它满足以下条件&#xff1a; 它是一个完全二叉树&#xff0c;即除了最后一层外&#xff0c;其他层的节点数都是满的&#xff0c;并且最后一层的节点从左到右依次排列。树中的每个节点的…

用 AI 生成 Vue 组件?

大家好我是奇兵&#xff0c;三个月前&#xff0c;Vercel 推出了其 AI 代码生成工具 —— v0&#xff08;v0.dev&#xff09;&#xff0c;这款工具可以快速生成前端组件代码&#xff0c;引起了前端圈的广泛关注。通过简单的描述&#xff0c;v0能够快速生成前端页面&#xff0c;让…

【AI】【他山之玉】用AI写整本书后得到的经验

【背景】 想着用AI高效完成一些自己想尝试的创作&#xff0c;达到创作欲望和效率的平衡&#xff0c;于是先去找有经验的人学习&#xff0c;总结如下。。 【用AI写书整体上并不节约时间】 AI写书在整体上可能不节约时间&#xff0c;因为需要大量修改&#xff0c;但是它真正能…

使用numpy处理图片——二值图像

大纲 载入图像灰阶处理二值处理 在《使用numpy处理图片——灰阶影像》一文中&#xff0c;我们将彩色图片转换成灰阶图片。本文将在这个基础上将灰阶图片转换成二值图像。 二值图像就是只有黑白两种颜色的图像。像素最终显示黑还是白&#xff0c;需要有一个判断标准。如果图片太…

Python 中的字符串分割函数 split() 详解

更多Python学习内容&#xff1a;ipengtao.com 在 Python 编程中&#xff0c;处理字符串是一项常见的任务。字符串分割是其中的一个常见操作&#xff0c;而 Python 提供了强大的 split() 函数&#xff0c;用于将字符串拆分成多个部分。本文将详细介绍 split() 函数的用法、参数和…

8. 自定义分页

EmployeeMapper.java自定义接口 /*** <p>* 查询 : 根据lastName查询员工列表&#xff0c;分页显示* </p>** param page 分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位(你可以继承Page实现自己的分页对象)* param lastName 状态* retu…

OpenAPI自助诊断-阿里云超好用的一个东西

一、【写在前面】 这个阿里云啊&#xff0c;我个人非常喜欢用&#xff0c;在今年的几个事件之前&#xff0c;本人认为是国内最好用的云&#xff0c;虽然今年发生了诸如语雀和API的故障&#xff0c;但是瑕不掩瑜&#xff0c;不可否认的是世界上做的最好的三朵云就是AWS&#xf…

将文本缩短为指定的长度textwrap.shorten()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 将文本缩短为指定的长度 textwrap.shorten() 请问运行结果是&#xff1a; import textwrap text "123 56 890" shortened_text textwrap.shorten(text, width9) print(shortened_…

HashMap集合万字源码详解(面试常考)

文章目录 HashMap集合1.散列2.hashMap结构3.继承关系4.成员变量5.构造方法6.成员方法6.1增加方法6.2将链表转换为红黑树的treeifyBin方法6.3扩容方法_resize6.3.1扩容机制6.3.2源码resize方法的解读 6.4 删除方法(remove)6.5查找元素方法(get)6.6遍历HashMap集合几种方式 7.初始…

Cdd诊断数据控中的zz rc yy

如上图所示的Cdd Candela Diagnostic Descriptions 诊断数据库会话定义中有许多的标识符缩写&#xff0c;如zz rc LL xx 等 其实这些字母没有意义&#xff0c;它们只是唯一地标识对话框中的组合组件。

开源数据库系统OpenGauss本地部署

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合…

03.用于LLMs不同的任务-transformer 架构

大多数现代LLMs都依赖于 transformer 架构,这是 2017 年论文 Attention Is All You Need 中介绍的深度神经网络架构。要理解LLMs,我们必须简要回顾一下最初的转换器,它最初是为机器翻译而开发的,将英语文本翻译成德语和法语。变压器架构的简化版本如图 1.4 所示。 图 1.4 …

华西建筑智能化寻找志同道合的创业团队

我今天四十多了&#xff0c;之前也创过业&#xff0c;做软件开发系统集成的。 19年进入华西建筑装饰工程有限公司负责机电安装及弱电智能化版块。后公司成立建筑智能化事业部&#xff0c;我负责。现在想全身心打造施工企业项目管理平台&#xff0c;同时进军智慧康养领域。我想…