Comment fonctionnent les images vectorielles dans Xcode (c'est-à-dire les fichiers PDF)?

177

Comment fonctionne la prise en charge vectorielle dans Xcode 6?

Quand j'essaye de redimensionner une image, elle a l'air irrégulière, qu'est-ce que ça donne?

Sensé
la source

Réponses:

351

Comment utiliser les vecteurs dans Xcode (7 et 6.3+):

  1. Enregistrez une image en tant que fichier .pdf à la taille @ 1x appropriée (par exemple 24x24 pour un bouton de barre d'outils ).
  2. Dans votre fichier Images.xcassets , créez un nouvel ensemble d'images .
  3. Dans l' inspecteur d'attributs , définissez les facteurs d'échelle sur Vecteur unique .
  4. Faites glisser et déposez votre fichier pdf dans la section Tous, Universel .
  5. Vous pouvez maintenant faire référence à votre image par son nom, comme vous le feriez pour n'importe quel fichier .png .

    UIImage(named: "myImage")

Comment utiliser les vecteurs dans les anciennes versions de Xcode (6.0 - 6.2):

  • Suivez les étapes ci-dessus, sauf pour l'étape 3, définissez Types sur Vecteurs .

Comment les vecteurs fonctionnent dans Xcode

La prise en charge des vecteurs est déroutante dans Xcode, car lorsque la plupart des gens pensent aux vecteurs, ils pensent à des images qui peuvent augmenter et diminuer tout en ayant une belle apparence. Cependant, Xcode 6 et 7 ne prennent pas entièrement en charge les vecteurs pour iOS, donc les choses fonctionnent un peu différemment.

Le système vectoriel est vraiment simple . Il prend votre .pdfimage et crée @1x.png, @2x.pnget @3x.pngactifs au moment de la construction . (Vous pouvez utiliser un outil pour examiner le contenu de Assets.car pour vérifier cela.)

Par exemple, supposons que l'on vous donne foo.pdfun élément vectoriel 44x44. Au moment de la construction, il générera les fichiers suivants:

Cela fonctionne de la même manière pour n'importe quelle image de taille. Par exemple, si vous avez une valeur de bar.pdf100x100, vous obtiendrez:


Implications:

  • Vous ne pouvez pas choisir une nouvelle taille pour l'image ; cela n'aura l'air bien que si vous le gardez à la taille 44x44. La raison en est que la prise en charge complète des vecteurs n'est pas implémentée . La seule chose que ces vecteurs font est de vous faire gagner du temps lors de la sauvegarde de vos images. Si vous avez un outil (par exemple un script Photoshop) qui en fait déjà un processus en une seule étape, la seule chose que vous gagnerez en utilisant des vecteurs pdf est une prise en charge à l'épreuve du temps (par exemple, si dans iOS 9, Apple commence à exiger @ 4x actifs, ceux-ci fonctionneront), et vous aurez moins de fichiers à maintenir .
  • Vous devriez demander tous vos actifs à la taille @ 1x, enregistrés sous forme de fichiers PDF . Entre autres choses, cela permettra à UIImageViews d'avoir la taille de contenu intrinsèque correcte.

Pourquoi cela fonctionne (probablement) de cette façon:

  • Cela le rend rétrocompatible avec les versions précédentes d'iOS.
  • Le redimensionnement des vecteurs peut être une tâche intensive de calcul au moment de l'exécution; en l'implémentant de cette façon, il n'y a aucun impact sur les performances .
Sensé
la source
8
Belle rédaction. Ceci est discuté dans la Session 411 de la WWDC 2014 - "Quoi de neuf dans Interface Builder" à l'heure 44:13. Notez qu'ils disent que la pixellisation est effectuée au moment de la construction. Il est également intéressant de noter que sur MAC, il utilisera des vecteurs lors de l'exécution. À un moment lointain dans le futur, j'espère que iOS le sera aussi.
Mike Vosseller le
15
Il ne met malheureusement pas à l'échelle les valeurs de tranche. Donc, si vous coupez les coins à 5, il ne sera pas mis à l'échelle à 10 et 15 pour les images 2x et 3x.
Jesse
5
@Jesse si vous souhaitez mettre à l'échelle les valeurs de tranche, vous pouvez le faire vous-même dans le code en utilisant resizableImageWithCapInsets:et en divisant vos valeurs de tranche par[UIScreen mainScreen].scale
Arie Litovsky
1
Pour clarifier la suggestion de @ArieLitovsky sur le découpage: vous devez supprimer le découpage de l'actif et le déplacer vers le code, quelque chose commeCGFloat scale = [UIScreen mainScreen].scale; UIImage *image = [[UIImage imageNamed:@"my_unsliced_asset"] resizableImageWithCapInsets:UIEdgeInsetsMake(10 * scale, 11 * scale, 12 * scale, 13 * scale)];
glyuck
6
Comment faire cela pour XCode 8? l'option semble avoir disparu!
Gerald le
26

Dans Xcode 8, vous pouvez toujours ajouter un pdf, créer un nouvel ensemble d'images et, dans l'inspecteur d'attributs, définir l'option Échelles à échelle unique. entrez la description de l'image ici

Maria
la source
15

Ceci est un complément à l'excellente réponse de @Senseful.

Comment créer des images vectorielles au format .pdf

Je vais vous dire comment faire cela dans Inkscape car il est gratuit et open source, mais les autres programmes devraient être similaires.

Dans Inkscape:

  1. Créez un nouveau projet.
  2. Accédez à Fichier> Propriétés du document et définissez la taille de page personnalisée sur la taille de votre @ 1x (44x44, 100x100, etc.) avec les unités en px.
  3. Faites votre oeuvre.
  4. Accédez à Fichier> Enregistrer sous ...> Format de document imprimable (* .pdf)> Enregistrer> OK. (Vous pouvez également aller à Imprimer> Imprimer dans un fichier> Format de sortie: PDF> Imprimer mais il n'y a pas autant d'options.)

Remarques:

  • Comme mentionné dans la réponse acceptée, vous ne pouvez pas redimensionner votre image car Xcode produit toujours les images pixellisées au moment de la construction. Si vous avez besoin de redimensionner votre image, vous devez créer un nouveau fichier .pdf avec une taille différente.
  • Si vous disposez déjà d'une image .svg dont la taille de page est incorrecte, procédez comme suit:

    1. Modifier la taille de la page (Inkscape> Fichier> Propriétés du document)
    2. Sélectionnez tous les objets (Ctrl + A) sur l'espace de travail et redimensionnez-les pour les adapter à la nouvelle taille de page. (Maintenez la touche Ctrl enfoncée pour conserver la taille de l'aspect.)
  • Pour convertir un fichier .svg en .pdf, vous pouvez également trouver des utilitaires en ligne pour faire le travail à votre place. Voici un exemple de cette réponse . Cela a l'avantage de vous permettre de définir facilement la taille .pdf.

Lectures complémentaires

Suragch
la source
12

Pour ceux qui ne sont toujours pas mis à jour, il y a eu des changements dans Xcode 9 (iOS 11).

Quoi de neuf dans Cocoa Touch (WWDC 2017 Session 201) (@ 32: 55) https://developer.apple.com/videos/play/wwdc2017/201/

En quelques mots, le catalogue d'actifs inclut désormais la nouvelle case à cocher dans l'inspecteur d'attributs nommée «Préserver les données vectorielles». Lorsqu'elle est cochée, les données PDF seront incluses dans le binaire compilé, augmentant bien sûr sa taille. Mais cela donne une chance à iOS de mettre à l'échelle les données vectorielles dans les deux sens et de fournir de belles images (avec ses propres difficultés). Pour iOS inférieur à 11, les anciens mécanismes de mise à l'échelle décrits dans les réponses à la hausse sont utilisés.

Dren
la source
1

Vous pouvez utiliser des fichiers PDF normaux dans votre projet sous forme d'images vectorielles et rendre des images de n'importe quelle taille à l'aide de cette extension. Cette méthode est bien meilleure car iOS ne générera pas d'images .PNG à partir de vos fichiers PDF, et vous pouvez rendre vos images avec la taille de votre choix:

    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
la source
1
J'ai essayé cela, mais il ne semble pas que cela redimensionne l'image à des tailles de pixels plus grandes? La UIImage elle-même que j'obtiens est de la bonne taille; c'est juste que l'image vectorielle est centrée et toujours à la taille de pixel d'origine du PDF. (Je voulais l'adapter à la taille de l'UIImage.) Savez-vous si cela serait possible?
DivideByZer0