SVG vers CGContext

Bonjour,


suite à  ce post, voici donc la deuxième question.


 


Comment récupérer un SVG dans un contexte, pour pouvoir appliquer les fonctions CGContextaddCurve, etc.


 


Parce que, tout ce que j'ai trouvé, donne un path, mais si on veut dessiner avec les méthodes CGContext..., on ne part pas d'un path...


 



 


Merci d'avance


Mots clés:

Réponses

  • busterTheobusterTheo Membre
    mars 2015 modifié #2

    J'ai trouvé ça https://itunes.apple.com/us/app/qwarkee/id498340809?mt=12


     


    Et ça


     


    QwarKee qui convertit un svg en CGContext


     


    Et


     


    PaintCode qui convertit un svg en path


     


     


    Je suis tenté par QwarKee. J'ai besoin de récupérer les controlPoints dans les CGContext pour ensuite les manipuler à  l'aide de poignées sur les tangentes.


     


    Est-ce le bon choix ?


     


    Et j'ai des doutes sur la conversion en swift !!!


  • Pas d'idée -  :'(


  • CéroceCéroce Membre, Modérateur

    Je trouve ce que tu essaie de faire un peu étrange. Je m'explique: un SVG peut décrire un tas d'objets, avec des attributs très divers, donc il paraà®t relativement logique de le rendre directement, dans une layer ou un CGContext.


     


    Maintenant, effectivement, si tu veux juste rendre une seule figure géométrique, tu peux utiliser PaintCode qui va prendre le SVG et te générer le code Core Graphics correspondant.


  • Ce que je désire, c'est récupéré un tracé illustrator, dans Xcode, sous forme de code (en swift), qui implémente les méthode CGContext, et non pas récupérer un path (ça, j'y parviens), car je ne pourrais pas avoir les coordonnées des points et ne pourrait donc pas les manipuler.


     


    PaintCode, ça fait cher ?


     


    Y'a pas moyen à  partir d'un xml du code svg, de fabriquer du CoreGraphic ?


     


    Qwarkee semble le faire, mais 40$ et objC seulement, apparemment


  • CéroceCéroce Membre, Modérateur

    PaintCode, ça fait cher ?

    Tout dépend si tu t'en sers ou pas. Personnellement, je n'ai pas fait cet investissement. 

    Y'a pas moyen à  partir d'un xml du code svg, de fabriquer du CoreGraphic ?

    Si, bien sûr, tu peux le parser. Le parseur SAX d'Apple est trop limité, utilise un parseur DOM, comme KISSxml. Tant que le SVG ne contient qu'un simple tracé, ça reste très faisable.

    Qwarkee semble le faire, mais 40$ et objC seulement, apparemment

    PaintCode est bien plus complet. ça me semble un meilleur investissement.
  • LeChatNoirLeChatNoir Membre, Modérateur
    mars 2015 modifié #7

    Je commence à  utiliser XMLParser pour parser un flux RSS.


     


    Pourquoi tu dis que c'est limité Céroce ?


    Ca m'a l'air pas trop mal...


     


    Un peu Old School mais ça fonctionne...


     


    Ca vaut pas XMLDocument d'OSX mais c'est déjà  pas mal.

  • XMLParser permet-il de traduire du svg



    <?xml version="1.0" encoding="utf-8"?>
    <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
    width="768px" height="1024px" viewBox="0 0 768 1024" enable-background="new 0 0 768 1024" xml:space="preserve">

    <path fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" d="M176.655,287.241c0.862,90.518,168.103,100.862,165.517,14.655
    S176.655,287.241,176.655,287.241z"/>
    </svg>


    en swift



    let context = UIGraphicsGetCurrentContext()
    CGContextSetLineWidth(context, 2.0)
    CGContextSetStrokeColorWithColor(context, UIColor(red: 255.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0).CGColor)
    CGContextMoveToPoint(context, startCurveX, startCurveY)
    CGContextAddCurveToPoint(context, aCurveP1X, aCurveP1Y, aCurveP2X, aCurveP2Y, aEndCurveX, aEndCurveY)
    CGContextAddCurveToPoint(context, bCurveP1X, bCurveP1Y, bCurveP2X, bCurveP2Y, startCurveX, startCurveY)
    CGContextStrokePath(context)

    ?


     


    Merci


  • zoczoc Membre
    Un parseur XML quel qu'il soit va être capable d'extraire les attributs des éléments XML, mais c'est tout. Dans le cas du SVG, le path est représenté par l'attribut "d" de l'élément "path", soit, dans ton exemple :
     
    M176.655,287.241c0.862,90.518,168.103,100.862,165.517,14.655S176.655,287.241,176.655,287.241z

    Ca, aucun parseur XML ne pourra l'interpréter pour toi. Mais sur NSHipster il y a un excellent article sur NSScanner, avec un exemple tout prêt pour parser ce genre de chaine: http://nshipster.com/nsscanner/
  • AliGatorAliGator Membre, Modérateur
    Oui tu devrais pouvoir bidouiller un truc. ça depend si tu veux savoir lire tous les SVG du monde avec toutes les possibilités que permet SVG ou si tu comptes juste lire tes SVG qui seront toujours exportés par le même outil et auront toujours la même tronche.


    Pour parser les path (<path d="...">) utilise NSScanner. NSHipster a justement écrit un article sur leur blog pour expliquer NSScanner et l'exemple qu'ils prennent... c'est le parsing d'un path SVG justement ! (En Swift qui plus est)
  • Ouaaaah, j'en frémis d'avance.


     


    J'y cours de ce pas. :p   :D   :p   :D   :p


  • CéroceCéroce Membre, Modérateur

    Pourquoi tu dis que c'est limité Céroce ?

    C'est un parseur SAX: ça te dit quand ça rencontre une balise, c'est à  peu près tout.
    (Par ailleurs, il peut même t'appeler la méthode déléguée qui renvoie le contenu plusieurs fois pour la même balise).

    Dès que tu dois gérer une hiérarchie d'objets de plus d'un niveau, ça devient casse-pied. Il faut un parseur DOM.
  • AliGatorAliGator Membre, Modérateur
    NSXMLParser n'est pas tant limité (ce n'est pas qu'il ne couvre pas tout le besoin fonctionnel) mais il est ch*ant à  utiliser car c'est du parsing SAX, donc événementiel. Et dans 99% des cas ce qu'on fait avec un passeur SAX c'est de construire nous-même un arbre DOM au fur et à  mesure qu'on reçoit les évènements et qu'on cumule les textes qu'il rencontre l'intérieur des balises etc... autrement dit on finit par rajouter au parleur SAX une couche DOM.
    Donc du coup autant partir tout de suite vers un parseur DOM c'est moins prise de tête à  utiliser.

    [EDIT] Grillé par Céroce
  • busterTheobusterTheo Membre
    mars 2015 modifié #14

    ça a l'air super, mais j'ai un bug dans le "case "c":", et je ne trouve rien sur offset



    path.addCurveToPoint(path.currentPoint.offset(points[2]), controlPoint1: path.currentPoint.offset(points[0]), controlPoint2: path.currentPoint.offset(points[1]))

    Une idée ?


     


    L'erreur :



     


    'CGPoint' does not have a member named 'offset'


  • LeChatNoirLeChatNoir Membre, Modérateur

    D'ac. Mais y a pas de parser DOM natif... J'imagine qu'il faut chercher une bibliothèque tierce.


     


    Vous en connaissez une bonne pour iOS ?

  • AliGatorAliGator Membre, Modérateur
    mars 2015 modifié #16
    On n'a pas déjà  eu cette discussion, avec comparatif des performances des passeurs XML et tout ?
    (Si c'est pas là  qu'on en a discuté y'a pléthore d'articles sur le net à  ce sujet)
  • LeChatNoirLeChatNoir Membre, Modérateur

    This one look great : https://github.com/graetzer/GDataXML-HTML


     


     


    buster : path.currentPoint est un CGPoint. Et un CGPoint est une simple strucutre avec x et y. Pas d'offset...


  • AliGatorAliGator Membre, Modérateur
    Je pense que Nate Cook a rajouté une extension à  CGPoint dans son code Swift et qu'il a oublié de mettre ce code dans son article.

    A mon avis ce qu'il a fait pour rajouter cette méthode "offset" sur CGPoint doit donner un truc dans le genre (pas testé) :
    extension CGPoint {
    mutating func offset(offset: CGPoint) {
    self.x += offset.x
    self.y += offset.y
    }
    }
  • busterTheobusterTheo Membre
    mars 2015 modifié #19

    Qu'est-ce qu'il a voulu dire alors, par ça ?



    path.currentPoint.offset(points[2]

    dans http://nshipster.com/nsscanner/


     


    dans le chapitre Example: Parsing SVG Path Data

  • Ah ok, Aligator,


    j'ai donc modifié la ligne comme ça



    path.addCurveToPoint(CGPointMake(path.currentPoint.x + points[2].x, path.currentPoint.y + points[2].y), controlPoint1: CGPointMake(path.currentPoint.x + points[0].x, path.currentPoint.y + points[0].y), controlPoint2: CGPointMake(path.currentPoint.x + points[1].x, path.currentPoint.y + points[1].y))

    et ça fonctionne mieux, sauf que je n'ai pas la deuxième moitié de mon rond. Mais je vais creuser, ça se précise.


    Merci à  vous tous... :p


  • En plus, y'a un pb de taille - C'est plus petit.


     


    Voir la copie d'écran ici


     


    La forme noire est le rendu dans Xcode, et le reste est la forme dans illustrator.


     


    Et ou est passé la seconde partie du path ?


     


    Voici le code complet, modifié, à  partir de celui de http://nshipster.com/nsscanner/



    import UIKit

    class ViewController: UIViewController {

    var svgPathData = "M293.655,294.853c0,77.586,165.411,78.147,165.411,0.147 S293.655,217.267,293.655,294.853z"

    let masqueLayer = CAShapeLayer()

    override func viewDidLoad() {
    super.viewDidLoad()

    masqueLayer.path = bezierPathFromData(svgPathData).CGPath
    self.view.layer.addSublayer(masqueLayer)
    }

    func bezierPathFromData(str: String) -> UIBezierPath {
    let scanner = NSScanner(string: str)

    // skip commas and whitespace
    let skipChars = NSMutableCharacterSet(charactersInString: ",")
    skipChars.formUnionWithCharacterSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    scanner.charactersToBeSkipped = skipChars

    // the resulting bezier path
    var path = UIBezierPath()

    // instructions code can be upper- or lower-case
    let instructionSet = NSCharacterSet(charactersInString: "MCSQTAmcsqta")
    var instruction: NSString?

    // scan for an instruction code
    while scanner.scanCharactersFromSet(instructionSet, intoString: &instruction) {

    var x = 0.0, y = 0.0
    var points: [CGPoint] = []

    // scan for pairs of Double, adding them as CGPoints to the points array
    while scanner.scanDouble(&x) && scanner.scanDouble(&y) {
    points.append(CGPoint(x: x, y: y))
    }

    println(points)

    // new point for bezier path
    switch instruction ?? "" {
    case "M":
    path.moveToPoint(points[0])
    case "C":
    path.addCurveToPoint(points[2], controlPoint1: points[0], controlPoint2: points[1])
    case "c":
    path.addCurveToPoint(CGPointMake(path.currentPoint.x + points[2].x, path.currentPoint.y + points[2].y), controlPoint1: CGPointMake(path.currentPoint.x + points[0].x, path.currentPoint.y + points[0].y), controlPoint2: CGPointMake(path.currentPoint.x + points[1].x, path.currentPoint.y + points[1].y))
    default:
    break
    }
    }
    return path
    }
    }
  • AliGatorAliGator Membre, Modérateur
    T'as pas un tag dans le XML de ton SVG exporté par Illustrator qui donne la taille du canvas, ou qui donne un facteur de mise à  l'échelle, à  appliquer à  tout le SVG (et donc à  ton path) ? Qui expliquerait la différence de taille ?
  • J'ai ça



    <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
    width="768px" height="1024px" viewBox="0 0 768 1024" enable-background="new 0 0 768 1024" xml:space="preserve">
    <path fill="#FFFFFF" stroke="#000000" stroke-miterlimit="10" d="M293.655,294.853c0,77.586,165.411,78.147,165.411,0.147
    S293.655,217.267,293.655,294.853z"/>
    </svg>

  • LeChatNoirLeChatNoir Membre, Modérateur

    width="768px" height="1024px"


  • zoczoc Membre
    mars 2015 modifié #25

    Et ou est passé la seconde partie du path ?

    Dans la partie de la chaine qui ne sera pas parsée à  cause de l'espace (caractère invalide) ?

    Mais de toute façon le parseur de Nate est incomplet: Il ne fait rien quand il décode un "S" (smooth curve to d'apres le standard SVG 1.1, cf. http://www.w3.org/TR/SVG11/paths.html), alors que ce caractère apparait dans ta chaine (mais pas dans celle qu'il utilise pour dessiner la moustache).

    Donc son code est une base de départ. A toi de l'enrichir pour couvrir l'ensemble des codes possibles...
  • J'ai trouvé un truc génial.


    Un plugin que l'on met sur illustrator, et qui encode le tracé (le path) en objC (pour swift, ils ont l'air en retard), et en plein d'autres formats intéressant - Notamment en svg, mais faut rajouter les commandes (M, C, c, etc.).


     


    Moi, ça m'a bien aidé.


Connectez-vous ou Inscrivez-vous pour répondre.