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 :

Différence entre MODE Delphi et MODE objfpc (aka Scanline and gtk2, l'éternel retour) [Lazarus]


Sujet :

Lazarus Pascal

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 135
    Par défaut Différence entre MODE Delphi et MODE objfpc (aka Scanline and gtk2, l'éternel retour)
    Bonjour !

    Jipété, le retour, avec ses misères...

    Je suis sur un projet EFG fort sympathique, FlipReverseRotate, et comme je suis aussi sous Linux, c'est la misère. Noire...

    Parce que quand on étudie un tas de trucs à la suite, la mémoire travaille en mode fifo et ce que j'ai capté il y a deux ans est depuis passé à la trappe, bien sûr.
    D'où la galère.

    Allez, 3 images.
    D'abord brut de dézippage, juste après "Outils / Convertir un projet Delphi..." :
    Nom : scanline_sans_correct_gtk2.png
Affichages : 668
Taille : 288,3 Ko

    Classique, les rayures sur la copie. J'ai la solution (extrait) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    var
      pbS,pbD: pByte;// pour la Source et la Destination
    for h := 0 to Bitmap.Height-1 do begin
      pbS := Bitmap.RawImage.GetLineStart(h);
      pbD := RESULT.RawImage.GetLineStart(h);
      cnt := 0;  idx := 0;
      for w := 0 to (Bitmap.Width * 3)-1 do begin
        pbD[idx] := pbS[w];
        cnt := w+1; // pour chercher le 4e byte
        if ( Frac(cnt / 3) = 0 ) then begin
          // bourrer le 4e byte du pRGBquad de la destination, le "Reserved", qui est inclus par le widgetset gtk2
          // sans demander l'avis à personne, sans informer... Faut deviner, à coups d'essais et d'échecs.
          inc(idx);
          pbD[idx]:=255;
        end;
        inc(idx);
      end;
    end;
    Ce qui est très curieux, c'est que le bouton Save me génère un fichier copié de la même taille que l'original, alors qu'il y a un byte de plus par pixel -- passerait-il à la trappe lors de l'enregistrement sans que, là aussi, "on" ne me dise rien ?
    Nom : mode_delphi.png
Affichages : 651
Taille : 151,8 Ko

    Mais attention ! Cette magnifique copie ne s'obtient qu'en {$mode Delphi} au niveau de l'entête des unités, car si je bascule en {$mode objfpc}{$H+}, c'est la cata :
    Nom : mode_fpc.png
Affichages : 662
Taille : 124,2 Ko

    C'est quoi la différence ?
    Un dernier mot : oui, je suis toujours avec mon vieux couple Laz 1.4 / Fpc 2.6.2, pour un projet Delphi 3 ça ira très bien,

    Merci et bon week-end,

  2. #2
    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
    Citation Envoyé par Jipété Voir le message
    Bonjour !

    Jipété, le retour, avec ses misères...

    Mais attention ! Cette magnifique copie ne s'obtient qu'en {$mode Delphi} au niveau de l'entête des unités, car si je bascule en {$mode objfpc}{$H+}, c'est la cata :

    C'est quoi la différence ?

    Merci et bon week-end,
    Re-salut la différence entre {$mode Delphi} et {$mode objfpc}{$H+} c'est qu'avec {$mode Delphi} l'écriture du code suit les conventions Delphi.
    Ce qui implique des différences mineures dans la façon d'écrire le code. Par exemple, lorsque tu manipule des "pointers" (c'est la cas le plus fréquent que je rencontre ) et c'est le cas ici.
    dans ton code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var
      pbS,pbD: pByte;// pour la Source et la Destination
    et tu utilises

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     for w := 0 to (Bitmap.Width * 3)-1 do begin
        pbD[idx] := pbS[w];
    en mode {$mode objfpc}{$H+} l'accès aux pointers sous forme de tableaux n'est pas correct


    De mémoire, en respectant ton code, pour ce faire, il faudrait que tu utilises un type genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Type
      pByteArray : array[0..maxint] of pByte;
     // ou (je ne me rappel plus trop de la formule magique
     // ByteArray : array[0..maxint] of Byte;
    //  pByteArray = ^ByteArray;
     
    var
      pbS,pbD: pByteArray;// pour la Source et la Destination
     
    for w := 0 to (Bitmap.Width * 3)-1 do begin
        pbD[idx]^ := pbS[w]^; // premier cas
       // pbD^[idx] := pbS^[w]; // deuxieme cas, comme ceci si je me souviens bien
    A+
    • "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

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

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

    Citation Envoyé par BeanzMaster Voir le message
    De mémoire, en respectant ton code, pour ce faire, il faudrait que tu utilises un type genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Type
      pByteArray : array[0..maxint] of pByte;
     // ou (je ne me rappelle plus trop de la formule magique
     // ByteArray : array[0..maxint] of Byte;
    //  pByteArray = ^ByteArray;
    Okay, j'en prends bonne note, mais les choses risquent d'évoluer.
    En tout cas j'ai pu simplifier mon bazar, qui devient :
    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
    var
            //pbS,pbD: pByte;
            pbS: pRGBTriple;
            pbD: pRGBQuad;
     
          for h := 0 to Bitmap.Height-1 do begin
            pbS := pRGBTriple(Bitmap.RawImage.GetLineStart(h));
            pbD := pRGBQuad(RESULT.RawImage.GetLineStart(h));
            for w := 0 to Bitmap.Width-1 do begin
              pbD[w].rgbBlue  := pbS[w].rgbtBlue;
              pbD[w].rgbGreen := pbS[w].rgbtGreen;
              pbD[w].rgbRed   := pbS[w].rgbtRed;
              pbD[w].rgbReserved := 255;
            end;
          end;
    EDIT
    Ces histoires de chapeaux, ça va me prendre la tête je sens...

    Mon nouveau code n'en a pas besoin,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            for w := 0 to Bitmap.Width-1 do begin
              pbD[w].rgbBlue  := pbS[w].rgbtBlue;
              pbD[w].rgbGreen := pbS[w].rgbtGreen;
              pbD[w].rgbRed   := pbS[w].rgbtRed;
              pbD[w].rgbReserved := 255;
            end;
    par contre un endroit qui n'était pas concerné réagit maintenant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
          IF   Reverse
          THEN BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO
              RowOut^[i] := RowIn^[Bitmap.Width-1-i]    // 2 chapeaux si pas mode Delphi ! !
          END
          ELSE BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO
              RowOut^[i] := RowIn^[i]    // 2 chapeaux si pas mode Delphi ! !
          END;
    Et si je coche la case Reverse, c'est pas glorieux :
    Nom : mode_objfpccheck-reverse.png
Affichages : 649
Taille : 292,2 Ko

    Bon, je sais comment m'en dépatouiller, mais y a du pain sur la planche, encore et toujours...
    /EDIT



    Quant à l'autre sujet, je verrai ça plus tard. Merci pour tes réponses,

  4. #4
    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
    Au vue de tes captures et des rayures (comme d'hab) je penche pour un problème dans le format 32bits vs 24bits. Si tu te sens plus à l'aise tu devrais également utiliser ta structure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    pbD[w].rgbBlue  := pbS[w].rgbtBlue;
              pbD[w].rgbGreen := pbS[w].rgbtGreen;
              pbD[w].rgbRed   := pbS[w].rgbtRed;
              pbD[w].rgbReserved := 255;
    Au lieu de RowOut^[i] := RowIn^[Bitmap.Width-1-i]
    • "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 confirmé
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 135
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 135
    Par défaut
    Citation Envoyé par BeanzMaster Voir le message
    Si tu te sens plus à l'aise tu devrais également utiliser ta structure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    pbD[w].rgbBlue  := pbS[w].rgbtBlue;
              pbD[w].rgbGreen := pbS[w].rgbtGreen;
              pbD[w].rgbRed   := pbS[w].rgbtRed;
              pbD[w].rgbReserved := 255;
    Au lieu de RowOut^[i] := RowIn^[Bitmap.Width-1-i]
    laisse tomber, c'est pire !

    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
      VAR
        i     :  INTEGER;
        j     :  INTEGER;
        //RowIn :  pRGBArray;
        //RowOut:  pRGBArray;
        RowIn :  pRGBTriple;
        RowOut:  pRGBQuad;
     
          IF   Reverse
          THEN BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO begin
    //          RowOut^[i] := RowIn^[Bitmap.Width-1-i]    // 2 chapeaux si pas mode Delphi ! !
              RowOut[i].rgbBlue  := RowIn[Bitmap.Width-1-i].rgbtRed;
              RowOut[i].rgbGreen := RowIn[Bitmap.Width-1-i].rgbtGreen;
              RowOut[i].rgbRed   := RowIn[Bitmap.Width-1-i].rgbtBlue;
              RowOut[i].rgbReserved := 255;
            end;
          END
          ELSE BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO begin
    //          RowOut^[i] := RowIn^[i]    // 2 chapeaux si pas mode Delphi ! !
              RowOut[i].rgbBlue  := RowIn[i].rgbtBlue;
              RowOut[i].rgbGreen := RowIn[i].rgbtGreen;
              RowOut[i].rgbRed   := RowIn[i].rgbtRed;
              RowOut[i].rgbReserved := 255;
            end;
          END;
        END;
    Nom : scanline.gif
Affichages : 624
Taille : 158,6 Ko

    Bon, je verrai ça plus tard, là j'en ai un peu marre et j'ai faim,

    EDIT :
    ça va, j'ai trouvé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
      VAR
        RowIn :  pRGBTriple;
        RowOut:  pRGBTriple;
     
          IF   Reverse
          THEN BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO
              RowOut[i] := RowIn[Bitmap.Width-1-i]    // PAS BESOIN ! 2 chapeaux si pas mode Delphi ! !
          END
          ELSE BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO
              RowOut[i] := RowIn[i]    // PAS BESOIN ! 2 chapeaux si pas mode Delphi ! !
          END;
    Va y avoir du sport si selon la routine il me faut utiliser pRGBTriple ou pRGBQuad ! Bref...

    Merci pour le coup de main, bon aprème,

  6. #6
    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
    Si tu peux mettre le code en piece jointe je pourrais plus facilement t'aider, si jamais là il me manque un bout de code et je pense que le problème vient du calcul du "scanline" de départ
    • "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 Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    11 135
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 135
    Par défaut
    Citation Envoyé par BeanzMaster Voir le message
    Si tu peux mettre le code en piece jointe je pourrais plus facilement t'aider, si jamais là il me manque un bout de code et je pense que le problème vient du calcul du "scanline" de départ
    Merci de ta proposition.
    Je te mets les codes, mais je ne veux surtout pas que tu te prennes la tête avec ça, d'autant plus qu'on dirait que je vois le bout du tunnel.

    le 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
    // BitmapFlipReverse is an example of how to write a function that returns
    // a TBitmap.  Given a 24-bit bitmap, the function will flip and/or reverse
    // the bitmap.
     
    // Copyright (C) 1998, Earl F. Glynn.  All Rights Reserved.
     
    program FlipReverseRotate;
     
    {.$MODE Delphi}
    {$mode objfpc}{$H+}
     
    uses
      Forms, Interfaces,
      ScreenFlipReverseRotate in 'ScreenFlipReverseRotate.pas' {FormFlipReverseRotate},
      FlipReverseRotateLibrary in 'FlipReverseRotateLibrary.pas';
     
    {$R *.res}
     
    begin
      Application.Initialize;
      Application.CreateForm(TFormFlipReverseRotate, FormFlipReverseRotate);
      Application.Run;
    end.

    le code de la form
    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
    180
    181
    182
    183
    184
    185
    // BitmapFlipReverseRotate is an example of how to write a function that returns
    // a TBitmap.  Given a 24-bit bitmap, the function will flip and/or reverse
    // the bitmap, followed by a rotation of 0, 90, 180 or 270 degrees counterclockwise.
     
    // Copyright (C) 1998, Earl F. Glynn.  All Rights Reserved.
    // May be used freely for non-comercial use.
     
    unit ScreenFlipReverseRotate;
     
    {.$MODE Delphi}
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      LCLIntf, LCLType, {LMessages, Messages,} SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      StdCtrls, ExtDlgs, ExtCtrls;
     
    type
      TFormFlipReverseRotate = class(TForm)
        ImageOriginal: TImage;
        ImageModified: TImage;
        OpenPictureDialogBMP: TOpenPictureDialog;
        CheckBoxStretch: TCheckBox;
        ButtonLoad: TButton;
        CheckBoxFlip: TCheckBox;
        CheckBoxReverse: TCheckBox;
        RadioGroupMethod: TRadioGroup;
        LabelTimer: TLabel;
        ButtonSave: TButton;
        RadioGroupRotate: TRadioGroup;
        SavePictureDialogBMP: TSavePictureDialog;
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure CheckBoxStretchClick(Sender: TObject);
        procedure ButtonLoadClick(Sender: TObject);
        procedure CheckBoxClickModifyImage(Sender: TObject);
        procedure RadioGroupRotateClick(Sender: TObject);
        procedure ButtonSaveClick(Sender: TObject);
      private
        BitmapOriginal   :  TBitmap;
        PROCEDURE ModifyOriginalImage;
      public
        { Public declarations }
      end;
     
    var
      FormFlipReverseRotate: TFormFlipReverseRotate;
     
    implementation
     
    {$R *.lfm}
     
    USES
      FlipReverseRotateLibrary;   // FlipReverseRotate90Scanline, ...
     
    procedure TFormFlipReverseRotate.FormCreate(Sender: TObject);
    begin
      OpenPictureDialogBMP.InitialDir := Application.Location;
      // Setup BitmapOriginal in case Flip /Reverse checkboxes used before
      // an image is loaded.
      BitmapOriginal := TBitmap.Create;
      BitmapOriginal.PixelFormat := pf24bit;
      BitmapOriginal.Width  := ImageOriginal.Width;
      BitmapOriginal.Height := ImageOriginal.Height;
    end;
     
     
    procedure TFormFlipReverseRotate.FormDestroy(Sender: TObject);
    begin
      BitmapOriginal.Free
    end;
     
     
    procedure TFormFlipReverseRotate.CheckBoxStretchClick(Sender: TObject);
    begin
      ImageOriginal.Stretch := CheckboxStretch.Checked;
      ImageModified.Stretch := CheckboxStretch.Checked
    end;
     
     
    procedure TFormFlipReverseRotate.ButtonLoadClick(Sender: TObject);
    begin
      IF  OpenPictureDialogBMP.Execute
      THEN BEGIN
        BitmapOriginal.Free;
     
        // Create new original
        BitmapOriginal := TBitmap.Create;
        BitmapOriginal.LoadFromFile(OpenPictureDialogBMP.Filename);
     
        // Assign TBitmap to TImage for display
        ImageOriginal.Picture.Graphic := BitmapOriginal;
     
        IF   BitmapOriginal.PixelFormat = pf24bit
        THEN BEGIN
          RadioGroupMethod.ItemIndex := 0;
          RadioGroupMethod.Enabled := TRUE
        END
        ELSE BEGIN
          RadioGroupMethod.ItemIndex := 1;
     
          // Force CopyRect to be only method available
          RadioGroupMethod.Enabled := FALSE
        END;
     
        ModifyOriginalImage;
        ButtonSave.Enabled := TRUE
      END
    end;
     
     
    procedure TFormFlipReverseRotate.CheckBoxClickModifyImage(Sender: TObject);
    begin
      IF   RadioGroupMethod.ItemIndex = 0
      THEN RadioGroupRotate.Visible := TRUE
      ELSE BEGIN
        RadioGroupRotate.ItemIndex := 0;
        RadioGroupRotate.Visible := FALSE
      END;
     
      ModifyOriginalImage
    end;
     
     
    // Use Scanline, CopyRect or StretchBlt to Flip or Reverse a bitmap.
    // For Scanline, a "Rotate 90 degrees" option is also available.
    PROCEDURE TFormFlipReverseRotate.ModifyOriginalImage;
      VAR
        BitmapFlipReverse:  TBitmap;
        BitmapRotate     :  TBitmap;
        StartTick        :  INTEGER;
    BEGIN
      StartTick := GetTickCount;
     
      // First Flip and/or reverse the bitmap.
      // Treat BitmapFlipReverse functions much like a TBitmap.Create.
      CASE RadioGroupMethod.ItemIndex OF   // celui du bas
        0:  BitmapFlipReverse := FlipReverseScanLine( CheckBoxFlip.Checked,
                                                      CheckBoxReverse.Checked,
                                                      BitmapOriginal);
     
        1:  BitmapFlipReverse := FlipReverseCopyRect( CheckBoxFlip.Checked,
                                                      CheckBoxReverse.Checked,
                                                      BitmapOriginal);
     
        2:  BitmapFlipReverse := FlipReverseStretchBlt(CheckBoxFlip.Checked,
                                                       CheckBoxReverse.Checked,
                                                       BitmapOriginal);
        ELSE
          // Should never happen.  Silence the compiler warning.
          BitmapFlipReverse := NIL
      END;
     
      IF   RadioGroupRotate.Visible  // celui du haut
      THEN BEGIN
        // Rotate 0, 90, 180, 270 degrees counterclockwise
        BitmapRotate := RotateScanLine90(90*RadioGroupRotate.ItemIndex,
                                         BitmapFlipReverse);
        ImageModified.Picture.Graphic := BitmapRotate;
        BitmapRotate.Free
      END
      ELSE ImageModified.Picture.Graphic := BitmapFlipReverse;
     
    //  A refresh may help reduce flicker on some screens but adds quite a bit
    //  to the total time.
    //  ImageModified.Refresh;
     
      BitmapFlipReverse.Free;
     
      LabelTimer.Caption := IntToStr(GetTickCount - StartTick) + ' ms'
    END {ModifyOriginalImage};
     
    procedure TFormFlipReverseRotate.RadioGroupRotateClick(Sender: TObject);
    begin
      ModifyOriginalImage
    end;
     
    procedure TFormFlipReverseRotate.ButtonSaveClick(Sender: TObject);
    begin
      IF   SavePictureDialogBMP.Execute
      THEN ImageModified.Picture.Bitmap.SaveToFile(SavePictureDialogBMP.Filename)
    end;
     
    end.

    la form
    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
    object FormFlipReverseRotate: TFormFlipReverseRotate
      Left = 379
      Height = 334
      Top = 192
      Width = 612
      ActiveControl = ButtonLoad
      BorderIcons = [biSystemMenu, biMinimize]
      BorderStyle = bsSingle
      Caption = 'Flip / Reverse / Rotate'
      ClientHeight = 334
      ClientWidth = 612
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      OnCreate = FormCreate
      OnDestroy = FormDestroy
      Position = poScreenCenter
      LCLVersion = '1.4.0.4'
      object ImageOriginal: TImage
        Left = 5
        Height = 225
        Top = 61
        Width = 300
        Stretch = True
      end
      object ImageModified: TImage
        Left = 309
        Height = 225
        Top = 61
        Width = 300
        Stretch = True
      end
      object LabelTimer: TLabel
        Left = 577
        Height = 13
        Top = 9
        Width = 33
        Alignment = taRightJustify
        Caption = 'Timer'
        ParentColor = False
      end
      object CheckBoxStretch: TCheckBox
        Left = 86
        Height = 22
        Top = 5
        Width = 71
        Caption = 'Stretch'
        OnClick = CheckBoxStretchClick
        TabOrder = 0
      end
      object ButtonLoad: TButton
        Left = 5
        Height = 25
        Top = 3
        Width = 75
        Caption = 'Load Image'
        OnClick = ButtonLoadClick
        TabOrder = 4
      end
      object CheckBoxFlip: TCheckBox
        Left = 309
        Height = 22
        Top = 5
        Width = 45
        Caption = 'Flip'
        OnClick = CheckBoxClickModifyImage
        TabOrder = 1
      end
      object CheckBoxReverse: TCheckBox
        Left = 383
        Height = 22
        Top = 5
        Width = 74
        Caption = 'Reverse'
        OnClick = CheckBoxClickModifyImage
        TabOrder = 2
      end
      object RadioGroupMethod: TRadioGroup
        Left = 180
        Height = 33
        Top = 292
        Width = 260
        AutoFill = True
        Caption = 'Method'
        ChildSizing.LeftRightSpacing = 6
        ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
        ChildSizing.EnlargeVertical = crsHomogenousChildResize
        ChildSizing.ShrinkHorizontal = crsScaleChilds
        ChildSizing.ShrinkVertical = crsScaleChilds
        ChildSizing.Layout = cclLeftToRightThenTopToBottom
        ChildSizing.ControlsPerLine = 3
        ClientHeight = 18
        ClientWidth = 256
        Columns = 3
        ItemIndex = 0
        Items.Strings = (
          'ScanLine'
          'CopyRect'
          'StretchBlt'
        )
        OnClick = CheckBoxClickModifyImage
        TabOrder = 3
      end
      object ButtonSave: TButton
        Left = 200
        Height = 25
        Top = 3
        Width = 75
        Caption = 'Save'
        Enabled = False
        OnClick = ButtonSaveClick
        TabOrder = 5
      end
      object RadioGroupRotate: TRadioGroup
        Left = 309
        Height = 33
        Top = 24
        Width = 249
        AutoFill = True
        Caption = 'Rotate (Counterclockwise)'
        ChildSizing.LeftRightSpacing = 6
        ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
        ChildSizing.EnlargeVertical = crsHomogenousChildResize
        ChildSizing.ShrinkHorizontal = crsScaleChilds
        ChildSizing.ShrinkVertical = crsScaleChilds
        ChildSizing.Layout = cclLeftToRightThenTopToBottom
        ChildSizing.ControlsPerLine = 4
        ClientHeight = 18
        ClientWidth = 245
        Columns = 4
        ItemIndex = 0
        Items.Strings = (
          '0'
          '90'
          '180'
          '270'
        )
        OnClick = RadioGroupRotateClick
        TabOrder = 6
      end
      object OpenPictureDialogBMP: TOpenPictureDialog
        DefaultExt = '.BMP'
        Filter = 'Bitmaps (*.bmp)|*.bmp'
        left = 56
        top = 30
      end
      object SavePictureDialogBMP: TSavePictureDialog
        DefaultExt = '.BMP'
        Filter = 'Bitmaps (*.bmp)|*.bmp'
        left = 232
        top = 31
      end
    end

    le module
    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
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    // The FlipReverseRotate Library provides three functions to flip and/or
    // reverse a bitmap.  You can choose which approach you'd like to use from the
    // three methods to flip or reverse a bitmap:  ScanLine, CopyRect, StretchBlt.
    //
    // A "Flip" operation takes the top of an image to the bottom and the bottom of
    // the image to the top.  It is a reflection along a horizontal line in the
    // middle of an image.
    //
    // A "Reverse" operation takes the left of an image to the right and the right
    // of the image to the left.  It is a reflection along a vertical line in the
    // middle of an image.
    //
    // Any Flip/Reverse operation is commutative, i.e., the flip and reverse can
    // be performed in any order to get the same result.  A flip followed by a
    // reverse is the same as a reverse followed by a flip.
    //
    // A "rotate" operation spins an image 0, 90, 180 or 270 degrees around an
    // axis in the center of the image.
    //
    // A flip/reverse operation along with a rotation is not commutative in general.
    // A flip followed by a rotation will not always result in the same image as a
    // rotation followed by a flip.  The rotation here ALWAYS follows any flip and/or
    // reversal.
    //
    // The examples here are intended for use with bitmaps that have 24 bits/pixel.
    // Palettes may be lost on 256-color bitmaps.
    //
    // Copyright (C) 1998, Earl F. Glynn.  All Rights Reserved.
    // May be used freely for non-comercial use.
     
    UNIT FlipReverseRotateLibrary;
     
    {.$MODE Delphi}
    {$mode objfpc}{$H+}
     
    INTERFACE
     
    USES
      Dialogs,
        LCLIntf, LCLType,// LMessages,   // TRGBTriple (put here to avoid TBitmap conflict in Implementation)
        Graphics;  // TBitmap
     
      // Flip/Reverse functions by Method
      FUNCTION FlipReverseScanLine(CONST Flip, Reverse:  BOOLEAN;
                                   CONST Bitmap:  TBitmap):  TBitmap;
     
      FUNCTION FlipReverseCopyRect(CONST Flip, Reverse:  BOOLEAN;
                                   CONST Bitmap:  TBitmap):  TBitmap;
     
      FUNCTION FlipReverseStretchBlt(CONST Flip, Reverse:  BOOLEAN;
                                     CONST Bitmap:  TBitmap):  TBitmap;
     
      // The Rotation function is only for the Scanline Method.
      // Note:  Windows NT supports a "plgblt" API call that can be used to rotate
      // images.
      FUNCTION RotateScanline90(CONST angle:  INTEGER;
                                CONST Bitmap:  TBitmap):  TBitmap;
     
    IMPLEMENTATION
     
      USES
        Classes,    // Rect
        SysUtils;   // Exception
     
      CONST
        MaxPixelCount = 65536;   // or some other arbitrarily large value
        // ouais, parce que ça fait un peu petit, ça : 256 x 256 seulement...
     
      TYPE
        EBitmapError = CLASS(Exception);
    //    TRGBArray    = ARRAY[0..MaxPixelCount-1] OF TRGBTriple;
    //    pRGBArray    = ^TRGBArray;
        TRGBArray = ARRAY[0..MaxPixelCount-1] OF TRGBQuad;
        pRGBArray   = ^TRGBArray;
     
     
      //////////////////////////////////////////////////////////////////////////////
     
      FUNCTION FlipReverseScanLine(CONST Flip, Reverse:  BOOLEAN;
                                   CONST Bitmap:  TBitmap):  TBitmap;
      VAR
        i     :  INTEGER;
        j     :  INTEGER;
        //RowIn :  pRGBArray;
        //RowOut:  pRGBArray;
        RowIn :  pRGBTriple;
        RowOut:  pRGBTriple;
      BEGIN
        IF   Bitmap.PixelFormat <> pf24bit
        THEN RAISE EBitmapError.Create('Can Flip/Reverse only 24-bit bitmap');
     
        RESULT := TBitmap.Create;
        RESULT.PixelFormat := Bitmap.PixelFormat;
        RESULT.Width       := Bitmap.Width;
        RESULT.Height      := Bitmap.Height;
     
        RESULT.BeginUpdate();
        FOR j := 0 TO Bitmap.Height-1 DO BEGIN
          RowIn :=  pRGBTriple(Bitmap.RawImage.GetLineStart(j));
          IF   Flip
    //      THEN RowOut := RESULT.Scanline[Bitmap.Height - 1 - j]
    //      ELSE RowOut := RESULT.Scanline[j];
          THEN RowOut := pRGBTriple(RESULT.RawImage.GetLineStart(Bitmap.Height - 1 - j))
          ELSE RowOut := pRGBTriple(RESULT.RawImage.GetLineStart(j));
     
          // Optimization technique:  Use two FOR loops so IF is outside of inner loop
          IF   Reverse
          THEN BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO begin
              RowOut[i] := RowIn[Bitmap.Width-1-i]    // 2 chapeaux si pas mode Delphi ! !
    {          RowOut[i].rgbtBlue  := RowIn[Bitmap.Width-1-i].rgbtBlue;
              RowOut[i].rgbtGreen := RowIn[Bitmap.Width-1-i].rgbtGreen;
              RowOut[i].rgbtRed   := RowIn[Bitmap.Width-1-i].rgbtRed;       }
    //          RowOut[i].rgbReserved := 255;
            end;
          END
          ELSE BEGIN
            FOR i := 0 TO Bitmap.Width-1 DO begin
              RowOut[i] := RowIn[i]    // 2 chapeaux si pas mode Delphi ! !
    {          RowOut[i].rgbtBlue  := RowIn[i].rgbtBlue;
              RowOut[i].rgbtGreen := RowIn[i].rgbtGreen;
              RowOut[i].rgbtRed   := RowIn[i].rgbtRed;             }
    //          RowOut[i].rgbReserved := 255;
            end;
          END;
        END;
        RESULT.EndUpdate();
      END {FlipReverseScanLine};
     
     
      //////////////////////////////////////////////////////////////////////////////
     
      // This function implements a suggestion by David Ullrich in a July 25, 1997
      // post to comp.lang.pascal.delphi.misc.
      //
      // The Graphics.PAS unit shows that CopyRect calls the Windows StretchBlt API
      // function.
      FUNCTION FlipReverseCopyRect(CONST Flip, Reverse:  BOOLEAN;
                                   CONST Bitmap:  TBitmap):  TBitmap;
        VAR
          Bottom:  INTEGER;
          Left  :  INTEGER;
          Right :  INTEGER;
          Top   :  INTEGER;
      BEGIN
        RESULT := TBitmap.Create;
        RESULT.PixelFormat := Bitmap.PixelFormat;
        RESULT.Width       := Bitmap.Width;
        RESULT.Height      := Bitmap.Height;
     
        // Flip Top to Bottom
        IF   Flip
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Top    := Bitmap.Height-1;
          Bottom := -1
        END
        ELSE BEGIN
          Top    := 0;
          Bottom := Bitmap.Height
        END;
     
        // Reverse Left to Right
        IF   Reverse
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Left  := Bitmap.Width-1;
          Right := -1;
        END
        ELSE BEGIN
          Left  := 0;
          Right := Bitmap.Width;
        END;
     
        RESULT.Canvas.CopyRect(Rect(Left,Top, Right,Bottom),
                               Bitmap.Canvas,
                               Rect(0,0, Bitmap.Width,Bitmap.Height));
      END {FlipReverseCopyRect};
     
     
      //////////////////////////////////////////////////////////////////////////////
     
      FUNCTION FlipReverseStretchBlt(CONST Flip, Reverse:  BOOLEAN;
                                     CONST Bitmap:  TBitmap):  TBitmap;
        VAR
          Bottom:  INTEGER;
          Left  :  INTEGER;
          Right :  INTEGER;
          Top   :  INTEGER;
      BEGIN
        RESULT := TBitmap.Create;
        RESULT.PixelFormat := Bitmap.PixelFormat;
        RESULT.Width       := Bitmap.Width;
        RESULT.Height      := Bitmap.Height;
     
        // Flip Top to Bottom
        IF   Flip
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Top    := Bitmap.Height-1;
          Bottom := -1
        END
        ELSE BEGIN
          Top    := 0;
          Bottom := Bitmap.Height
        END;
     
        // Reverse Left to Right
        IF   Reverse
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Left  := Bitmap.Width-1;
          Right := -1;
        END
        ELSE BEGIN
          Left  := 0;
          Right := Bitmap.Width;
        END;
     
        StretchBlt(RESULT.Canvas.Handle, Left, Top, Right-Left, Bottom-Top,
                   Bitmap.Canvas.Handle,
                   0,0, Bitmap.Width, Bitmap.Height, cmSrcCopy);
      END {FlipReverseStretchBlt};
     
     
      //////////////////////////////////////////////////////////////////////////////
     
      // Rotate 24-bits/pixel Bitmap any multiple of 90 degrees.
      FUNCTION RotateScanLine90(CONST angle:  INTEGER;
                                CONST Bitmap:  TBitmap):  TBitmap;
     
        // These four internal functions parallel the four cases in rotating a
        // bitmap using the Pixels property.  See the RotatePixels example on
        // the Image Processing page of efg's Computer Lab for an example of the
        // use of the Pixels property (which is very slow).
     
        // A Bitmap.Assign could be used for a simple copy.  A complete example
        // using ScanLine is included here to help explain the other three cases.
        FUNCTION SimpleCopy:  TBitmap;
          VAR
            //i     :  INTEGER;
            //j     :  INTEGER;
            //rowIn :  pRGBQuad;//pRGBArray;
            //rowOut:  pRGBQuad;//pRGBArray;
            h,w: Integer;
            //cnt: single;
            //idx: Integer;
            //pbS,pbD: pByte;
            pbS: pRGBTriple;
            pbD: pRGBQuad;
        BEGIN
          RESULT := TBitmap.Create;
          RESULT.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
          RESULT.Width  := Bitmap.Width;
          RESULT.Height := Bitmap.Height;
     
          RESULT.BeginUpdate();
          // Out[i, j] = In[i, j]
    {      FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
            rowIn  := pRGBQuad(Bitmap.RawImage.GetLineStart(j));
            rowOut := pRGBQuad(RESULT.RawImage.GetLineStart(j));
            // Could optimize the following by using a function like CopyMemory
            // from the Windows unit.
            FOR i := 0 TO Bitmap.Width - 1 DO BEGIN
    //          RowOut[i] := RowIn[i];
              // Why does this crash with RowOut[i] := RowIn[i]?  Alignment?
              // Use this longer form as workaround.
              WITH rowOut[i] DO BEGIN
    //            rgbtRed   := rowIn[i].rgbtRed;
      //          rgbtGreen := rowIn[i].rgbtGreen;
        //        rgbtBlue  := rowIn[i].rgbtBlue;
                rgbRed   := rowIn[i].rgbRed;
                rgbGreen := rowIn[i].rgbGreen;
                rgbBlue  := rowIn[i].rgbBlue;
                rgbReserved := rowIn[i].rgbReserved;
              END
            END
          END;     }
     
    {      for h := 0 to Bitmap.Height-1 do begin
            pbS := Bitmap.RawImage.GetLineStart(h);
            pbD := RESULT.RawImage.GetLineStart(h);
            cnt := 0;  idx := 0;
            for w := 0 to (Bitmap.Width * 3)-1 do begin
              pbD[idx] := pbS[w];
              cnt := w+1; // pour chercher le 4e byte de la destination
              if ( Frac(cnt / 3) = 0 ) then begin
                // "bourrer" le 4e byte, le "Reserved", qui a l'air inclus par le widgetset gtk2
                inc(idx);
                pbD[idx]:=255;
              end;
              inc(idx);
            end;
          end;       }
     
          for h := 0 to Bitmap.Height-1 do begin
            pbS := pRGBTriple(Bitmap.RawImage.GetLineStart(h));
            pbD := pRGBQuad(RESULT.RawImage.GetLineStart(h));
            for w := 0 to Bitmap.Width-1 do begin
              pbD[w].rgbBlue  := pbS[w].rgbtBlue;
              pbD[w].rgbGreen := pbS[w].rgbtGreen;
              pbD[w].rgbRed   := pbS[w].rgbtRed;
              pbD[w].rgbReserved := 255;
            end;
          end;
          RESULT.EndUpdate();
        END {SimpleCopy};
     
     
        FUNCTION Rotate90DegreesCounterClockwise:  TBitmap;
           VAR
            i     :  INTEGER;
            j     :  INTEGER;
            rowIn :  pRGBArray;
            h,w: Integer;
            cnt: single;
            idx: Integer;
            pbS,pbD: pByte;
        BEGIN
          RESULT := TBitmap.Create;
          RESULT.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
          RESULT.Width  := Bitmap.Height;
          RESULT.Height := Bitmap.Width;
     
          RESULT.BeginUpdate();
          // Out[j, Right - i - 1] = In[i, j]
          FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
    //        rowIn  := Bitmap.ScanLine[j];
            rowIn  := pRGBArray(Bitmap.RawImage.GetLineStart(j));
            FOR i := 0 TO Bitmap.Width - 1 DO
              pRGBArray(RESULT.ScanLine[Bitmap.Width - i - 1])[j] := rowIn[i]
          END;
          RESULT.EndUpdate();
        END {Rotate90DegreesCounterClockwise};
     
     
        // Could use Rotate90DegreesCounterClockwise twice to get a
        // Rotate180DegreesCounterClockwise.  Rotating 180 degrees is the same
        // as a Flip and Reverse
        FUNCTION Rotate180DegreesCounterClockwise:  TBitmap;
          VAR
            i     :  INTEGER;
            j     :  INTEGER;
            rowIn :  pRGBArray;
            rowOut:  pRGBArray;
        BEGIN
          RESULT := TBitmap.Create;
          RESULT.PixelFormat := Bitmap.PixelFormat;    // only pf24bit for now
          RESULT.Width  := Bitmap.Width;
          RESULT.Height := Bitmap.Height;
     
          RESULT.BeginUpdate();
          // Out[Right - i - 1, Bottom - j - 1] = In[i, j]
          FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
    //        rowIn  := Bitmap.ScanLine[j];
      //      rowOut := RESULT.ScanLine[Bitmap.Height - j - 1];
            rowIn  := pRGBArray(Bitmap.RawImage.GetLineStart(j));
            rowOut := pRGBArray(RESULT.RawImage.GetLineStart(Bitmap.Height - j - 1));
            FOR i := 0 TO Bitmap.Width - 1 DO
              rowOut[Bitmap.Width - i - 1] := rowIn[i]
          END;
          RESULT.EndUpdate();
        END {Rotate180DegreesCounterClockwise};
     
     
        // Could use Rotate90DegreesCounterClockwise three times to get a
        // Rotate270DegreesCounterClockwise
        FUNCTION Rotate270DegreesCounterClockwise:  TBitmap;
          VAR
            i    :  INTEGER;
            j    :  INTEGER;
            rowIn:  pRGBArray;
        BEGIN
          RESULT := TBitmap.Create;
          RESULT.PixelFormat := pf32bit;//Bitmap.PixelFormat;    // only pf24bit for now
          RESULT.Width  := Bitmap.Height;
          RESULT.Height := Bitmap.Width;
     
          RESULT.BeginUpdate();
          // Out[Bottom - j - 1, i] = In[i, j]
          FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
    //        rowIn  := Bitmap.ScanLine[j];
            rowIn  := pRGBArray(Bitmap.RawImage.GetLineStart(j));
            FOR i := 0 TO Bitmap.Width - 1 DO
    //          pRGBArray(RESULT.Scanline[i])[Bitmap.Height - j - 1] := rowIn[i]
              pRGBArray(RESULT.RawImage.GetLineStart(i))[Bitmap.Height - j - 1] := rowIn[i]
          END;
          RESULT.EndUpdate();
        END {Rotate270DegreesCounterClockwise};
     
     
      BEGIN
    //    IF   Bitmap.PixelFormat <> pf24bit
    //    THEN RAISE EBitmapError.Create('Can Rotate90 only 24-bit bitmap');
     
        IF   (angle >= 0) AND (angle MOD 90 <> 0)
        THEN RAISE EBitmapError.Create('Rotate90:  Angle not positive multiple of 90 degrees');
     
        CASE (angle DIV 90) MOD 4 OF
          0:  RESULT := SimpleCopy;
          1:  RESULT := Rotate90DegreesCounterClockwise;  // Anticlockwise for the Brits
          2:  RESULT := Rotate180DegreesCounterClockwise;
          3:  RESULT := Rotate270DegreesCounterClockwise
          ELSE
            RESULT := NIL    // avoid compiler warning
        END;
      END {RotateScanline90};
     
    END.


    Ce qu'il y a de bien avec EFG, c'est qu'il y a toujours des trucs à apprendre.
    Courage et merci, ne te prends pas la tête (j'insiste).
    En général, je commente le code d'origine et je mets mes modifs dessous.

    L'image : sunflower.zip

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 135
    Par défaut
    Bon, voilà

    Résumé de mes notes (2 h de manips) :

    inverser 0 et 1 dans la PROCEDURE ModifyOriginalImage et mettre RadioGroupRotate invisible donc copie par CopyRect et pas de SimpleCopyScanline --> copie ok (25 ms)

    remis 0 et 1 à l'origine --> traits verticaux sur les 3 quarts de l'image et dernier quart noir --> il y a bien un problème dans FlipReverseScanline

    re-essai avec 0 1 inversé (copie par CopyRect pour avoir un BitmapFlipReverse correct) et réactivation SimpleCopyScanline --> 3 quarts corrects et dernier quart noir --> il n'est donc pas possible d'utiliser pRGBArray pour la destination :
    - essai avec le couple pRGBTriple-pRGBQuad --> image allongée en traits
    - essai avec les pBytes = idem
    - essai avec pRGBQuad-pRGBQuad --> OK ! (bizarre qu'il faille un pRGBQuad pour la source, qui est un fichier 24 bits)
    - re-essai avec les pBytes en mode sans correction du 4e byte = 3 quarts ok, 4e noir --> modif de for w := 0 to (Bitmap.Width * 3)-1 en for w := 0 to (Bitmap.Width * 4)-1 = OK

    On dirait que malgré le pf24bit du fichier source, on travaille dans le code avec des bitmaps 32 bits car, in fine, ça, ça fonctionne bien, pour la SimpleCopyScanline :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
          FOR  j := 0 TO Bitmap.Height - 1 DO BEGIN
            rowIn  := pRGBQuad(Bitmap.RawImage.GetLineStart(j));
            rowOut := pRGBQuad(RESULT.RawImage.GetLineStart(j));
            FOR i := 0 TO Bitmap.Width - 1 DO
              RowOut[i] := RowIn[i];
          END;
    Et sans chapeaux !

    Ensuite, re-invisible RadioGroupRotate et 0 1 normal donc FlipReverseScanline tout seul --> des traits sur 3/4 d'image et ils recommencent sur le dernier quart (alors que c'est le code allégé strictement identique à celui de SimpleCopyScanline...

    En fait ici il faut utiliser en entrée pRGBTriple, et pRGBQuad en sortie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        FOR j := 0 TO Bitmap.Height-1 DO BEGIN
          RowIn :=  pRGBTriple(Bitmap.RawImage.GetLineStart(j));
          RowOut := pRGBQuad(RESULT.RawImage.GetLineStart(j));
          FOR i := 0 TO Bitmap.Width-1 DO begin
            RowOut[i].rgbBlue  := RowIn[i].rgbtBlue;
            RowOut[i].rgbGreen := RowIn[i].rgbtGreen;
            RowOut[i].rgbRed   := RowIn[i].rgbtRed;
            RowOut[i].rgbReserved := 255;
          end;
        END;
    Toujours sans chapeaux.

    Au bout du compte, réintégration des tests Flip et Reverse dans la proc qui va bien
    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
      FUNCTION FlipReverseScanLine(CONST Flip, Reverse:  BOOLEAN;
                                   CONST Bitmap:  TBitmap):  TBitmap;
      VAR
        i     :  INTEGER;
        j     :  INTEGER;
        //RowIn :  pRGBArray;
        //RowOut:  pRGBArray;
        RowIn :  pRGBTriple;
        RowOut:  pRGBQuad;
      BEGIN
        IF   Bitmap.PixelFormat <> pf24bit
        THEN RAISE EBitmapError.Create('Can Flip/Reverse only 24-bit bitmap');
     
        RESULT := TBitmap.Create;
        RESULT.PixelFormat := Bitmap.PixelFormat;
        RESULT.Width       := Bitmap.Width;
        RESULT.Height      := Bitmap.Height;
     
        RESULT.BeginUpdate();
        FOR j := 0 TO Bitmap.Height-1 DO BEGIN
          RowIn :=  pRGBTriple(Bitmap.RawImage.GetLineStart(j));
          IF   Flip
          THEN RowOut := pRGBQuad(RESULT.RawImage.GetLineStart(Bitmap.Height - 1 - j))
          ELSE RowOut := pRGBQuad(RESULT.RawImage.GetLineStart(j));
     
          // Optimization technique:  Use two FOR loops so IF is outside of inner loop
          IF   Reverse
          THEN
          FOR i := 0 TO Bitmap.Width-1 DO begin
            RowOut[i].rgbBlue  := RowIn[Bitmap.Width-1-i].rgbtBlue;
            RowOut[i].rgbGreen := RowIn[Bitmap.Width-1-i].rgbtGreen;
            RowOut[i].rgbRed   := RowIn[Bitmap.Width-1-i].rgbtRed;
            RowOut[i].rgbReserved := 255;
          end
          ELSE
          FOR i := 0 TO Bitmap.Width-1 DO begin
            RowOut[i].rgbBlue  := RowIn[i].rgbtBlue;
            RowOut[i].rgbGreen := RowIn[i].rgbtGreen;
            RowOut[i].rgbRed   := RowIn[i].rgbtRed;
            RowOut[i].rgbReserved := 255;
          end;
        END;
        RESULT.EndUpdate();
      END; {FlipReverseScanLine}

    et réactivation de la SimpleCopyScanline, et ma foi,

    Nom : mode_delphi.png
Affichages : 614
Taille : 151,8 Ko

    Puis il faudra essayer de comprendre pourquoi pRGBTriple ou pRGBquad pour l'entrée, et enfin travailler sur les 3 autres options de rotation (90, 180 et 270), mais à chaque jour suffit sa peine,


    EDIT :
    PS : j'ai supprimé le message précédent (celui avec la grande image), confus et qui n'apportait rien. Le pb était ailleurs, comme expliqué ci-dessus.

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 11 135
    Par défaut
    Salut,

    Je n'ai pas encore attaqué les rotations 90, 180 et 270, car j'ai voulu creuser certains points qui me semblaient mystérieux, et bien sûr la galère du TBitmap sous Linux/Gtk2 réapparaît, donc on ne s'étendra pas dessus, ce n'est pas le sujet.

    Je vous note juste deux ou trois points, si jamais certains voulaient travailler sur ce projet :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TFormFlipReverseRotate.btnLoadClick(Sender: TObject);
    begin
    ...
      ShowMessage(GetPixelFormat(BitmapOriginal));
      // les vieux démons sont de retour :
      // mon fichier de test exp32a_250.bmp est un 32 bits, vu ici comme un 24...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TFormFlipReverseRotate.btnSaveClick(Sender: TObject);
    begin
      IF   spd.Execute
      THEN imgModified.Picture.Bitmap.SaveToFile(spd.Filename)
      // résultat tout noir et en 24 bits si la source est en 32 bits, ok si en 24
    end;
    Cœur des fonctions FlipReverseCopyRect et FlipReverseStretchBlt, noter mes commentaires et le fait que j'ai supprimé le "-1" rajouté par EFG : est-ce une obligation sous Windows qu'il faut virer sous Linux ?
    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
        // Flip Top to Bottom
        IF   Flip
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Top    := src.Height;//-1; // pas compris, car génère un trait noir si présent
          Bottom := -1
        END
        ELSE BEGIN
          Top    := 0;
          Bottom := src.Height
        END;
     
        // Reverse Left to Right
        IF   Reverse
        THEN BEGIN
          // Unclear why extra "-1" is needed here.
          Left  := src.Width;//-1; // pas compris, car génère un trait noir si présent
          Right := -1;
        END
        ELSE BEGIN
          Left  := 0;
          Right := src.Width;
        END;
    Allez, j'ai du boulot avec les 3 rotations en attente...


    PS : j'ai remodelé la fiche et les codes pour avoir une logique dans l'affichage, et c'est beaucoup plus cool, si si !
    Pour ce faire, j'ai "publié" le code d'origine dans un nouveau dossier et en avant, après avoir corrigé ça, bien sûr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // suite "publication" du projet efg et modifs mineures de l'ihm,
    // au premier F9, bim !
    // FlipReverseRotate.lpr(23,1) Error: Can't open resource file ".../ma_version/FlipReverseRotate.res"
    // bravo la "publication" incomplète...
    Bah...
    Nom : new_fliprevrot.png
Affichages : 596
Taille : 170,3 Ko

    EDIT :
    Citation Envoyé par Jipété;
    Allez, j'ai du boulot avec les 3 rotations en attente...
    Torché en 10 minutes, tout était déjà en place, hé hé hé.

    Et je vous ai gardé le meilleur pour la fin : efg aussi, il a parfois miséré...
    Dans son SimpleCopy dans RotateScanline, lisez mon commentaire :
    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
          RESULT.BeginUpdate();
          // Out[i, j] = In[i, j]
          FOR  j := 0 TO src.Height - 1 DO BEGIN
            rowIn  := pRGBQuad(   src.RawImage.GetLineStart(j));
            rowOut := pRGBQuad(RESULT.RawImage.GetLineStart(j));
            FOR i := 0 TO src.Width - 1 DO 
              RowOut[i] := RowIn[i];
            {// gardé pour mémoire :
            FOR i := 0 TO src.Width - 1 DO BEGIN
              //  RowOut[i] := RowIn[i];
              // Why does this crash with RowOut[i] := RowIn[i]?  Alignment? - la misère, efg ?
              // Use this longer form as workaround.
              WITH rowOut[i] DO BEGIN
                rgbRed      := rowIn[i].rgbRed;
                rgbGreen    := rowIn[i].rgbGreen;
                rgbBlue     := rowIn[i].rgbBlue;
                rgbReserved := rowIn[i].rgbReserved;
              END
            END     }
          END;
          RESULT.EndUpdate();
    Bon, j'ai changé "Bitmap" partout en "src", plus parlant pour moi, et bien sûr il m'a fallu adapter et donc transformer ses pRGBArray de 3 bytes en pRGBQuad mais voilà,

    Merci à tous,

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

Discussions similaires

  1. [Free Pascal] You need ObjFpc (-S2) or Delphi (-Sd) mode to compile this module
    Par Maxence45 dans le forum Free Pascal
    Réponses: 2
    Dernier message: 17/02/2007, 15h56
  2. Différence entre mode release et mode debug
    Par WELCOMSMAIL dans le forum Visual C++
    Réponses: 1
    Dernier message: 06/11/2006, 10h20
  3. différence entre executable et mode debug de visual
    Par thony76 dans le forum Visual C++
    Réponses: 7
    Dernier message: 05/09/2006, 16h00
  4. Réponses: 5
    Dernier message: 11/12/2002, 12h31

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