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 :

Combiner zoom, rotation et transparence avec BGRABitmap [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut Combiner zoom, rotation et transparence avec BGRABitmap
    Bonsoir,

    Je souhaite pouvoir effectuer tout à la fois un zoom, une rotation ou encore une transparence sur un graphique contenu dans un BGRABitmap.
    Le problème est que je ne parviens pas à associer les trois effets simultanément.

    Je suis parti du code suivant, inspiré d'une démo trouvé sur le forum anglais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    procedure TfrmMap.bgraMainRedraw(Sender: TObject; Bitmap: TBGRABitmap);
    begin
      Bitmap.PutImageAngle(Bitmap.Width/2-0.5, Bitmap.Height/2-0.5, bmp, tbAngle.Position, bmp.Width/2-0.5, bmp.Height/2-0.5, tbOpacity.Position);
    end;
    bmp est le graphique d'origine (taille: 1920x1080px) modifié et affiché dans Bitmap (taille: 856x624px).
    Le code ci-dessus effectue superbement une rotation avec transparence en prenant le centre de Bitmap comme axe de rotation.
    Mais je n'ai pas trouvé une procédure ou fonction qui permette en même temps de zoomer le graphique d'origine.

    Aussi j'ai modifié le code de la manière suivante :

    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 TfrmMap.bgraMainRedraw(Sender: TObject; Bitmap: TBGRABitmap);
    var
      affine: TBGRAAffineBitmapTransform;
      LBGRATemp: TBGRABitmap;
    begin
      LBGRATemp := TBGRABitmap.Create(bgraMain.ClientWidth, bgraMain.ClientHeight, BGRABlack);
      try
        affine := TBGRAAffineBitmapTransform.Create(bmp, false);
        affine.GlobalOpacity := tbOpacity.Position;
        affine.RotateDeg(tbAngle.Position);
        affine.Scale(tbZoom.Position / 100);
        affine.Translate(bgraMain.ClientWidth / 2, bgraMain.ClientHeight / 2); 
        LBGRATemp.Fill(affine);
        Bitmap.PutImage(0, 0, LBGRATemp, dmSet, tbOpacity.Position);             
      finally
        LBGRATemp.Free;
        affine.Free;
      end;
    end;
    Et là j'avais les trois effets (transparence, rotation et zoom) réunis ! Le hic toutefois, c'est que la rotation ne s'effectue plus à partir du centre de l'image !
    Quelle procédure ou fonction dois-je ajouter à la variable affine pour parvenir à ce résultat ?
    Merci d'avance pour votre aide.

  2. #2
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 887
    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 887
    Points : 11 416
    Points
    11 416
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Dans son tuto, Gilles utilise un code un peu différent : présente-t-il le même inconvénient ?

  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 353
    Points
    4 353
    Billets dans le blog
    2
    Par défaut
    Bonjour,
    je ne suis pas a la maison pour vérifier mais dans ton exemple tu as 4 étapes :

    Opacité --> Rotation --> Scale --> Translation

    Ton problème je pense est l'ordre des transformations. C'est important. Pour ma part je ferai comme ceci

    Scale --> Rotation --> Opacité --> (Translation si besoin)

    A+

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonsoir Tourlourou,

    Citation Envoyé par tourlourou Voir le message
    Gilles utilise un code un peu différent : présente-t-il le même inconvénient ?
    J'avais repéré hier la série de tutoriaux de Gilles Vasseur (au demeurant bienvenus) mais n'avais pas eu le temps de les étudier en profondeur.
    J'ai modifié la procédure principale de la façon suivante :

    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
     
      LBGRATemp := TBGRABitmap.Create(imgResult.ClientWidth, imgResult.ClientHeight, BGRABlack);
      try
        fStep := 0;
        ratio := round((imgResult.Width / imgTo.Picture.Width) * 100);
     
        repeat //
          Inc(fStep);
     
          // traitement ici...
          LX := imgResult.ClientWidth div 2;
          LY := imgResult.ClientHeight div 2;
          LBGRATemp.PutImageAngle(LX, LY, fBGRATo, fStep, fBGRATo.Width div 2, fBGRATo.Height div 2, Opacity);
          LBGRATemp.Draw(imgResult.Canvas, 0, 0);
          Application.ProcessMessages;
          sleep(100 - fSpeed);
     
          //inc(ratio);
          BGRAReplace(fBGRATo, fBGRATo.Resample(fBGRATo.Width + 2, fBGRATo.Height + 2));
          fBGRATo.StretchPutImage(fBGRATo.ClipRect, fBGRATest, dmSet);
          //until (ratio = 100);
          until (fStep = 360);
      finally
        LBGRATemp.Free;
        btnGo.Enabled := True;
      end;
    Tel quel, ce code redimensionne l'image d'origine (quel magnifique rouge-gorge !) tout en la faisant tourner par incrément d'un degré autour de son centre.
    L'incrément de 2 dans la procédure Resample est arbitraire. Il est censé être remplacé par un pourcentage de la taille originale de l'image.
    C'est dire que le code a encore besoin d'être amélioré !
    Merci pour ton aide.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonsoir BeanzMaster,

    Citation Envoyé par BeanzMaster Voir le message
    Ton problème je pense est l'ordre des transformations. C'est important. Pour ma part je ferai comme ceci :

    Scale --> Rotation --> Opacité --> (Translation si besoin)
    Merci de me faire profiter de ton expérience.
    Si je laisse de côté l'opacité qui n'est pas vraiment un problème, j'en suis venu à penser qu'il valait mieux tourner l'image en premier pour ne pas perdre les parties de cette image qui sont dans les coins !
    Après, il y a le problème de la "Translation" qui doit effectivement être considérée.
    Mais je ne suis qu'au début de ma découverte de TBGRABitmap qui me semble très prometteur.
    Merci beaucoup pour ton aide.

  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 353
    Points
    4 353
    Billets dans le blog
    2
    Par défaut
    Salut j'ai fait quelques recherche vite fait pour pouvoir effectuer un zoom et une rotation en même temps, regardes du coté de la fonction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload;
    procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload;
    procedure PutImageAffine(Origin,HAxis,VAxis: TPointF; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload;
    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload;
    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AOpacity: Byte=255); overload;
    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); overload;
    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AResampleFilter: TResampleFilter; AMode: TDrawMode; AOpacity: Byte=255); virtual; abstract; overload;
    procedure PutImageAffine(AMatrix: TAffineMatrix; Source: TBGRACustomBitmap; AOutputBounds: TRect; AOpacity: Byte=255; ACorrectBlur: Boolean = false); overload;
    A l'aide des matrices tu pourras effectuer un zoom et une rotation

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonjour BeanzMaster,

    Merci pour ces quelques recherches. Je me suis essayé avec PutImageAffine, mais je n'ai pas trouvé comment faire pivoter l'image à partir de son centre durant "l'affinage".

    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
    procedure TfrmMap.bgraMainRedraw(Sender: TObject; Bitmap: TBGRABitmap);
    var
      LBGRATemp: TBGRABitmap;
      percent, ratio: single;
    begin
      percent := (LBGRABase.Width / Bitmap.Width) / 100;
      ratio := tbZoom.Position * percent;
      LBGRATemp := TBGRABitmap.Create(LBGRABase.Width, LBGRABase.Height, BGRAWhite);
      try
        LBGRATemp.PutImageAffine(AffineMatrixScale(ratio, ratio) *
                                 AffineMatrixRotationDeg(tbAngle.Position),
                                 LBGRABase, tbOpacity.Position);
        LBGRATemp.Draw(Bitmap.Canvas, 0, 0);
      finally
        LBGRATemp.Free;
      end;
    end;

  8. #8
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonsoir BeanzMaster,

    Citation Envoyé par Péhelji
    J'en suis venu à penser qu'il valait mieux tourner l'image en premier pour ne pas perdre les parties de cette image qui sont dans les coins !
    Je suis venu à bout de ce problème et à combiner les trois effets avec la procédure suivante :

    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
     
      offsetX := round(((tbZoom.Position - 100) * LBGRABase.Width  div 2) / 100);
      offsetY := round(((tbZoom.Position - 100) * LBGRABase.Height div 2) / 100);
     
      LBGRATemp := TBGRABitmap.Create(LBGRABase.Width, LBGRABase.Height);
      try
        LBGRATemp.PutImageAngle(LBGRATemp.Width/2-0.5, LBGRATemp.Height/2-0.5, LBGRABase, tbAngle.Position,
                                LBGRABase.Width/2-0.5, LBGRABase.Height/2-0.5, tbOpacity.Position);
        rc := LBGRATemp.ClipRect;
        rc.Inflate(round(offsetX), round(offsetY));
     
        Bitmap.Canvas.CopyRect(Bitmap.ClipRect, LBGRATemp.Canvas, rc);
      finally
        LBGRATemp.Free;
      end;
    Peut-être serait-il possible d'améliorer la fluidité du zoom en utilisant BGRAVirtualScreen ou encore BGRACanvas2D ?

    J'ai trouvé de quoi plancher sur le sujet avec la démo LayerOriginal fournie avec BGRABitmap, et aussi celle postée ici par Circular.

  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 353
    Points
    4 353
    Billets dans le blog
    2
    Par défaut
    Salut,

    je n'ai pas beaucoup de temps en ce moment et je n'utilise que très rarement BGRABitmap mais, pour ce qui est de la fluidité lis les tutoriels de Gilles,. Tu n'as pas vraiment besoin du BGRAVirtualScreen.
    Le BGRACanvas2D c'est comme le TCanvas donc pas besoin dans ton cas.

    Voila comment à fait Gilles pour la rotation et le zoom :

    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
    procedure TGVTransition.DoGrowCenterRotate(CCW: Boolean);
    // *** GrowCenterCCWRotate et GrowCenterCWRotate ***
    var
      LBGRATemp: TBGRABitmap;
    begin
      LBGRATemp := fLBGRATo.Resample(
        ComputeInterpolationInt(C_MinResample, ClientWidth),
        ComputeInterpolationInt(C_MinResample, ClientHeight)) as TBGRABitmap;
      try
        fLBGRAFrom.PutImageAngle(ClientWidth / 2, ClientHeight / 2, LBGRATemp,
          ifthen(CCW, ComputeInterpolation(360, 0), ComputeInterpolation(-360, 0)),
          LBGRATemp.Width / 2, LBGRATemp.Height / 2,DestinationOpacity);
      finally
        LBGRATemp.Free;
      end;
    end;
    Moins de calcul déja ici

    Petite question que souhaites tu réaliser au final ? Une animation ? un mini-éditeur ?

    https://gilles-vasseur.developpez.co...sitions/bgra1/
    https://gilles-vasseur.developpez.co...sitions/bgra2/
    https://gilles-vasseur.developpez.co...sitions/bgra3/
    https://gilles-vasseur.developpez.co...sitions/bgra4/
    https://gilles-vasseur.developpez.co...sitions/bgra5/
    https://gilles-vasseur.developpez.co...sitions/bgra6/
    https://gilles-vasseur.developpez.co...sitions/bgra7/
    https://gilles-vasseur.developpez.co...sitions/bgra8/

  10. #10
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonjour BeanzMaster,

    J'ai téléchargé les tutoriels de Gilles et j'ai testé les démos et le test simple livré avec le tutoriel n°8. C'est pour le moins bluffant !
    C'est effectivement vers les transitions GrowCenter et GrowCenterCWRotate que je dois rechercher la solution à mon problème.
    Quoique j'étais parvenu à une meilleure fluidité avec la séquence suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
      LBGRATemp := TBGRABitmap.Create(LBGRABase.Width, LBGRABase.Height{, BGRAWhite});
      try
        LBGRATemp.PutImageAffine(
          AffineMatrixScale(ratio, ratio) *
          AffineMatrixTranslation(LBGRABase.Width/2-0.5, LBGRABase.Height/2-0.5) *
          AffineMatrixRotationDeg(tbAngle.Position) *
          AffineMatrixTranslation(-LBGRABase.Width/2-0.5, -LBGRABase.Height/2-0.5),
          LBGRABase, tbOpacity.Position);
        LBGRATemp.Draw(Bitmap.Canvas, 0, 0);
      finally
        LBGRATemp.Free;
      end;
    La rotation est nickel au centre du canvas... mais le zoom n'opère qu'à partir du coin supérieur gauche !
    Le nœud du problème se situe au niveau des paramètres passés à AffineMatrixTranslation. Je vais voir si les fonctions ComputeInterpolation des tutos ne seraient pas la solution.

    Citation Envoyé par BeanzMaster Voir le message
    Petite question que souhaites tu réaliser au final ? Une animation ? un mini-éditeur ?
    Je travaille sur une application de cartographie et, dans un premier temps, je souhaite pouvoir ajuster des cartes de différentes tailles en les superposant (j'ai testé BGRALayers), chaque couche devant être modifiable par zoom, rotation, transparence et bien entendu déplacement.
    Merci encore pour ta recherche et tes conseils.

  11. #11
    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 353
    Points
    4 353
    Billets dans le blog
    2
    Par défaut
    Bonsoir

    Utiliser des calques sera en effet la solution. Mais je ne comprends pas bien ton désir de vouloir faire un zoom et une rotation en même temps. Le problème dans ta translation vient du fait que tu redimensionnes ton image, du coup la largeur et la hauteur ne sont par conséquent plus les mêmes que LBGRABase.

    Je ne sais pas si j'aurai assez de temps cette semaine et jusqu'après les fêtes. Mais je tenterai quelque chose si je peux.

    Bonne fin de soirée.

  12. #12
    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 353
    Points
    4 353
    Billets dans le blog
    2
    Par défaut
    Salut, j'ai eu un peu de temps aujourd'hui (j'en avais marre de ce que je faisait du coup...)

    La fonction PutAffine n'est pas l'idéal, ou sinon il faudrait procéder en 2 étapes (Zoom + Rotation puis une translation).

    Voilà le code à l'arrache que j'ai fait. Il devrait correspondre à ce que tu recherches.

    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
    unit Unit1;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
      ExtDlgs, BGRABitmapTypes, BGRABitmap; //, BGRATransform;
     
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        Button1: TButton;
        Label1: TLabel;
        Label2: TLabel;
        Label3: TLabel;
        Label4: TLabel;
        Label5: TLabel;
        OpenPictureDialog1: TOpenPictureDialog;
        Panel1: TPanel;
        ScrollBar1: TScrollBar;
        ScrollBar2: TScrollBar;
        ScrollBar3: TScrollBar;
        ScrollBar4: TScrollBar;
        ScrollBar5: TScrollBar;
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Panel1Paint(Sender: TObject);
        procedure ScrollBar1Change(Sender: TObject);
      private
        DisplayBuffer : TBGRABitmap;
        SrcBitmap : TBGRABitmap;
     
      public
        procedure RotateAndZoom(Ratio:Single; Angle : Single; Opacity : Byte);
     
     
     
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      DisplayBuffer := TBGRABitmap.Create(Panel1.ClientWidth, Panel1.ClientHeight);
      SrcBitmap := TBGRABitmap.Create;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if openPictureDialog1.Execute then
      begin
        SrcBitmap.LoadFromFile(OpenPictureDialog1.FileName);
        DisplayBuffer.PutImage(0,0,SrcBitmap,dmDrawWithTransparency,255);
        Panel1.Invalidate;
      end;
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FreeAndNil(DisplayBuffer);
      FreeAndNil(SrcBitmap);
    end;
     
    procedure TForm1.Panel1Paint(Sender: TObject);
    begin
      DisplayBuffer.Draw(Panel1.Canvas,0,0);
    end;
     
    procedure TForm1.ScrollBar1Change(Sender: TObject);
    begin
      DisplayBuffer.Canvas.Clear;
      RotateAndZoom(Scrollbar1.position / 100, Scrollbar2.Position, ScrollBAr3.Position);
      Panel1.Invalidate;
    end;
     
    procedure TForm1.RotateAndZoom(Ratio: Single; Angle: Single; Opacity : Byte);
    var
      LBGRATemp: TBGRABitmap;
      LNewWidth, LNewHeight, LMidWidth, LMidHeight : Integer;
    begin
      LNewWidth := round(SrcBitmap.Width * ratio);
      LNewHeight := round(SrcBitmap.Height * ratio);
      LMidWidth := LNewWidth shr 1;
      LMidHeight := LNewHeight shr 1;
      LBGRATemp := SrcBitmap.Resample(LNewWidth, LNewHeight) as TBGRABitmap;
      try
         DisplayBuffer.PutImageAngle(LMidWidth + ScrollBar4.Position, LMidHeight + ScrollBar5.Position, LBGRATemp,
          Angle,
          LMidWidth, LMidHeight,Opacity);
      finally
        LBGRATemp.Free;
      end;
    end;
     
    end.
    Un simple array ou un TList avec un record genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    TBitmapLayer = record
      OriginalBitmap : TBGRABitmap;
      OffsetX, OffsetY : Integer;
      Angle : Integer;
      ZoomRatio : Single;
    end;
    devrait faire l'affaire pour gérer tes calques.

    Bonne soirée.

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonjour BeanzMaster,

    Citation Envoyé par BeanzMaster
    Je ne sais pas si j'aurai assez de temps cette semaine et jusqu'après les fêtes. Mais je tenterai quelque chose si je peux.
    (...)
    Salut, j'ai eu un peu de temps aujourd'hui.
    D'abord merci de m'avoir accordé ce peu de temps pour "pondre" un code qui est fonctionnel dans le principe (je viens de le tester) et pardon d'avoir tardé à te répondre, mais d'une part j'ai moi-même été assez pris la semaine passée et, d'autre part, vas-t-en savoir pourquoi, je n'ai pas reçu du forum la moindre notification de tes deux derniers messages !

    Dans l'intervalle, après avoir étudié les tutos de Gilles, je me suis aperçu que mon code initial n'était pas si mauvais que çà et qu'il demandait juste à être affiné.
    Et je suis arrivé à un rendu qui me convient avec la fonction suivante :

    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
     
    var
      BGRATemp: TBGRABitmap;
      BitmapRect, BGRATempRect: TRect;
      offsetX, offsetY: single;
    begin
      BitmapRect := Bitmap.ClipRect;
     
      BGRATemp := TBGRABitmap.Create(BGRABase.Width, BGRABase.Height);
      BGRATempRect := BGRATemp.ClipRect;
      try
        BGRATemp.PutImageAngle(BGRATemp.Width / 2 - 0.5, BGRATemp.Height / 2 - 0.5,
                               BGRABase, tbAngle.Position,
                               BGRABase.Width / 2 - 0.5, BGRABase.Height / 2 - 0.5,
                               tbOpacity.Position);
     
        offsetX := (BGRABase.Width / tbZoom.Position) * 100 * ratioX;
        offsetX := (BGRABase.Width - offsetX) / 2;
        offsetY := (BGRABase.Height / tbZoom.Position) * 100 * ratioY;
        offsetY := (BGRABase.Height - offsetY) / 2;
     
        if (offsetX < 0) or (offsetY < 0) then
           begin
             offsetX := (tbZoom.Position * Bitmap.Width) / 100 / ratioX;
             offsetX := (Bitmap.Width - offsetX) / 2;
             offsetY := (tbZoom.Position * Bitmap.Height) / 100 / ratioY;
             offsetY := (Bitmap.Height - offsetY) / 2;
             BitmapRect.Inflate(-round(offsetX), -round(offsetY));
           end else
             BGRATempRect.Inflate(-round(offsetX), -round(offsetY));
     
        Bitmap.Canvas.CopyRect(BitmapRect, BGRATemp.Canvas, BGRATempRect);
      finally
        BGRATemp.Free;
      end;
    end;
    Cela peut paraître beaucoup de calcul mais se justifie pour afficher l'image au centre du contrôle fenêtré, et ce quelque soit le zoom ou l'angle considéré, une condition essentielle que ton merveilleux petit bout de code fait "à l'arrache" ne prends pas en compte . En le compilant, je me suis aperçu de la lenteur du processus quand il s'agit d'effectuer un zoom ou une rotation sur une image de 3400x3400px (qui me sert d'étalon pour mes tests), ce qui ne pose aucun problème au code ci-dessus . D'autant que plusieurs images, superposées, doivent pouvoir être modifiées indépendamment les unes des autres ou simultanément !

    Citation Envoyé par BeanzMaster
    Je ne comprends pas bien ton désir de vouloir faire un zoom et une rotation en même temps.
    En fait, je me suis mal exprimé. Ce que je voulais dire, c'est qu'au final, le rendu devait tenir compte des trois effets recherchés, même si chacun était actionné indépendamment, ce que tu as très bien réalisé en utilisant des Scrollbars (tout comme moi-même j'utilisais des Trackbars, mais le principe est le même).

    Si tu ne vois rien à rajouter, peut-être pourrais-tu m'indiquer si c'est à moi d'activer la balise "Résolu", puisque j'estime qu'au travers de tes réponses tu as solutionné ma difficulté du départ.
    Encore merci à toi.

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonjour BeanzMaster,

    En reprenant et en retravaillant ton bout de code, je suis parvenu à un rendu encore plus satisfaisant que celui décrit dans mon dernier message où j'écrivais :

    En le compilant, je me suis aperçu de la lenteur du processus quand il s'agit d'effectuer un zoom ou une rotation sur une image de 3400x3400px.
    En fait, "la lenteur du processus" ne venait pas de la taille de l'image d'origine, mais de l'association du zoom et de la rotation dans la même procédure de dessin.
    En stockant l'image zoomée et non en la recréant à chaque modification, j'ai réussi à faire tourner de façon satisfaisante une image carrée de 17000px de côté !
    Voici le code final :

    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
    unit Unit1;
     
    {$mode objfpc}{$H+}
     
    interface
     
    uses
      Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
      StdCtrls, ExtDlgs, BGRAGraphicControl, BGRABitmap, BGRABitmapTypes;
     
    type
     
      { TForm1 }
     
      TForm1 = class(TForm)
        BGRAGraphicControl1: TBGRAGraphicControl;
        Button1: TButton;
        Edit1: TEdit;
        OpenPictureDialog1: TOpenPictureDialog;
        TrackBar_Angle: TTrackBar;
        TrackBar_Zoom: TTrackBar;
        TrackBar_Opacity: TTrackBar;
        procedure BGRAGraphicControl1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
        procedure Button1Click(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure TrackBar_AngleChange(Sender: TObject);
        procedure TrackBar_ZoomChange(Sender: TObject);
      private
        { private declarations }
      public
        { public declarations }
        BGRASource: TBGRABitmap;
        BGRATemp: TBGRABitmap;
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.lfm}
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      BGRASource := TBGRABitmap.Create;
      BGRATemp := TBGRABitmap.Create;
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      FreeAndNil(BGRASource);
      FreeAndNil(BGRATemp);
    end;
     
    procedure TForm1.BGRAGraphicControl1Redraw(Sender: TObject; Bitmap: TBGRABitmap);
    begin
      Bitmap.PutImageAngle(Bitmap.Width/2-0.5, Bitmap.Height/2-0.5,
                           BGRATemp, TrackBar_Angle.Position,
                           BGRATemp.Width/2-0.5,
                           BGRATemp.Height/2-0.5, TrackBar_Opacity.Position);
     
      Edit1.Text := 'Zoom = ' + IntToStr(TrackBar_Zoom.Position) + '% ; ' +
                   ' NewWidth = ' + IntToStr(BGRATemp.Width) + ' ; ' +
                   ' NewHeight = ' + IntToStr(BGRATemp.Height) + ' ;';
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if openPictureDialog1.Execute then
      begin
        BGRASource.LoadFromFile(OpenPictureDialog1.FileName);
        BGRATemp := BGRASource.Duplicate(true) as TBGRABitmap;
        BGRAGraphicControl1.RedrawBitmap;
      end;
    end;
     
    procedure TForm1.TrackBar_AngleChange(Sender: TObject);
    begin
      BGRAGraphicControl1.RedrawBitmap;
    end;
     
    procedure TForm1.TrackBar_ZoomChange(Sender: TObject);
    var
      NewWidth, NewHeight: Integer;
    begin
      NewWidth := round(BGRASource.Width * (TrackBar_Zoom.Position / 100));
      NewHeight := round(BGRASource.Height * (TrackBar_Zoom.Position / 100));
     
      if Assigned(BGRATemp) then BGRATemp.Free;
     
      BGRATemp := TBGRABitmap.Create(NewWidth, NewHeight);
      //BGRATemp := BGRASource.Resample(NewWidth, NewHeight) as TBGRABitmap;
      BGRATemp.StretchPutImage(BGRATemp.ClipRect, BGRASource, dmDrawWithTransparency);
     
      BGRAGraphicControl1.RedrawBitmap;
    end;
     
    end.
    Je me suis également aperçu que la méthode Resample testée à la ligne 95 levait assez rapidement une erreur EOutOfMemory avec le message "TBGRAWinBitmap.ReallocBitmap : Windows error 8", contrairement à l'utlisation des deux lignes de code situées au-dessus.
    Nous sommes venus à bout du problème du départ ! Encore un grand merci à toi !

  15. #15
    Membre confirmé

    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 140
    Points : 623
    Points
    623
    Par défaut
    Bonjour,

    Le sujet est un peu ancien, cela dit je voulais mentionner que la solution par matrice affine peut fonctionner. Le problème du centrage vient du fait que Scale et Rotate se font sur un centre à la coordonnée (0,0). La solution consiste donc à d'abord faire une translation pour ramener le centre de l'image à la coordonnée (0,0), puis la rotation et le zoom, puis à refaire une translation dans l'autre sens.

    Cela a été un peu évoqué plus haut et cela était presque bon. Voilà donc la solution :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      LBGRATemp := TBGRABitmap.Create(LBGRABase.Width, LBGRABase.Height{, BGRAWhite});
      try
        LBGRATemp.PutImageAffine(
          AffineMatrixTranslation(LBGRABase.Width/2-0.5, LBGRABase.Height/2-0.5) *
          AffineMatrixScale(ratio, ratio) *
          AffineMatrixRotationDeg(tbAngle.Position) *
          AffineMatrixTranslation(-LBGRABase.Width/2-0.5, -LBGRABase.Height/2-0.5),
          LBGRABase, tbOpacity.Position);
        LBGRATemp.Draw(Bitmap.Canvas, 0, 0);
      finally
        LBGRATemp.Free;
      end;
    Scale et Rotate sont entre les deux translations.

    Cordialement

  16. #16
    Nouveau membre du Club
    Homme Profil pro
    Développeur occasionnel
    Inscrit en
    Janvier 2018
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Finistère (Bretagne)

    Informations professionnelles :
    Activité : Développeur occasionnel
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2018
    Messages : 49
    Points : 26
    Points
    26
    Par défaut
    Bonjour circular17,

    Citation Envoyé par circular17 Voir le message
    Le sujet est un peu ancien, cela dit je voulais mentionner que la solution par matrice affine peut fonctionner.
    Un grand merci au contraire d'avoir pris un peu de temps pour revenir sur un cas particulier et présenter un code plus simple et fonctionnel.
    Comme tu le dis toi-même, mon code publié dans le message #10 "était presque bon", mais il était aussi le fruit d'un tâtonnement incertain, puisque je n'avais pas compris l'ordre des différentes fonctions prises en paramètres dans PutImageAffine.

    Citation Envoyé par circular17 Voir le message
    La solution consiste donc à d'abord faire une translation pour ramener le centre de l'image à la coordonnée (0,0), puis la rotation et le zoom, puis à refaire une translation dans l'autre sens.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
        LBGRATemp.PutImageAffine(
          AffineMatrixTranslation(LBGRABase.Width/2-0.5, LBGRABase.Height/2-0.5) *
          AffineMatrixScale(ratio, ratio) *
          AffineMatrixRotationDeg(tbAngle.Position) *
          AffineMatrixTranslation(-LBGRABase.Width/2-0.5, -LBGRABase.Height/2-0.5),
          LBGRABase, tbOpacity.Position);
    En résumé, les fonctions sont exécutées selon leur ordre de déclaration et sont séparées par l'opérateur *.

    Un grand merci à toi pour cette merveilleuse bibliothèque qui souffre seulement de ne pas être suffisamment documentée !

  17. #17
    Membre confirmé

    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 140
    Points : 623
    Points
    623
    Par défaut
    Citation Envoyé par Péhelji Voir le message
    En résumé, les fonctions sont exécutées selon leur ordre de déclaration et sont séparées par l'opérateur *.
    Oui en fait dans l'ordre inverse. C'est une convention en mathématiques de multiplication des matrices, en supposant que TPointF soit un vecteur colonne.

    Un grand merci à toi pour cette merveilleuse bibliothèque qui souffre seulement de ne pas être suffisamment documentée !
    Ah ben oui j'aimerais bien aussi plus de documentation. Le wiki est en principe en libre accès mais peu de gens y contribuent. Cela dit des gens ont fait la traduction

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

Discussions similaires

  1. [D5] Zoom d'image PNG avec transparence
    Par Thierry Laborde dans le forum Delphi
    Réponses: 9
    Dernier message: 12/06/2006, 16h41
  2. Réponses: 13
    Dernier message: 01/12/2005, 06h34
  3. Texte en transparence avec TextOut
    Par TigreRouge dans le forum MFC
    Réponses: 2
    Dernier message: 06/06/2005, 23h57
  4. [Rotations] Rotations Locales/Globales avec Quaternions
    Par Clorish dans le forum Algorithmes et structures de données
    Réponses: 2
    Dernier message: 24/05/2005, 17h41
  5. probleme de transparence avec fog
    Par Daedar dans le forum OpenGL
    Réponses: 10
    Dernier message: 03/05/2004, 09h14

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