Modifier la couleur d'une image vectorielle

bxdieselbxdiesel Membre
13:59 modifié dans API AppKit #1
Bonjour,

J'ai  besoin d'afficher des images que l'utilisateur doit pouvoir zoomer fortement, soit à  l'écran soit pour l'impression.
Pour cela, j'utilise des images vectorielles créées avec Illustrator et exportées en pdf.
Ces images sont chargées dans des NSImage, et effectivement, les images zoomées sont nickel, comme prévu.

Problème : à  partir d'une image de base, je voudrais que l'utilisateur puisse changer la couleur.
Donc, je transforme la NSImage en CIImage et je lui applique un filtre de couleur, par exemple CIColorControls. Mais là , quand je l'affiche dans le contexte CoreImage, l'image est floue si le zoom est important. Je suppose que le CIImage transforme toute image source en image bitmap ??
Ou alors je m'y prends mal.

Merci d'avance pour vos idées pour modifier la couleur de ces images vectorielles.

Réponses

  • CéroceCéroce Membre, Modérateur
    13:59 modifié #2
    Core Image ne fonctionne qu'avec des images bitmaps.

    Je vois deux manières de procéder:
    - parcourir le PDF (voir Quartz 2D Programming Guide / PDF Document parsing) et changer la couleur des objets graphiques. Comme le PDF est un format complexe, tu as peut être intérêt à  convertir les images Illustrator en SVG, mais il faudra recoder le dessin, ce qui est aussi pas mal de travail. Il existe des parsers SVG open-source.
    - rendre le PDF dans un contexte bitmap de grande taille (par exemple, avec une résolution de 1200 dpi) et appliquer le filtre Core Image.
  • bxdieselbxdiesel Membre
    13:59 modifié #3
    Merci pour ces pistes.
    Je vais les étudier et notamment voir les performances car j'ai un grand nombre d'images à  afficher et à  zoomer simultanément (plusieurs centaines, voire milliers).
  • CéroceCéroce Membre, Modérateur
    13:59 modifié #4
    Ah mais, il fallait le dire tout de suite !

    Pour avoir ce genre de performances, tu ne peux pas utiliser Core Graphics. Il n'est pas fait pour ça ! Au mieux tu peux tenter ta chance avec OpenGL, mais si les images sont complexes, ça va quand même être dur dur pour la carte graphique.
  • bxdieselbxdiesel Membre
    13:59 modifié #5
    dans 1286530421:

    Ah mais, il fallait le dire tout de suite !

    C'est vrai, j'ai décrit le problème mais pas précisé le besoin.

    En fait, ce que j'ai à  faire ressemble au fonctionnement de Pages.
    L'utilisateur peut créer des objets (cf. zone de texte dans Pages) auxquels il peut appliquer une mise en forme, une couleur de fond, une bordure.
    Ces objets sont sélectionnables, redimensionnables, déplaçables donc je suis parti d'une sous-classe de NSView, vu que ça hérite de NSResponder.

    Dans la capture d'écran ci-jointe, on voit les bordures dessinées par Pages. C'est pour celles-ci que je pensais utiliser des images vectorielles et changer leur couleur à  la demande.
    Mais peut-être est-il plus simple d'utiliser des png avec une bonne résolution. Et utiliser les CIFilter.
    De plus, d'après les essais que je viens de faire, les temps de redimensionnement des images vectorielles sont très longs si le tracé est complexe, ce qui est le cas dans les motifs graphiques utilisés par Pages pour certaines bordures.
    Ou alors récupérer le NSBezierPath depuis le pdf...
  • CéroceCéroce Membre, Modérateur
    13:59 modifié #6
    OK, je comprends mieux ton besoin.
    Tu peux ignorer ma réponse précédente, je pensais que tu voulais faire des animations avec des zooms et des rotations.

    J'ai déjà  programmé ce genre de choses, et je peux te faire part de mon expérience.

    dans 1286535881:

    Ces objets sont sélectionnables, redimensionnables, déplaçables donc je suis parti d'une sous-classe de NSView, vu que ça hérite de NSResponder.

    Ces objets, appelons-les des figures, doivent répondre aux clics, voire à  la frappe, donc avoir une vue par figure paraà®t relativement logique.
    Cependant, pour des raisons de performances, Apple déconseille de créer une NSView par objet graphique. Il faut donc n'avoir qu'une NSView qui dessine toute la page. La vue va devoir retransmettre tous les événements aux figures.

    dans 1286535881:

    Dans la capture d'écran ci-jointe, on voit les bordures dessinées par Pages. C'est pour celles-ci que je pensais utiliser des images vectorielles et changer leur couleur à  la demande.
    Mais peut-être est-il plus simple d'utiliser des png avec une bonne résolution. Et utiliser les CIFilter.

    C'est certainement plus simple, mais ça va créer de gros problèmes à  l'impression: le rendu sera forcément mauvais.

    dans 1286535881:

    De plus, d'après les essais que je viens de faire, les temps de redimensionnement des images vectorielles sont très longs si le tracé est complexe, ce qui est le cas dans les motifs graphiques utilisés par Pages pour certaines bordures.


    Il faut décoreler deux aspects:

    - l'impression
    Pour avoir un résultat nickel, il faut soit travailler en vectoriel, soit utiliser des bitmaps de très grandes dimensions. La deuxième option va consommer énormément de mémoire et donc rendre le programme très lent.

    - l'affichage à  l'écran
    Quand on agrandit ou fait tourner la figure à  la souris, il faut que ça aille vite, mais la résolution est celle de l'écran. On peut tout à  fait imaginer un système de cache qui contient l'image vectorielle rendue dans une bitmap basse résolution. Je te conseille de jeter un oe“il aux CGLayers, qui permettent de placer des bitmaps dans la mémoire vidéo, et qui sont donc très rapides.


    dans 1286535881:

    Ou alors récupérer le NSBezierPath depuis le pdf...

    C'est un gros travail, mais c'est probablement la bonne solution si tu veux pouvoir donner la couleur que tu veux à  la forme vectorielle.

    Considère le SVG... s'il ne contient que des courbes de Bézier, son parsing restera relativement facile. Voici un exemple avec une seule courbe:
    <br />&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br />&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; clip-rule=&quot;evenodd&quot; stroke-miterlimit=&quot;10&quot; viewBox=&quot;103.00 123.44 355.07 287.44&quot;&gt;<br />&nbsp; &nbsp; &lt;defs/&gt;<br />&nbsp; &nbsp; &lt;path d=&quot;M 103.50 125.50 C 222.50 116.50 282.50 146.50 293.50 213.50 C 304.50 280.50 116.50 278.50 202.50 336.50 C 288.50 394.50 479.50 452.50 455.50 367.50 C 431.50 282.50 379.50 188.50 441.50 219.50 &quot; stroke=&quot;#000000&quot; stroke-width=&quot;1.00&quot; fill=&quot;none&quot;/&gt;<br />&lt;/svg&gt;<br />
    



    Pendant que j'y suis: pour le dessin complexe, oublie Cocoa. NSBezierPath, NSImage, NSColor et compagnie répondent aux besoins de la majorité des applis, mais ils sont limités, et on ne sait pas trop comment ils travaillent, d'où des surprises permanentes. J'avais fini par créer mes propres warpers ObjC pour chaque objet Core Graphics. Core Graphics est bien documentée et les API sont bien fichues.
  • bxdieselbxdiesel Membre
    13:59 modifié #7
    Merci encore pour toutes ces pistes. ça m'éclaircit les idées sur la question.
    ça me promet encore de longues heures pour maitriser tout ça mais bon, quand on aime, on compte pas  :D

    dans 1286541738:

    Cependant, pour des raisons de performances, Apple déconseille de créer une NSView par objet graphique. Il faut donc n'avoir qu'une NSView qui dessine toute la page. La vue va devoir retransmettre tous les événements aux figures.

    J'avais lu ça aussi mais je suis tombé sur la méthode scaleUnitSquareToSize: de NSView qui permet d'avoir un grand nombre de subviews avec de bonnes performances. J'ai fait des essais et avec des dessins pas trop élaborés (une bordure, un gradient, du texte et une petite photo par figure) : même avec 2000 figures dans la vue principale, le scrollWheel reste fluide. En plus pour le dessin, il n'y a pas à  gérer le zoom vu que la frame des subviews ne change pas.
    De plus je m'étais dit que si j'avais besoin d'animer les figures, ça serait facile avec une NSView et CoreAnimation.
    Mais bon, si ça rame avec des figures plus complexes, je prendrai ta solution.
  • CéroceCéroce Membre, Modérateur
    13:59 modifié #8
    dans 1286556489:

    J'avais lu ça aussi mais je suis tombé sur la méthode scaleUnitSquareToSize: de NSView qui permet d'avoir un grand nombre de subviews avec de bonnes performances.

    Là , je ne vois pas trop le rapport ???
    Cette méthode modifie la matrice de transformation courante, c'est idéal pour changer le niveau de zoom, mais je ne vois pas comment ça influe sur les performances.

    Essaie d'afficher des bitmaps de grande taille (par ex. 1000 x 1000 pixels), tu vas te rendre compte de la lenteur.
    Par ailleurs, tu n'as pas besoin de Core Animation: les CALayers utilisent des CGLayers.
  • bxdieselbxdiesel Membre
    13:59 modifié #9
    Bon, j'ai fait le parser pour transformer le svg en chemin de Bézier. C'est génial, merci encore pour l'idée. Ce n'était effectivement pas un gros boulot vu que je ne récupère que les formes.

    dans 1286779970:

    Par ailleurs, tu n'as pas besoin de Core Animation: les CALayers utilisent des CGLayers.

    Je n'ai pas encore utilisé ces classes donc je me penche là -dessus dès que j'ai un moment.
Connectez-vous ou Inscrivez-vous pour répondre.