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 :

GetLineStart (équiv. ScanLine) : Access Violation sous Windows, pas sous Linux [Lazarus]


Sujet :

Lazarus Pascal

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 998
    Points : 15 482
    Points
    15 482
    Par défaut GetLineStart (équiv. ScanLine) : Access Violation sous Windows, pas sous Linux
    Bonjour,

    encore un truc à péter les plombs et à y passer des heures et des heures...

    Je vous ai préparé une jolie copie d'écran d'un bout de code rodé et éprouvé sous Linux avec Laz 1.4 et qui me génère un Access Violation sous XP avec Laz 1.6 je vous raconte pas !
    Enfin si, je vous explique :

    Nom : sigsegv.jpg
Affichages : 387
Taille : 50,7 Ko

    Ça se passe sur la ligne suivant celle en rouge, là où l'on trouve l'équivalent du ScanLine et qui d'habitude fonctionne du feu de Dieu mais cette fois, est-ce dû au fait que 2 lignes au-dessus je fais un autre "ScanLine" dans un autre Bitmap ?, toujours est-il que je me prends ligne 57 un AV qui fait peur, dans le sens où d'habitude sous Windows quand il n'y a qu'un seul GetLineStart il n'y a pas de souci (sinon je serais déjà venu pleurer ici, vous vous en doutez bien ), et surtout, surtout, ce code ne pose aucun problème sous Linux.

    Qu'est-ce que je dois faire ? C'est vraiment désespérant car je suis bloqué de chez bloqué sur ça : je ne vois pas par quoi je pourrais remplacer un code qui fonctionne...

    Ah, je réalise à l'instant que non, ce n'est pas une histoire d'imbrication, voilà avec quoi j'ai bien bossé hier sans aucun souci sous Linux, et qui me génère également un AV au bout d'une vingtaine d'entrées dans le TMemo de contrôle en fin de proc (ligne 40) sous Windows (on se demande, des fois, si on ne marche pas sur la tête ) : il n'y a qu'un seul Bitmap, dans un premier temps je le remplis avec des couleurs aléatoires, et dans un second temps je relis ses pixels pour en extraire la valeur numérique et mettre ça dans un mémo (maquette de test pour un autre projet)
    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
    const
      IMAGE_WIDTH  = 32;
      IMAGE_HEIGHT = 32;
     
    FUNCTION RGBAtoQuadBGRA(CONST red, green, blue, reserved: BYTE): TRGBQuad;
    BEGIN
      WITH RESULT DO BEGIN
        rgbRed   := red;
        rgbGreen := green;
        rgbBlue  := blue;
        rgbReserved := reserved;
      END
    END;
     
    procedure TForm1.Button1Click(Sender: TObject);
    var
      h,w: Integer;
      aBmp: TBitmap;
      p: pRGBQuad; // need LCLtype
    begin
      DoubleBuffered := True;
      image1.Picture := nil;
     
      aBmp := TBitmap.Create;
      with aBmp do begin
        PixelFormat := pf24bit; // image OK
        SetSize(IMAGE_WIDTH, IMAGE_HEIGHT);
     
        BeginUpdate();
        for h := 0 to IMAGE_HEIGHT-1 do begin
          p := pRGBQuad(RawImage.GetLineStart(h));
          for w := 0 to IMAGE_WIDTH-1 do
            p[w] := RGBAtoQuadBGRA(h*8, w*8, (h+w) *4, 255);
        end;
        EndUpdate();
      end;
     
      image1.Picture.Assign(aBmp);
     
      // relecture du bitmap
      for h := 0 to IMAGE_HEIGHT-1 do begin
        p := pRGBQuad(aBmp.RawImage.GetLineStart(h));
        for w := 0 to IMAGE_WIDTH-1 do
          memo1.Lines.Add(IntToStr(RGBtoColor(p[w].rgbRed,p[w].rgbGreen,p[w].rgbBlue)));
      end;
     
      aBmp.Free;
    end;
    J'ai tout mis, vous pouvez tester, y a qu'à poser un TImage de 32x32 (ou autre, je vous laisse expérimenter mais pensez à adapter les 2 constantes), un TButton, copier/coller ce code et hop, roule ma poule !

    Toutes les idées sont les bienvenues (Anapurna, tu crois que c'est encore un truc mal initialisé ? Mais ça fonctionne tip-top sous Linux, bon sang ! [hé oui, Jon, c'est comm' ça la vie ])

    EDIT : ah, j'ai essayé ça, mais c'est la même misère...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      for h := 0 to IMAGE_HEIGHT-1 do begin
        {$IFDEF LINUX}
          p := pRGBQuad(aBmp.RawImage.GetLineStart(h));
        {$ELSE}
          p := pRGBQuad(aBmp.ScanLine[h]);
        {$ENDIF}
        for w := 0 to IMAGE_WIDTH-1 do
          memo1.Lines.Add(inttostr(RGBtoColor(p[w].rgbRed,p[w].rgbGreen,p[w].rgbBlue)));
      end;

  2. #2
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 564
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 564
    Points : 3 968
    Points
    3 968
    Par défaut
    Hi


    A défaut de mieux, je te propose de tester ton code avec Laz 1.4 sous XP pour voir si d'abord le problème se reproduit. Deux solutions:
    - le même problème se reproduit, dans ce cas la mise en oeuvre de GetLineStart est défectueuse sous Windows depuis longtemps et il faut voir pourquoi.
    - l'exécution se déroule sans encombre, il faut alors comparer les sources de GetLineStart entre les deux versions sous XP, une différence d'implémentation pourra sans doute donner des pistes sur la solution.

    Pas génial mais bon je n'ai pas trop le temps de me consacrer à Lazarus depuis mon récent déménagement...

    Les différences de comportement entre les plates-formes sont une vraie source d'emmerdements comme je l'ai vu avec mon petit jeu LazLightsOut, c'est pas toujours grave mais cela augmente le temps passé à régler des problèmes parfois agaçants.

    Cdlt

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 998
    Points : 15 482
    Points
    15 482
    Par défaut
    Bonjour e-ric,

    et merci de ta proposition de test.

    Tes idées de solutions m'ont mis la puce à l'oreille, je suis allé jeter un œil au code-source (sans rien trouver de probant, voir plus bas) mais en le consultant je me suis souvenu de mots rencontrés dans des vieux codes trouvés chez efg (pas n'importe où, donc), ai fouillé mes vieux projets de test, y ai trouvé des choses sympathiques que j'ai intégrées dans la procédure proposée dans mon premier post, et ça donne ça :
    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
      LineWidth: Integer; ///test
      myScanLine: pByte; ///test
    begin
      image1.Picture := nil;
     
      aBmp := TBitmap.Create;
      with aBmp do begin
        PixelFormat := pf24bit; // image OK
        SetSize(IMAGE_WIDTH, IMAGE_HEIGHT);
        LineWidth := RawImage.Description.BytesPerLine; ///test
     
        BeginUpdate();
        myScanLine := RawImage.Data; // première ligne  ///test
        for h := 0 to IMAGE_HEIGHT-1 do begin
          //p := pRGBQuad(RawImage.GetLineStart(h));
          p := pRGBQuad(myScanline);  /// new
          for w := 0 to IMAGE_WIDTH-1 do
            p[w] := RGBAtoQuadBGRA(h*8, w*8, (h+w) *4, 255);
          Inc(myScanLine, LineWidth); // ligne(s) suivante(s) ///test
        end;
        EndUpdate();
      end;
     
      image1.Picture.Assign(aBmp);
     
      myScanLine := aBmp.RawImage.Data; // première ligne  ///test
      for h := 0 to IMAGE_HEIGHT-1 do begin
        {$IFDEF LINUX}
          p := pRGBQuad(aBmp.RawImage.GetLineStart(h));
        {$ELSE}
          //p := pRGBQuad(aBmp.ScanLine[h]);
          p := pRGBQuad(myScanline);  ///test
        {$ENDIF}
        for w := 0 to IMAGE_WIDTH-1 do
          memo1.Lines.Add(inttostr(RGBtoColor(p[w].rgbRed,p[w].rgbGreen,p[w].rgbBlue)));
        Inc(myScanLine, LineWidth); // ligne(s) suivante(s) ///test
      end;
    Malheureusement ça plante toujours de la même manière...

    Quant au code de GetLineStart, c'est le même en 1.4 et en 1.6, dans GraphType :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function TRawImage.GetLineStart(ALine: Cardinal): PByte;
    begin
      Result := Data;
      if Result = nil then Exit;
      if ALine = 0 then Exit;
      Inc(Result, ALine * Description.BytesPerLine);
    end;
    et data c'est ça, dans la même unité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      TRawImage = object
        Description: TRawImageDescription;
        Data: PByte;

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 998
    Points : 15 482
    Points
    15 482
    Par défaut
    Halte au feu !

    J'ai compris : j'ai simplement rajouté un ShowMessage(IntToStr(LineWidth)); à l'endroit qui va bien et qui m'a affiché 96 soit 32 x 3, 32 la largeur de l'image, 3 parce que 3 pixels (r,g,b) et ça, ça ne pouvait pas coller avec des pRGBQuad (r,g,b,reserved) !

    J'ai changé mon aBmp.PixelFormat de pf24bit à pf32bit et l'image est là et sans AV !
    (ou alors je changerai le pRGBQuad en pRGBTriple, enfin, je verrai...)

    Plus qu'à adapter, car il me semblait bien qu'avec Windows les bitmaps c'était du pf24bit ...

    EDIT : d'ailleurs, tiens, avec exactement le même code sous Linux à gauche et sous XP à droite (zoomé pour bien voir) :

    Nom : compar_l_w.png
Affichages : 287
Taille : 2,8 Ko

    Elle est où, la vérité ? Bah, ça va m'occuper

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 998
    Points : 15 482
    Points
    15 482
    Par défaut
    Bonsoir,

    j'ai donc fait un test rapide : à gauche Linux à droite XP.
    Nom : compar_pf24_pf32.png
Affichages : 312
Taille : 4,8 Ko

    Dans chaque camp, à gauche PixelFormat := pf24bit et à droite pf32bit.

    Au-delà de la constatation que Linux ne supporte pas le pf24bit, il y avait cette histoire de couleurs différentes selon la plate-forme, et j'ai ressorti d'un endroit brumeux et poussiéreux de ma mémoire une sordide histoire d'inversion et pour vous la faire courte et régler le problème, voilà comment j'ai retouché la fonction de conversion trouvée chez efg il y a longtemps :
    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
    FUNCTION RGBAtoQuadBGRA(CONST red, green, blue, reserved: BYTE): TRGBQuad;
    BEGIN
      // red and blue are crossed in Linux
      WITH RESULT DO BEGIN
      {$IFDEF LINUX}// source : jpt, october 2016
        rgbRed   := blue;
        rgbGreen := green;
        rgbBlue  := red;
      {$ELSE}       // source : efg, 199x
        rgbRed   := red;
        rgbGreen := green;
        rgbBlue  := blue;
      {$ENDIF}
        rgbReserved := reserved;
      END
    END {RGBQuad}
    Et avec ça, plus de souci de couleurs

    Sinon, je confirme cette histoire d'AV avec la fonction de lecture (et pas celle d'écriture) des pixels pointés par GetLineStart dans le monde Windows, Linux supportant bien le défaut, allez comprendre...

    Affaire classée.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 998
    Points : 15 482
    Points
    15 482
    Par défaut
    Bonsoir,

    Je reviens sur ce que j'ai posté hier soir ; dans l'absolu, il faudrait que je supprime tout, mais je laisse, pour montrer à quel point on peut se tromper, des fois...

    Car en fait, après une longue matinée passée à faire des tests croisés entre Linux et XP avec des combinaisons diverses et variées, et une partie de l'après-midi à mettre mes notes en forme et en application dans des vieux projets les trouvailles de la matinée, il apparaît que, pour faire court et simple, :
    1- je me suis grave gourré hier soir, parce que ce qui change c'est
    2- la manière dont les bits sont organisés dans les pixels selon la plateforme1 (on oublie les machins préhistoriques à 8, 15 ou 16 bits, on se concentre sur 24 ou 32 bits), et donc, ce qui importe c'est
    3- la manière d'y accéder : à chaque plateforme sa fonction et voilà.

    Tout est synthétisé dans le code ci-après, qui n'a normalement besoin que d'un "nouveau projet" avec un TImage posé sur la fiche et réglé à 256x256 :
    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
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    uses
      {$IFDEF LINUX}
      BaseUnix, // timespec
      Linux, // clock_gettime
      {$ENDIF}
      LCLIntf,
      LCLtype; 
     
    const
      //ONE_OVER_BILLION = 1E-9; // nano
      ONE_OVER_MILLION = 1E-6; // micro
      ONE_OVER_MILLIER = 1E-3; // milli
     
    {$IFDEF LINUX}
    function GetTickCount64: QWord; // vient de "4inline", liens dans GetTickCount64
    var
      tp: timespec; // timespec record tv_sec seconds tv_nsec nanoseconds
    begin
      //clock_gettime(CLOCK_MONOTONIC, @tp); // orig
      clock_gettime(CLOCK_MONOTONIC_RAW, @tp);
      Result := (Int64(tp.tv_sec) * 1000000000) + int64(tp.tv_nsec);
    end;
    {$ENDIF}
     
    FUNCTION RGBtoRGBTriple(CONST red, green, blue:  BYTE):  TRGBTriple;
    BEGIN
      WITH RESULT DO
      BEGIN
        rgbtRed   := red;
        rgbtGreen := green;
        rgbtBlue  := blue
      END
    END {RGBtoRGBTriple};
     
    FUNCTION RGBAtoRGBAQuad(CONST red, green, blue, reserved: BYTE): TRGBQuad;
    BEGIN
      WITH RESULT DO BEGIN
        rgbRed   := red;
        rgbGreen := green;
        rgbBlue  := blue;
        rgbReserved := reserved;
      END
    END {RGBAtoRGBAQuad};
     
    procedure TForm1.FormCreate(Sender: TObject);
    const
      IMAGE_WIDTH  = 256;
      IMAGE_HEIGHT = 256;
    var
      StartTime, StopTime, Delta    :  QWord;
      h,w: Integer;
      aBmp: TBitmap;
      {$IFDEF WINDOWS}
      p   :  pRGBTriple;
      {$ELSE}
      p   :  pRGBQuad;
      {$ENDIF}
    begin
      DoubleBuffered := True;
      {$IFDEF LINUX}
      StartTime := GetTickCount64;
      {$ENDIF}
     
      aBmp := TBitmap.Create;
      with aBmp do begin
        PixelFormat := pf24bit;
        SetSize(IMAGE_WIDTH, IMAGE_HEIGHT);
     
        BeginUpdate();
        for h := 0 to IMAGE_HEIGHT-1 do begin
          {$IFDEF WINDOWS}
          p := pRGBTriple(RawImage.GetLineStart(h));
          for w := 0 to IMAGE_WIDTH-1 do
            p[w] := RGBtoRGBTriple(h, w, (h+w) div 2);
          {$ELSE}
          p := pRGBQuad(RawImage.GetLineStart(h));
          for w := 0 to IMAGE_WIDTH-1 do
            p[w] := RGBAtoRGBAQuad(h, w, (h+w) div 2, 255);
          {$ENDIF}
        end;
        EndUpdate();
     
        image1.Picture.Assign(aBmp);
        Free;
      end;
     
      {$IFDEF LINUX}
      StopTime := GetTickCount64;
      Delta := StopTime - StartTime;
      //Caption := IntToStr(Delta) + ' nanosecondes';
      Caption := FloatToStr(Delta * ONE_OVER_MILLIER) + ' microsecondes';
      //Caption := FloatToStr(Delta * ONE_OVER_MILLION) + ' millisecondes';
      {$ENDIF}
    end;
    Si tout va bien, vous devriez obtenir ceci (à gauche XP, à droite Linux avec le temps d'exécution, si quelqu'un sait le faire sous Windows ça serait intéressant) :

    Nom : pf24bit_L_W.jpg
Affichages : 286
Taille : 19,9 Ko

    Vous allez dire "mais y a pas de différences entre les 2 images !"
    Ben non, et heureusement d'ailleurs, c'était le but de la manip.
    ---
    1 : étant entendu qu'on peut définir sous Linux PixelFormat := pf24bit et que l'animal va travailler sur 32 bits... On avait vaguement abordé le sujet il y a qq années, mais sans creuser trop profond. On aurait peut-être dû, mais faut aussi faire avancer les chantiers en cours, alors bon...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 6
    Dernier message: 23/06/2009, 05h24
  2. Pas de signaux sous windows
    Par bobyboby dans le forum GTK+ avec C & C++
    Réponses: 0
    Dernier message: 24/02/2009, 12h57
  3. [Mac] Lien ne fonctionnant pas mais ok sous Windows
    Par bractar dans le forum Balisage (X)HTML et validation W3C
    Réponses: 11
    Dernier message: 26/01/2006, 19h38
  4. [Systeme] Process marche sous windows, pas sous linux
    Par Zapan dans le forum Général Java
    Réponses: 12
    Dernier message: 14/01/2006, 14h06
  5. Pas de fork sous Windows?
    Par chezjm dans le forum POSIX
    Réponses: 8
    Dernier message: 11/06/2002, 13h15

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