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

Lazarus Pascal Discussion :

Travailler avec TBitmap et des fichiers bmp sous Linux [Lazarus]


Sujet :

Lazarus Pascal

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut Travailler avec TBitmap et des fichiers bmp sous Linux
    Bonjour,

    avant que je ne jette définitivement l'éponge, je viens voir si quelqu'un aurait une idée.

    Le contexte : un vieux couple Lazarus/FreePascal (mais comme le graphisme n'a pas été mis à jour, ce n'est pas un problème) tournant dans une machine Debian 32 bits, et des fichiers bitmap à 32 bits par pixel.

    Comme on le voit sur l'image ci-dessous, les fichiers sont bien ouverts avec The Gimp (ligne du haut) et l'outil en Lazarus (en bas) doit lui aussi les ouvrir, les afficher (à gauche), les dupliquer et afficher la copie (à droite).
    Nom : rendus_gimp_laz.jpg
Affichages : 903
Taille : 44,6 Ko

    On voit tout de suite que si pour l'un ça se passe bien, pour l'autre ce n'est pas du tout ça.
    Le problème n° 1, c'est que je ne vois aucune différence dans les headers des fichiers ; bien sûr les tailles sont différentes, mais la chose qui aurait pu générer ce résultat catastrophique est la même pour les deux fichiers, je veux parler du "20" à l'adresse 1C, qui veut dire 32 bits.

    Je confirme cette valeur avec un peu de calcul sur les dimensions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    //600x400x32 :    600x400 = 2400000
    //                et l'adresse 22 23 24 25 (biSizeImage) contient 00 A6 0E 00 soit 000EA600 soit 960000 soit 240000x4 donc pf32
    // 32bitkc :      250x250 = 62500
    //                et l'adresse 22 23 24 25 (biSizeImage) contient 90 D0 03 00 soit 0003D090 soit 250000 soit 62500 x4 donc pf32
    Alors, qu'est-ce que c'est qui met sa pagaille pour que je récupère cette collection de raies ? Voilà le début des headers, à partir de la ligne 30 c'est le début des datas, on s'en fiche.

    Nom : compar_hexa_xbr-32kc.jpg
Affichages : 836
Taille : 96,3 Ko

    Les plus observateurs remarqueront que le fichier du bas a des valeurs aux adresses 26-2D, ça concerne les informations de définition de l'image (improprement appelée "résolution", pas d'incidence normalement.

    Le problème n° 2 c'est qu'avec plein d'autres fichiers en 32 bits, ça se passe comme ça :

    Nom : 196x128x32.png
Affichages : 843
Taille : 3,4 Ko

    et pour avoir une image correcte à droite, il me faut basculer le code de copie en mode 24 bits (), genre
    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
    // pbD et pbS sont des pointeurs de bytes pour se balader 
    // en mode scanline dans la RawImage des TBitmap Source et Destination
    idx := 0;
    for w := 0 to (src.Width * 3)-1 do begin // byte par byte de g. à dte
      pbD^[idx] := pbS^[w];
      if ( (w+1) mod 3 = 0 ) then begin // w+1 pointe le 3e byte de la source
        // 1- inverser R et B dans la destination qu'on vient de traiter
        tempByte    := pbD^[idx-2];
        pbD^[idx-2] := pbD^[idx-0];
        pbD^[idx-0] := tempByte;
        // 2- ajouter le canal alpha puisqu'il le FAUT sous Linux SI la longueur est PAIRE
        // OU inférieure à 32, go figure !
        if src.Width < 32 then begin
          inc(idx);
          pbD^[idx] := 255;
        end else // longueur => 32, il faut tester si paire ou impaire
        if not Odd(src.Width) then begin 
          inc(idx);
          pbD^[idx] := 255;
        end;                      
      end;
      inc(idx);
    end;
    Une idée de comment solutionner ces pagailles et avoir un code maintenable (parce que là...) ?

    Merci,

    PS : j'ai testé avec TLazIntfImage, c'est un milliard de fois plus compliqué...

  2. #2
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bonjour,

    comme je sais que vous aimez les jolies images, en voilà une magnifique, assortie d'une interrogation énorme :
    (j'ai changé une couleur par rapport à celle d'hier, car noir sur noir c'était compliqué)

    Nom : copie_192x128x24+code.png
Affichages : 802
Taille : 25,8 Ko

    Tout le monde aura compris que le bout de code à droite est celui qui est utilisé pour générer la copie.
    pf24_S et _D sont des booléens déterminant le PixelFormat, le reste se devine sans souci.
    Bien.
    Le fichier est un bête 192x128 de 24 bits par pixel généré avec The Gimp.

    Et dans la copie, la zone noire fait 48 pixels de large ; d'où sort cette valeur ?
    Question subsidiaire : comment savoir s'il s'agit d'un pb de lecture de la source ou d'écriture de la destination ?

    Bon, ce 48 c'est quand même 192 / 4
    Ce "4" me mettant la puce à l'oreille, je fais un test rapide en remplaçant la ligne de balayage des bytes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      for w := 0 to (src.Width*3)-1 do begin // px à px de g. à dte sans padding
    par la même en plus long :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
      for w := 0 to (src.Width*4)-1 do begin // px à px de g. à dte sans padding
    ce qui, pour moi, n'a aucun sens quand on examine les valeurs dans le fichier source avec un éditeur hexa et qu'on voudrait faire une recopie à l'identique, mais en tout cas, il n'y a plus de zone noire à droite.

    Le plus fou, c'est que les fichiers générés en fin de copie sont strictement les mêmes : mêmes tailles sur le disque, mêmes contenus à l'éditeur hexa, sauf les bouts de ligne noirs, bien sûr.
    Quand je dis que ce sont les mêmes, je pense surtout en termes de taille et autre pixelformat, toutes choses censées impacter le type et le contenu des lignes.
    Les miniatures générées par Linux sur le Bureau :

    Nom : fic_good_et_bad.png
Affichages : 737
Taille : 33,9 Ko

    À y perdre son latin et y manger son chapeau...

    Bon week-end,

  3. #3
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Bonjour Jipété,

    Tu fournis des images, mais je crois que des fichiers à analyser par nous-mêmes seraient plus intéressants pour l'expérimentation ( et le CODE surtout !!!).

    Pour ce qui est du format bmp (que j'ai abandonné parce qu'il n'offre pas de canal alpha), il me semble que ton problème vient de tes images en 32 bits. Si tu regardes bien les spécifications de bmp, ce format est "factice" en ce sens qu'au maximum 24 bits sont gérés : un octet par couleur plus un indéterminé. Quand tu proposes une image bmp en 32 bits, tu devrais enlever pour chaque groupe de 3 octets l'octet de remplissage (voilà pourquoi quand tu passes par le format 24 bits, tout revient dans l'ordre).

    Ce qui est vrai, c'est que certains logiciels utilisent ce quatrième octet (en fait, le premier XRBG) pour gérer le canal alpha.

    Pour plus d'infos, voir le format bmp.

    Comme je fais ça loin de ma documentation (donc de mémoire), ces infos sont à vérifier !

    Excellent week-end,

    Gilles
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  4. #4
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Merci pour ta réponse, Gilles,

    2 choses :
    1- tu es trop windowsien, je t'assure que le bmp peut être utilisé avec 32 bits par pixel, d'ailleurs l'info est même dispo chez Microsoft (faut chercher biBitCount 32 dans les Members, 1re rubrique après Syntax)
    Chacun ensuite en fait ce qu'il veut, d'ailleurs l'option est bien présente dans The Gimp (j'avais donné en son temps une copie d'écran de la boîte de dialogue), mais ne nous dispersons pas.

    2- j'ai donc créé viteuf un microscopique projet de test sans aucune correction, qui se vautre lamentablement : projettest.zip
    Sous Linux.

    Nom : demotest.png
Affichages : 774
Taille : 61,3 Ko

    Parce que la maison ne reculant devant aucun sacrifice, j'ai démarré une machine virtuelle XP équipée d'un Laz 1.8.2 et, sans rien changer au code, les 2 fichiers présents dans l'archive s'affichent parfaitement.

    Comment veux-tu ne pas être découragé devant tant d'adversité ?
    EDIT :
    Je ne mets pas l'image des 6 carrés qui deviennent des rectangles pleins de rayures, vous la retrouverez dans mes posts.
    Bah :
    Nom : avec192x128x24.png
Affichages : 804
Taille : 7,8 Ko

    Un dernier mot à propos du projet : l'image jaune n'étant qu'une ligne de 7 pixels, c'est assez petit pour ne rien voir à l'écran, j'ai donc configuré Stretch := True pour les 2 TImage directement dans l'EDI, et le problème est présent dans les deux cas, donc là on le voit mieux.

    Enjoy,

  5. #5
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Salut Jipété,

    Merci pour les fichiers !

    1- tu es trop windowsien, je t'assure que le bmp peut être utilisé avec 32 bits par pixel, d'ailleurs l'info est même dispo chez Microsoft (faut chercher biBitCount 32 dans les Members, 1re rubrique après Syntax)
    Sans doute, mais il y a de quoi dans ce cas précis : bmp est quand même un format de Windows . Pour l'utilisation en 32 bits, je n'ai pas dit qu'elle n'existait pas, j'ai (sans doute maladroitement) dit qu'elle était factice avec son octet vide inutilisé.

    J'ai testé ton code sous Mint et le résultat est le même que celui que tu décris. Pour simplifier les problèmes, j'ai d'abord utilisé la méthode de copie toute simple avec Assign et j'obtiens bien la bonne copie (encore heureux !).
    Pour simplifier encore, je ne vais pas utiliser le composant TImage, car il n'est pas et ne peut pas être équivalent entre Windows et Linux pour des raisons internes aux OS (une question d'accès au canevas, je crois me souvenir, mais quelqu'un pourrait préciser sans doute - je vais essayer de retrouver la référence). Je vais plutôt m'appuyer sur un canevas d'une PaintBox, par exemple => je te tiens au courant.

    Gilles

    [EDIT] As-tu aussi pensé à tes travaux précédents avec l'ordre des octets ? Je te renvoie à une discussion que tu avais menée en... 2016 : https://www.developpez.net/forums/d1...ws-sous-linux/
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  6. #6
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    Dis, tu ne crois pas que le problème rencontré est similaire à celui traité dans cette discussion ? Mêmes symptômes...

    https://www.developpez.net/forums/d1...l-enfer-terre/

    D'autre part, je pense que tu n'utilises pas TRawImage correctement, car tu supposes à tort que Windows et Linux gèrent de la même manière le bitmap. Regarde ici pour la description de TRawImageDescription.

    Personnellement, je préfère utiliser des bibliothèques comme BGRABitmap qui fonctionnent de manière moderne et efficace : plus rapides, plus polyvalentes (avec canal alpha et anticrénelage) et véritablement multiplateformes. Les outils standards de Lazarus le sont aussi tant qu'on essaye pas de sortir des techniques courantes.
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  7. #7
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bonsoir Gilles (et les autres lecteurs),

    Citation Envoyé par gvasseur58 Voir le message
    Dis, tu ne crois pas que le problème rencontré est similaire à celui traité dans cette discussion ? Mêmes symptômes...
    Moui, c'est possible, pour tout te dire, j'avoue que je ne me souviens plus de quoi j'ai causé il y a deux ans (ou six mois !), pour la bonne et simple raison que lorsque j'ai un truc à faire, j'attrape le taureau par les cornes et je fonce.

    Et aussi que je n'ai pas encore trouvé de méthode définitive (entendre "fiable à 100 %") pour ouvrir les fichiers, tous les fichiers (enfin, les bmp, jpg et png d'abord, tif dans un second temps – pour les gif je m'appuierai sur l'excellent boulot de Jérôme). Résultat, j'aurais tendance à oublier ces vieilles discussions : à chaque nouveau problème une nouvelle solution, et les vieilles chausse-trappes réapparaissent,

    Citation Envoyé par gvasseur58 Voir le message
    Personnellement, je préfère utiliser des bibliothèques comme BGRABitmap qui fonctionnent de manière moderne et efficace : plus rapides, plus polyvalentes (avec canal alpha et anticrénelage) et véritablement multiplateformes. Les outils standards de Lazarus le sont aussi tant qu'on essaye pas de sortir des techniques courantes.
    Tu parles des compos BGRA, je l'entends bien, mais j'ai posté récemment une image (peut-être pas assez claire ?)
    Nom : lazpaint641_n_atool.png
Affichages : 741
Taille : 197,6 Ko
    où l'on voit bien que Lazpaint (qui s'appuie dessus) ne peut pas ouvrir un fichier que j'ouvre sans problème.
    Et il n'y a pas de message d'erreur, rien qu'un quadrillage genre calque transparent de Photoshop.

    Même souci avec un fichier .bmp d'origine os/2 que j'ouvre sans problème en m'appuyant sur les données du header, lire ci-après.
    Plus une embrouille avec un tif, qui me génère un AV quand j'ouvre le dossier le contenant.
    En haut l'explorateur Lazpaint, en bas celui de Linux :
    Nom : AV_fic-tif.png
Affichages : 785
Taille : 47,4 Ko

    Citation Envoyé par gvasseur58 Voir le message
    D'autre part, je pense que tu n'utilises pas TRawImage correctement, car tu supposes à tort que Windows et Linux gèrent de la même manière le bitmap. Regarde ici pour la description de TRawImageDescription.
    Le pourquoi du comment de mon rejet de TRawImageDescription : trop de déboires et de déconvenues, et je n'ai jamais compris pourquoi ce type remontait des informations différentes de ce qu'on peut voir en examinant le header d'un fichier avec un éditeur hexa (à tel point que je me suis bricolé une unité qui va lire ces infos plutôt que d'interroger ce TRID. Sans parler de la pauvreté de l'aide.

    Citation Envoyé par gvasseur58 Voir le message
    Pour simplifier encore, je ne vais pas utiliser le composant TImage, car il n'est pas et ne peut pas être équivalent entre Windows et Linux pour des raisons internes aux OS (une question d'accès au canevas, je crois me souvenir, mais quelqu'un pourrait préciser sans doute - je vais essayer de retrouver la référence). Je vais plutôt m'appuyer sur un canevas d'une PaintBox, par exemple => je te tiens au courant.
    avec plaisir, car c'est un composant que je n'utilise jamais : je ne me sens pas d'atomes crochus avec lui, il me semble confus, archaïque, et j'avoue que je trouve le TImage beaucoup plus simple et sympathique.

    Citation Envoyé par gvasseur58 Voir le message
    J'ai testé ton code sous Mint et le résultat est le même que celui que tu décris.
    Ceci est une bonne nouvelle, quelque part.

    Citation Envoyé par gvasseur58 Voir le message
    Pour simplifier les problèmes, j'ai d'abord utilisé la méthode de copie toute simple avec Assign et j'obtiens bien la bonne copie (encore heureux !).
    Pourquoi je ne l'utilise pas, et pourquoi je veux passer par les bytes ? Parce que j'ai trouvé deux projets en Delphi dont le sujet me passionne, je veux parler du traitement d'images et des manières de les redimensionner, et pour ça, il faut aller chercher les composantes de chaque pixel pour faire des calculs dessus.
    Donc tant que je ne peux pas faire des copies 1/1 pour commencer, je ne peux pas aller plus loin.

    Citation Envoyé par gvasseur58 Voir le message
    [EDIT] As-tu aussi pensé à tes travaux précédents avec l'ordre des octets ? Je te renvoie à une discussion que tu avais menée en... 2016 : https://www.developpez.net/forums/d1...ws-sous-linux/
    Non, je l'avais oubliée... J'y vais de ce pas.

    EDIT : je suis allé voir et je me rends compte aujourd'hui qu'il y a deux ans j'en savais beaucoup moins que maintenant...

    Il est bien, mon bout de code, elles sont jolies les images, mais on ne sait pas du tout si c'est la vérité qui est encodée dans les fichiers de sortie, pour la bonne et simple raison qu'il n'y en a pas !

    Si je reprends le projet de cet après-midi et que je fais enregistrer le bmp de sortie, il présente le même défaut que ce qu'on voit dans le TImage. Quelque part c'est bien, car il y a eu des cas dans mes autres tests de ces derniers jours où les deux étaient différents, en plus !

    Bon, pour en revenir à mon histoire de copie de bytes, j'ai fait un truc simple : rajouter un TMemo comme système de log,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
          for w := 0 to (Width*3)-1 do begin
            pbD^[w] := pbS^[w];
            memo1.Lines.Add(inttostr(pbS^[w]) +'---'+inttostr(pbD^[w]));
          end;
          Caption := IntToStr(w); // 20, ok
          // padding -- attention : à commenter pour l'autre fichier
          for p := 1 to 3 do begin
            pbD^[w+p] := 0;
            memo1.Lines.Add(inttostr(pbD^[w+p]));
          end;
    et regarder le résultat (et c'est là qu'on s'arrache les cheveux, parce que les datas sont bonnes) :
    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
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
      0---  0
    255---255
    255---255
    0
    0
    0
    On voit bien que les 7 pixels sont strictement identiques, byte source à gauche, destination à droite), on a bien 0 255 255 7 fois, S comme D.
    Pourquoi ne le sont-ils pas dans le bmp, puisque ce qu'on voit c'est le contenu du bmp en mode "dissection sous le microscope" ?

    Sans doute parce que je crois être au plus bas niveau avec mon histoire de copie de bytes, mais ça ne doit pas être le cas et il doit y avoir des couches qui font leur (sale) cuisine entre les données du fichier et les instructions pour les traiter.
    C'est la seule explication que je vois.
    Parce que mine de rien,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
            memo1.Lines.Add(inttostr(pbD^[w+p])); // ici les données sont bonnes
          end;
        end;
      bmp.EndUpdate();
      // et ici elles ne le sont plus, puisque si je n'enregistre pas, l'affichage est quand même en vrac
      bmp.SaveToFile(Application.Location + 'test1.bmp');
      image2.Picture.Bitmap.Assign(bmp);
    Voilà...

  8. #8
    Rédacteur

    Avatar de gvasseur58
    Homme Profil pro
    Cultivateur de code (bio)
    Inscrit en
    Février 2013
    Messages
    1 436
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Cultivateur de code (bio)
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2013
    Messages : 1 436
    Billets dans le blog
    84
    Par défaut
    [EDIT Je n'avais pas rafraîchi mon écran et j'arrive aux mêmes conclusions que toi ! Je laisse le message, car il contient un code d'illustration]

    Bonjour Jipété,

    Sans avoir totalement résolu le problème, j'ai tout de même progressé .

    J'ai fait un dump de la description des images sur Windows et Linux Mint. Pour cela, j'ai déposé un TMemo baptisé mmo et utilisé Image1.Picture.Bitmap.RawImage.Description.Astring et bmp.RawImage.Description.AsString pour lire la description complète des bitmaps.
    Pour les deux, il y a une inversion des bits dans l'image de destination, mais ça ne perturbe en rien l'affichage.
    Surtout, avec Linux, tu obtiens automatiquement un BitsPerPixel de 32 (au lieu de 24), ce qui décale forcément toute l'image et expliquerait l'espace noir correspondant à exactement 1/4 de l'image (un octet tous les trois octets).

    Du coup, il suffit de tenir compte de ce quatrième octet pour obtenir une réplique parfaite. Voici un code (à visée pédagogique, car il peut être simplifié) qui montre l'opération :

    Code pascal : 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
    procedure TForm1.Button1Click(Sender: TObject);
    var
      w,h, wd, i: integer;
      work: array[0..2] of Byte;
      pbS,pbD: pByteArray;
      bmp: TBitmap;
      procedure Load(f: String);
      var
        Pict: TPicture;
      begin
        Pict := TPicture.Create;
        Pict.LoadFromFile(f);
        Image1.Picture.Assign(Pict);
        Pict.Free
      end;
    begin
      opd.InitialDir := Application.Location;
      if not opd.Execute then exit;
      load(opd.FileName);
      bmp := TBitmap.Create;
      bmp.PixelFormat := Image1.Picture.Bitmap.PixelFormat;
      bmp.Width  := Image1.Picture.Bitmap.Width;
      bmp.Height := Image1.Picture.Bitmap.Height;
     
      bmp.BeginUpdate();
     
      with Image1.Picture.Bitmap do
        for h := 0 to Height-1 do
        begin
          pbS := pByteArray(RawImage.GetLineStart(h));
          pbD := pByteArray(bmp.RawImage.GetLineStart(h));
     
          w := 0;
          wd := 0;
          while w < (Width*3)-1 do
          begin
            // paquet de 3 octets source
            for i := 0 to 2 do
            begin
              work[i] := pbS^[w];
              inc(w);
            end;
            // paquet de 4 octets destination
            pbD^[wd] := work[0];
            pbD^[wd + 1] := work[1];
            pbD^[wd + 2] := work[2];
            pbD^[wd + 3] := 0;
            inc(wd, 4);
          end;
          Caption := IntToStr(w);
        end;
      mmo.Append(Image1.Picture.Bitmap.RawImage.Description.AsString);
      mmo.Append(bmp.RawImage.Description.AsString);
     
      bmp.EndUpdate();
     
      image2.Picture.Bitmap.Assign(bmp);
      bmp.Free;
    end;

    Si l'expérience montre bien où est le problème, elle ne le résout qu'en partie : le code suppose qu'il s'agit d'une image en 24 bits transformée en 32 bits, ce qui nécessiterait bien sûr des tests (avec RawImage.Description).

    Bon dimanche !

    Gilles
    Accès à mon site et à mon blog. Actualités, cours et ressources Delphi, Lazarus et Pascal.
    Pensez à la balise - Quelqu'un vous a aidé ou vous appréciez une intervention ? Pensez au

  9. #9
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Citation Envoyé par gvasseur58 Voir le message
    Si l'expérience montre bien où est le problème, elle ne le résout qu'en partie : le code suppose qu'il s'agit d'une image en 24 bits transformée en 32 bits, ce qui nécessiterait bien sûr des tests (avec RawImage.Description).
    Que je me refuse à employer,

    Voilà ce que j'ai constaté, au fil de nombreux essais.
    Ça vient d'une fonction perso OuvreImage(f: string): TBitmap; (d'où le RESULT) qui s'appuie sur une analyse du header du fichier passé.

    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
      // plus efficace pour ouvrir les fichiers parfois étranges (xbgr...)
      lii := TLazIntfImage.Create(0,0);
      try
        if OffsetToDatas = 54 then begin // synonyme de VersionHeader = 1
          lii.DataDescription := GetDescriptionFromDevice(0);
          lii.LoadFromFile(f);
        end else begin  // 70, 122 pour bgra, 138 pour xbgr, n/a pour jpg et d'autres encore
          OuvreFichier; // utilise TPicture pour l'assigner à RESULT -- c'est la proc "Load" du projet de test 
          with RESULT do
            lii.LoadFromBitmap(Handle, Handle, Width, Height); 
        end;
        RESULT.LoadFromIntfImage(lii); // renvoie un bitmap "bien" rempli
      finally
        lii.Free;
      end;
    On voit bien avec le test sur la version du header que les gens du TLazInftImage ont dû galérer également puisque selon cette version, il me faut changer la manière dont j'ouvre le fichier.
    Je vais donc tenter de l'implémenter dans le projet de test rapide "pour le fofo", qui va instantanément se transformer en usine à gaz (3 à 5 modules en plus, je ne sais pas exactement à l'heure où j'écris ces lignes).

    Ces quelques lignes d'adaptation sont également utilisées pour ouvrir le fichier d'entrée dans plein d'autres projets de tests, du coup à chaque fois il faut que je revoie tout ça, à chaque fois ça devient un machin à la Gaston Lagaffe inmaintenable, et quand j'y suis enfin (ou je crois y être) à chaque fois il y a quand même un dernier fichier qui décide de jouer la fille de l'air et me met tout en vrac...

    D'où mon désarroi, mon désespoir, et le temps qui fiche le camp...
    Parce que, mine de rien, les deux projets Delphi (dont l'un a tourné tip-top dans mon vieux Win2000 virtuel et son D7 perso au bout de 10 minutes environ), je les ai découverts il y a 3 semaines à peu près...

  10. #10
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bonjour,

    j'ai passé la matinée sur ce $£µ*§@#&! de fichier, voilà mes conclusions : pour faire court et simple, le bug n'est pas dans le fichier, il est dans (ma vieille version de) Lazarus.
    Faut voir maintenant si ça a changé avec la 2.0...
    Je redonne le fichier : 32bitsKC.bmp.zip

    Démonstration :
    à coups d'éditeur hexa (voir + bas la grande image) on sait qu'à l'adresse 22 se trouve "size in bytes of the image, including padding".
    Décortiquons :
    @22..25 --> 90 d0 03 00 --> 3d090hex --> 250000déc, c'est la taille de l'image en bytes
    @12..15 --> FA --> 250 (pixels) pour la largeur
    @16..19 --> FA --> 250 (lignes) pour la hauteur

    Taille de l'image / nombre de lignes = taille d'une ligne :
    250000 / 250 = 1000 bytes

    si on a 4 bytes par pixel ça nous donne 250 pixels par ligne, ça tombe bien, ça correspond au contenu de l'adresse 12..15 ;
    si on a 3 bytes par pixel ça nous donne 333 pixels par ligne, ce qui ne correspond à rien et c'est ce qu'on voit d'affiché ("largeur" = largeur de la zone blanche quand la couleur commence -- là j'ai enlevé le stretch des TImage pour avoir un affichage 1/1 rogné) :
    Nom : compar_largeurs.png
Affichages : 271
Taille : 28,6 Ko

    41 pixels de 4 bytes ça nous fait 164 bytes et c'est joli.
    Et 164 bytes répartis dans des pixels de 3 bytes, ça nous fait 164 / 3 = 55 (arrondi) pixels, suivis par des pixels en vrac, ce qu'on voit sur l'image du bas.

    La bonne question c'est : pourquoi Lazarus ne respecte-t-il pas le biBitCount qui est à 32 (20 à @1C) soit 4 bytes par pixel pour ce fichier ?


    Voilà ce qu'en disait le grand gourou il y a deux ans :
    Citation Envoyé par Andnotor Voir le message
    Il y a clairement un problème d'offset si l'image d'origine n'est pas supportée sous Lazarus. Par exemple si la taille de l'entête est calculée par SizeOf(BITMAPV5HEADER) plutôt que récupérée dans le fichier lui-même ou peut-être en supposant qu'il y a toujours des informations de couleur.
    Sauf qu'on ne trouve rien de particulier dans le fichier, il a la même structure que d'autres 32 bits qui s'ouvrent sans problème, c'est tout.

    Et surtout, il s'ouvre bien avec Gimp, ImageJ, ImageMagick, LibreOffice et le visionneur par défaut sous Linux, ainsi qu'avec XnView, en insertion d'objet dans Wordpad et dans un message OutlookExpress sous XP.
    Il n'y a qu'avec Lazarus que ça coince.

    Un peu la même histoire qu'ici, où l'OP commence par incriminer Gimp quand au final c'est son logiciel périmé qui est en cause.

    Ce qui est ennuyeux (et hallucinant), c'est qu'ouvrir ce fichier avec Gimp et le récrire ensuite génère un fichier VersionHeader 4 avec les datas en plus qui vont bien, mais il s'ouvre toujours aussi mal avec Lazarus, alors que d'autres fichiers avec la même structure et la même version du header s'ouvrent très bien.
    Nom : 2good-1bad.png
Affichages : 279
Taille : 63,8 Ko

    Récrit sans les informations de couleur (= header v1) donne le même résultat foireux.
    Donc la seule chose qui ne change pas dans toutes ces manips, ce sont les dimensions du fichier.

    Y aurait-il des tests bizarres à l'ouverture qui font que 250 ET 250 ET 1000 génèrent un défaut ? Nul ne le saura jamais, à moins d'aller voir au fin fond des routines qui font le boulot...


    Lecture intéressante à propos du format bmp.

  11. #11
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bon, voilà le cœur du truc, torché en 10 minutes (à comparer aux 3 semaines du RawImage...) :
    vous noterez 3 lignes en commentaire pour bien les repérer, il faut les activer ! Sinon, les grandes largeurs impaires (397 ici) échouent lamentablement, et je ne sais pas pourquoi : ça le faisait déjà avec RawImage et associés…
    Nom : 397.png
Affichages : 287
Taille : 77,7 Ko
    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
      mss := TMemoryStream.Create;
      src.SaveToStream(mss);
      mss.Position := GetOffsetToDatas(src);
      dst.BeginUpdate();
      for h := src.Height-1 downto 0 do begin // parcours inversé pour les streams
        pbD := pByte(dst.RawImage.GetLineStart(h));
        wd := 0;
        for ws := 0 to (src.Width*3)-1 do begin
          aByte := mss.ReadByte;
          //memo1.Lines.Add(IntToStr(ws)+'  '+IntToStr(aByte));
          pbD[wd] := aByte;
          if ((ws + 1) mod 3 = 0) then begin // = traitement du 3e byte de la source terminé
            // R et B inversés pour jouer --> en fait elles sont naturellement inversées SI pf32bit
            tmpbyte := pbD[wd-2];
            pbD[wd-2] := pbD[wd];
            pbD[wd] := tmpbyte;
            // 4e byte  bidouille obligatoire sinon les grandes largeurs impaires sont en vrac
    //        if (src.Width < 32) // tout comme les toutes petites
    //        or (not Odd(src.Width)) then begin // largeur > 32, test si paire (= not impair)
              inc(wd);
              pbD[wd] := 255;
    //        end;
          end;
          inc( wd);
        end;
        p := 0; // ok pour skipper les bytes de padding
        while (((src.Width*3) + p) mod 4 <> 0) do begin mss.ReadByte; inc(p); end;
      end;
      dst.EndUpdate();
    //  mss.Position:=0; mss.SaveToFile('/root/Desktop/mss.bmp');
      mss.Free;
      image2.Picture.Bitmap.Assign(dst);
    Il me reste un fichier cassé à l'origine, et qui le reste :
    Nom : 32bits_kc.png
Affichages : 280
Taille : 41,7 Ko

    mais le plus curieux, c'est que l'enregistrement du bitmap dst génère un fichier correct, regardez sa miniature créée par Linux sur le Bureau.

    Je verrai ça demain à tête reposée, après avoir fait le ménage dans le projet de test, qui est une joyeuse pagaille, vous vous en doutez.
    Ce soir j'en ai un peu ras la casquette,

  12. #12
    Membre Expert
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Billets dans le blog
    2
    Par défaut
    J'ai fait un petit test avec lazarus 2.0 sous Windows il semblerai que certain petits problèmes ont été corrigés. Mais c'est pas à 100% juste.

    J'ai testé avec des BMP 24bits et 32bits

    Avec le code suivant

    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
    procedure TForm1.Button1Click(Sender : TObject);
    begin
      if OPD.Execute then
      begin
        Image1.Picture.LoadFromFile(OPD.FileName);
        label1.caption := 'Depth : '+ Image1.Picture.Bitmap.RawImage.Description.Depth.ToString;
        label2.caption := 'BPP : '+ Image1.Picture.Bitmap.RawImage.Description.BitsPerPixel.ToString;
      end;
    end;
     
    procedure TForm1.Button2Click(Sender : TObject);
    var
      h,w : Longword;
      Dst, Src : PByte;
      bmpDst : TBitmap;
    begin
      bmpDst := TBitmap.Create;
      if Image1.Picture.Bitmap.RawImage.Description.BitsPerPixel = 24 then
        bmpDst.PixelFormat := pf24bit
      else
        bmpDst.PixelFormat := pf32bit;
     
      bmpDst.SetSize(Image1.Picture.bitmap.Width, Image1.Picture.bitmap.Height);
     
      for h := 0 to Image1.Picture.bitmap.Height-1 do
      begin
        Src := pByte(Image1.Picture.bitmap.RawImage.GetLineStart(h));
        Dst := pByte(BmpDst.RawImage.GetLineStart(h));
     
        if Image1.Picture.Bitmap.RawImage.Description.BitsPerPixel = 24 then
        begin
          for w := 0 to (Image1.Picture.bitmap.Width*3)-1 do
          begin
           // memo1.Lines.Add(IntToStr(w) +'  '+ IntToStr(Src[w]));
            Dst[w] := Src[w];
          end;
        end
        else  if Image1.Picture.Bitmap.RawImage.Description.BitsPerPixel = 32 then
        begin
          for w := 0 to (Image1.Picture.Bitmap.Width*4)-1 do
          begin
           // memo1.Lines.Add(IntToStr(w) +'  '+ IntToStr(Src[w]));
            Dst[w] := Src[w];
          end;
        end;
      end;
      Image2.Picture.Bitmap.Assign(BmpDst);
      BmpDst.Free;
    end;

    Resultat

    Nom : 2019-02-12_194456.jpg
Affichages : 269
Taille : 23,3 Ko

    et avec FondRGB 32bits XBGR

    Nom : 2019-02-12_195317.jpg
Affichages : 287
Taille : 21,8 Ko

    Comme on peut le voir le Depth et le BPP sont à 24 bits alors que le fichier BMP est bien un 32 bits. Vu qu'il n'y a pas de pixel transparent, Lazarus afin d'optimiser la taille prise en mémoire il le traite comme un 24 bits

    [EDIT] Ton erreur viens à mon avis du PixelFormat de ton bitmap de destination qui est erroné
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  13. #13
    Membre Expert
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Billets dans le blog
    2
    Par défaut
    Bonne nouvelle après plusieurs chargement de différent fichiers BMP provenant de ma "test-suite" il semblerai bien que le support du fichier BMP est été amélioré dans cette version 2.0
    Certains fichiers BMP résistent encore et d'autres retournent toujours des valeurs erronées pour le Depth et BPP mais c'est déja bien mieux que les précédentes versions
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  14. #14
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Citation Envoyé par BeanzMaster Voir le message
    J'ai fait un petit test avec lazarus 2.0 sous Windows il semblerait que certains petits problèmes ont été corrigés. Mais c'est pas à 100% juste.
    Comment se fait-il que je n'ai rien trouvé dans les liens donnés par Gilles concernant les informations de version ?
    Tu devrais faire un test sous Linux,

    Citation Envoyé par BeanzMaster Voir le message
    [EDIT] Ton erreur viens à mon avis du PixelFormat de ton bitmap de destination qui est erroné
    Qu'est-ce que tu appelles bitmap de destination ? Le dst ou le Image2.Picture.Bitmap utilisé pour l'affichage ?

    Dans l'attente de ta réponse, regarde ça, juste pour rire (le dst.PixelFormat est à 32) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
      image2.Picture.Bitmap.PixelFormat:=pf24bit;
      image2.Picture.Bitmap.LoadFromBitmapHandles(dst.Handle, dst.Handle, nil);
      memo1.Lines.Add(IntToStr(BitsPerPixel(image2.Picture.Bitmap.PixelFormat)) + ' bpp');// 24
     
      image2.Picture.Bitmap.PixelFormat:=pf24bit;
      image2.Picture.Bitmap := dst; // affecte le pf du timage
      memo1.Lines.Add(IntToStr(BitsPerPixel(image2.Picture.Bitmap.PixelFormat)) + ' bpp');// 32
    Ah, petit bug sans incidence : l'un des deux fichiers .bmp dans le zip, le 196x128x24.bmp,
    doit être renommé 192x128x24.bmp pour être en phase avec la réalité de son contenu. Désolé,

  15. #15
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    J'ai trouvé !

    Il s'est glissé une microscopique différence suite à un malencontreux couper/coller, à un endroit limite invisible, et découvert en comparant mot à mot la fonction fautive avec une autre toute fraîche dérivée du Button4 et parfaitement fonctionnelle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // La ligne coupable :
      lii.LoadFromFile(f);
    // La ligne correcte
      lii.LoadFromFile(f, ReaderBMP);
    Hé bien croyez-moi, cette simple ligne planquée au milieu de plein d'autres avec plein de lignes en commentaires aussi, m'aura occupé toute la journée ou presque.

    Et comme il n'y avait pas de message d'erreur ni d'information à la compilation et pas plus à l'exécution, je m'étais concentré sur tout sauf sur cette ligne.

    Désolé pour le dérangement.

  16. #16
    Membre Expert
    Avatar de BeanzMaster
    Homme Profil pro
    Amateur Passionné
    Inscrit en
    Septembre 2015
    Messages
    1 899
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Amateur Passionné
    Secteur : Tourisme - Loisirs

    Informations forums :
    Inscription : Septembre 2015
    Messages : 1 899
    Billets dans le blog
    2
    Par défaut
    Salut


    Citation Envoyé par Jipété Voir le message

    Le aBmp est chargé par la fonction Load vue précédemment, qui utilise probablement mal une TLazInfImage, car je suis tombé hier sur un bout de code russe, qui va peut-être me mettre le pied à l'étrier, dans la mesure où je peux dessiner un bitmap de 250 px de large en pf32 sans raies verticales !
    Dans TGifViewer j'utilise un truc dans le même genre pour exporter les frame vers un TBitmap (Regardes, le RawImage.Description.Init_?????, incohérent non ?)

    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
    Function TFastBitmap.BuildBitmap: Graphics.TBitmap;
    Var
      Temp : Graphics.TBitmap;
      IntfBmp : TLazIntfImage;
      ImgFormatDescription: TRawImageDescription;
      W,H,X,Y : Integer;
      SrcPix : PColor32;
    Begin
     
      (* /!\ Le code si dessous fonctionne parfaitement sous Windows et Mac.
         Mais sous Linux ce code produit des erreur au niveau de la transparence
     
        BmpHandle := 0;
        MskHandle := 0;
        W := FWidth;
        H := FHeight;
        Buffer := PByte(GetSurfaceBuffer);
     
        RawImage.Init;
        {$IFDEF WINDOWS}
        RawImage.Description.Init_BPP32_B8G8R8A8_BIO_TTB(W,H);
        {$ELSE}
        RawImage.Description.Init_BPP32_R8G8B8A8_BIO_TTB(W,H);
        {$ENDIF}
     
        RawImage.Data := Buffer;
        RawImage.DataSize := FSize;
     
        if not RawImage_CreateBitmaps(RawImage, BmpHandle, MskHandle,False) then
          Raise Exception.Create('Impossible de créer le TBitmap')
        else
        begin
          Temp := Graphics.TBitmap.Create;
          Temp.Width := W;
          Temp.Height := H;
          Temp.PixelFormat := pf32bit;
          Temp.Handle := BmpHandle;
          Temp.MaskHandle := MskHandle;
          Temp.Transparent := True;
          //Temp.TransparentColor := FTransparentColor;
          //temp.TransparentMode := tmAuto;
          Result := Temp;
        End;
      *)
     
      Result := nil;
     
      W := FWidth;
      H := FHeight;
     
      // Pour que la transparence soit gérée correctement sous Linux on est obligé de passer par TLazIntfImage
      IntfBmp := TLazIntfImage.Create(W,H);
      ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(W, H);
      IntfBmp.DataDescription := ImgFormatDescription;
     
      SrcPix := Self.GetSurfaceBuffer;
      For Y:=0 to H-1 do
        For X:=0 to W-1 do
        begin
          IntfBmp.Colors[x, y]:=SrcPix^.ToFPColor;
          inc(SrcPix);
        end;
     
      begin
        Temp := Graphics.TBitmap.Create;
        Temp.LoadFromIntfImage(IntfBmp);
        Result := Temp;
        IntfBmp.Free;
      End;
      if Result = nil then
        Raise Exception.Create(rsBitmapCreateError);
    End;
    Ensuite pour pouvoir importer un bitmap j'avais fait comme ça (Test du RedShift pour savoir les données sont en RGB ou BGR suivant l'OS)

    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
    Function TFastBitmap.ImportFromRawImage(Const ARawImage: TRawImage): Boolean;
    var
      BufferData : PByte;
    begin
      SetSize(ARawImage.Description.Width,ARawImage.Description.Height);
      result:=false;
      // On verifie si la taille des deux tampons sont identique
      // Si ce n'est pas le cas, cela veut dire que le TRawImage n'est pas au format 32bit
      if (ARawImage.DataSize= FSize) then
      begin
        try
          BufferData := PByte(Self.getSurfaceBuffer);
          Move(ARawImage.Data^, BufferData^, self.Size);
          {$IFDEF WINDOWS}
            if (ARawImage.Description.RedShift = 0) and ((ARawImage.Description.BlueShift = 16)) then Self.SwapRB; // Le RawImage est-il en RGB, si oui on échange
          {$ELSE}
            if (ARawImage.Description.RedShift = 16) and ((ARawImage.Description.BlueShift = 0)) then Self.SwapRB; // Le RawImage est-il en BGR, si oui on échange
          {$ENDIF}
        finally
          result:=true;
        end;
      end;
    End;
     
    Function TFastBitmap.ImportFromBitmap(Const ABitmap: Graphics.TBitmap): Boolean;
    var
      LTempBitmap: Graphics.TBitmap;
      ok,ResetAlpha:Boolean;
     
      procedure SetAlpha(Value : Byte);
      var
        i : Integer;
        PixPtr : PColor32;
        maxi : Integer;
      begin
        i:=0;
        Maxi := (FWidth * FHeight)-1;
        PixPtr :=PColor32(FData);// Self.GetScanLine(0);
        While i<Maxi do
        begin
          PixPtr^.Alpha:= Value;
          inc(PixPtr);
          inc(i);
        end;
      end;
     
    begin
      ResetAlpha:=False;
      result:=false;
      if (ABitmap.PixelFormat <> pf32bit)  then
      begin
        LTempBitmap := Graphics.TBitmap.Create;
        try
          ResetAlpha:=True;
          LTempBitmap.SetSize(ABitmap.Width, ABitmap.Height);
          LTempBitmap.PixelFormat := pf32bit;
          LTempBitmap.Canvas.Draw(0, 0, ABitmap);
        finally
          ok:=Self.ImportFromRawImage(LTempBitmap.RawImage);
          if ResetAlpha then SetAlpha(255);
          FreeAndNil(LTempBitmap);
          result:=true and (ok);
        end;
      end
      else
      begin
       ok:=Self.ImportFromRawImage(ABitmap.RawImage);
       result:=true and (ok);
      end;
    End;

    Citation Envoyé par Jipété Voir le message
    Moi je pète un câble, là...
    Quelqu'un saura réparer ça ?
    La différence que j'ai noté c'est dans le Button4 tu utilises image1.Picture.Bitmap.Assign(b); et que dans le Button5 tu utilises image1.Picture.Bitmap := LoadFile(....);
    Citation Envoyé par Jipété Voir le message
    J'ai trouvé !

    Il s'est glissé une microscopique différence suite à un malencontreux couper/coller, à un endroit limite invisible, et découvert en comparant mot à mot la fonction fautive avec une autre toute fraîche dérivée du Button4 et parfaitement fonctionnelle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // La ligne coupable :
      lii.LoadFromFile(f);
    // La ligne correcte
      lii.LoadFromFile(f, ReaderBMP);
    Hé bien croyez-moi, cette simple ligne planquée au milieu de plein d'autres avec plein de lignes en commentaires aussi, m'aura occupé toute la journée ou presque.

    Et comme il n'y avait pas de message d'erreur ni d'information à la compilation et pas plus à l'exécution, je m'étais concentré sur tout sauf sur cette ligne.

    Désolé pour le dérangement.
    Le fait d'indiquer le Reader voudrait donc, peut-être dire que le problème vient du "ReaderBMP" utilisé (celui de FPC ou de Lazarus) Mais cela ne résout pas le problème de la copie de Image1-->BmpTemp-->Image2 avec des images en 32bits (j'ai essayé avec des PNG avec transparence donc bien 32bits) et l'affichage reste foireux dans l'image2. Il y a donc bien quelques choses qui cloche (qui manque) dans le code avec Linux à ce niveau. (vu avec TGIFViewer cf commentaire du code plus haut à ce sujet)


    Bon dimanche
    • "L'Homme devrait mettre autant d'ardeur à simplifier sa vie qu'il met à la compliquer" - Henri Bergson
    • "Bien des livres auraient été plus clairs s'ils n'avaient pas voulu être si clairs" - Emmanuel Kant
    • "La simplicité est la sophistication suprême" - Léonard De Vinci
    • "Ce qui est facile à comprendre ou à faire pour toi, ne l'est pas forcément pour l'autre." - Mon pèrei

    Mes projets sur Github - Blog - Site DVP

  17. #17
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bonjour,

    la nuit porte conseil, et ces rayures m'ont inspiré : trop parfaites pour être honnêtes, il n'y avait qu'une solution : la destination de la copie est en 32 bits.

    Et effectivement, après avoir rajouté un bouton sur la fiche, j'y ai copié.collé le code du Button1 puis lui ai apporté quelques modifs :

    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
    var
      wd,ws,h: integer;
      pbS,pbD: pByteArray;
      tmpbyte: Byte;
      dst: TBitmap;
    begin
      opd.InitialDir := Application.Location;
      if not opd.Execute then exit;
      load(opd.FileName);
      dst := TBitmap.Create;
      dst.PixelFormat := pf32bit;
      dst.Width  := Image1.Picture.Bitmap.Width;
      dst.Height := Image1.Picture.Bitmap.Height;
      dst.BeginUpdate();
      with Image1.Picture.Bitmap do
        for h := 0 to Height-1 do begin
          pbS := pByteArray(    RawImage.GetLineStart(h));
          pbD := pByteArray(dst.RawImage.GetLineStart(h));
          wd := 0;
          for ws := 0 to (Width*3)-1 do begin
            pbD^[wd] := pbS^[ws];
            if ((ws + 1) mod 3 = 0) then begin // = traitement du 3e byte de la source terminé
              // 1- R et B de la dest sont inversés
              tmpbyte := pbD^[wd-2];
              pbD^[wd-2] := pbD^[wd];
              pbD^[wd] := tmpbyte;
              // 2- il faut ajouter un 4e byte à la dest
              inc(wd);
              pbD^[wd] := 255;
            end;
            inc(wd); // pour avancer dans la dest
          end;
          Caption := IntToStr(ws)+'--'+IntToStr(wd); // 20--28
          // padding : plus besoin en pf32bit
        end;
      dst.EndUpdate();
      image2.Picture.Bitmap.Assign(dst);
      dst.Free;
    end;
    Et voilà.
    Reste plus qu'à tester avec ma collection de fichiers en 24 bits tordus ou étranges...

    Et ensuite il faudra trouver une procédure pour les sources en 32 bits.
    La voilà (je vous la laisse intégrer)
    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
      dst.BeginUpdate();
      with Image1.Picture.Bitmap do
        for h := 0 to Height-1 do begin
          pbS := pByteArray(    RawImage.GetLineStart(h));
          pbD := pByteArray(dst.RawImage.GetLineStart(h));
          for w := 0 to (Width*4)-1 do begin
            pbD^[w] := pbS^[w];
            if ((w + 1) mod 4 = 0) then begin // = traitement du 4e byte de la source terminé
              // R et B de la dest sont inversés
              tmpbyte := pbD^[w-3];
              pbD^[w-3] := pbD^[w-1];
              pbD^[w-1] := tmpbyte;
            end;
          end;
          // padding : plus besoin en pf32bit
        end;
      dst.EndUpdate();
    Elle fonctionne très bien avec le bmp 32 bits jaune généré par le button2, mais un sondage rapide montre que ça va être une vraie catastrophe avec plein d'autres fichiers de ma collection, à commencer par celui que j'ai montré hier sur lequel butte Lazpaint : moi aussi maintenant...

    Un exemple pour me pourrir le dimanche, et en plus la preview de l'opd (à g.) me colle la honte :

    Nom : previewok.png
Affichages : 767
Taille : 61,3 Ko

    Mes rendus sont rectangulaires, c'est normal, je rappelle que les TImage sont Stretched à True histoire d'agrandir le fichier jaune du départ qui n'occupe qu'une ligne de 7 pixels.

    La seule piste que je vois, pour l'instant, c'est que le 32 bits qui fonctionne bien a une version de header du fichier à 1, quand les autres sont à 4 (ou 5), avec des datas plus loin dans la structure du fichier.
    Mais si la preview s'en accommode, pourquoi le traitement du bmp ne s'en sort-il pas proprement ? C'est dément et illogique (ou buggé...)
    Va encore falloir que je parte dans des traitements de fou sur les tests de la version du header et ce genre de choses...
    Tiens, je vais me faire un café,


    Ah, si certains veulent jouer : 32bitsOK.bmp.zip

  18. #18
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Bonjour Jérôme,

    pour ne rien te cacher, je ne me souviens pas si la source est en 24 ou 32 bits, donc on passe sur ça, c'était juste pour l'ami Yves, lui illustrer les misères qu'on peut rencontrer, d'autant plus que j'ai un truc complètement hallucinant que je ne sais plus par quel bout prendre.

    Qu'on en juge : sur ce magnifique montage on a en fond la vue de l'éditeur hexadécimal ouvert sur un fichier de 3x2 en 24 bits, avec 3 pixels en surbrillance orange, ce sont les 3 qu'on voit juste dessous dans la maquette d'étude, la ligne du haut.
    Celle où se trouve le pointeur et qui est analysée par le colorpicker en bas à gauche, où l'on peut lire, en Delphi, FF 00 FF, ce qui correspond bien à ce qu'on voit dans l'éditeur hexa, pixel du centre.
    Nom : bug_du_183.png
Affichages : 700
Taille : 37,8 Ko

    Le gag c'est le log dans le mémo, à droite, où j'ai mis en surbrillance la valeur 183, dont je ne sais pas d'où elle sort puisqu'elle n'est pas dans le fichier.
    183dec c'est B7hex.
    Mais en attendant, ça décale tout ce qui suit et donc les couleurs en vrac sauf la 1re de chaque ligne…
    Le bleu clair de la seconde ligne c'est bien BF BF 7F, soit 191 191 127. Et le 183 de la 1re ligne à l'index 3 (1re colonne du mémo) correspond ici à la data 0, inexistante au milieu des datas de cette ligne (je ne compte pas le padding).


    Pour obtenir ces colonnes dans le mémo, rien de plus simple :
    (Les observateurs noteront que j'ai remplacé pByteArray par pByte, avec un résultat aussi nul.)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      for h := 0 to src.Height-1 do begin
    //  pbS := pByte(src.RawImage.GetLineStart(h)); test avec dessous, résultat identique
        pbS := pByte(image1.Picture.Bitmap.RawImage.GetLineStart(h));
        for ws := 0 to (src.Width*3)-1 do memo1.Lines.Add(IntToStr(ws) +'  '+ IntToStr(pbS[ws]));
      end;
    C'est tout simplement ma boucle de copie où tout a été enlevé sauf la ligne de log, et je ne sais pas quoi ni où chercher.

    Une dernière précision : si, en fin de boucle, je demande à enregistrer le fichier source, bien sûr il n'y a pas de 183 dedans, ça serait trop facile sinon…

    Face à ça, à part un prêtre exorciseur spécialise du vaudou, je ne vois pas trop...

  19. #19
    Expert confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 159
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 159
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Face à ça, à part un prêtre exorciseur spécialise du vaudou, je ne vois pas trop...
    Bon, pas de panique, je vais me débrouiller autrement (bidouilles, bidouilles, mais c'est pas un tas de ferraille avec un peu d'électronique dedans qui va me résister : quand on ne peut pas passer par devant, on passe par derrière, c'est bien connu, )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      mss := TMemoryStream.Create;
      src.SaveToStream(mss);
      mss.Position := 54; // pour test rapide -- à affiner
      for h := 0 to src.Height-1 do begin
        //memo1.Lines.Add(IntToStr(h)+'  '+IntToStr(src.Width*3));
        for ws := 0 to (src.Width*3)-1 do
          memo1.Lines.Add(IntToStr(ws)+'  '+IntToStr(mss.ReadByte));
        // attention, le stream embarque le padding, méfi !
        p := 0; // ok pour skipper les bytes de padding
        while (((src.Width*3)+p) mod 4 <> 0) do begin mss.ReadByte; inc(p); end;
      end;
      mss.Free;
    Et avec ça, plus de 183 qui traîne dans le mémo,
    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
    0  191
    1  191
    2  127
    3  127
    4  191
    5  191
    6  191
    7  127
    8  191
    0  0
    1  139
    2  255
    3  255
    4  0
    5  255
    6  128
    7  128
    8  0
    Juste faire gaffe que les lignes sont à l'envers par rapport à l'affichage dans le TImage, mais bon.

    C'est mardi, ch'suis à la bourre, pas le temps de tester les couleurs mais le coup du stream ça me démangeait pour virer ce 183 (dont au final je ne saurai pas d'où il vient), donc voilà.

    À pluche,

  20. #20
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 940
    Billets dans le blog
    6
    Par défaut
    Est-il possible que le TRawImage code les pixels sur 4 octets alors qu'ils sont codés sur 3 octets dans le fichier ?
    Il faudrait s'en assurer avec son BytesPerPixel.
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Déplacer des fichiers Excel sous Windows avec SAS
    Par Antoun dans le forum Outils BI
    Réponses: 6
    Dernier message: 19/11/2009, 17h05
  2. [Vxi] liens avec des fichiers .jpg, bmp, ou gif
    Par chendo dans le forum Designer
    Réponses: 1
    Dernier message: 14/10/2009, 09h48
  3. Gestion des fichiers users sous linux
    Par darkvodka dans le forum C++
    Réponses: 2
    Dernier message: 29/09/2007, 19h04
  4. Créer et utiliser des fichiers excel sous linux
    Par cronos6 dans le forum Zope
    Réponses: 2
    Dernier message: 02/06/2006, 09h14
  5. Lire des fichiers iso sous linux
    Par wodel dans le forum Applications et environnements graphiques
    Réponses: 3
    Dernier message: 28/11/2005, 10h17

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