Jak działają obrazy wektorowe w Xcode (tj. Plikach PDF)?

177

Jak działa obsługa wektorów w Xcode 6?

Kiedy próbuję zmienić rozmiar obrazu, wygląda na poszarpany, co daje?

Rozsądne
źródło

Odpowiedzi:

351

Jak używać wektorów w Xcode (7 i 6.3+):

  1. Zapisz obraz jako plik .pdf w odpowiednim rozmiarze @ 1x (np. 24x24 dla przycisku paska narzędzi ).
  2. W pliku Images.xcassets utwórz nowy zestaw obrazów .
  3. W Inspektorze atrybutów ustaw współczynniki skali na Pojedynczy wektor .
  4. Przeciągnij i upuść plik pdf do sekcji All, Universal .
  5. Możesz teraz odwoływać się do swojego obrazu, używając jego nazwy, tak jak do każdego pliku .png .

    UIImage(named: "myImage")

Jak używać wektorów w starszych wersjach Xcode (6.0 - 6.2):

  • Wykonaj powyższe kroki, z wyjątkiem kroku 3, ustaw Typy na Wektory .

Jak działają wektory w Xcode

Obsługa wektorów jest myląca w Xcode, ponieważ kiedy większość ludzi myśli o wektorach, myślą o obrazach, które można skalować w górę iw dół i nadal dobrze wyglądać. Jednak Xcode 6 i 7 nie mają pełnej obsługi wektorów dla iOS, więc rzeczy działają trochę inaczej.

System wektorowy jest naprawdę prosty . Zajmuje swój .pdfwizerunek i tworzy @1x.png, @2x.pngi @3x.pngaktywa w czasie kompilacji . (Możesz użyć narzędzia do sprawdzenia zawartości Assets.car, aby to sprawdzić).

Na przykład załóżmy, że otrzymałeś foo.pdfzasób wektorowy 44x44. W czasie kompilacji wygeneruje następujące pliki:

Działa to tak samo dla każdego rozmiaru obrazu. Na przykład, jeśli masz bar.pdf100x100, otrzymasz:


Implikacje:

  • Nie możesz wybrać nowego rozmiaru obrazu ; będzie dobrze wyglądać tylko wtedy, gdy zachowasz rozmiar 44x44. Powodem jest to, że nie zaimplementowano pełnej obsługi wektorów . Jedyne, co robią te wektory, to oszczędzanie czasu na zapisywanie zasobów graficznych. Jeśli masz narzędzie (np. Skrypt Photoshopa), które już sprawia, że ​​jest to jednoetapowy proces, jedyne, co zyskasz używając wektorów pdf, to przyszłościowe wsparcie (np. Jeśli w iOS 9 Apple zaczyna wymagać zasobów @ 4x, po prostu zadziałają) i będziesz mieć mniej plików do utrzymania .
  • Powinieneś poprosić o wszystkie swoje zasoby w rozmiarze @ 1x, zapisane jako pliki PDF . Między innymi pozwoli to UIImageViews mieć prawidłowy wewnętrzny rozmiar zawartości.

Dlaczego (prawdopodobnie) działa w ten sposób:

  • Dzięki temu jest wstecznie kompatybilny z poprzednimi wersjami iOS.
  • Zmiana rozmiaru wektorów może wymagać dużej mocy obliczeniowej w czasie wykonywania; implementując to w ten sposób, nie ma żadnych hitów wydajności .
Rozsądne
źródło
8
Niezły opis. Jest to omówione w sesji 411 WWDC 2014 - „Co nowego w programie Interface Builder” o godzinie 44:13. Zauważ, że mówią, że rasteryzacja jest wykonywana w czasie kompilacji. Co ciekawe, na MAC będzie używać wektorów w czasie wykonywania. Miejmy nadzieję, że w pewnym odległym momencie w przyszłości iOS też.
Mike Vosseller
15
Niestety nie skaluje wartości wycinków. Więc jeśli pokroisz rogi na 5, nie przeskalujesz go do 10 i 15 dla obrazów 2x i 3x.
Jesse
5
@Jesse, jeśli chcesz skalować wartości wycinków, możesz to zrobić samodzielnie w kodzie, używając resizableImageWithCapInsets:i dzieląc wartości [UIScreen mainScreen].scale
wycinków
1
Aby wyjaśnić sugestię @ArieLitovsky dotyczącą wycinania: należy usunąć wycinanie z zasobu i przenieść go do kodu, na przykładCGFloat scale = [UIScreen mainScreen].scale; UIImage *image = [[UIImage imageNamed:@"my_unsliced_asset"] resizableImageWithCapInsets:UIEdgeInsetsMake(10 * scale, 11 * scale, 12 * scale, 13 * scale)];
glyuck
6
Jak mam to zrobić dla XCode 8? wydaje się, że opcja zniknęła!
Gerald
26

W Xcode 8 nadal możesz dodać plik PDF, utworzyć nowy zestaw obrazów, aw Inspektorze atrybutów ustawić opcję Skale na pojedynczą skalę. wprowadź opis obrazu tutaj

Maria
źródło
15

To uzupełnienie doskonałej odpowiedzi @Senseful.

Jak tworzyć obrazy wektorowe w formacie .pdf

Powiem, jak to zrobić w Inkscape, ponieważ jest darmowy i open source, ale inne programy powinny być podobne.

W Inkscape:

  1. Utwórz nowy projekt.
  2. Przejdź do Plik> Właściwości dokumentu i ustaw niestandardowy rozmiar strony na dowolny rozmiar @ 1x (44x44, 100x100 itd.) Z jednostkami w pikselach.
  3. Stwórz swoją grafikę.
  4. Przejdź do Plik> Zapisz jako ...> Format dokumentu do druku (* .pdf)> Zapisz> OK. (Alternatywnie możesz przejść do Drukuj> Drukuj do pliku> Format wyjściowy: PDF> Drukuj, ale nie ma tak wielu opcji).

Uwagi:

  • Jak wspomniano w zaakceptowanej odpowiedzi, nie możesz zmienić rozmiaru obrazu, ponieważ Xcode nadal tworzy rasteryzowane obrazy w czasie kompilacji. Jeśli chcesz zmienić rozmiar obrazu, powinieneś utworzyć nowy plik .pdf o innym rozmiarze.
  • Jeśli masz już obraz .svg o nieprawidłowym rozmiarze strony, wykonaj następujące czynności:

    1. Zmień rozmiar strony (Inkscape> Plik> Właściwości dokumentu)
    2. Wybierz wszystkie obiekty (Ctrl + A) w obszarze roboczym i zmień ich rozmiar, aby dopasować je do nowego rozmiaru strony. (Przytrzymaj klawisz Ctrl, aby zachować rozmiar proporcji).
  • Aby przekonwertować plik .svg na .pdf, możesz również znaleźć narzędzia online, które wykonają to zadanie za Ciebie. Oto jeden przykład z tej odpowiedzi . Ma to tę zaletę, że umożliwia łatwe ustawienie rozmiaru .pdf.

Dalsza lektura

Suragch
źródło
12

Dla tych, którzy wciąż nie aktualizowali, nastąpiły zmiany w Xcode 9 (iOS 11).

Co nowego w Cocoa Touch (sesja 201 WWDC 2017) (@ 32:55) https://developer.apple.com/videos/play/wwdc2017/201/

Krótko mówiąc, Katalog zasobów zawiera teraz nowe pole wyboru w Inspektorze atrybutów o nazwie „Zachowaj dane wektorowe”. Gdy zaznaczone, dane PDF zostaną uwzględnione w skompilowanym pliku binarnym, oczywiście zwiększając jego rozmiar. Ale daje to szansę iOS na skalowanie danych wektorowych w obu kierunkach i dostarczanie ładnych obrazów (z własnymi trudnościami). W przypadku iOS poniżej 11 używane są stare mechanizmy skalowania opisane w odpowiedziach w górę.

Dren
źródło
1

Możesz używać zwykłych plików PDF w swoim projekcie jako obrazów wektorowych i renderować obrazy o dowolnym rozmiarze za pomocą tego rozszerzenia. Jest to o wiele lepsze, ponieważ iOS nie generuje obrazów .PNG z plików PDF, a ponadto możesz renderować obrazy o dowolnym rozmiarze:

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

}
Bruno Paulino
źródło
1
Próbowałem tego, ale nie wygląda na to, że skaluje obraz do większych rozmiarów w pikselach? Sam UIImage, który otrzymuję, ma prawidłowy rozmiar; po prostu obraz wektorowy jest wyśrodkowany i nadal ma oryginalny rozmiar w pikselach pliku PDF. (Chciałem wyskalować to do rozmiaru UIImage.) Czy wiesz, czy to byłoby możliwe?
DivideByZer0