Как векторные изображения работают в XCode (например, файлы PDF)?

177

Как работает векторная поддержка в Xcode 6?

Когда я пытаюсь изменить размер изображения, оно выглядит неровным, что дает?

Senseful
источник

Ответы:

351

Как использовать векторы в Xcode (7 и 6.3+):

  1. Сохраните изображение в формате .pdf с подходящим размером @ 1x (например, 24x24 для кнопки панели инструментов ).
  2. В вашем файле Images.xcassets создайте новый набор изображений .
  3. В Инспекторе Атрибутов установите Коэффициенты Масштабирования на Единственный Вектор .
  4. Перетащите PDF-файл в раздел « Все, универсальный ».
  5. Теперь вы можете ссылаться на свое изображение по его имени, как и любой другой файл .png .

    UIImage(named: "myImage")

Как использовать векторы в старых версиях Xcode (6.0 - 6.2):

  • Выполните шаги, описанные выше, за исключением шага 3, установите Типы на Векторы .

Как работают векторы в Xcode

Векторная поддержка сбивает с толку в Xcode, потому что, когда большинство людей думает о векторах, они думают об изображениях, которые могут увеличиваться и уменьшаться и при этом хорошо выглядеть. Тем не менее, Xcode 6 и 7 не имеют полной векторной поддержки iOS, поэтому все работает немного по-другому.

Система векторов действительно проста . Он берет свой .pdfобраз, и создает @1x.png, @2x.pngи @3x.pngактивы на время сборки . (Вы можете использовать инструмент для проверки содержимого Assets.car, чтобы убедиться в этом.)

Например, предположим, что вам дан foo.pdfвектор, который является векторным активом 44x44. Во время сборки он сгенерирует следующие файлы:

  • foo@1x.png в 44x44
  • foo@2x.png в 88x88
  • foo@3x.png в 132x132

Это работает так же для любого размера изображения. Например, если у вас есть bar.pdf100x100, вы получите:

  • bar@1x.png в 100x100
  • bar@2x.png в 200x200
  • bar@3x.png в 300x300

Последствия:

  • Вы не можете выбрать новый размер для изображения ; это будет хорошо смотреться, только если вы сохраните размер 44х44. Причина в том, что полная поддержка векторов не реализована . Единственное, что делают эти векторы, это экономит ваше время сохранения ваших изображений. Если у вас есть инструмент (например, скрипт Photoshop), который уже делает этот процесс одношаговым, единственное, что вы получите, используя векторы pdf, - это поддержка будущего (например, если в iOS 9 Apple начинает требовать ресурсы @ 4x, они просто будут работать), и у вас будет меньше файлов для обслуживания .
  • Вы должны запросить все ваши активы в размере @ 1x, сохраненные в виде файлов PDF . Среди прочего, это позволит UIImageViews иметь правильный внутренний размер контента.

Почему это (вероятно) работает так:

  • Это делает его обратно совместимым с предыдущими версиями iOS.
  • Изменение размеров векторов может быть сложной вычислительной задачей во время выполнения; реализовав это таким образом, вы не столкнетесь с производительностью .
Senseful
источник
8
Ницца пиши. Это обсуждается на Сессии 411 WWDC 2014 года «Что нового в Интерфейсном Разработчике» во время 44:13. Обратите внимание, что они говорят, что растеризация выполняется во время сборки. Также интересно на MAC это будет использовать векторы во время выполнения. В какой-то отдаленной точке в будущем, надеюсь, iOS тоже будет.
Майк Восселлер
15
К сожалению, это не масштабирует значения среза. Так что, если вы нарежете углы на 5, это не увеличит его до 10 и 15 для 2х и 3х изображений.
Джесси
5
@Jesse, если вы хотите масштабировать значения среза, вы можете сделать это самостоятельно в коде, используя resizableImageWithCapInsets:и разделяя значения среза на[UIScreen mainScreen].scale
Arie Litovsky
1
Чтобы прояснить предложение @ArieLitovsky о нарезке: вы должны удалить срезание из ресурса и переместить его в код, что-то вродеCGFloat scale = [UIScreen mainScreen].scale; UIImage *image = [[UIImage imageNamed:@"my_unsliced_asset"] resizableImageWithCapInsets:UIEdgeInsetsMake(10 * scale, 11 * scale, 12 * scale, 13 * scale)];
гляк
6
Как мне сделать это для XCode 8? вариант, похоже, исчез!
Джеральд
26

В Xcode 8 вы все еще можете добавить PDF-файл, создать новый набор изображений, а в инспекторе атрибутов установить параметр «Масштабировать в один масштаб». введите описание изображения здесь

Мария
источник
15

Это дополнение к отличному ответу @Senseful.

Как сделать векторные изображения в формате .pdf

Я расскажу, как это сделать в Inkscape, поскольку он бесплатный и с открытым исходным кодом, но другие программы должны быть похожими.

В Inkscape:

  1. Создать новый проект.
  2. Перейдите в «Файл»> «Свойства документа» и задайте для пользовательского размера страницы любой размер @ 1x (44x44, 100x100 и т. Д.) С единицами измерения в пикселях.
  3. Сделайте свою работу.
  4. Перейдите в Файл> Сохранить как ...> Формат документа для печати (* .pdf)> Сохранить> ОК. (Можно также выбрать «Печать»> «Печать в файл»> «Формат вывода: PDF> Печать», но вариантов не так много.)

Ноты:

  • Как упомянуто в принятом ответе, вы не можете изменить размер своего изображения, потому что XCode все еще производит растеризованные изображения во время сборки. Если вам нужно изменить размер изображения, вы должны создать новый файл .pdf другого размера.
  • Если у вас уже есть изображение .svg с неправильным размером страницы, сделайте следующее:

    1. Изменить размер страницы (Inkscape> Файл> Свойства документа)
    2. Выделите все объекты (Ctrl + A) в рабочей области и измените их размер, чтобы соответствовать новому размеру страницы. (Удерживайте Ctrl, чтобы сохранить размер аспекта.)
  • Чтобы преобразовать файл .svg в формат .pdf, вы также можете найти онлайн-утилиты, которые сделают эту работу за вас. Вот один пример из этого ответа . Преимущество этого состоит в том, что вы можете легко установить размер .pdf.

дальнейшее чтение

Suragch
источник
12

Для тех, кто еще не обновился, были внесены изменения в Xcode 9 (iOS 11).

Что нового в Cocoa Touch (WWDC 2017, Сессия 201) (@ 32: 55) https://developer.apple.com/videos/play/wwdc2017/201/

В двух словах, каталог активов теперь включает новый флажок в инспекторе атрибутов под названием «Сохранить векторные данные». Если этот флажок установлен, данные PDF будут включены в скомпилированный двоичный файл, что, конечно, увеличит его размер. Но это дает iOS возможность масштабировать векторные данные в обоих направлениях и получать красивые изображения (со своими собственными трудностями). Для iOS ниже 11 используются старые механизмы масштабирования, описанные в ответах вверх.

Dren
источник
1

Вы можете использовать обычные PDF-файлы внутри вашего проекта в качестве векторных изображений и рендерить изображения любого размера, используя это расширение. Этот способ намного лучше, потому что iOS не будет генерировать изображения .PNG из ваших PDF-файлов, плюс вы можете отображать изображения любого размера, который вам нужен:

    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
        }
    }

}
Бруно Паулино
источник
1
Я пробовал это, но не похоже, что он масштабирует изображение до больших размеров пикселей? Сам UIImage, который я получаю, имеет правильный размер; просто векторное изображение центрируется и все еще имеет исходный размер в пикселях PDF. (Я хотел масштабировать его до размера UIImage.) Вы знаете, возможно ли это?
DivideByZer0