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 {@Overridepublic 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;} elsepublisher_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);elseLog.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可能是更好的选择。