iOS开发关于“发送原图”功能问题的记录

移动开发 iOS
近期在做“发送原图”功能的时候,遇到一个bug:在Android、Windows、Mac 客户端发送原图,iOS客户端接收,保存原图后,原图物理尺寸不变,存储空间变小,对应的location等Exif信息丢失。与此同时,iOS客户端之间互发原图没有问题。针对这个问题,做了以下测试调研。

本文主要记录一个bug从发现、定位到延期解决的过程。文末添加了已踩过的坑

[[208835]]

 

近期在做“发送原图”功能的时候,遇到一个bug:在Android、Windows、Mac 客户端发送原图,iOS客户端接收,保存原图后,原图物理尺寸不变,存储空间变小,对应的location等Exif信息丢失。与此同时,iOS客户端之间互发原图没有问题。针对这个问题,做了以下测试调研,现记录下来:

iOS开发关于“发送原图”功能问题的记录
微信中发送原图样式

一. 首先介绍一下发送一张原图的流程:

  • 比如 Android 端发送一张原图,先上传到 IM 的服务器,上传成功后再发送消息体;(上传成功后,服务器会分配三个url分别对应缩略图、大图、原图)
  • 接收方接收到消息体,下载缩略图;
  • 点击缩略图,下载大图;
  • 再点击“查看原图”按钮,下载原图;
  • 下载成功后,长按图片,保存原图。

二. 问题定位是在***一步,保存图片的部分:

  • 下载的图片大小与服务器存储大小是完全一致的,保存之后大小就发生了变化(目前是“jpg”格式变小,“png”格式图片变大);
  • 下载的方式分别尝试了 AFNetwoking 下载、SDWebImage 的普通下载和高级下载方式(因为产品需求要求显示下载原图进度)
  • 结论下载的图片大小与服务器存储大小是完全一致的是因为在 SDWebImage 高级下载方法的 completionBlock 中有已下载的 bit 值
  • 尝试了能找到的各种保存图片的方式,均不行

验证测试:将安卓端产生的图片(包括拍照“jpg”和屏幕截图“png”)从浏览器下载到电脑,大小不变,将该图片文件拖到项目中,执行保存图片的方法,大小也发生了变化。

补充测试:安卓端拍摄一张图片(大小为5M),发送给 iOS 客户端(下载大小为5M),保存(大小为3M),再将该保存的图片发给安卓客户端(保存后为3M),安卓客户端再发送给iOS 客户端(保存后大小为3M)。结论:该压缩只会进行一次

保存图片后,图片的Exif信息丢失,但是Exif信息的大小远小于文件损失的大小。图片物理尺寸没有发生变化

三. 竞品的该功能现状:

  • Android、Windows、Mac发送原图,iOS客户端接收
  • 腾讯系(QQ、WeChat)各端发送接收原图都没有问题
  • 钉钉 的图片变小,Exif 信息丢失
  • BearyChat 发送原图的图片变小,Exif 信息丢失
  • Slack 只支持发送图片,没有发送原图功能

四. 基于现有情况的分析

  • iOS 系统在保存图片的时候,会对图片进行编解码操作,可能在位图上进行优化
  • 一张图片的存储大小的计算方式:水平像素垂直像素1色黑白或3基色*颜色深度bit数 = MB数,可能是不同系统的基数不同导致
  • 如果要解决这个问题,要先研究一下图片编解码这些很底层的东西,目前来看,性价比很低
  • 如果您之前踩过类似的坑并找到有效的解决方法,方便的话,劳烦请私信告知

五. 补充点干货

1. 关于iOS11新增的“.heic”格式图片

什么是“.heic”格式图片?

之前叫“live”图片,打开下图红框中的按钮即可打开该模式,拍照后会截取拍照前后大概两秒的一个片段,与“Gif”图不同的是,该格式还包含了声音(目前只有)

[[208836]]

什么样的手机才能拍出“.heic”格式图片?

只有在 iOS11系统下且CPU为A10及其以上(***也得是iPhone 7),其他情况下拍出来的都是普通“live”图,即在需要转换格式的时候会自动转换为“.jpg/.jpeg”格式

如何判断一张图片是否是“.heic”格式?

SDWebImage-NSData+ImageContentType.m 已更新,刚开始遇到这个问题的时候提了个issue,还让我提供对应url。。

 

  1. + (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data { 
  2.     if (!data) { 
  3.         return SDImageFormatUndefined; 
  4.     } 
  5.       
  6.     // File signatures table: http://www.garykessler.net/library/file_sigs.html 
  7.     uint8_t c; 
  8.     [data getBytes:&c length:1]; 
  9.     switch (c) { 
  10.         case 0xFF: 
  11.             return SDImageFormatJPEG; 
  12.         case 0x89: 
  13.             return SDImageFormatPNG; 
  14.         case 0x47: 
  15.             return SDImageFormatGIF; 
  16.         case 0x49: 
  17.         case 0x4D: 
  18.             return SDImageFormatTIFF; 
  19.         case 0x52: { 
  20.             if (data.length >= 12) { 
  21.                 //RIFF....WEBP 
  22.                 NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; 
  23.                 if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { 
  24.                     return SDImageFormatWebP; 
  25.                 } 
  26.             } 
  27.             break; 
  28.         } 
  29.         case 0x00: { 
  30.             if (data.length >= 12) { 
  31.                 //....ftypheic ....ftypheix ....ftyphevc ....ftyphevx 
  32.                 NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(4, 8)] encoding:NSASCIIStringEncoding]; 
  33.                 if ([testString isEqualToString:@"ftypheic"
  34.                     || [testString isEqualToString:@"ftypheix"
  35.                     || [testString isEqualToString:@"ftyphevc"
  36.                     || [testString isEqualToString:@"ftyphevx"]) { 
  37.                     return SDImageFormatHEIC; 
  38.                 } 
  39.             } 
  40.             break; 
  41.         } 
  42.     } 
  43.     return SDImageFormatUndefined; 
  44. + (nonnull CFStringRef)sd_UTTypeFromSDImageFormat:(SDImageFormat)format { 
  45.     CFStringRef UTType; 
  46.     switch (format) { 
  47.         case SDImageFormatJPEG: 
  48.             UTType = kUTTypeJPEG; 
  49.             break; 
  50.         case SDImageFormatPNG: 
  51.             UTType = kUTTypePNG; 
  52.             break; 
  53.         case SDImageFormatGIF: 
  54.             UTType = kUTTypeGIF; 
  55.             break; 
  56.         case SDImageFormatTIFF: 
  57.             UTType = kUTTypeTIFF; 
  58.             break; 
  59.         case SDImageFormatWebP: 
  60.             UTType = kSDUTTypeWebP; 
  61.             break; 
  62.         case SDImageFormatHEIC: 
  63.             UTType = kSDUTTypeHEIC; 
  64.             break; 
  65.         default
  66.             // default is kUTTypePNG 
  67.             UTType = kUTTypePNG; 
  68.             break; 
  69.     } 
  70.     return UTType; 

对于“.heic”格式图片我们应该怎么处理?

  • 首先肯定不是服务器去支持这个类型,因为 Windows、Android 是不支持该类型的图片正常显示的,尤其是 Windows 明确表示以后也不会支持。
  • 微信目前的处理方式是转换成了 jpg 格式,因此直接使用 UIImageJPEGRepresentation(originalImage, 0.82); 转换为jpg即可
  • 但是经多次测试后发现,必须设置压缩比为0.82,转换后的大小才尽可能的接近原图大小

 

责任编辑:未丽燕 来源: si1ence
相关推荐

2013-07-21 18:18:00

iOS开发ASIHttpRequ

2011-05-11 10:02:37

iOS

2014-05-06 09:44:54

MySQL LogsMySQL

2013-06-03 16:27:49

iOS开发移动应用移动开发

2014-03-12 10:13:00

iOSSEL对象

2015-09-10 09:10:46

2011-08-02 11:30:41

iOS开发 邮件发送

2015-07-15 10:37:10

IOS用户行为统计代码

2013-07-23 07:24:57

iOS开发学习iOS开发问题集锦

2014-06-10 13:44:58

iOSUIImage知识点

2013-06-13 09:03:15

iOS7WWDC苹果

2011-08-18 11:19:13

IOS开发Core Plot S

2013-05-27 13:37:42

Android开发移动开发屏幕截图

2011-08-09 10:27:41

iOS剪贴板

2013-09-02 15:26:44

.NET开发邮件系统.Net

2012-10-08 12:59:01

iOS 6.0开发框架功能更新

2011-07-08 14:09:51

iPhone UI

2010-05-11 10:43:10

Unix awk

2009-11-26 15:16:44

Cisco路由器IOS

2023-06-15 14:56:51

iOS 17苹果
点赞
收藏

51CTO技术栈公众号