草庐IT

swift - 在上传到谷歌云存储之前调整和压缩图像

coder 2023-09-16 原文

我制作了一个函数,可以在保持宽高比的同时将图像调整为最大宽度和高度。此外,我正在根据 compressionQuality 压缩图像 - 我已经使用 3024x4032 jpeg 图像 @ 11.7 mb 对此进行了测试。

maxWidth = 800px
maxHeight = 1200px
compressionQuality = 0.5

该函数确实将图像大小从 11.7mb 减小到 0.51mb,但是宽度和高度没有正确减小。上传到 Firebase 后,图像尺寸是 1600 x 2134px 的两倍......但它应该是 800x1066px(一半)

你能看出哪里出了问题吗?

import UIKit
import Foundation

class ImageEdit {
        static let instance = ImageEdit()

    func resizeAndCompressImageWith(image: UIImage, maxWidth: CGFloat, maxHeight: CGFloat, compressionQuality: CGFloat) -> Data? {

    let horizontalRatio = maxWidth / image.size.width
    let verticalRatio = maxHeight / image.size.height


    let ratio = min(horizontalRatio, verticalRatio)

    let newSize = CGSize(width: image.size.width * ratio, height: image.size.height * ratio)
    var newImage: UIImage

    if #available(iOS 10.0, *) {
        let renderFormat = UIGraphicsImageRendererFormat.default()
        renderFormat.opaque = false
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
        newImage = renderer.image {
            (context) in
            image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        }
    } else {
        UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), true, 0)
        image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
    }

            let data = UIImageJPEGRepresentation(newImage, compressionQuality)



    return data

}

}

这是将图像上传到 firebase 的代码。

func uploadImageToFirebaseAndReturnImageURL(directory: String, image: UIImage!, maxWidth: CGFloat, maxHeight: CGFloat, compressionQuality: CGFloat, handler: @escaping(_ imageURL: String)  -> ()) {
        let imageName = NSUUID().uuidString // create unique image name

        if let uploadData = ImageEdit.instance.resizeAndCompressImageWith(image: image, maxWidth: maxWidth, maxHeight: maxHeight, compressionQuality: compressionQuality) {

            DB_STORE.child(directory).child(imageName).putData(uploadData, metadata: nil, completion: { (metadata, error) in

                if error != nil {
                    print(error ?? "Image upload failed for unknown reason")
                    return
                }

                // if URL exist, then return imageURL
                if let imageURL = metadata?.downloadURL()?.absoluteString {
                  handler (imageURL)


                }
                return

            })
        }



    }

最佳答案

我将您的代码复制到测试项目中并添加了一些打印语句,并尝试调整原始尺寸为 3360x2108 的图像。 (注意:我在此测试代码中使用了强制解包,但不建议将其用于任何生产代码)。

这是我调用调整大小代码的函数:

func resizeImage() {
    guard let image = UIImage.init(named: "landscape") else {
        return
    }
    print("Original Image Size: width: \(image.size.width) height: \(image.size.height)")

    let _ = ImageEdit.instance.resizeAndCompressImageWith(image: image, maxWidth: 800.0, maxHeight: 1200.0, compressionQuality: 0.5)
}

这是我的调整大小代码的更新版本。我只是在最后添加一些代码来实例化一些图像实例,以便在转换后注销它们的实际大小:

import UIKit

class ImageEdit {
    static let instance = ImageEdit()

    func resizeAndCompressImageWith(image: UIImage, maxWidth: CGFloat, maxHeight: CGFloat, compressionQuality: CGFloat) -> Data? {

        let horizontalRatio = maxWidth / image.size.width
        let verticalRatio = maxHeight / image.size.height


        let ratio = min(horizontalRatio, verticalRatio)
        print("Image Ratio: \(ratio)")

        let newSize = CGSize(width: image.size.width * ratio, height: image.size.height * ratio)
        print("NewSize: \(String(describing: newSize))")
        var newImage: UIImage

        if #available(iOS 10.0, *) {
            print("UIGraphicsImageRendererFormat")
            let renderFormat = UIGraphicsImageRendererFormat.default()
            renderFormat.opaque = false
            let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
            newImage = renderer.image {
                (context) in
                image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
            }
        } else {
            print("UIGraphicsBeginImageContextWithOptions")
            UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), true, 0)
            image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
            newImage = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
        }
        print("NewImageSize: width: \(newImage.size.width) height: \(newImage.size.height)")

        let png = UIImagePNGRepresentation(newImage)
        let pngImg = UIImage.init(data: png!)!
        print("PNG - width: \(pngImg.size.width) - height: \(pngImg.size.height)")

        let data = UIImageJPEGRepresentation(newImage, compressionQuality)
        let jpgImg = UIImage.init(data: data!)!
        print("JPG - width: \(jpgImg.size.width) - height: \(jpgImg.size.height)")

        let fullData = UIImageJPEGRepresentation(newImage, 1.0)
        let jpgFull = UIImage.init(data: fullData!)!
        print("JPG FULL - width: \(jpgFull.size.width) - height: \(jpgFull.size.height)")

        return data

    }
}

在装有 iOS 11 的模拟器上运行时,我将其记录到调试器中:

Original Image Size: width: 3360.0 height: 2108.0
Image Ratio: 0.238095238095238
NewSize: (800.0, 501.904761904762)
UIGraphicsImageRendererFormat
NewImageSize: width: 800.0 height: 502.0
PNG - width: 2400.0 - height: 1506.0
JPG - width: 2400.0 - height: 1506.0
JPG FULL - width: 2400.0 - height: 1506.0

如果我注释掉你的

if #available(iOS 10.0, *) {

block 我仍然看到相同的测量结果。

看来newImage是直接从

生成的
UIGraphicsImageRendererFormat 
or 
UIGraphicsBeginImageContextWithOptions 

生成指定大小的图像。但是,出于某种原因,通过

运行该图像
UIImagePNGRepresentation(newImage)
or
UIImageJPEGRepresentation(newImage, compressionQuality)

生成的图像尺寸比原始图像大 3 倍。即使我更新

UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
to
UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale)

这似乎并不重要。

在我的测试用例中 UIScreen.main.scale = 3.0。

因此看来,通过 PNG 或 JPEG 表示方法转换图像会将其乘以这些函数生成的最终图像大小的 UIScreen.main.scale。

关于swift - 在上传到谷歌云存储之前调整和压缩图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48288430/

有关swift - 在上传到谷歌云存储之前调整和压缩图像的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  4. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  5. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

  6. ruby-on-rails - 在 Ruby (on Rails) 中使用 imgur API 获取图像 - 2

    我正在尝试使用Ruby2.0.0和Rails4.0.0提供的API从imgur中提取图像。我已尝试按照Ruby2.0.0文档中列出的各种方式构建http请求,但均无济于事。代码如下:require'net/http'require'net/https'defimgurheaders={"Authorization"=>"Client-ID"+my_client_id}path="/3/gallery/image/#{img_id}.json"uri=URI("https://api.imgur.com"+path)request,data=Net::HTTP::Get.new(path

  7. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  8. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  9. ruby-on-rails - 在 Ruby on Rails 中发送响应之前如何等待多个异步操作完成? - 2

    在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.

  10. ruby-on-rails - 为什么在 Rails 5.1.1 中删除了 session 存储初始化程序 - 2

    我去了这个website查看Rails5.0.0和Rails5.1.1之间的区别为什么5.1.1不再包含:config/initializers/session_store.rb?谢谢 最佳答案 这是删除它的提交:Setupdefaultsessionstoreinternally,nolongerthroughanapplicationinitializer总而言之,新应用没有该初始化器,session存储默认设置为cookie存储。即与在该初始值设定项的生成版本中指定的值相同。 关于

随机推荐