IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 Delphi Discussion :

Manipulation laborieuse des pixels d'un bitmap vs les pixels de la form


Sujet :

Delphi

  1. #21
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Oui, mais dans cette ligne (with PRGBQuad(@aPixels[y, x])^ do), pourquoi l'arrobase et l'accent circonflexe ?
    Juste pour compliquer un peu ! PRGBQuad(@aPixels[y, x])^ égale TRGBQuad(aPixels[y, x])

    Mais c'est pas très logique tout cela

    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA (TRGBQuad) et non en RGBA (TColor), les rouge et bleu sont inversés. Le résultat est joli mais faux !
    On se retrouve ainsi avec un tableau de TColor qui est convertit en TRGBQuad (histoire d'inverser rouge et bleu) pour être reconvertit en TColor (SrcBmp.Pixels) qui va au final être implicitement reconvertit en TRGBQuad pour le stockage... Outre la lenteur de travailler pixel par pixel, c'est difficile de faire plus compliqué !

    Donc commencez par normaliser tout cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var
      aPixels: array[0..IMAGE_HEIGHT -1, 0..IMAGE_WIDTH -1] of TRGBQuad;
    Un transtypage au remplissage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    aPixels[y, x] := TRGBQuad((x + y) or ((x - y) shl 8 ) or ((x + x)shl 16));
    //ou
    dword(aPixels[y, x]) := (x + y) or ((x - y) shl 8 ) or ((x + x)shl 16);
    Puis travaillez aussi sur le bitmap en TRGBQuad (ScanLine).
    Pas besoin de boucle si le standard Windows considérant le premier pixel en bas à gauche est appliqué. Une simple copie mémoire suffit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    var
      SrcBmp: TBitmap;
    begin
      SrcBmp := TBitmap.Create;
      try
        SrcBmp.PixelFormat := pf32bit;
        SrcBmp.Width       := IMAGE_WIDTH;
        SrcBmp.Height      := IMAGE_HEIGHT;
     
        CopyMemory(SrcBmp.ScanLine[SrcBmp.Height -1], @aPixels, IMAGE_HEIGHT *IMAGE_WIDTH *SizeOf(TRGBQuad));
     
        img_Result.Picture.Graphic := SrcBmp;
      finally
        SrcBmp.Free;
      end;
    end;
    L'image résultante sera inversée par rapport à SetDIBitsToDevice puisque la hauteur de ce dernier est définie en négative. Donc soit la remettre en positif, soit inverser le remplissage de SrcBmp.
    Toujours une copie mais cette fois-ci ligne par ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    var
      SrcBmp: TBitmap;
      y :integer;
    begin
      SrcBmp := TBitmap.Create;
      try
        SrcBmp.PixelFormat := pf32bit;
        SrcBmp.Width       := IMAGE_WIDTH;
        SrcBmp.Height      := IMAGE_HEIGHT;
     
        for y := 0 to IMAGE_HEIGHT -1 do
          CopyMemory(SrcBmp.ScanLine[y], @aPixels[y], IMAGE_WIDTH *SizeOf(TRGBQuad));
     
        img_Result.Picture.Graphic := SrcBmp;
      finally
        SrcBmp.Free;
      end;
    end;
    Non ?


  2. #22
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Oui, sauf que dans ton code le boulot pour "redescendre" sur le canvas de la fiche cette Array de TColor est fait par SetDIBitsToDevice.
    Je pourrais essayer de lui faire manger de la cible genre TBitmap ou TImage, à cette fonction Windows, mais mon souci, c'est qu'elle n'existe pas dans Lazarus, qu'un forum a suggéré d'utiliser BitBlt, que je n'y arrive pas dans ton code (normal, BitBlt veut un handle to source device context comme source, et pas une array de pixels), alors imagine dans Lazarus, et c'est comme ça que je me retrouve ici à poser mes questions incompréhensibles...
    Désolé...
    SetDIBitsToDevice est déclarée dans l'unité Windows (plus exactement dans func.inc), normal c'est une API Windows.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    function SetDIBitsToDevice(_para1:HDC; _para2:longint; _para3:longint; _para4:DWORD; _para5:DWORD;_para6:longint; _para7:longint; _para8:UINT; _para9:UINT; _para10:pointer;var _para11:BITMAPINFO; _para12:UINT):longint;
      external 'gdi32' name 'SetDIBitsToDevice';
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #23
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Salut à tous,

    alors là, Andnotor, tu m'en bouches un coin ! Quelle analyse ! Et quel résultat ! ! !
    Pour faire court et simple et rapide, une image de 480x480 met moins d'une milliseconde (je n'ai pas modifié le compteur, dont la résolution est la milliseconde), c'est quand même fantastique, par rapport aux 1500 d'hier soir !
    (Ah, tiens, j'ai aussi testé en mode rectangle 640x480 ce matin à la fraîche [hier j'avais peur des AV qui rodent sournoisement, ] : 2 secondes pour l'afficher ))

    Un grand bravo, un grand merci !
    Non mais, quelle équipe sur ce forum, champions du monde !

    Maintenant, mon petit retour :

    Citation Envoyé par Andnotor Voir le message
    Juste pour compliquer un peu ! PRGBQuad(@aPixels[y, x])^ égale TRGBQuad(aPixels[y, x])
    Tu ne compliques rien du tout, au contraire, c'est très bien : tu simplifies l'écriture (dans l'ide), tu simplifies donc sa lecture et sa compréhension. Moi ça me va.

    Citation Envoyé par Andnotor Voir le message
    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA (TRGBQuad) et non en RGBA (TColor), les rouge et bleu sont inversés.
    Indépendamment du fait qu'il n'y a pas un seul mot sur ce "détail" dans msdn (), c'est le "par conséquent" qui me choque : toutes (parce qu'in fine tout est API dans le monde Windows, nan ?) les API's graphiques sont comme ça ? Première fois que j'en entends parler...

    J'aimerais bien une petite précision sur ce point.


    Citation Envoyé par Paul TOTH Voir le message
    SetDIBitsToDevice est déclarée dans l'unité Windows (plus exactement dans func.inc), normal c'est une API Windows.
    Oui, Paul, ch'sais bien, les gens de Lazarus/FreePascal en ont pourtant traduit tout plein, mais pas toutes...

    D'ailleurs, impossible de tester le code de ce matin sous Debian, Lazarus ne connait pas "CopyMemory",
    Va encore falloir retourner le web à la recherche de l'instruction-miracle !

    Bonne journée (va falloir que je bouge) et encore merci pour les lumineuses idées matinales
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  4. #24
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 628
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 628
    Points : 10 553
    Points
    10 553
    Par défaut
    Citation Envoyé par Jipété Voir le message
    J'aimerais bien une petite précision sur ce point.
    Peut-être que je vais répondre à côté de la plaque: mais le BRG est hérité des CPU 16bits et du little/ big endian

    La couche alpha n'existait pas qu'il n'y avait pas de carte graphique.
    Si tu lis la documentation d'Embarcadero, il y a 3 niveaux de transparence: aucune, full (*), partial (**)

    Et donc en 16bits , une couleur sur 24 bits 0x112233 pouvait être soit 0x112233 soit 0x00332211.
    Donc Microsoft avait le choix entre le RGB ou le BGR.

    * -> On prend un point (souvent le coin supérieur gauche ou le point(0, 0)) et tous les points qui ont cette couleur sera remplacé par la couleur du fond

    ** -> c'est la vraie transparence: elle varie de 0 à 255. Ensuite, je ne rappelle jamais c'est dans quel sens si on parle d'opacité ou de transparence
    Mais comme par défaut Delphi travaille en bmp, elle ne sera pas supportée.

    Et même avec les extensions png de Delphi/ Embarcadero, je trouve que ce n'est pas terrible

  5. #25
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Citation Envoyé par foetus Voir le message
    Peut-être que je vais répondre à côté de la plaque
    Tout à fait, oui

    La demande de précision portait sur le fait que
    SetDIBitsToDevice est une API et travaille par conséquent en 32 bits en BGRA
    Moi je ne vois pas le rapport entre le fait que SetDIBitsToDevice soit une API (puisque tout est API chez Ouinouin), et que du coup (= par conséquent) elle travaille en BGRA.

    Je ne vois pas le lien de cause à effet, et surtout je n'ai rien vu en gros en gras en rouge et clignotant dans msdn...

    Et sinon, juste pour toi et concernant ce canal Alpha, Transparent = 0 et Opaque = 255

    Nom : rainbow_transp.jpg
Affichages : 475
Taille : 8,4 Ko

    Dans cet exemple, l'arc-en-ciel a une transparence de 192.
    Valà,
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  6. #26
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    pourquoi l'arrobase et l'accent circonflexe ?
    Juste pour compliquer un peu !
    Je ne faisais que répondre à la question (c'est pas moi qui complique)


    La spécialité n'est pas le TRGBQuad (qui est une donnée brute) mais le TColor Delphi qui sera interprété en fonction du quatrième octet (poids fort).
    Ainsi si on défini par exemple une couleur sur clBtnFace (du gris clair par défaut : la couleur de fond des fenêtres), sa représentation héxa est $FF000005. Rien à voir avec du gris parce que ce n'est pas une couleur mais un index sur une couleur.

    D'autres valeurs sont possible pour l'octet de poids fort : $00, $01 et $02. Voir ici pour plus d'infos.
    Lorsqu'on définit une couleur $00xxxxxx, on sélectionne en fait dans la palette système la couleur la plus approchante. Si la profondeur des couleurs du système est réglée sur 24 bits ou plus, on aura exactement notre couleur.
    Ca n'a plus grand intérêt maintenant mais trouvait tout son sens à l'époque sur des affichages inférieurs à 24 bits.

    La plupart du temps, on utilise mal le TColor (moi y compris) en le considérant à tord comme du RGBA alors qu'il ne l'est pas du tout. Mais le fait que ce soit un dword (un tableau de quatre octets) rendent les opérations transparentes... jusqu'à ce qu'on tente de l'utiliser sur une API Windows

    En bref, TColor est pour Delphi et les encapsulations Delphi des API Windows. Pour des appels directs aux API, ça ne va plus.

  7. #27
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    Citation Envoyé par Jipété Voir le message
    D'ailleurs, impossible de tester le code de ce matin sous Debian, Lazarus ne connait pas "CopyMemory",
    Va encore falloir retourner le web à la recherche de l'instruction-miracle !
    Pas besoin d'aller si loin

  8. #28
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Pas besoin d'aller si loin
    Je l'ai vue il y a une heure, je viens d'y répondre
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  9. #29
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    re,

    alors oui "PRGBQuad(@aPixels[y, x])^" = "TRGBQuad(aPixels[y, x])" mais c'est pas toujours le cas des fois ça ne fonctionne pas "Transtypage incorrect"
    mais en passant par version pointeur ça passe plus facilement.

    Ex:
    si tu veux avoir les composantes RGB de Canvas.Pixels[x, y] et tu fais:
    R := TRGBTriple(SrcBmp.Canvas.Pixels[1, 1]).rgbtRed; <--- Transtypage incorrect

    alors que ceci fonctionne parfaitement:
    R := PRGBTriple(SrcBmp.Canvas.Pixels[1, 1]).rgbtRed;

    En règle générale j'utilise toujours la version pointeur.
    Quand à l'arobase c'est un oubli qui n'avait aucune incidence sur le code ... merci le compilo
    pour le reste ... tout à été expliqué (RGBA -- BGR )
    oui l'accès par la méthode Pixels est la pire au niveau performance mais ce n'était pas la question posé ici !
    j'ai rendu le code fonctionnel en inversant les composantes R et B sans vouloir trop compliquer la chose ... mais c'est l'inverse qui c'est produit

    modif:
    pour l'arobase: le compilo ne dit rien mais il y a bien une violation d'accès si on le met pas !!!

  10. #30
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Oui, Paul, ch'sais bien, les gens de Lazarus/FreePascal en ont pourtant traduit tout plein, mais pas toutes...

    D'ailleurs, impossible de tester le code de ce matin sous Debian, Lazarus ne connait pas "CopyMemory",
    Va encore falloir retourner le web à la recherche de l'instruction-miracle !

    Bonne journée (va falloir que je bouge) et encore merci pour les lumineuses idées matinales
    euh...ben oui tu parles d'API Windows, c'est assez logique que ça n'existe pas sous Linux non ?

    c'est un peu comme l'API XWindow sous Windows...
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  11. #31
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    Citation Envoyé par Cirec Voir le message
    alors que ceci fonctionne parfaitement:
    R := PRGBTriple(SrcBmp.Canvas.Pixels[1, 1]).rgbtRed;
    Ca compile mais ne fonctionne pas !
    Tu considères ici que le contenu de Pixels[1,1] est un pointeur. C'est une VA assurée

    Pour que ça fonctionne (et encore), il faudrait passer par une variable intermédiaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    RGB := SrcBmp.Canvas.Pixels[1, 1];
    R := PRGBTriple(@RGB).rgbtRed;
    Mais à nouveau, c'est le bleu qui sera retourné et non le rouge...

  12. #32
    Membre éprouvé
    Avatar de Cirec
    Profil pro
    Inscrit en
    Octobre 2010
    Messages
    467
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2010
    Messages : 467
    Points : 1 072
    Points
    1 072
    Par défaut
    Ca compile mais ne fonctionne pas !
    Tu considères ici que le contenu de Pixels[1,1] est un pointeur. C'est une VA assurée
    oui je l'avoue l'exemple est très mal choisi ... par-contre pas de VA mais le résultat de l'opération était fausse alors que oui passer par une variable
    compile fonctionne et renvoi la bonne valeur ...
    Mais à nouveau, c'est le bleu qui sera retourné et non le rouge...
    oui c'est vrai ou t'en tiens compte ou tu peux créer un type adapté:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    type
      TBGRQUAD = packed record
        rgbRed: Byte;
        rgbGreen: Byte;
        rgbBlue: Byte;
        rgbReserved: Byte;
      end;
      PBGRQuad = ^TBGRQuad;
    et donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
             aRGB := SrcBmp.Canvas.Pixels[105, 220];
              B := PBGRQuad(@aRGB).rgbBlue;
              G := PBGRQuad(@aRGB).rgbGreen;
              R := PBGRQuad(@aRGB).rgbRed;
              Label1.Caption := Format('R:=%d G:=%d B:=%d', [R,G,B]);
              Label2.Caption := Format('R:=%d G:=%d B:=%d', [GetRValue(aRGB),GetGValue(aRGB),GetBValue(aRGB)]);
    du coup tout est bon

  13. #33
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    Citation Envoyé par Cirec Voir le message
    par-contre pas de VA
    Pur coup de chance mais mets du noir et tu verras ce qu'il dit à la lecture de l'adresse $00000000

  14. #34
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Bonsoir,
    Citation Envoyé par Cirec Voir le message
    re,

    alors oui "PRGBQuad(@aPixels[y, x])^" = "TRGBQuad(aPixels[y, x])" mais c'est pas toujours le cas des fois ça ne fonctionne pas "Transtypage incorrect"
    mais en passant par version pointeur ça passe plus facilement.

    Ex:
    si tu veux avoir les composantes RGB de Canvas.Pixels[x, y] et tu fais:
    R := TRGBTriple(SrcBmp.Canvas.Pixels[1, 1]).rgbtRed; <--- Transtypage incorrect

    alors que ceci fonctionne parfaitement:
    R := PRGBTriple(SrcBmp.Canvas.Pixels[1, 1]).rgbtRed;
    Je vais dire une bêtise à la Jean Yanne ("et si vous empruntez une route département'... - J'emprunte jamais les départementales !"), mais je viens de faire une recherche sur PRGBTriple dans les dossiers où je range le graphisme, et dans les quelques fichiers .pas que j'ai trouvés, la ligne est en commentaire : j'ai dû commencer à tout passer en TRGBQuad.
    Il en reste un peu dans un dossier où traînent des sources de efg, en cours de conversions.

    À ce propos, personne ne m'a répondu au sujet de pf24bit / pf32bit... Alors je pose la question autrement : si je dois créer un bitmap, qu'est-ce que je choisis ? Selon quels critères ?
    J'aurais tendance à dire qu'à notre époque, vu la quantité de mémoire dans les machines, qui peut le plus peut le moins donc en avant pour le 32, mais je préfère lire vos avis d'experts, avant.

    Bonne soirée,
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  15. #35
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    Citation Envoyé par Jipété Voir le message
    À ce propos, personne ne m'a répondu au sujet de pf24bit / pf32bit... Alors je pose la question autrement : si je dois créer un bitmap, qu'est-ce que je choisis ? Selon quels critères ?
    J'aurais tendance à dire qu'à notre époque, vu la quantité de mémoire dans les machines, qui peut le plus peut le moins donc en avant pour le 32, mais je préfère lire vos avis d'experts, avant
    tout dépend du besoin, mais sans contrainte particulière 32 bits c'est mieux car les pixels sont alignés en mémoire et l'accès et plus simple et plus rapide.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  16. #36
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 679
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 679
    Points : 13 082
    Points
    13 082
    Par défaut
    32 bits aussi. Ca laisse également la porte ouverte aux images avec transparence même si au départ on utilise que des fonctions style BitBlt, StrechBlt qui ne la supportent pas (la composante alpha étant simplement ignorée).

    Pour l'anecdote, les lignes sont toujours alignées sur un multiple de quatre octets quelque soit la profondeur des couleurs

  17. #37
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Bonjour à tous,

    hier soir j'avais promis des images (sur l'autre forum), les voici !

    Mais d'abord, besoin d'un poil d'explications, les réjouissances commençant sous w2k avec ce bout de code en D7 et une note de Paul venant du forum Lazarus où nous avons discuté du remplacement de CopyMemory (D7 connaît "Move", mais je n'ai pas dû l'utiliser comme il faut) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     ////////////////////////////////////////////////////////////////////////////////
     //
     // PT : étrangement sous Lazarus c'est ScanLine[0] qui pointe sur le début du
     // bitmap et non ScanLine[H - 1] comme sous Delphi (Bitmap avec la tête en bas)
     //
     ////////////////////////////////////////////////////////////////////////////////
     
    //d7    SrcBmp.BeginUpdate; // inconnu sous D7
    //AV    Move(Pixels, SrcBmp.ScanLine[IMAGE_HEIGHT-1]^, IMAGE_WIDTH*IMAGE_HEIGHT*SizeOf(TRGBQuad));
    //AV    Move(Pixels, SrcBmp.ScanLine[0]^, IMAGE_WIDTH*IMAGE_HEIGHT*SizeOf(TRGBQuad));
    //d7    SrcBmp.EndUpdate(); // inconnu sous D7
     
    //OK
      for y := 0 to IMAGE_HEIGHT -1 do
        CopyMemory(SrcBmp.ScanLine[IMAGE_HEIGHT-1-y], @Pixels[y], IMAGE_WIDTH*SizeOf(TRGBQuad));
    Question à Paul :
    Pourquoi as-tu écrit ce qui précède, que j'ai noté en commentaire ? Car en D7, si j'applique l'inversion comme montré dans le code, l'image est toute à l'envers, la pauvrette :
    Nom : scanlineinversé.jpg
Affichages : 601
Taille : 116,3 Ko

    L'image de gauche est calculée dans FormCreate et dessinée dans FormPaint avec SetDIBitsToDevice, celle de droite est dessinée grâce au bouton qui crée un bitmap temporaire, le remplit avec CopyMemory en utilisant les pixels précédemment créés, et l'assigne à un TImage.
    Il me suffit de repasser en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        for y := 0 to IMAGE_HEIGHT -1 do
          CopyMemory(SrcBmp.ScanLine[y], @Pixels[y], IMAGE_WIDTH*SizeOf(TRGBQuad));
    pour que les deux représentations soient identiques.

    Les plus observateurs noteront au passage que j'ai tout basculé en mode TRGBQuad, pourquoi se gêner, ça permet de profiter d'un magnifique arc-en-ciel et de jouer avec la transparence :
    Nom : gest_transparence.jpg
Affichages : 457
Taille : 30,1 Ko

    Comme vous pouvez le constater, ça fonctionne du feu de Dieu sous Lazarus/Linux !

    Mais à une condition !
    Comme je suis parti de ce site et du code qu'on peut y trouver, plus les explications et les images, on va dire que son arc-en-ciel me sert de référence.
    Hé bien sous Lazarus, il m'a fallu inverser le rouge et le bleu pour que je retrouve le même dégradé que celui du site !

    Je me disais aussi, en regardant ce montage (à gauche D7-w2k, on reconnaît le code de Paul à son "Hello World" [que je ne peux pas faire sous Lazarus, qui ne connaît pas SetDIBitsToDevice], à droite le même code à la virgule près sous Laz-Debian) qu'il y avait quelque chose qui clochait :
    Nom : D7w2k_et_LazDebian.jpg
Affichages : 581
Taille : 65,2 Ko

    Voici donc la correction :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // /!\ INVERSION R<-->B sous Lazarus pour retrouver l'arc-en-ciel /!\
      Pixels^[v, h].rgbBlue  := R; // blue
      Pixels^[v, h].rgbGreen := G; // green
      Pixels^[v, h].rgbRed   := B; // red
      Pixels^[v, h].rgbReserved := 255;   // alpha
    Vu ? Je mets dans rgbBlue le byte du R et dans rgbRed le byte du B et voilà ! Va falloir jouer avec les {$DEFINE} si je veux du code compatible entre les deux plateformes.

    En attendant, merci à tous pour le coup de main !
    Bon, j'ai déjà cliqué sur , je ne peux pas faire plus
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  18. #38
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 628
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 628
    Points : 10 553
    Points
    10 553
    Par défaut
    Rien n'est étrange : Sous Windows tu traînes les boulets de Windows 95/ CPU 16bits - BGR au lieu de RGB, bitmap qui stocke de bas en haut, bitmap qui stocke les lignes multiples de 4, bitmap qui ne gère pas la transparence ni la compression (enfin si mais c'est un truc Microsoft pour t'en décourager)...

    Sinon c'est quoi ton code?
    Comment tu fais ton dégradé et tes 2 carrés à même la fenêtre?
    Tu ne pètent pas les performances? (moi aussi j'ai fait des tests en écrivant directement dans le buffer: 800ms pour colorier en uni un rectangle de 80x600-700 )

  19. #39
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    Citation Envoyé par foetus Voir le message
    Rien n'est étrange : Sous Windows tu traînes les boulets de Windows 95/ CPU 16bits - BGR au lieu de RGB, bitmap qui stocke de bas en haut, bitmap qui stocke les lignes multiples de 4, bitmap qui ne gère pas la transparence ni la compression (enfin si mais c'est un truc Microsoft pour t'en décourager)...
    ce n'est pas tout à fait vrai, tu peux exploiter le canal alpha d'un TBitmap avec AlphaBlend (attention Jipété, c'est une API Windows non disponible sous Linux

    Citation Envoyé par foetus Voir le message
    Sinon c'est quoi ton code?
    Comment tu fais ton dégradé et tes 2 carrés à même la fenêtre?
    Tu ne pètent pas les performances? (moi aussi j'ai fait des tests en écrivant directement dans le buffer: 800ms pour colorier en uni un rectangle de 80x600-700 )
    je pense que Jipété ne regarde pas les choses avec assez de recul:

    TBitmap sous Lazarus et D7 ne sont pas identiques
    1) BeginUpdate/EndUpdate n'existe pas sous Delphi
    2) ScanLine[0] est la ligne du HAUT sous Lazarus, mais c'est la ligne du BAS sous Delphi
    3) ScanLine[1] est APRES la ligne 0 sous Lazarus, mais AVANT la ligne 0 sous Delphi
    4) l'ordre des lignes est inversé sous Delphi (il faudrait vérifier que TBitmap supporte les hauteurs négatives....ça peut résoudre le problème)

    finalement quand on boucle sur chaque ligne, il est possible de redresser le bitmap
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for Index := 0 to H - 1 do
    begin
      Move(Pixels[Index], Bitmap.ScanLine[{$IFDEF DELPHI}H - 1 -{$ENDIF}Index}]^, W * 4); // 4 pour un pf32bit, 3 pour un 24bit...avec un tableau de pixels adapté à cette taille
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  20. #40
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 718
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 718
    Points : 15 098
    Points
    15 098
    Par défaut
    Citation Envoyé par foetus Voir le message
    Sinon c'est quoi ton code?
    Comment tu fais ton dégradé et tes 2 carrés à même la fenêtre?
    Tu ne pètes pas les performances? (moi aussi j'ai fait des tests en écrivant directement dans le buffer: 800ms pour colorier en uni un rectangle de 80x600-700 )
    Bah, le code c'est presque celui de Paul, à peine adapté pour les TRGBQuad (merci à AndnNotor), Quant à la partie droite, qui compte le temps mis à faire le taf, ça vient + ou - de chez efg.
    C'est tout du brouillon, encore, hein, pas bien fini, mais suffisant pour voir comment ça se goupille.

    Attention au nom des objets (fiche, bouton) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    const
      IMAGE_WIDTH  = 640;//480;//256;
      IMAGE_HEIGHT = 480;//256;
     
    type
    //   TPixels = array[0..IMAGE_HEIGHT - 1, 0..IMAGE_WIDTH - 1, 0..3] of Byte;
       TPixels = array[0..IMAGE_HEIGHT-1, 0..IMAGE_WIDTH-1] of TRGBQuad;
       PPixels = ^TPixels;
     
    var
      Pixels: PPixels;
     
    procedure Tfrm_DibTest.FormCreate(Sender: TObject);
    var
      x, y: Integer;
      h, v: Integer;
    begin
      DoubleBuffered := True;
      GetMem(Pixels, IMAGE_WIDTH*IMAGE_HEIGHT*SizeOf(TRGBQuad));
      for x := 0 to IMAGE_WIDTH - 1 do
        for y := 0 to IMAGE_HEIGHT - 1 do
          begin
            Pixels^[y, x].rgbBlue  := x + y;
            Pixels^[y, x].rgbGreen := x - y;
            Pixels^[y, x].rgbRed   := x + x;
            Pixels^[y, x].rgbReserved := 255;
          end;
    end;
     
    procedure Tfrm_DibTest.FormPaint(Sender: TObject);
    var
      BitsInfos: TBitmapInfo;
      Bmp: TBitmap;
    begin
      FillChar(BitsInfos, SizeOf(BitsInfos), 0);
      with BitsInfos do
      begin
        with bmiHeader do
        begin
          biSize          := SizeOf(TBitmapInfoHeader);
          biWidth         := IMAGE_WIDTH;
          biHeight        := -IMAGE_HEIGHT; // inverser le DIB pour avoir la tête en haut
          biPlanes        := 1;
          biBitCount      := 32;
        end;
      end;
      Bmp := TBitmap.Create;
      try
        Bmp.PixelFormat := pf32Bit;
        Bmp.width := IMAGE_WIDTH+10; //+10 pour faire une bordure blanche autour des couleurs
        Bmp.Height:= IMAGE_HEIGHT+10;
        SetDIBitsToDevice(
    //cirec      Canvas.Handle,
          Bmp.Canvas.Handle,
          5, 5, IMAGE_WIDTH, IMAGE_HEIGHT,
          0, 0, 0, IMAGE_HEIGHT,
    //cirec      @aPixels,
          Pixels,
          BitsInfos,
          0
        );
        with Bmp.Canvas do
        begin
          Brush.Style := bsClear;
          Font.Name := 'Arial';
          Font.Size := 12;
          Font.Style := [fsBold];
          TextOut(11, 11, 'Hello World');
          Font.Color := clWhite;
          TextOut(10, 10, 'Hello World');
        end;
        Canvas.Draw(10, 10, Bmp);
      finally
        Bmp.Free;
      end;
    end;
     
    procedure Tfrm_DibTest.btn_GoClick(Sender: TObject);
    var
      x, y: Integer;
      SrcBmp: TBitmap;
      Delta        :  INTEGER;
      LoopCount    :  INTEGER;
      StartTime    :  DWORD; // Use DWORD to keep D3 and D4 happy
    begin
      img_Result.Picture:=nil; 
      frm_DibTest.Caption := '';
      StartTime := GetTickCount;
     
      SrcBmp := TBitmap.Create;
      try
        with SrcBmp do begin
          SrcBmp.PixelFormat:=pf32bit;
          SrcBmp.Width := IMAGE_WIDTH;
          SrcBmp.Height := IMAGE_HEIGHT;
        end;
     
    ////////////////////////////////////////////////////////////////////////////////
    //
    // PT : étrangement sous Lazarus c'est ScanLine[0] qui pointe sur le début du
    // bitmap et non ScanLine[H - 1] comme sous Delphi (Bitmap avec la tête en bas)
    //
    ////////////////////////////////////////////////////////////////////////////////
     
    //d7    SrcBmp.BeginUpdate;
    //AV    Move(Pixels, SrcBmp.ScanLine[IMAGE_HEIGHT-1]^, IMAGE_WIDTH*IMAGE_HEIGHT*(SizeOf(Byte)*4));
    //AV    Move(Pixels, SrcBmp.ScanLine[0]^, IMAGE_WIDTH*IMAGE_HEIGHT*(SizeOf(Byte)*4));
    //d7    SrcBmp.EndUpdate();
     
     
        for y := 0 to IMAGE_HEIGHT-1 do
    //      CopyMemory(SrcBmp.ScanLine[y], @Pixels[y], IMAGE_WIDTH*SizeOf(TRGBQuad));
          CopyMemory(SrcBmp.ScanLine[IMAGE_HEIGHT-1-y], @Pixels[y], IMAGE_WIDTH*SizeOf(TRGBQuad));
     
        img_Result.Picture.Graphic := SrcBmp;
      finally
        SrcBmp.Free;
      end;
     
      Delta := GetTickCount - StartTime; // ms
      frm_DibTest.Caption := IntToStr(Delta) + ' Total ms; ' +
        Format('%.1f', [Delta / LoopCount]) + ' ms/bitmap';
    end;
    Le dégradé, tu parles de l'arc-en-ciel ?
    D'abord tu suis le lien, pour bien comprendre , ensuite tu regardes ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    const // à changer
      IMAGE_WIDTH  = 768;//640;//480;//256;
      IMAGE_HEIGHT = 20;//480;//256;
     
    var // à ajouter
      R, G, B: Byte;
     
    // dégradé :
    // http://blog.vermot.net/2011/11/03/generer-un-degrade-en-arc-en-ciel-en-fonction-d-une-valeur-programmatio/
    //                   interval = longueur de la zone d'affichage
    //                              value = pointeur de boucle
    function MakeRainbow(LongueurAffichage: double; Compteur: double):TColor;
    var
    //  r,g,b: integer;
      x: longint;
    begin 
      x := round((1536 / LongueurAffichage) * Compteur);
      if (x >= 0)    and (x < 256)  then begin r:=255; g:=x; b:=0;end;
      if (x >= 256)  and (x < 512)  then begin r:=511-x; g:=255; b:=0;end;
      if (x >= 512)  and (x < 768)  then begin r:=0; g:=255; b:=x-512;end;
      if (x >= 768)  and (x < 1024) then begin r:=0; g:=1023-x; b:=255;end;
      if (x >= 1024) and (x < 1280) then begin r:=x-1024; g:=0; b:=255;end;
      if (x >= 1280) and (x < 1536) then begin r:=255; g:=0; b:=1535-x;end;
    //  result := RGBToColor(r,g,b);
    end;
     
    //dans FormCreate : mettre ce qui suit à la place de l'autre taf :
    // rainbow OK
       for h := 0 to IMAGE_WIDTH-1 do
       begin
         MakeRainbow(IMAGE_WIDTH, h); // calcule R,G,B
         for v := 0 to IMAGE_HEIGHT-1 do begin // remplissage colonne
           Pixels^[v, h].rgbBlue := B; // blue
           Pixels^[v, h].rgbGreen := G; // green
           Pixels^[v, h].rgbRed := R; // red
           Pixels^[v, h].rgbReserved := 255;   // alpha
         end;
       end;
    Je te laisse le soin d'enlever le "Hello World" dans le OnPaint.

    Ah, un truc curieux : en passant des triangles et losanges colorés à l'arc-en-ciel ou l'inverse, le premier run est très long ! Après ça va vite. Pas d'explication pour le moment...
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 3 PremièrePremière 123 DernièreDernière

Discussions similaires

  1. Réponses: 1
    Dernier message: 31/03/2015, 15h36
  2. bibliothèques pour lire les pixels d'un bitmap
    Par nonozor dans le forum Bibliothèques
    Réponses: 2
    Dernier message: 28/08/2008, 00h15
  3. Lire les pixels de grandes images sans les ouvrir
    Par psicot dans le forum Multimédia
    Réponses: 1
    Dernier message: 16/04/2007, 18h59
  4. Manipuler avec des classes
    Par poussinphp dans le forum FMOD
    Réponses: 3
    Dernier message: 03/06/2006, 18h20
  5. Réponses: 14
    Dernier message: 04/01/2006, 14h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo