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 :

[Graphisme -- Linux] Travailler avec TBitmap.RawImage : l'enfer sur Terre [Lazarus]


Sujet :

Lazarus Pascal

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut [Graphisme -- Linux] Travailler avec TBitmap.RawImage : l'enfer sur Terre
    Bonsoir,

    j'ai passé toute la journée à essayer de copier un fichier .bmp à coups de GetLineStart et autres pByte et en fait, l'enfer est un paradis quand on compare avec une journée perdue avec Lazarus et RawImage...

    Promis, je vous la fais très courte :
    fichier source avec PixelFormat en 24 bits, et PixelFormat en 24 bits demandé pour le fichier destination, on pourrait se dire qu'il suffit de copier les bytes de la source dans la destination, mais non !
    Ça ne le fait pas : image destination aux trois quarts pleine de traits, et le dernier quart tout noir.
    Nom : copie_lena24_ratée.png
Affichages : 409
Taille : 129,5 Ko

    La journée dessus à essayer de comprendre ce qui pouvait bien se passer, jusqu'à ce que j'emploie les grands moyens, des ShowMessage partout :
    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
          dst.PixelFormat := pf24bit;
          dst.Width  := src.Width;
          dst.Height := src.Height;
    if src.PixelFormat=pf24bit then ShowMessage('24') else ShowMessage('32');
    if dst.PixelFormat=pf24bit then ShowMessage('24') else ShowMessage('32');
    // 24 deux fois = tutti va bene
    
          dst.BeginUpdate();
          CurrRowS := UInt(src.RawImage.GetLineStart(0));
          OffSetS  := UInt(src.RawImage.GetLineStart(1)) - CurrRowS;
          CurrRowD := UInt(dst.RawImage.GetLineStart(0));
          OffSetD  := UInt(dst.RawImage.GetLineStart(1)) - CurrRowD;
    ShowMessage(inttostr(offsetS)); // 720 fichier 240 de large x 3 px
    ShowMessage(inttostr(offsetD)); // 960 ! Soit 240 x 4. Pourquoi ? 
    // Catastrophe ! comme si le widgetset rajoutait un px
    // Après c'est les boucles classiques sur la hauteur et la largeur pour recopier les bytes de l'un vers l'autre.
    // Ai tenté de gérer le byte surnuméraire mais la catastrophe se déplace sans disparaître
    (Désolé, on dirait que la coloration syntaxique du code a sauté)

    Et le plus dément, c'est que le fichier résultant a, à la taille du header près (qui varie un poil [v4 pour la source, v1 pour la copie]), la même taille de datas. Donc le byte surnuméraire n'est pas enregistré, même s'il participe (par l'offset) au parcours de la zone de datas de la destination.

    Ça m'anéantit, ce genre de truc absolument pas documenté, qui m'aura coûté une journée, et que je ne vois pas comment contourner...

    Si quelqu'un a une idée, merci d'avance.
    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

  2. #2
    Membre chevronné

    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2012
    Messages
    1 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Retraité
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 035
    Points : 2 053
    Points
    2 053
    Par défaut
    Il semble que la destination veuille le canal alpha en plus soit 4 pixels par couleur mais le 4ème n'est pas pris en compte dans la profondeur de l'image qui reste en 24 bits. Essaie avec une image source en RGBA 24 bits.

    Pour tout arranger sous windows RGBA garde 24 bits par pixels contre 32 pour Linux

    http://wiki.freepascal.org/Fast_dire...itmap.RawImage

  3. #3
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Salut

    Ce qui est bizarre c'est qu'il n'y a pas de padding de fin de ligne

    As tu comparé les 2 RawImage.Description ?

    Je ne sais pas comment tu fais pour copier ton image, mais le code ci-dessous :

    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
    Unit Unit1;
     
    {$mode objfpc}{$H+}
     
    Interface
     
    Uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, ExtDlgs;
     
    Type
     
      { TForm1 }
     
      TForm1 = Class(TForm)
        Button1: TButton;
        Button2: TButton;
        Image1: TImage;
        Image2: TImage;
        OPD: TOpenPictureDialog;
        Procedure Button1Click(Sender: TObject);
        Procedure Button2Click(Sender: TObject);
        Procedure FormDestroy(Sender: TObject);
      private
     
      public
         SrcBmp, DstBmp : TBitmap;
      End;
     
    Var
      Form1: TForm1;
     
    Implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    Procedure TForm1.FormDestroy(Sender: TObject);
    Begin
        FreeAndNil(SrcBmp);
    end;
     
    Procedure TForm1.Button1Click(Sender: TObject);
    Begin
      if OPD.Execute then
      begin
        if not(Assigned(SrcBmp)) then SrcBmp := TBitmap.Create;
        SrcBmp.LoadFromFile(OPD.FileName);
        Image1.Picture.Bitmap.Assign(SrcBmp);
      End;
    end;
     
    Procedure TForm1.Button2Click(Sender: TObject);
    Var
      i, x,y : Integer;
      SrcPtr, DstPtr : PByte;
     
    Begin
      DstBmp := TBitmap.Create;
      DstBmp.PixelFormat := pf24bit;
      DstBmp.Width := SrcBmp.Width;
      DstBmp.Height := SrcBmp.Height;
     
     
      For y := 0 to SrcBmp.Height-1 do
      begin
        SrcPtr := SrcBmp.RawImage.GetLineStart(y);
        DstPtr := DstBmp.RawImage.GetLineStart(y);
        For x:=0 to SrcBmp.Width-1 do
        begin
          // 24 bits
          For i:=0 to 2 do  // ----> Copie les Valeur R+G+B
          Begin
             DstPtr^ := SrcPtr^;
             Inc(SrcPtr);
             Inc(DstPtr);
          End;
        End;
         // For i:=0 to 3 do -----> 32 bits
      End;
      Image2.Picture.Bitmap.Assign(DstBmp);
      FreeAndNil(DstBmp);
    end;
    Fonctionne parfaitement

    EDIT :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     CurrRowS := UInt(src.RawImage.GetLineStart(0)); // = 0 et sera toujours égal à zéro
     OffSetS  := UInt(src.RawImage.GetLineStart(1)) - CurrRowS;  // = 720 - 0 = 720
    Le pixelformat n'as pas l'air d'être initialisé correctement pour le bmp de destination, chez toi. Je vais testé sous linux pour comparé

    Citation Envoyé par mm_71 Voir le message
    Il semble que la destination veuille le canal alpha en plus soit 4 pixels par couleur mais le 4ème n'est pas pris en compte dans la profondeur de l'image qui reste en 24 bits. Essaie avec une image source en RGBA 24 bits.

    Pour tout arranger sous windows RGBA garde 24 bits par pixels contre 32 pour Linux

    http://wiki.freepascal.org/Fast_dire...itmap.RawImage
    Son image source est déja une image en 24bits j'ai la même, qui date de une de nos autres discussions
    • "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

  4. #4
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Je suis sous linux je viens de vérifier

    Il semble bien que la destination reste avec un pixelformat à pf24bit, mais dans le RawImage.Description.BitsPerPixel est définis à 32. C'est déconcertant et décourageant de telles erreurs à ce niveau.

    Du coup obliger de distinguer les pixelformats avec (DstBmp.RawImage.Description.BitsPerPixel
    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
    Procedure TForm1.Button2Click(Sender: TObject);
    Var
      i, x,y : Integer;
      SrcPtr, DstPtr : PByte;
     
    Begin
      DstBmp := TBitmap.Create;
      DstBmp.PixelFormat := pf24bit;
      DstBmp.Width := SrcBmp.Width;
      DstBmp.Height := SrcBmp.Height;
     
      For y := 0 to SrcBmp.Height-1 do
      begin
        SrcPtr := SrcBmp.RawImage.GetLineStart(y);
        DstPtr := DstBmp.RawImage.GetLineStart(y);
        For x:=0 to SrcBmp.Width-1 do
        begin
          For i:=0 to 2 do
          Begin
             DstPtr^ := SrcPtr^;
             Inc(SrcPtr);
             Inc(DstPtr);
          End;
          if (SrcBmp.RawImage.Description.BitsPerPixel = 24) and (DstBmp.RawImage.Description.BitsPerPixel = 32) then
          //  if (SrcBmp.PixelFormat = pf24bit) and (DstBmp.PixelFormat = pf32bit) then
          begin
            DstPtr^ := 255;
            Inc(DstPtr);
          end;
        End;
      End;
     
      Image2.Picture.Bitmap.Assign(DstBmp);
      FreeAndNil(DstBmp);
    end;
    • "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

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Citation Envoyé par mm_71 Voir le message
    Il semble que la destination veuille le canal alpha en plus soit 4 pixels par couleur mais le 4ème n'est pas pris en compte dans la profondeur de l'image qui reste en 24 bits.
    Mais c'est quoi cette pagaille ?
    Ai suivi ton lien (que j'avais déjà pratiqué en son temps, sans arriver à rien de définitif), ça part mal :
    Citation Envoyé par wiki
    Example assume that bitmap PixelFormat is pf24bit.
    C'est quoi ce PixelFormat qui n'est pas dans le tableau sous l'exemple ?
    Nom : tableau.png
Affichages : 365
Taille : 7,5 Ko

    Le Depth ? Dans GraphType (puisqu'il n'y a pas d'aide sur RawImage) je trouve
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        Depth: Byte; // used bits per pixel
        BitsPerPixel: Byte; // bits per pixel. can be greater than Depth.
    Mais rien pour expliquer plus. used, par qui ? Par quoi ? Pour quoi ?
    Donc quand je demande aBmp.PixelFormat c'est Depth qui vient, mais quand je me déplace dans la structure aBmp.RawImage.Data c'est BitsPerPixel qui est utilisé ?


    Par ailleurs, je vois comme une incohérence à écrire (1re ligne du tableau) RGBA et 24 Depth/BPP. Pas vous ?
    Citation Envoyé par mm_71 Voir le message
    Essaie avec une image source en RGBA 24 bits.
    Au-delà (pour moi !) de l'incohérence signalée juste au dessus, je n'ai pas ça en magasin, et Gimp n'est pas capable de générer cette incongruité,
    Et Jérome a répondu pendant que je planchais sur cette réponse.

    +++
    Citation Envoyé par BeanzMaster Voir le message
    Ce qui est bizarre c'est qu'il n'y a pas de padding de fin de ligne
    Dans la mesure où je comptais copier byte à byte, cette notion disparaît.

    Citation Envoyé par BeanzMaster Voir le message
    As-tu comparé les 2 RawImage.Description ?
    Non. Je n'ai aucune confiance dans ce RawImage, et le problème d'hier le confirme.
    Maintenant, c'est sûr que si aBmp.PixelFormat me renvoie des infos calculées depuis aBmp.RawImage, je suis marron.

    Citation Envoyé par BeanzMaster Voir le message
    Je ne sais pas comment tu fais pour copier ton image, mais le code ci-dessous [--snip--] fonctionne parfaitement.
    Je m'en doute.

    Pour copier, au tout début j'ai commencé avec ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
          dst.BeginUpdate();
          for h := 0 to src.Height - 1 do begin
            pbS := UInt(src.RawImage.GetLineStart(h));// pbS,pbD : pByte
            pbD := UInt(dst.RawImage.GetLineStart(h));
            for w := 0 to src.Width - 1 do pbD[w] := pbS[w];
          end;
          dst.EndUpdate();
    et là je me suis retrouvé avec mes traits.

    Après, tu sais comment c'est, tu pars dans toutes les directions, tu essayes tout et n'importe quoi en te frappant la tête contre les murs et en te disant "pourquoi, mais pourquoi ?" tout en pleurant toutes les larmes de ton corps les yeux rivés sur ce pbD[w] := pbS[w];, et voilà, quoi.

    Citation Envoyé par BeanzMaster Voir le message
    Le pixelformat n'as pas l'air d'être initialisé correctement pour le bmp de destination, chez toi.
    Parce que tu n'as pas bien lu le bout de code minable que j'ai posté et que j'améliore un peu, ça sera plus clair :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if src.PixelFormat=pf24bit then ShowMessage('24') else ShowMessage('32'); // vu 24
    if dst.PixelFormat=pf24bit then ShowMessage('24') else ShowMessage('32'); // vu 24
    // 24 deux fois = tutti va bene
    Citation Envoyé par BeanzMaster Voir le message
    Il semble bien que la destination reste avec un pixelformat à pf24bit, mais dans le RawImage.Description.BitsPerPixel est définis à 32. C'est déconcertant et décourageant de telles erreurs à ce niveau.
    Merci d'avoir confirmé ce point.

    Citation Envoyé par BeanzMaster Voir le message
    Du coup obliger de distinguer les pixelformats avec (DstBmp.RawImage.Description.BitsPerPixel
    Je garde ça dans un coin, mais en attendant, quelqu'un sait comment transformer le positionnement d'un déplacement de x bytes dans un fichier (offset récupéré dans le fichier sans utiliser RawImage) en pointeur pour parcourir rapidement la suite du fichier sans utiliser de stream (qui doit ralentir, je suppose) ?

    Annexe : partant de ce lien, il m'a fallu l'adapter mais ça a l'air de fonctionner et il y a dedans une ou deux choses intéressantes, genre
    I have only implemented support for "pf24bit" pixel format.

    In order to optimize code, I'm precalculating offset between scanlines to avoid too many calls to "ScanLine" as it may result in degraded performance. The other benefit of this approach is taking automatically into account byte padding in memory.
    :
    Nom : embarcadero.png
Affichages : 359
Taille : 59,5 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
    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
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    unit Unit1;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      {$IFDEF LINUX}
      BaseUnix, // timespec
      Linux, // clock_gettime
      {$ENDIF}
      LCLtype, LCLintf, Classes, SysUtils, FileUtil, Forms, Controls, Graphics,
      Math,
      Dialogs, ExtCtrls, StdCtrls;
     
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        Button1: TButton;
        Image1: TImage;
        Image2: TImage;
        Panel1: TPanel;
        rdg2: TRadioGroup;
        rdg1: TRadioGroup;
        procedure Button1Click(Sender: TObject);
        procedure rdg1SelectionChanged(Sender: TObject);
        procedure rdg2SelectionChanged(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    type
      TColor2Grayscale = (
        c2gAverage,
        c2gLightness,
        c2gLuminosity
      );
     
      TBitmapAccess = (
        baScanLine,
        baPixels
      );
     
    var
      c2g: TColor2Grayscale;
      ba : TBitmapAccess;
      R,G,B: byte;
     
    const
      ONE_OVER_MILLION = 1E-6; // micro
      ONE_OVER_MILLIER = 1E-3; // milli
     
    {$IFDEF LINUX}
    function GetTickCount64: QWord;
    var
      tp: timespec; // timespec record tv_sec seconds tv_nsec nanoseconds
    begin
      //clock_gettime(CLOCK_MONOTONIC, @tp); // orig
      clock_gettime(CLOCK_MONOTONIC_RAW, @tp);
      // multiplier les secondes par 1000 pour pouvoir y ajouter les millisec,
      // multiplier les secondes par 1000000 pour pouvoir y ajouter les microsec,
      // multiplier les secondes par 1000000000 pour pouvoir y ajouter les nanosec
      // du coup le "result" sera le nombre de nsec depuis le démarrage de la machine
      Result := (Int64(tp.tv_sec) * 1000000000) + int64(tp.tv_nsec);
    end;
    {$ENDIF}
     
    function RGBToGray(R, G, B: byte; cg: TColor2Grayscale): TColor;
    var
      res: Uint;
    begin
      case cg of
        c2gAverage:
          res := (R + G + B) div 3;
        c2gLightness:
          res := ( max(max(R, G), B) + min(min(R, G), B) ) div 2;
        c2gLuminosity:
          res := round(0.2989*R + 0.5870*G + 0.1141*B); // coeffs from Matlab
        else
          raise Exception.Create('Unknown Color2Grayscale value');
      end;
      Result := RGBtoColor(res,res,res);
    end;
     
    procedure ColorToGray(aBitmap: Graphics.TBitmap;
      cg: TColor2Grayscale;
      ba: TBitmapAccess);
    var
      w, h: UInt;
      x: byte;
      CurrRow, OffSet: UInt;
      pRed, pGreen, pBlue: PByte;
      StartTime, StopTime, Delta    :  QWord;
      BW,BH: integer;
    begin
      {$IFDEF LINUX}
      StartTime := GetTickCount64;
      {$ENDIF}
      BW := aBitmap.Width -1; //Prevent Repeated Calls to TBitMap.Width -- trouvé chez efg
      BH := aBitmap.Height-1; //Prevent Repeated Calls to TBitMap.Height
     
      if ba = baPixels then 
      begin
        if aBitmap <> nil then
          for h := 0 to BH do
            for w := 0 to BW do begin
              RedGreenBlue(aBitmap.Canvas.Pixels[w,h], R,G,B);
              aBitmap.Canvas.Pixels[w,h] := RGBToGray(R,G,B, cg);
            end;
      end
      else // ba = baScanLine 
      begin
        if aBitmap.PixelFormat <> pf24bit then
          raise Exception.Create(
            'Not implemented. PixelFormat has to be "pf24bit"');
        aBitmap.BeginUpdate();
        CurrRow := UInt(aBitmap.RawImage.GetLineStart(0));
        OffSet  := UInt(aBitmap.RawImage.GetLineStart(1)) - CurrRow;
        for h := 0 to BH do
        begin
          for w := 0 to BW do
          begin
            pBlue  := pByte(CurrRow + w*3);
            pGreen := pByte(CurrRow + w*3 + 1);
            pRed   := pByte(CurrRow + w*3 + 2);
            x := RGBToGray(pRed^, pGreen^, pBlue^, cg);
            pBlue^  := x;
            pGreen^ := x;
            pRed^   := x;
          end;
          inc(CurrRow, OffSet);
        end;
        aBitmap.EndUpdate();
      end;
      {$IFDEF LINUX}
      StopTime := GetTickCount64;
      Delta := StopTime - StartTime;
      Form1.Caption := FloatToStr(Delta * ONE_OVER_MILLIER) + ' microsecondes';
      {$ENDIF}
    end;
     
    { TForm1 }
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      image1.Picture.Bitmap.LoadFromFile(Application.Location + '150x100x24x72_v2.bmp');
      image2.Picture.Bitmap.Assign(image1.Picture.Bitmap);
      ColorToGray(image2.Picture.Bitmap, c2g, ba);
    end;
     
    procedure TForm1.rdg1SelectionChanged(Sender: TObject);
    begin
      case rdg1.ItemIndex of
        0: c2g := c2gAverage;
        1: c2g := c2gLightness;
        2: c2g := c2gLuminosity;
      end;
    end;
     
    procedure TForm1.rdg2SelectionChanged(Sender: TObject);
    begin
      case rdg2.ItemIndex of
        0: ba := baScanLine;
        1: ba := baPixels;
      end;
    end;
     
    end.
    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. #6
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Ok je viens de mettre un point d'arrêt sur DstBmp := TBitmap.CreateVoici les descriptions la première après le chargement de l'image

    Nom : Screenshot_20180729_113628.jpeg
Affichages : 367
Taille : 42,6 Ko

    Et le deuxième après la création du bitmap DstBmp.Height := SrcBmp.Height
    Nom : Screenshot_20180729_113654.jpeg
Affichages : 362
Taille : 42,5 Ko

    Je suis remonter jusqu'a function TGtk2WidgetSet.RawImage_DescriptionFromDrawable(out ADesc: TRawImageDescription; ADrawable: PGdkDrawable; ACustomAlpha: Boolean ): boolean; dans lazarus/lcl/interfaces/gtk2/gtk2widgetset.inc
    Ligne 3009 à 3026 environ à grand coup de F7

    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
     // Depth
      if IsBitmap
      then ADesc.Depth := 1
      else ADesc.Depth := Visual^.Depth;
     
      if IsBitmap or (Visual^.byte_order = GDK_MSB_FIRST)
      then ADesc.ByteOrder := riboMSBFirst
      else ADesc.ByteOrder := riboLSBFirst;
     
      ADesc.LineOrder := riloTopToBottom;
     
      case ADesc.Depth of
        0..8:   ADesc.BitsPerPixel := ADesc.Depth;
        9..16:  ADesc.BitsPerPixel := 16;
        //--------------- Correction -------------------------------
        //17..24 : ADesc.BitsPerPixel := 24
        // plus, ou seulement la ligne suivante
        //25..32 : ADesc.BitsPerPixel := 32
        //-------------------------------------------------------------
        17..32: ADesc.BitsPerPixel := 32; //===========> C'est la que le problème commence <===================
      else
        ADesc.BitsPerPixel := 64;
      end;
    Je continue toujours dans la même fonction je tombe sur ce petit truc qui m'interpelle, et qui n'a rien à voir :

    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
      else begin
        // Try retrieving the lineend
        Image := gdk_image_new(GDK_IMAGE_NORMAL, Visual, 1, 1);
        if Image = nil
        then begin
          DebugLn('TGtk2WidgetSet.GetWindowRawImageDescription testimage creation failed ');
          Exit(False);
        end;
        try
          // the minimum alignment we can detect is bpp
          // that is no problem since a line consists of n x bytesperpixel bytes
          case Image^.bpl of
            1: ADesc.LineEnd := rileByteBoundary;
            2: ADesc.LineEnd := rileWordBoundary;
            4: ADesc.LineEnd := rileDWordBoundary;
            8: ADesc.LineEnd := rileQWordBoundary;
           // ========> pas de 24 bits alors qu'on sait qu'il peut y avoir un padding de fin de ligne. Quid ??????? un oublis ??? <===============================
          else
            DebugLn('TGtk2WidgetSet.GetWindowRawImageDescription Unknown line end: %d', [Image^.bpl]);
            Exit(False);
          end;
        finally
          gdk_image_destroy(Image);
          Image := nil;
        end;
    Conclusion le PixelFormat n'es pas prise en compte sous Linux. Je referrai la même manip sous windows pour comparer.

    Puis dans function TGtk2WidgetSet.RawImage_QueryDescription(AFlags: TRawImageQueryFlags; var ADesc: TRawImageDescription): Boolean; dans lazarus/lcl/interfaces/gtk2/gtk2lclIntf.inc ligne 620 :

    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
      if riqfRGB in AFlags then
      begin
        ADesc.Format := ricfRGBA;
        ADesc.Depth := Desc.Depth;
        ADesc.BitOrder := Desc.BitOrder;
        ADesc.ByteOrder := Desc.ByteOrder;
        ADesc.LineOrder := Desc.LineOrder;
        ADesc.LineEnd := Desc.LineEnd;
        ADesc.BitsPerPixel := Desc.BitsPerPixel; //==========> Il à été définis à 32 bits et non à 24 la propriété TBitmap.pixelFormat n'est pas prise en compte <======================
        ADesc.RedPrec := Desc.RedPrec;
        ADesc.RedShift := Desc.RedShift;
        ADesc.GreenPrec := Desc.GreenPrec;
        ADesc.GreenShift := Desc.GreenShift;
        ADesc.BluePrec := Desc.BluePrec;
        ADesc.BlueShift := Desc.BlueShift;
      end;
    Voili voilou. Pour du Cross-compile c'est quand même bien embêtant ce genre de truc. On se prend la tête avec des "petites bétises" pour ne pas être vulgaire.
    • "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

  7. #7
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Jipété Voir le message
    ...
    mais en attendant, quelqu'un sait comment transformer le positionnement d'un déplacement de x bytes dans un fichier (offset récupéré dans le fichier sans utiliser RawImage) en pointeur pour parcourir rapidement la suite du fichier sans utiliser de stream (qui doit ralentir, je suppose) ?
    Avec un fichier BMP ou juste fichier contenant les données de l'image ?

    DataStartPosition = Taille fichier BMP - Taille de l'entête - GapSize.

    Ou sinon plus simple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      TBMPFileHeader = Packed Record   // < Taille de l'en-tête commune 14 octets
        bfType: Array[0..1] Of Char; // Signature 
        bfSize: Longword;   // Taille totale du fichier
        bfReserved1: Word;  // Hospot X -> OS2x
        bfReserved2: Word;  // Hospot Y -> OS2x
        bfOffBits: Longword; // Position des données de l'image dans le fichier
      End;
     
    DataStartPosition = BMPFileHeader.bfOffBits;
    Si non dans le deuxième cas

    DataStartPosition = 0

    PositionX va de 0 à IMAGE_WIDTH - 1
    PositionY va de 0 à IMAGE_HEIGHT - 1
    PIXEL_SIZE suivant pixelformat :
    pf24bit PIXEL_SIZE = 3
    pf32bit PIXEL_SIZE = 4

    GetScanlineOffset = DataStartPosition + (PostionY * (IMAGE_WIDTH*PIXEL_SIZE)
    GetOffsetAtXY = DataStartPosition + (((PostionY * IMAGE_WIDTH) + PostionX)*PIXEL_SIZE)


    Citation Envoyé par Jipété Voir le message
    Annexe : partant de ce lien, il m'a fallu l'adapter mais ça a l'air de fonctionner et il y a dedans une ou deux choses intéressantes, genre :
    Je vais pouvoir vérifier un truc avec GetTickCount
    • "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

  8. #8
    Membre chevronné

    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2012
    Messages
    1 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Retraité
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 035
    Points : 2 053
    Points
    2 053
    Par défaut
    Son image source est déja une image en 24bits j'ai la même, qui date de une de nos autres discussions
    Ce que je voulais dire c'est qu'une image RGB depth 24 bits utilise 3 pixels. Une image RGBA sous Linux Gtk2 en utilise 4 mais depth reste à 24 bits.
    Il est donc possible que pour une mystérieuse raison la copie veuille rajouter un canal alpha et que ça fasse tout foirer.
    Vu aussi ton message plus bas ou bitsperpixel et défini à 32 par défaut et ça semble confirmer la chose, le dpeth de l'image ne reflète pas forcément le nombre de bits par pixel.

  9. #9
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par mm_71 Voir le message
    Ce que je voulais dire c'est qu'une image RGB depth 24 bits utilise 3 pixels. Une image RGBA sous Linux Gtk2 en utilise 4 mais depth reste à 24 bits.
    Il est donc possible que pour une mystérieuse raison la copie veuille rajouter un canal alpha et que ça fasse tout foirer.
    Vu aussi ton message plus bas ou bitsperpixel et défini à 32 par défaut et ça semble confirmer la chose, le dpeth de l'image ne reflète pas forcément le nombre de bits par pixel.
    Oui, le problème c'est qu'entre Windows et Linux. Sous winows le rawimage.Description du bitmap de destination est correcte. Le pixelformat demandé est bien 24bits. Il devrait être identique sur les deux plateformes Y'a pas photo.

    J'ai essayé de faire ma correction marqué plus haut


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      case ADesc.Depth of
        0..8:   ADesc.BitsPerPixel := ADesc.Depth;
        9..16:  ADesc.BitsPerPixel := 16;
        17..32: ADesc.BitsPerPixel := 32;
      else
        ADesc.BitsPerPixel := 64;
      end;
      if ADesc.Depth = 24 then ADesc.BitsPerPixel := 24;

    Cela ne suffit pas et l'affichage est en vrac

    Plus haut dans le code il y a :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      // Depth
      if IsBitmap
      then ADesc.Depth := 1
      else ADesc.Depth := Visual^.Depth;
    et un peu plus haut encore

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
      if ADrawable = nil
      then begin
        Visual := gdk_visual_get_system;
        IsBitmap := False;
      end
      else begin
        gdk_drawable_get_size(ADrawable, @Width, @Height);
        Depth := gdk_drawable_get_depth(ADrawable);
        Visual := gdk_window_get_visual(ADrawable);
        // ============= > pixmaps and bitmaps do not have a visual, but for pixmaps we need one <=============
        if Visual = nil  then Visual := gdk_visual_get_best_with_depth(Depth);
     
        IsBitmap := Depth = 1;
      end;
    La fonction gdk_visual_get_best_with_depth(Depth); est peut-être le fautif

    Voila mes infos systeme

    Nom : Screenshot_20180729_132717.jpeg
Affichages : 381
Taille : 40,1 Ko
    • "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

  10. #10
    Membre chevronné

    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2012
    Messages
    1 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Retraité
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 035
    Points : 2 053
    Points
    2 053
    Par défaut
    Voila mes infos systeme...
    Et moi dans les logs nvidia linux mint 18.3 j'ai:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    23.232] (**) NVIDIA(0): Depth 24, (--) framebuffer bpp 32
    23.232] (==) NVIDIA(0): RGB weight 888
    .............
    23.937] (--) Depth 24 pixmap format is 32 bpp
    Cela semble confirmer que depth 32 n'existe pas vraiement sous Linux et que ce soit traduit par depth 24 + alpha.

    En entrée on peut savoir à quoi on a affaire selon que le résultat de la division du nombre de pixels par ligne par 3 ou 4 donne un résultat entier mais en sortie ?

    Et dans le message de jipété 29/07 00:53 si on remplace

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    dst.PixelFormat := pf24bit;
    par
    dst.PixelFormat := pf32bit;
    Ça fait quoi ?

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Citation Envoyé par mm_71 Voir le message
    Et dans le message de jipété 29/07 00:53 si on remplace

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    dst.PixelFormat := pf24bit;
    par
    dst.PixelFormat := pf32bit;
    Ça fait quoi ?
    Pas tenté car cela ne pouvait pas me venir à l'esprit, au contraire, puisque Gimp est capable de générer des fichiers 24 bpp. Alors pourquoi pas nous ?
    J'avais dans la tête quelque chose du genre "si tu copies les 3 bytes R, G, B, tu vas les retrouver en sortie" et j'avoue avoir, au début, un peu zappé cette histoire que je pensais plus liée à l'affichage qu'à la structure du fichier lui-même.
    Après tout, quand je vais à la photocopieuse et que je lui fais manger les 10 pages d'un rapport, je retrouve en sortie 10 pages copiées et non pas 3+1 + 3+1 +3+1 +1(+ 3 ? pour faire un compte rond ?)

    C'est dans quel fichier de log tes infos ?
    Et Jérome, c'est quelle commande que tu as lancée pour avoir les infos du serveur X ?
    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

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

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par http://wiki.freepascal.org/Developing_with_Graphics
    Besides these there are also non-native drawing classes located in the units graphtype (TRawImage), intfgraphics (TLazIntfImage) and lazcanvas (TLazCanvas, this one exists in Lazarus 0.9.31+). TRawImage is the storage and description of a memory area which contains an image. TLazIntfImage is an image which attaches itself to a TRawImage and takes care of converting between TFPColor and the real pixel format of the TRawImage. TLazCanvas is a non-native Canvas which can draw to an image in a TLazIntfImage.
    //...
    TBitmap.RAWImage - allows to directly access bitmap internal memory. Color channels can be swapped for some platforms so ReadChannels and WriteChannels need to be used to convert pixel color to TColor or TFPColor correctly. Or pixel data can be accessed directly with respect to TRAWImage.Description.
    Si je comprends bien, TRawImage est une forme de stockage en mémoire d'une image, d'où l'utilité de passer de 24 à 32 bits pour FPC, pour accélérer ou standardiser des traitements, mais c'est TLazIntfImage qui y donne accès en tant qu'image. Ceci ne garantit pas l'identité de format entre plusieurs images apparemment créées identiquement. Surtout entre des plateformes différentes.
    Pour le cas de JP, pour être sûr, charger le BitMap dans les 2 objets Source et Destination devrait permettre d'avoir la même structure de ligne et copier ensuite ligne par ligne aisément.
    Reste le problème de détecter le format interne de stockage de façon fiable. Si la Description ne l'est pas... mais je n'ai pas analysé en détail vos échanges !
    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 !

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Yves,
    Citation Envoyé par tourlourou Voir le message
    Pour le cas de JP, pour être sûr, charger le BitMap dans les 2 objets Source et Destination devrait permettre d'avoir la même structure de ligne et copier ensuite ligne par ligne aisément.
    J'avais commencé par là et il m'a rapidement fallu déchanter...

    Citation Envoyé par tourlourou Voir le message
    Reste le problème de détecter le format interne de stockage de façon fiable. Si la Description ne l'est pas... mais je n'ai pas analysé en détail vos échanges !
    Ou alors c'est un problème de terminologie, de la manière dont on appelle les choses ?
    Mais comme l'aide est en dessous de tout (le nombre de fois que j'aurais écrit cette phrase, depuis 5 ou 6 ans, c'est impressionnant ), on ne sait pas ce qu'on manipule, il faut faire des essais à n'en plus finir, c'est tuant.
    Pi quand tu changes d'environnement faut tout recommencer parce que le rouge devient bleu ou une image normale se retrouve pleine de traits, bref...

    C'est dommage parce que ça,
    Or pixel data can be accessed directly with respect to TRAWImage.Description.
    , ça fait rêver mais bon, je vais passer par les streams, après une petite analyse des datas du BitmapFileHeader et dans une moindre mesure son acolyte le BitmapInfoHeader, je saurai ex-ac-te-ment où je mets les mains.

    Bon, là je plie, j'en ai ma claque.
    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

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

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    après une petite analyse des datas du BitmapFileHeader et dans une moindre mesure son acolyte le BitmapInfoHeader, je saurai ex-ac-te-ment où je mets les mains
    Incertain ! Ce n'est vrai que pour la structure du fichier ; pas pour celle de ses représentations en mémoire, dont l'endianité peut être différente, voire (je suppose) le nombre d'octets utilisés par pixel, l'expérience prouvant que ce n'est pas toujours le cas, ou qu'il est délicat de créer un BitMap selon ses souhaits les plus intimes !
    Après tout, pourquoi ne pas travailler avec un fichier chargé dans un MemoryStream, en accédant aux pixels d'après le pointeur Memory, et en calculant les offsets des lignes et des pixels d'après les données des headers ?
    Pour l'affichage, il suffirait de charger le flux dans un TImage.
    L'avantage de travailler sur un format fichier serait de se passer des traductions imposées par le langage et l'OS, voire le moteur graphique.
    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 !

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Citation Envoyé par tourlourou Voir le message
    Après tout, pourquoi ne pas travailler avec un fichier chargé dans un MemoryStream, en accédant aux pixels d'après le pointeur Memory, et en calculant les offsets des lignes et des pixels d'après les données des headers ?
    Pour l'affichage, il suffirait de charger le flux dans un TImage.
    Yes ! Je me suis sans doute mal exprimé dans mon précédent post (la chaleur c'est dément...), mais c'est tout-à-fait ça que je vise.
    En gros je refais un éditeur hexa (j'en ai tellement vu d'images, postées ici bien souvent) à ma sauce (ça va plaire à Jérome, ça ) mais au lieu d'afficher des traductions ascii, je regroupe les bytes et je fais afficher des pixels coloriés,

    Courage, on y arrivera.
    Juste besoin d'une précision (c'est le mot qui me fait tilter, tu aurais utilisé "compteur", "index" ou similaire je n'aurais pas relevé) : qu'est-ce que tu appelles
    Citation Envoyé par tourlourou Voir le message
    pointeur Memory
     ? Qu'est-ce qui se cache là-dessous ? Un vrai pointeur (auquel cas ça va speeder mais faut pas se louper sinon gare aux AV !), ou un bête compteur ? Un exemple ?

    (j'ai déjà la première partie meulée, la plus facile : src et dst à 24 bpp ou src et dst à 32 bpp1, c'est simple, c'est la même routine qui fait ça

    Plus que les deux autres, où il va falloir jouer avec le padding, alors je me les garde pour le matin à la fraîche, )
    ---
    1 : sauf qu'avec RawImage c'était l'horreur.
    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

  16. #16
    Expert confirmé
    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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Yes ! Je me suis sans doute mal exprimé dans mon précédent post (la chaleur c'est dément...), mais c'est tout-à-fait ça que je vise.
    En gros je refais un éditeur hexa (j'en ai tellement vu d'images, postées ici bien souvent) à ma sauce (ça va plaire à Jérome, ça ) mais au lieu d'afficher des traductions ascii, je regroupe les bytes et je fais afficher des pixels coloriés,


    Citation Envoyé par Jipété Voir le message
    Courage, on y arrivera.
    Juste besoin d'une précision (c'est le mot qui me fait tilter, tu aurais utilisé "compteur", "index" ou similaire je n'aurais pas relevé) : qu'est-ce que tu appelles  ? Qu'est-ce qui se cache là-dessous ? Un vrai pointeur (auquel cas ça va speeder mais faut pas se louper sinon gare aux AV !), ou un bête compteur ? Un exemple ?
    pointeur Memory = Dans TMemoryStream tu as une propiété "Memory" de type PByte

    Citation Envoyé par Jipété Voir le message
    (j'ai déjà la première partie meulée, la plus facile : src et dst à 24 bpp ou src et dst à 32 bpp1, c'est simple, c'est la même routine qui fait ça

    Plus que les deux autres, où il va falloir jouer avec le padding, alors je me les garde pour le matin à la fraîche, )
    ---
    1 : sauf qu'avec RawImage c'était l'horreur.
    Le plus dur n'est pas lire les donnée ici mais d'écrire les donnée dans RawImage correctement et en plus cela fonctionne différemment suivant l'OS. une vrai plaie !

    J'ai vérifié le cheminement sous Windows

    Citation Envoyé par mm_71 Voir le message
    Ce que je voulais dire c'est qu'une image RGB depth 24 bits utilise 3 pixels. Une image RGBA sous Linux Gtk2 en utilise 4 mais depth reste à 24 bits.
    Il est donc possible que pour une mystérieuse raison la copie veuille rajouter un canal alpha et que ça fasse tout foirer.
    Vu aussi ton message plus bas ou bitsperpixel et défini à 32 par défaut et ça semble confirmer la chose, le dpeth de l'image ne reflète pas forcément le nombre de bits par pixel.
    Depth est correcte, (c'est une longue histoire avec RawImage) le depth est en 24bits car l'image est en 24 bits et donc pas d'alpha
    C'est BitsPerPixel qui est incorrecte il devrait aussi être à 24.
    Normalement on lui demande de créer par défaut un bitmap se basant sur les capacité d'affichage (pfDevice)

    Que l'on soit sous Windows ou Linux BitperPixels devrait être égale à 24. Je comprend très bien la différence entre Depth et BitperPixels.

    "Write Once, Compile Every Where !!!" Que l'on soit sur Linux, Windows, Mac on est dans l'attente à ce qu'un simple "BMP := TBitmap.Create" retourne les mêmes valeurs quelque soit 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
    function TWin32WidgetSet.RawImage_DescriptionFromDevice(ADC: HDC; out ADesc: TRawImageDescription): Boolean;
    var
      DC: HDC;
    begin
      Result := True;
     
      ADesc.Init;
     
      if ADC = 0
      then DC := Windows.GetDC(0)
      else DC := ADC;
     
      ADesc.Format := ricfRGBA;
      ADesc.Width := Windows.GetDeviceCaps(DC, HORZRES);
      ADesc.Height := Windows.GetDeviceCaps(DC, VERTRES);
      ADesc.Depth := Windows.GetDeviceCaps(DC, BITSPIXEL) * Windows.GetDeviceCaps(DC, PLANES);
      ADesc.BitOrder := riboReversedBits;
      ADesc.ByteOrder := riboLSBFirst;
      ADesc.LineOrder := riloTopToBottom;
      ADesc.LineEnd := rileDWordBoundary;
      ADesc.BitsPerPixel := ADesc.Depth; //-----------------> PixelFormat depuis le depth, donc bien 24  <-----------------------------

    Sous Linux le format est-il volontairement mis à 32bits par pixel avec GTK

    pour afficher une image on peut trouver ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        gdk_draw_rgb_32_image(TGTKDeviceContext(Canvas.Handle).Drawable,
                            TGTKDeviceContext(Canvas.Handle).GC, R.Left, R.Top, ABmp.Width, ABmp.Height, //(R.Right-R.Left), (R.Bottom-R.Top), //???
                            GDK_RGB_DITHER_NORMAL,
                            PByte(ABmp.getSurfaceBuffer),ABmp.Width*4);
    gdk_draw_rgb_32 donc pixelformat = pour les images 24, et 32 = 32 ?????

    Pour les images 16 bits et inférieure , on n'utilise pas gdk_draw_rgb_32 ? pour l'affichage ? si non pourquoi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    case ADesc.Depth of
        0..8:   ADesc.BitsPerPixel := ADesc.Depth;
        9..16:  ADesc.BitsPerPixel := 16;
    Il y a quand même quelques chose qui m'échappe, Pourquoi en forçant ADesc.BitsPerPixel := 24

    Dans GTk2Widgetset.inc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      case ADesc.Depth of
        0..8:   ADesc.BitsPerPixel := ADesc.Depth;
        9..16:  ADesc.BitsPerPixel := 16;
        17..32: ADesc.BitsPerPixel := 32;
      else
        ADesc.BitsPerPixel := 64;
      end;
      if ADesc.Depth = 24 then ADesc.BitsPerPixel := 24;  //------> Force à utiliser le format 24 bits
    provoque une erreur ? Dans lclproc

    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
    {------------------------------------------------------------------------------
      procedure RaiseGDBException(const Msg: string);
     
      Raises an exception.
      Normally gdb does not catch fpc Exception objects, therefore this procedure
      raises a standard "division by zero" exception which is catched by gdb.
      This allows one to stop a program, without extra gdb configuration.
     ------------------------------------------------------------------------------}
    procedure RaiseGDBException(const Msg: string);
    begin
      debugln(rsERRORInLCL, Msg);
      // creates an exception, that gdb catches:
      debugln(rsCreatingGdbCatchableError);
      DumpStack;
      {$ifndef HASAMIGA} // On Amiga Division by 0 is not catchable, just crash
      if (length(Msg) div (length(Msg) div 10000))=0 then ;   ----> SIGFPE ICI DIVISION PAR ZERO ??????? 
     
      {$endif}
    end;
    si il y a lieu d'avoir une conversion 24 --> 32 bits sous Unix. Cela ne devrait pas être à nous de nous en chargé

    En commentant "if (length(Msg) div (length(Msg) div 10000))=0 then " Ca passe et le rawimage. description est correcte le "BitPerPixel" et le "pixelformat" sont bien à 24 bits. Mais l'affichage est foireux
    Nom : Screenshot_20180729_200057.jpeg
Affichages : 379
Taille : 44,2 Ko

    Le soucis et le choix du "BitsPerPixel" provient donc de la façon dont l'affichage d'une image est réalisé en fonction de l'OS.
    Maintenant il faudrait donc modifier certaine partie de la LCL mais faudrais déja trouvé ou. Et je n'ai pas trop de temps pour ça.
    Il devrait être possible d'obtenir quelques choses d'homogène entre Linux GTK et Windows. Faudrait testé avec QT pour voir si il y a également une différence avec ce "pixelformat" et le "BitsPerPixel"
    • "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 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
    Points : 4 346
    Points
    4 346
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Et Jérome, c'est quelle commande que tu as lancée pour avoir les infos du serveur X ?
    Ourils KDE --> KInfoCenter
    • "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

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 730
    Points : 15 132
    Points
    15 132
    Par défaut
    Citation Envoyé par BeanzMaster Voir le message
    pointeur Memory = Dans TMemoryStream tu as une propriété "Memory" de type PByte

    Le plus dur n'est pas lire les données ici mais d'écrire les donnée dans RawImage correctement et en plus cela fonctionne différemment suivant l'OS. une vrai plaie !
    OK merci.
    Je m'en dépatouillerai quand j'aurai réglé le problème d'affichage (lire tout en bas), et je vous rassure, les copies 1/1 (ou plutôt, 24/24 ou 32/32) génèrent des fichiers parfaits,

    Citation Envoyé par BeanzMaster Voir le message
    Il y a quand même quelques chose qui m'échappe, Pourquoi en forçant ADesc.BitsPerPixel := 24

    Dans GTk2Widgetset.inc
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
      case ADesc.Depth of
        0..8:   ADesc.BitsPerPixel := ADesc.Depth;
        9..16:  ADesc.BitsPerPixel := 16;
        17..32: ADesc.BitsPerPixel := 32;
      else
        ADesc.BitsPerPixel := 64;
      end;
      if ADesc.Depth = 24 then ADesc.BitsPerPixel := 24;  //------> Force à utiliser le format 24 bits
    provoque une erreur ? Dans lclproc

    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
    {------------------------------------------------------------------------------
      procedure RaiseGDBException(const Msg: string);
     
      Raises an exception.
      Normally gdb does not catch fpc Exception objects, therefore this procedure
      raises a standard "division by zero" exception which is catched by gdb.
      This allows one to stop a program, without extra gdb configuration.
     ------------------------------------------------------------------------------}
    procedure RaiseGDBException(const Msg: string);
    begin
      debugln(rsERRORInLCL, Msg);
      // creates an exception, that gdb catches:
      debugln(rsCreatingGdbCatchableError);
      DumpStack;
      {$ifndef HASAMIGA} // On Amiga Division by 0 is not catchable, just crash
      if (length(Msg) div (length(Msg) div 10000))=0 then ;   ----> SIGFPE ICI DIVISION PAR ZERO ??????? 
     
      {$endif}
    end;
    si il y a lieu d'avoir une conversion 24 --> 32 bits sous Unix. Cela ne devrait pas être à nous de nous en charger

    En commentant "if (length(Msg) div (length(Msg) div 10000))=0 then " Ca passe et le rawimage.description est correct, le "BitPerPixel" et le "pixelformat" sont bien à 24 bits. Mais l'affichage est foireux
    Je t'en ai déjà parlé : c'est une erreur de division par zéro forcée : Normally gdb does not catch fpc Exception objects, oui, je sais, l'anglais et toi vous n'êtes pas copains, donc normalement GDB ne peut pas "attraper" les exceptions des objets FPC, donc "ils" forcent cette erreur pour qu'on puisse aller voir. Quoi et où, l'histoire ne le dit pas,
    Peut-être en utilisant l'affichage de la pile d'appels ?

    Citation Envoyé par BeanzMaster Voir le message
    Le soucis et le choix du "BitsPerPixel" provient donc de la façon dont l'affichage d'une image est réalisé en fonction de l'OS.
    Maintenant il faudrait donc modifier certaines parties de la LCL mais faudrait déja trouver où. Et je n'ai pas trop de temps pour ça.
    Il devrait être possible d'obtenir quelque chose d'homogène entre Linux GTK et Windows. Faudrait tester avec QT pour voir si il y a également une différence avec ce "pixelformat" et le "BitsPerPixel"
    Oui, enfin, c'est pas trop à nous de mettre les mains dans le cambouis à ce niveau-là de profondeur, je crois.

    Suffisamment à faire avec ce qu'on découvre au quotidien, et là ça fait deux heures que je suis dessus mais faire afficher un TImage dans un TPanel génère une différence de positionnement à gauche de 1 px et de largeur de 2 px si la source des pixels est un TLazIntfImage, par rapport à un bête TBitmap...

    Un truc de malade avec peut-être une copie d'écran (mais + tard).
    Je ne m'en sortirai pas de ces machins de malades...
    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

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

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

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 858
    Points : 11 301
    Points
    11 301
    Billets dans le blog
    6
    Par défaut
    @Jipété : coucou, voici un petit exemple d'utilisation de pointeur en récupérant celui de la zone mémoire du flux :
    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
    procedure TForm1.Button1Click(Sender: TObject);
    var
      Flux: TMemoryStream;
      P: PChar;
      F, D1, SourceDir, SourceFile: string;
      FileInfos: TSearchRec;
    begin
      Flux:=TMemoryStream.Create;
      SourceDir:='E:\Documents\InfoProjects\iPhone Croatie été 2018';
      PosDate := 202;
      i:=FindFirst(SourceDir+'\*.JPG', faAnyFile, FileInfos);
      while i=0
      do begin
        SourceFile:=FileInfos.Name;
        F:=SourceDir+'\'+SourceFile;
        Flux.LoadFromFile(F);
        P:=Flux.Memory; // je récupère le pointeur sur la zone mémoire du flux
        Inc(P, PosDate); // je l'avance à la date EXIF
        D1:=StrPas(P);
        SetLength(D1, 19); // car #0 en 20ème position
    Pour des données, ça ne va pas forcément plus vite que de récupérer par un BlockRead après avoir affecté Position, mais ça permet de se servir de l'arithmétique des pointeurs si on l'affecte à un PRGBArray, par exemple.
    On peut aussi faire ses propres méthodes qui mettront la bonne endianité, ou convertiront un pixel 32 bits en pixel 24 bits ou autre.
    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 !

  20. #20
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    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 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Je ne m'en sortirai pas de ces machins de malades...
    Moi avec C++/ Delphi Embarcadero j'avais trouvé le truc : utiliser Graphics32 (*) qui propose un TImage32 dont tu as un accès rapide à sa mémoire (via scanline si je ne dis pas de bêtises, c'est à dire sans mutex)

    Et ensuite, moi c'était différent par rapport à vous parce que je n'avais pas besoin d'ouvrir d'images externes : que des images embarquées des .pam compressées en .bz2 et sans entête (que les données brutes en somme)
    Et j'avais trouvé sur StackOverflow l'algo pour afficher 2 surfaces (1 en dessous, 1 au dessus) avec des transparences différentes

    Avec mon approche , il faudrait faire comme soit BeanzMaster et coder tous les algos format image soit faire confiance aux bibliothèques reconnues (libpng, libtiff, ...)


    * -> La documentation de Graphics32 est tout aussi dégueulasse parce qu'il y a une histoire de couches (layers), dont la documentation te vante leurs mérites, mais je n'ai jamais trouvé un code complet qui les utilisent

    ** -> Le seul problème des TImage32 elles utilisent des "lazy initialisation" Des fois, il ne faut pas l'oublier et et des fois c'est prise de tête de faire cette initialisation entre la création du composant que tu ne maîtrises pas trop et la première utilisation.

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

Discussions similaires

  1. [Lazarus] Impossible de travailler correctement en 32 bits avec TBitmap
    Par Jipété dans le forum Lazarus
    Réponses: 35
    Dernier message: 26/09/2017, 15h51
  2. Travailler avec un contrôle checkbox activeX sur une feuille de calcul
    Par Pounet95 dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 25/01/2016, 19h59
  3. Ouvrir le poste de travail (avec ShellExecute) ?
    Par benj63 dans le forum C++Builder
    Réponses: 4
    Dernier message: 17/08/2003, 11h09
  4. Documentation sur la manière de travailler avec le XML en java
    Par DelPiero62 dans le forum Format d'échange (XML, JSON...)
    Réponses: 8
    Dernier message: 26/03/2003, 09h16
  5. Travailler avec des bits
    Par Vulvulune dans le forum Langage
    Réponses: 5
    Dernier message: 02/03/2003, 19h09

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