为啥从 FileManager 数据初始化的 UIImages 有错误的比例?

Posted

技术标签:

【中文标题】为啥从 FileManager 数据初始化的 UIImages 有错误的比例?【英文标题】:Why do UIImages initialized from FileManager data have the wrong scale?为什么从 FileManager 数据初始化的 UIImages 有错误的比例? 【发布时间】:2017-05-14 01:16:21 【问题描述】:

我使用 Alamofire 从我编写的请求脚本中下载图像。然后我将图像保存到设备中,然后使用以下函数调用它:

    private static func save(image: UIImage, fileName: String) -> String? 
        let fileURL = documentsUrl.appendingPathComponent(fileName)
        if let imageData = UIImageJPEGRepresentation(image, 1.0) 
            do
                try imageData.write(to: fileURL) // When the images are downloaded, they seem to have the correct scale set already. Maybe we should verify this
                if image.scale != UIScreen.main.scale 
                    print("save - image scale: \(image.scale) does not match device scale: \(UIScreen.main.scale)")
                
                print("Saving image to file: \(fileURL)")
                return fileName // ----> Save fileName
            
            catch
                print("Error info: \(error)")
            
        
        print("Error saving image")
        return nil
    


    private static func loadImage(_ fileName: String) -> UIImage? 
        let fileURL = documentsUrl.appendingPathComponent(fileName)
        print("Loading image from file: \(fileURL)")
        do 
            let imageData = try Data(contentsOf: fileURL)
            //let image = UIImage(data: imageData) // Bad - the image will appear twice as big as it should be, and very blurry!
            let image = UIImage(data: imageData, scale: UIScreen.main.scale) // Alamofire extension...important. Make sure that images we downloaded are recalled with the right scale for our device
            return image
         catch 
            print("Error loading image : \(error)")
        
        return nil
    

如果我下载 200x200 像素的图像,ios 会在 iPhone 7 模拟器中将其识别为 2.0 比例的 100x100 点图像。如果我保存该图像并在没有在 Alamofire 提供的 UIImage 初始化程序扩展中设置比例的情况下调用它,iOS 会将其视为比例为 1.0 的 200x200 点图像。

为什么会发生这种情况?这是以正确的比例和分辨率保存和加载图像的最佳做法吗?

【问题讨论】:

不清楚您的问题出在哪里。您在代码中的什么地方看到了意想不到的结果?什么叫saveUIImage 是从哪里来的? jpeg 文件格式不会“保存”设备比例 顺便说一句更好用UIImage(contentsOfFile: fileURL.path) @LeoDabus 为什么?每个人的用例是什么? 来自文档This method loads the image data into memory and marks it as purgeable. If the data is purged and needs to be reloaded, the image object loads that data again from the specified path. 【参考方案1】:

从文件加载图像时,您必须告知正确的比例因子。仅当从包/资产目录系统加载时,才能为您识别图像比例因子。

这是代码行:

let image = UIImage(data: imageData, scale: UIScreen.main.scale)

您告诉图像比例被解释为设备的比例。在 iPhone 7 中它是 2.0。在 iPhone 7 Plus 上,它将是 3.0。从文件加载图像时,不应按设备比例缩放。相反,你必须明确地告诉它。 改用这个:

let image = UIImage(data: imageData, scale: 1.0)

【讨论】:

我知道如何让它正常工作(这是问题所在)。我想知道的是 why iOS 从文件加载图像的方式与从捆绑资源甚至通过网络加载图像的方式不同。您什么时候不想将比例应用于图像?这是 iOS 3 天的错误还是遗留问题? 我们无法准确判断为什么苹果会这样做。但我认为 \@2x 模式不是一个标准化的解决方案,只是一个 xcode/apple 内部标准。因此,如果您从服务器下载文件,则无法保证 \@2x 图像真的应该被解释为 \@2x。也许它是由服务器的所有者错误地命名的。因此,苹果决定最好告诉系统如何处理它。【参考方案2】:

如果使用UIImage.init(contentsOfFile:)或其他类似方法,则取决于该目录下png资源的文件名、屏幕比例和其他图像。

我对以下图片进行了快速测试。所有图像都相同,只是文件名不同。图像分辨率为 200x200。用 iPhone 7 测试。

图片文件夹

├─ Images
  ├─ image1.png
  ├─ image2@2x.png
  ├─ image3.png
  ├─ image3@2x.png

代码

let imagesDirectory = .... // Images directory 

if let image1 = UIImage.init(contentsOfFile: imagesDirectory + "image1.png") 
    print("image1 scale: \(image1.scale)")


if let image2 = UIImage.init(contentsOfFile: imagesDirectory + "image2.png") 
    print("image2 scale: \(image2.scale)")


if let image22x = UIImage.init(contentsOfFile: imagesDirectory + "image2@2x.png") 
    print("image2@2x scale: \(image22x.scale)")


if let image3 = UIImage.init(contentsOfFile: imagesDirectory + "image3.png") 
    print("image3 scale: \(image3.scale)")

输出

image1 scale: 1.0
image2 scale: 2.0
image2@2x scale: 2.0
image3 scale: 2.0

您可以看到相同图像的输出,但文件名不同:)

结论

使用适当的后缀(如@2x 和@3x)保存图像。

【讨论】:

以上是关于为啥从 FileManager 数据初始化的 UIImages 有错误的比例?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 FileManager.default.attributesOfItem 在 NSFileCreationDate 中返回当前日期?

为啥 NSFileManager 不工作?

如何在没有 EntityDataSource 的情况下从 SQL Server 获取数据到 DevExpress FileManager

Qt QListwidget为啥信号没用

从 Filemanager 加载时 UIImage 自动旋转

Material-UI XGrid:我可以控制行的初始排序顺序吗?为啥 apiRef.getAllRowIds() 不再尊重排序顺序?