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

Composants FMX Delphi Discussion :

Utilisation de TImageViewer


Sujet :

Composants FMX Delphi

  1. #1
    Membre confirmé

    Profil pro
    senior scientist
    Inscrit en
    Mai 2003
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : senior scientist

    Informations forums :
    Inscription : Mai 2003
    Messages : 94
    Billets dans le blog
    1
    Par défaut Utilisation de TImageViewer
    Bonjour,
    Je veux visualiser une image dans un TImageviewer et pouvoir adresser les pixels à l'aide la souris.
    Par défaut, qu'elle que soit la taille du composant définie à la création, la taille de l'image visualisée est adaptée à la fenêtre du composant (option "bestfit").
    Le niveau de zoom peut alors être changé en utilisant la molette centrale de la souris, et le centrage de l'image ajusté avec les curseurs latéraux (option "scroll"). C'est parfait.
    Maintenant, en promenant la souris (option "hittest'' et utilisation de l'événement "mousemove"), j'obtiens des coordonnées X et Y pour chaque pixel, qui semblent être des coordonnées ''écran''.
    J'ai bien trouvé la méthode "screentolocal" mais elle donne des coordonnées dans le composant (donc après centrage et zoom).
    Quelle est la méthode pour les transformer en coordonnées dans l'image initiale ?
    Merci, d'avance.

  2. #2
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 231
    Par défaut
    Je suis persuadé avoir déjà vu un sujet similaire utilisant de BitmapScale et ViewportPosition pour gérer cela, si je le retrouve

    EDIT :

    Je ne fais pas de FMX mais tente ce code je me base sur le même principe du ViewportPosition pour les coordonnées d'un TStringGrid FMX :
    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
    procedure TForm1.ImageViewer1MouseMove(Sender: TObject; 
      Shift: TShiftState; X, Y: Single);
    var
      ImageViewer: TImageViewer;
      Image: TBitmap;
      ImageX, ImageY: Single;
      ScaleX, ScaleY, BitmapScale: Single;
    begin
      ImageViewer := Sender as TImageViewer;
      Image := ImageViewer.Bitmap;
     
      // Vérifier qu'une image est chargée
      if Assigned(Image) and not Image.IsEmpty then
      begin
        BitmapScale := Image.BitmapScale;
     
        // Calculer les facteurs d'échelle de l'image dans le composant
        ScaleX := ImageViewer.Width / (Image.Width * BitmapScale);
        ScaleY := ImageViewer.Height / (Image.Height * BitmapScale);
     
        // Convertir les coordonnées de la souris en coordonnées d'image
        ImageX := (X / ScaleX) + ImageViewer.ViewportPosition.X;
        ImageY := (Y / ScaleY) + ImageViewer.ViewportPosition.Y;
     
        // Vérifier que les coordonnées sont dans les limites de l'image
        if (ImageX >= 0) and (ImageX <= Image.Width) and
           (ImageY >= 0) and (ImageY <= Image.Height) then
        begin
          Label1.Text := Format('Pixel: X=%.0f, Y=%.0f', [ImageX, ImageY]);
        end
        else
        begin
          Label1.Text := 'En dehors de l''image';
        end;
      end;
    end;

    EDIT 2 :

    Une variante sur StackOverflow FMX TImageviewer : get coordinate in used Bitmap
    Je pense que cela ne gère pas bien le déplacement et c'est pour cela que l'auteur a demandé de l'aide pour corriger sa fonction

    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
     
    procedure TmainForm.imgviewer_layoutMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    var
      ImageViewer: TImageViewer;
      Image: TBitmap;
      ImageX, ImageY: Single;
      ScaleX, ScaleY, BitmapScale: Single;
    begin
      ImageViewer := Sender as TImageViewer;
      Image := ImageViewer.Bitmap;
     
      // Ensure we have an image loaded in the ImageViewer
      if Assigned(Image) and not Image.IsEmpty then
      begin
        BitmapScale := Image.BitmapScale;
     
        // Calculate the scale factors of the image within the ImageViewer
        ScaleX := ImageViewer.Width / (Image.Width * BitmapScale);
        ScaleY := ImageViewer.Height / (Image.Height * BitmapScale);
     
        // Adjust the X, Y to the image coordinates
        ImageX := X / ScaleX;
        ImageY := Y / ScaleY;
     
        // Ensure coordinates are within the bounds of the image
        if (ImageX >= 0) and (ImageX <= Image.Width) and
           (ImageY >= 0) and (ImageY <= Image.Height) then
        begin
          UpdateStatus('INFO LAYOUT DOWN ' + Point2Str(ImageX, ImageY));
        end
        else
        begin
          UpdateStatus('INFO LAYOUT DOWN: Outside Image');
        end;
      end
      else
      begin
        UpdateStatus('INFO LAYOUT DOWN: No Image Loaded');
      end;
    end;
    Et la variante qui gère le déplacement dans la zone client qui corrige la fonction ci-dessus

    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
    procedure TmainForm.imgviewer_layoutMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    var ImageViewer:       TImageViewer;
        Image:             TBitmap;
        ImageLeft,
        ImageTop:          Single;
        ImageX,
        ImageY:            Single;
        ScaledImageWidth,
        ScaledImageHeight: Single;
        Scale:             Single;
    begin
        //Get controls
      ImageViewer:=Sender as TImageViewer;
      Image:=ImageViewer.Bitmap;
     
      if Assigned(Image) and not Image.IsEmpty then begin
     
        //Get scaled image size
        Scale:=Viewer.BitmapScale;
        ScaledImageWidth:=Image.Width*Scale;
        ScaledImageHeight:=Image.Height*Scale;
     
        //Get bitmap's top and left positions.
        ImageLeft:=(ImageViewer.Width-ScaledImageWidth)/2;
        if ImageLeft<0 then ImageLeft:=0;
        ImageTop:=(ImageViewer.Height-ScaledImageHeight)/2;
        if ImageTop<0 then ImageTop:=0;
     
        //Get bitmap's mouse coordinates
        ImageX:=(X+ImageViewer.ViewportPosition.X-ImageLeft)/Scale;
        ImageY:=(Y+ImageViewer.ViewportPosition.Y-ImageTop)/Scale;
     
        //Report results
        if (X>=ImageLeft) and (X<=ImageLeft+ScaledImageWidth)
           and (Y>=ImageTop) and (Y<=ImageTop+ScaledImageHeight)
        then UpdateStatus('INFO LAYOUT DOWN '+Point2Str(ImageX,ImageY))
        else UpdateStatus('INFO LAYOUT DOWN: OutsideImage');
      end
      else UpdateStatus('INFO LAYOUT DOWN: No Image Loaded');
    end;
    Aide via F1 - Utilisez l'I.A. - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité ! Sachez-le : l'IA remplace la très grande majorité des développeurs, pas seulement les ignares ...

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre confirmé

    Profil pro
    senior scientist
    Inscrit en
    Mai 2003
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : senior scientist

    Informations forums :
    Inscription : Mai 2003
    Messages : 94
    Billets dans le blog
    1
    Par défaut
    Oui, j'ai vu le paramètre "bitmapscale": mais il y en au moins à trois niveaux (TimageViewer, TimageViewer.Bitmap et TImageViewer.Bitmap.Image).
    Sans plus de documentation (ce qui est malheureusement de plus en plus le cas ), il est difficile de comprendre l'algo sous-jacent.
    Merci, si tu retrouves ces informations.

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 231
    Par défaut
    J'ai mis à jour ma réponse pendant que tu lisais, le code est théorique, je ne fais jamais de FMX

    EDIT :
    J'ai juste un doute si les X Y de ViewportPosition doivent etre scalé ou pas ?

    donc soit

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        ImageX := (X / ScaleX) + ImageViewer.ViewportPosition.X;
        ImageY := (Y / ScaleY) + ImageViewer.ViewportPosition.Y;
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        ImageX := (X + ImageViewer.ViewportPosition.X) / ScaleX;
        ImageY := (Y + ImageViewer.ViewportPosition.Y) / ScaleY;
    A étudier

    Et la dernière variante de TmainForm.imgviewer_layoutMouseDown me semble la plus pertinente mais l'algo devient un poil complexe pour gérer le coin (0,0), si cela a été ajouté, je suppose cela utile
    Aide via F1 - Utilisez l'I.A. - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité ! Sachez-le : l'IA remplace la très grande majorité des développeurs, pas seulement les ignares ...

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre confirmé

    Profil pro
    senior scientist
    Inscrit en
    Mai 2003
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : senior scientist

    Informations forums :
    Inscription : Mai 2003
    Messages : 94
    Billets dans le blog
    1
    Par défaut
    J'ai essayé avec ta philo:
    - TImageviewer n'a pas de propriété "zoom" ni "viewportposition".
    - "zoom" devrait pouvoir être remplacé par la propriété "bitmapscale" de TImageviewer ou bien de TImageViewer.Bitmap.Image qui sont des scalaires réels ("single").
    - ta propriété "viewportposition" pourrait correspondre à la propriété "scale" d'un TImage qui est bien un TPosition (en gros un vecteur 2D).
    - le problème qui bloque pour vérifier, c'est que TImageViewer.Bitmap.Image n'est pas un TImage, mais un TBitmapImage qui ne possède pas cette propriété .
    J'ai bien peur d'être obligé de regarder le code source de FMX

    Moi non plus je ne suis pas un afficionado de FMX: je voudrais simplement pouvoir utiliser Delphi pour faire des opérations graphiques scientifiques standards ...!

  6. #6
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 231
    Par défaut
    Zoom c'était un Helper
    Cela se remplace par

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        // Calculate the scale factors of the image within the ImageViewer
        ScaleX := ImageViewer.Width / (Image.Width * BitmapScale);
        ScaleY := ImageViewer.Height / (Image.Height * BitmapScale);
    Prend bien la dernière version fournie de TmainForm.imgviewer_layoutMouseDown dans ma première réponse et lit la conversation du StackOverflow



    ViewportPosition c'est une propriété de TCustomScrollBox dont hérite le TImageViewer
    Aide via F1 - Utilisez l'I.A. - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité ! Sachez-le : l'IA remplace la très grande majorité des développeurs, pas seulement les ignares ...

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 231
    Par défaut
    En Delphi 10 Seattle, ce code compile, faut juste le vérifier, il est faux, voir la variante 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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    procedure TForm1.ImageViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    var ImageViewer:       TImageViewer;
        Image:             TBitmap;
        ImageLeft,
        ImageTop:          Single;
        ImageX,
        ImageY:            Single;
        ScaledImageWidth,
        ScaledImageHeight: Single;
        Scale:             Single;
    begin
        //Get controls
      ImageViewer:=Sender as TImageViewer;
      Image:=ImageViewer.Bitmap;
     
      if Assigned(Image) and not Image.IsEmpty then
      begin
     
        //Get scaled image size
        Scale := Image.BitmapScale;
        ScaledImageWidth := Image.Width*Scale;
        ScaledImageHeight := Image.Height*Scale;
     
        //Get bitmap's top and left positions.
        ImageLeft:=(ImageViewer.Width-ScaledImageWidth)/2;
        if ImageLeft <0 then
          ImageLeft := 0;
     
        ImageTop:=(ImageViewer.Height-ScaledImageHeight)/2;
        if ImageTop < 0 then
          ImageTop := 0;
     
        //Get bitmap's mouse coordinates
        ImageX := (X + ImageViewer.ViewportPosition.X - ImageLeft) / Scale;
        ImageY := (Y + ImageViewer.ViewportPosition.Y - ImageTop) / Scale;
     
        //Report results
        if (X >= ImageLeft) and (X <= ImageLeft + ScaledImageWidth) and (Y>=ImageTop) and (Y <= ImageTop + ScaledImageHeight) then
          Label1.Text :=  'INFO LAYOUT DOWN '+  Format('Pixel: X=%.0f, Y=%.0f', [ImageX, ImageY])
        else
          Label1.Text := 'INFO LAYOUT DOWN: OutsideImage';
      end
      else
        Label1.Text := 'INFO LAYOUT DOWN: No Image Loaded';
    end;
    Ce n'est pas parfait, il doit manquer des opérations de transformation sur l'inversion du ZOOM
    Sans Zoom, cela fonctionne très bien et cela supporte bien le Scroll
    Avec Zoom, les chiffres ne correspondent plus

    Nom : image.png
Affichages : 85
Taille : 176,2 Ko
    Aide via F1 - Utilisez l'I.A. - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité ! Sachez-le : l'IA remplace la très grande majorité des développeurs, pas seulement les ignares ...

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  8. #8
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 231
    Par défaut
    Nom : image.png
Affichages : 85
Taille : 221,9 Ko

    Voici une versionavec ImageViewer.BitmapScale basé sur le code de StackOverflow, il n'est pas très lisible à mon gout, on va donc le simplifier

    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
    procedure TForm1.ImageViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    var ImageViewer:       TImageViewer;
        Image:             TBitmap;
        ImageLeft,
        ImageTop:          Single;
        ImageX,
        ImageY:            Single;
        ScaledImageWidth,
        ScaledImageHeight: Single;
    begin
        //Get controls
      ImageViewer:=Sender as TImageViewer;
      Image:=ImageViewer.Bitmap;
     
      if Assigned(Image) and not Image.IsEmpty then
      begin
        //Get scaled image size
        ScaledImageWidth := Image.Width*ImageViewer.BitmapScale;
        ScaledImageHeight := Image.Height*ImageViewer.BitmapScale;
     
        //Get bitmap's top and left positions.
        ImageLeft:=(ImageViewer.Width-ScaledImageWidth)/2;
        if ImageLeft <0 then
          ImageLeft := 0;
     
        ImageTop:=(ImageViewer.Height-ScaledImageHeight)/2;
        if ImageTop < 0 then
          ImageTop := 0;
     
        //Get bitmap's mouse coordinates
        ImageX := (X + ImageViewer.ViewportPosition.X - ImageLeft) / ImageViewer.BitmapScale;
        ImageY := (Y + ImageViewer.ViewportPosition.Y - ImageTop) / ImageViewer.BitmapScale;
     
        //Report results
        if (X >= ImageLeft) and (X <= ImageLeft + ScaledImageWidth) and (Y>=ImageTop) and (Y <= ImageTop + ScaledImageHeight) then
          Label1.Text :=  'INFO LAYOUT DOWN '+  Format('Pixel: X=%.0f, Y=%.0f', [ImageX, ImageY])
        else
          Label1.Text := 'INFO LAYOUT DOWN: OutsideImage';
      end
      else
        Label1.Text := 'INFO LAYOUT DOWN: No Image Loaded';
    end;


    Voici une version beaucoup plus simple via ContentBounds mais ne supporte qu'un Zoom en avant uniquement
    car le calcul du Zoom arrière n'est pas fiable via ContentBounds donc on va repartir sur BitmapScale

    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
    procedure TForm1.ImageViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    var
      V: TImageViewer;
      B: TBitmap;
      ZoomX, ZoomY: Single;
      ImgX, ImgY: Single;
    begin
      V := Sender as TImageViewer;
      B := V.Bitmap;
     
      if Assigned(B) and not B.IsEmpty then
      begin
        // Zoom reel: taille du contenu (apres bestfit/zoom molette) / taille bitmap
        ZoomX := V.ContentBounds.Width / B.Width;
        ZoomY := V.ContentBounds.Height / B.Height;
     
        if (ZoomX > 0) and (ZoomY > 0) then
        begin
          // ViewportPosition est dans le repere du contenu (donc meme echelle que X/Y apres zoom)
          ImgX := (V.ViewportPosition.X + X) / ZoomX;
          ImgY := (V.ViewportPosition.Y + Y) / ZoomY;
     
          if (ImgX >= 0) and (ImgX < B.Width) and (ImgY >= 0) and (ImgY < B.Height) then
            Label1.Text := Format('Pixel: X=%d Y=%d', [Trunc(ImgX), Trunc(ImgY)])
          else
            Label1.Text := 'En dehors de l''image';
        end;
      end
      else
        Label1.Text := 'Aucune image';
    end;


    ou encore TImageViewer.BitmapScale qui gère le zoom en avant ou en arrière

    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
    procedure TForm1.ImageViewer1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    var
      V: TImageViewer;
      B: TBitmap;
      Z: Single;
      OffsetX, OffsetY: Single;
      ImgX, ImgY: Single;
    begin
      V := Sender as TImageViewer;
      B := V.Bitmap;
     
      if Assigned(B) and not B.IsEmpty then
      begin
        Z := V.BitmapScale; // zoom réel du TImageViewer (Seattle)
        if Z <= 0 then
          Exit;
     
        // Décalage quand l'image affichée est plus petite que la zone visible (best fit centré)
        OffsetX := (V.Width  - (B.Width  * Z)) * 0.5;
        OffsetY := (V.Height - (B.Height * Z)) * 0.5;
     
        if OffsetX < 0 then OffsetX := 0;
        if OffsetY < 0 then OffsetY := 0;
     
        // Coordonnées image = (coord locale + scroll - centrage) / zoom
        ImgX := (V.ViewportPosition.X + X - OffsetX) / Z;
        ImgY := (V.ViewportPosition.Y + Y - OffsetY) / Z;
     
        if (ImgX >= 0) and (ImgX < B.Width) and
           (ImgY >= 0) and (ImgY < B.Height) then
          Label1.Text := Format('Pixel: X=%d Y=%d', [Trunc(ImgX), Trunc(ImgY)])
        else
          Label1.Text := 'En dehors de l''image';
      end
      else
        Label1.Text := 'Aucune image';
    end;
    Aide via F1 - Utilisez l'I.A. - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité ! Sachez-le : l'IA remplace la très grande majorité des développeurs, pas seulement les ignares ...

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  9. #9
    Membre confirmé

    Profil pro
    senior scientist
    Inscrit en
    Mai 2003
    Messages
    94
    Détails du profil
    Informations personnelles :
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : senior scientist

    Informations forums :
    Inscription : Mai 2003
    Messages : 94
    Billets dans le blog
    1
    Par défaut
    Merci à @ShailLeTroll pour les précisions et le code .
    J'ai profité d'un peu de temps ce week-end pour mieux comprendre.
    Il y a en effet deux situations distinctes (et deux calculs différents) suivant que l'image originale mise à l'échelle est plus petite ou plus grande que la fenêtre du composant.
    Dommage que la fonction correspondante ne soit pas disponible dans la version actuelle de FMX

    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
     
    procedure TForm46.ImageViewer1MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Single);
    begin
     
      var V := Sender as TImageViewer;   //image fenêtrée, zoomée
      var bmp := V.Bitmap;               //image originale
      var scale := V.BitmapScale;        //facteur de zoom
      var xy := TPointF.Create(0, 0);    //coordonnées du pixel dans l'image
     
    //calcul des coordonnées du pixel dans l'image originale
    //si l'image originale est plus petite que la fenêtre, les coordonnées sont
    //rapportées à leurs centres respectifs.
    //si elle est plus grande (il faut alors autoriser le "scrolling" pour explorer
    //la totalité de l'image), leur décalage relatif est fourni par le paramètre
    //"ViewPortPosition" du composant.
     
      if (V.Width > (bmp.Width*scale))   //image plus petite que la fenêtre ?
        then xy.X := bmp.Width/2 + (X - V.Width/2)/scale
        else xy.X := (X + V.ViewportPosition.X)/scale;
      EnsureRange(xy.X, 0, bmp.Width-1);
      if (V.Height > (bmp.Height*scale))
        then xy.Y := bmp.Height/2 + (Y - V.Height/2)/scale
        else xy.Y := (Y + V.ViewportPosition.Y)/scale;
      EnsureRange(xy.Y, 0, bmp.Height-1);
     
    //contrôle
      Label3.Text := Format('%8.4f   %.0f,%.0f   (%.0f,%.0f  <->  %.0f,%.0f)',
        [scale, V.ViewportPosition.X, V.ViewportPosition.Y, X, Y, xy.X, xy.Y]);
    end;

Discussions similaires

  1. Utilisation de TImage dans un TImageViewer
    Par Gouyon dans le forum Composants FMX
    Réponses: 10
    Dernier message: 22/03/2019, 09h42
  2. utiliser les tag [MFC] [Win32] [.NET] [C++/CLI]
    Par hiko-seijuro dans le forum Visual C++
    Réponses: 8
    Dernier message: 08/06/2005, 15h57
  3. Réponses: 4
    Dernier message: 05/06/2002, 14h35
  4. utilisation du meta type ANY
    Par Anonymous dans le forum CORBA
    Réponses: 1
    Dernier message: 15/04/2002, 12h36
  5. [BCB5] Utilisation des Ressources (.res)
    Par Vince78 dans le forum C++Builder
    Réponses: 2
    Dernier message: 04/04/2002, 16h01

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