"Rasteriser" une image vectorielle

AntilogAntilog Membre
06:01 modifié dans API AppKit #1
Bonjour à  tous,

Je reviens avec une question sur les images, mon casse-tête favori.

Le besoin est celui-ci :
A partir de n'importe quel type d'image lisible directement par NSImage, je voudrais créer un fichier texte décrivant en hexadécimal chaque pixel de l'image, en RVB 256 nuances par composant : donc un pixel sera décrit entre 000000 et FFFFFF.

Voilà  ci-dessous ce que j'ai écrit, et qui fonctionne dans certains cas, avec mes commentaires pour l'occasion
C'est normal que j'ai tout mis dans l'awakeFromNib, car c'est juste pour l'instant un test sur le moteur lui-même, l'interface n'existe pas encore! ! !

- (void)awakeFromNib <br />{ <br />&nbsp; &nbsp; &nbsp; &nbsp; inputImage = [NSImage imageNamed:@&quot;TOTO&quot;]; <br />&nbsp; &nbsp; &nbsp;  // lockFocus/unlockFocus pour génèrer le NSCachedImageRep , probablement pas utile ici<br />&nbsp; &nbsp; &nbsp; &nbsp; [inputImage lockFocus]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [inputImage unlockFocus]; <br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; NSSize sz = [inputImage size]; <br />&nbsp; &nbsp; &nbsp; &nbsp; int w = (int)sz.width; <br />&nbsp; &nbsp; &nbsp; &nbsp; int h = (int)sz.height; <br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; // Création d'une représentation avec les param. qu'il me faut : <br />&nbsp; &nbsp; &nbsp; &nbsp; // même taille que l'image d'origine, 8 bits par composant <br />&nbsp; &nbsp; &nbsp; &nbsp; NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; initWithBitmapDataPlanes: NULL <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pixelsWide: w <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pixelsHigh: h <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  bitsPerSample: 8 <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  samplesPerPixel: 4 <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasAlpha: YES <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isPlanar: NO <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; colorSpaceName: NSCalibratedRGBColorSpace <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  bytesPerRow: 0 <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bitsPerPixel: 32]; <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; // Copie de l'image d'origine dans ma nouvelle représentation, <br />&nbsp; &nbsp; &nbsp; &nbsp; // Afin qu'elle s'adapte : augmentation du nombre de couleurs ou au <br />&nbsp; &nbsp; &nbsp; &nbsp; // contraire, perte de couleurs, passage en RVBA, rasterisation si besoin <br />&nbsp; &nbsp; &nbsp; &nbsp; // Il faut que l&#39;imageRep ait une couche alpha, sinon ça ne fonctionne pas!!?? <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; NSGraphicsContext* gc = [NSGraphicsContext graphicsContextWithBitmapImageRep:imageRep]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [NSGraphicsContext saveGraphicsState]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [NSGraphicsContext setCurrentContext:gc]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [[NSColor whiteColor] set]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [[NSBezierPath bezierPathWithRect:NSMakeRect(0.0, 0.0, w, h)] fill]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [inputImage drawAtPoint:NSZeroPoint fromRect:NSMakeRect(0.0, 0.0,w,h) operation:NSCompositeCopy fraction:1.0f]; <br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; [NSGraphicsContext restoreGraphicsState]; <br />&nbsp; &nbsp; &nbsp; &nbsp; outputImage = [[NSImage alloc] initWithSize:sz]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [outputImage addRepresentation:imageRep]; <br />&nbsp; &nbsp; &nbsp; &nbsp; [imgWell setImage:outputImage]; <br /><br />&nbsp; &nbsp; &nbsp; &nbsp; //Création de la chaà®ne de caractères définissant les pixels en hexa <br />&nbsp; &nbsp; &nbsp; &nbsp; NSBitmapImageRep* btmpImageRep = [NSBitmapImageRep imageRepWithData:[outputImage TIFFRepresentation]]; <br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; unsigned char * data = [btmpImageRep bitmapData]; <br />&nbsp; &nbsp; &nbsp; &nbsp; int bpp = [btmpImageRep bitsPerPixel]/8; <br />&nbsp; &nbsp; &nbsp; &nbsp; int bpr = [btmpImageRep bytesPerRow]; <br />&nbsp; &nbsp; &nbsp; &nbsp; NSMutableString* hex = [[NSMutableString alloc] initWithCapacity:w*h*3+h*2]; <br />&nbsp; &nbsp; &nbsp; &nbsp; unsigned char* p; <br />&nbsp; &nbsp; &nbsp; &nbsp; int x,y; <br />&nbsp; &nbsp; &nbsp; &nbsp; for (y=0 ; y&lt;h ; y++) <br />&nbsp; &nbsp; &nbsp; &nbsp; { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p = data + y * bpr; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (x=0 ; x&lt;w ; x++) <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; { <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [hex appendFormat:@&quot;%02X%02X%02X&quot;,*p, *(p+1), *(p+2)]; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; p+= bpp; <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [hex appendString:@&quot;&#092;r&#092;n&quot;]; <br />&nbsp; &nbsp; &nbsp; &nbsp; } <br />&nbsp; &nbsp; &nbsp; &nbsp; [hex writeToFile:@&quot;test.txt&quot; atomically:YES encoding:NSWindowsCP1250StringEncoding error:NULL]; <br /><br />}


Alors, ça fonctionne... dans certains cas.
Pour une image GIF 256 couleurs , c'est impeccable, ça transcrit les couleurs indexées en valeurs RVB.
Pour une image TIFF 65535 couleurs, c'est également OK
Pour une image PDF, par contre, ça bloque, il semble que malgré tous mes efforts pour rasteriser le dessin, il n'en fasse qu'à  sa tête. Par contre, un pdf constitué simplement d'une image bitmap fonctionne. Quelqu'un a une explication ? Ou une méthode pour arriver à  mes fins ?

Merci d'avance

Réponses

  • 06:01 modifié #2
    Est-ce que tu prends le temps de convertir le PDF vers un autre format avant ?
  • AliGatorAliGator Membre, Modérateur
    06:01 modifié #3
    La seule idée/différence que je vois sur le coup c'est que le PDF, comme le PostScript, décrit les images comme des données vectorielles, et non pas sous forme bitmap.
    Bon j'ai pas décortiqué ton code, et pourtant du peu que j'ai lu tu sembles essayer de rasteriser ton image dans un NSBitmapImageRep donc ça devrait effectuer la pixellisation, mais bon, doit y avoir un truc qui traà®ne.
  • AntilogAntilog Membre
    06:01 modifié #4
    Oui, c'est bien l'idée, la recopie dans le GraphicContext obtenu avec la bitmapImageRep était destiné à  "normaliser" l'image: transformer n'importe quel type d'image en bitmap avec 256*256*256 couleurs!

    Ce qui est le plus étonnant, c'est que l'image obtenue (outputImage) s'affiche bien dans une imageWell, mais la transformation en texte n'est pas correcte (en particulier le blanc est noir, et le reste est ... bizarre)
  • schlumschlum Membre
    06:01 modifié #5
    Pourquoi ne pas utiliser directement "TIFFRepresentation" de NSImage ??  ???
    Sinon, il manque plusieurs "release" dans ce code.
  • AntilogAntilog Membre
    06:01 modifié #6
    dans 1238797664:

    Pourquoi ne pas utiliser directement "TIFFRepresentation" de NSImage ??  ???
    Sinon, il manque plusieurs "release" dans ce code.


    1. Parce que je ne pense pas que je pourrais être maà®tre de la profondeur des couleurs
    2. Ca ne m'étonne pas vraiment, je ne release rien du tout  >:)
    Ce n'est pas grave, dans l'état actuel du "programme", il ne fait que ça: ouvrir une image de son bundle, la convertir, l'afficher et écrire le fichier  ::)
  • schlumschlum Membre
    06:01 modifié #7
    Autre question... Pourquoi ne pas lire directement le "bitmapData" du NSImageRep dans lequel tu dessines au lieu de passer par une nouvelle image, ajouter la représentation puis demander le TIFFRepresentation de l'image...
  • AntilogAntilog Membre
    06:01 modifié #8
    dans 1238800734:

    Autre question... Pourquoi ne pas lire directement le "bitmapData" du NSImageRep dans lequel tu dessines au lieu de passer par une nouvelle image, ajouter la représentation puis demander le TIFFRepresentation de l'image...


    Heu... Oui, j'aurais dû le faire directement, j'avais créé l'image afin d'afficher le résultat, mais je n'étais pas obligé de repartir de l'image... Merci

    Par contre, j'ai testé entre temps, et un pdf créé à  partir de Pages fonctionne "presque" correctement (presque car le dernier pixel de chaque ligne est à  515151).
    Il semble donc que le pdf que j'utilise depuis le début est particulier (ce ne serait pas étonnant, il vient d'un PC). Je vais étudier de plus près ce qu'il a de spécial...
  • CéroceCéroce Membre, Modérateur
    06:01 modifié #9
    Et méfie-toi de la méthode -[NSImage size], elle ne renvoie pas les dimensions en pixels de l'image.

    En fait, ça ne marche que si l'image est en 72 ppp.
    Par contre, si ton image est en 300 ppp, il faudra multiplier les dimensions par 300/72. C'est le bordel, et c'est lié au fait qu'une NSImage peut contenir plusieurs représentations. Tu peux obtenir les vraies dimensions avec -[NSImageRep pixelsHigh] et pixelsWide.

    Je te laisse réfléchir aux conséquences quand NSImage est issue d'un PDF, qui par définition, n'a pas de dimensions en pixels.
  • schlumschlum Membre
    06:01 modifié #10
    dans 1239086633:

    Je te laisse réfléchir aux conséquences quand NSImage est issue d'un PDF, qui par définition, n'a pas de dimensions en pixels.


    Il y a forcément une dimension par défaut indicative, sinon les logiciels qui l'ouvriraient ne sauraient plus où donner de la tête pour l'afficher  ;)
  • AntilogAntilog Membre
    06:01 modifié #11
    dans 1239086633:

    Et méfie-toi de la méthode -[NSImage size], elle ne renvoie pas les dimensions en pixels de l'image.

    En fait, ça ne marche que si l'image est en 72 ppp.
    Par contre, si ton image est en 300 ppp, il faudra multiplier les dimensions par 300/72. C'est le bordel, et c'est lié au fait qu'une NSImage peut contenir plusieurs représentations. Tu peux obtenir les vraies dimensions avec -[NSImageRep pixelsHigh] et pixelsWide.

    Je te laisse réfléchir aux conséquences quand NSImage est issue d'un PDF, qui par définition, n'a pas de dimensions en pixels.


    Comme le dit schlum, il y a forcément une dimension en pixels, même si elle est indicative. Elle doit correspondre à  la dimension de la page (décrite dans le pdf en unités, avec une unité par défaut modifiable à  1/72 pouce).
    Pour le fait de récupérer la dimension de l'image, ça ne me pose pas de problème particulier: comme c'est un pdf, je pourrais de toutes façons modifier la taille comme je veux, si besoin était.
    En plus, si je pars de l'imageRep, il faudrait que je boucle sur toutes les éventuelles imageRep pour prendre une décision!
  • AntilogAntilog Membre
    avril 2009 modifié #12

    Il semble donc que le pdf que j'utilise depuis le début est particulier (ce ne serait pas étonnant, il vient d'un PC). Je vais étudier de plus près ce qu'il a de spécial...


    J'y reviens...
    En fait, le pdf est particulier car le fond de page est transparent, et pas blanc comme le montrent Aperçu et Adobe Reader...  >:D

    Mais j'avais copié mon image sur un rectangle que j'avais exprès rempli de blanc, parce que j'avais pensé au cas où il y aurait de la transparence dans l'image...
    Pourquoi ça ne marche pas???  :crackboom:-
  • schlumschlum Membre
    06:01 modifié #13
    NSCompositeCopy
    Source image. (R = S)

    NSCompositeSourceOver
    Source image wherever source image is opaque, and destination image elsewhere. (R = S + D*(1 - Sa))

  • AntilogAntilog Membre
    06:01 modifié #14
    dans 1239955679:

    NSCompositeCopy
    Source image. (R = S)

    NSCompositeSourceOver
    Source image wherever source image is opaque, and destination image elsewhere. (R = S + D*(1 - Sa))



    Oups!!!

    :o :o
    Désolé
Connectez-vous ou Inscrivez-vous pour répondre.