矢量图像如何在Xcode中工作(即pdf文件)?

问题描述 投票:163回答:5

矢量支持如何在Xcode 6中工作?

当我尝试调整图像大小时,它看起来是锯齿状的,是什么给出的?

xcode vector-graphics
5个回答
340
投票

How to use vectors in Xcode (7 and 6.3+):

  1. 将图像保存为适当的@ 1x大小的.pdf文件(例如24x24 for a toolbar button)。
  2. 在Images.xcassets文件中,创建一个新的图像集。
  3. 在“属性”检查器中,将“比例因子”设置为“单个矢量”。
  4. 将pdf文件拖放到All,Universal部分。
  5. 现在,您可以按名称引用图像,就像使用任何.png文件一样。 UIImage(named: "myImage")

How to use vectors in older versions of Xcode (6.0 - 6.2):

  • 按照上述步骤操作,步骤3除外,将“类型”设置为“矢量”。

How vectors work in Xcode

矢量支持在Xcode中令人困惑,因为当大多数人想到矢量时,他们会想到可以向上和向下扩展并且看起来仍然很好的图像。但是,Xcode 6和7没有iOS的完全矢量支持,因此工作方式略有不同。

矢量系统非常简单。它需要你的.pdf图像,并在构建时创建@1x.png@2x.png@3x.png资产。 (你可以use a tool to examine the contents of Assets.car来验证这一点。)

例如,假设您获得了foo.pdf,这是一个44x44矢量资产。在构建时,它将生成以下文件:

对于任何尺寸的图像,这都是相同的。例如,如果您的bar.pdf为100x100,您将获得:


Implications:

  • 您无法为图像选择新尺寸;如果你把它保持在44x44的大小,它只会看起来很好。原因是没有实现完整的矢量支持。这些向量唯一能做的就是节省您保存图像资源的时间。如果你有一个工具(例如一个Photoshop脚本)已经使这个步骤一步到位,你将通过使用pdf向量获得的唯一的东西是未来的支持(例如,如果在iOS 9 Apple开始需要@ 4x资产,这些只会工作),你将有更少的文件要维护。
  • 您应该要求@ 1x大小的所有资产,保存为PDF文件。除此之外,这将允许UIImageViews具有正确的内在内容大小。

Why it (probably) works this way:

  • 这使它向后兼容以前的iOS版本。
  • 调整矢量大小可能是运行时的计算密集型任务;通过这种方式实现它,没有性能命中。

22
投票

在Xcode 8中,您仍然可以添加pdf,创建新的图像集,并在Attributes Inspector中将Scales设置为Single Scale选项。 enter image description here


14
投票

这是@Senseful的优秀答案的补充。

How to make vector images in .pdf format

我将告诉你如何在Inkscape中这样做,因为它是免费的和开源的,但其他程序应该是类似的。

在Inkscape中:

  1. 创建一个新项目。
  2. 转到文件>文档属性,并将自定义页面大小设置为@ 1x大小(44x44,100x100等),单位为px。
  3. 制作你的作品。
  4. 转到文件>另存为...>可打印文档格式(* .pdf)>保存>确定。 (或者,您可以转到“打印”>“打印到文件”>“输出格式:PDF>打印”,但选项不多。)

笔记:

  • 如接受的答案中所述,您无法调整图像大小,因为Xcode仍会在构建时生成光栅化图像。如果您需要调整图像大小,则应创建一个不同大小的新.pdf文件。
  • 如果您的.svg图像已经是错误的页面大小,请执行以下操作: 更改页面大小(Inkscape>文件>文档属性) 选择工作区上的所有对象(Ctrl + A)并调整它们以适应新的页面大小。 (按住Ctrl键保持宽高比。)
  • 要将.svg文件转换为.pdf,您还可以找到在线实用程序来为您完成工作。来自Here is one examplethis answer。这样可以让您轻松设置.pdf大小。

Further reading


8
投票

对于那些仍未更新的人,Xcode 9(iOS 11)有所变化。

Cocoa Touch的新变化(WWDC 2017 Session 201)(@ 32:55)https://developer.apple.com/videos/play/wwdc2017/201/

简而言之,资产目录现在包含名为“保存矢量数据”的属性检查器中的新复选框。选中后,PDF数据将包含在已编译的二进制文件中,当然会增加其大小。但它为iOS提供了在两个方向上缩放矢量数据并提供漂亮图像的机会。(有其自身的困难)。对于低于11的iOS,使用在答案中向上描述的旧缩放机制。


1
投票

您可以将项目中的普通PDF文件用作矢量图像,并使用此扩展名渲染任意大小的图像。这种方式更好,因为iOS不会从PDF文件中生成.PNG图像,而且您可以渲染任意大小的图像:

    extension UIImage {

    static func fromPDF(filename: String, size: CGSize) -> UIImage? {
        guard let path = Bundle.main.path(forResource: filename, ofType: "pdf") else { return nil }
        let url = URL(fileURLWithPath: path)
        guard let document = CGPDFDocument(url as CFURL) else { return nil }
        guard let page = document.page(at: 1) else { return nil }

        let imageRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        if #available(iOS 10.0, *) {
            let renderer = UIGraphicsImageRenderer(size: size)
            let img = renderer.image { ctx in
                UIColor.white.withAlphaComponent(0).set()
                ctx.fill(imageRect)
                ctx.cgContext.translateBy(x: 0, y: size.height)
                ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
                ctx.cgContext.concatenate(page.getDrawingTransform(.artBox, rect: imageRect, rotate: 0, preserveAspectRatio: true))
                ctx.cgContext.drawPDFPage(page);
            }

            return img
        } else {
            // Fallback on earlier versions
            UIGraphicsBeginImageContextWithOptions(size, false, 2.0)
            if let context = UIGraphicsGetCurrentContext() {
                context.interpolationQuality = .high
                context.setAllowsAntialiasing(true)
                context.setShouldAntialias(true)
                context.setFillColor(red: 1, green: 1, blue: 1, alpha: 0)
                context.fill(imageRect)
                context.saveGState()
                context.translateBy(x: 0.0, y: size.height)
                context.scaleBy(x: 1.0, y: -1.0)
                context.concatenate(page.getDrawingTransform(.cropBox, rect: imageRect, rotate: 0, preserveAspectRatio: true))
                context.drawPDFPage(page)
                let image = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
                return image
            }
            return nil
        }
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.