Partage
  • Partager sur Facebook
  • Partager sur Twitter

vb. affichage et scroll de grandes images panorama

    22 février 2021 à 16:56:37

    Salut a tous!

    Voici mon soucis j'ai un soft en vb.net 3.5. J'y affiche des images dans une form ( en fait un panel qui contient une picturebox)

    Avec autoscroll a On j'arrive a afficher une image jusqu'a 65535 pixel de large. 

    Mais mon besoin va jusqu'a 250000pixels. ET la je suis perdu! En cherchant je ne sais pas par ou commencer. Je ne comprends pas trop commetn focntionne le paint ni si la picturebox est la bonne solution. 

    J'ai d'abord voulu gérer moi meme le scrol, mais le décalage de la picturebox est en entier.. et donc je ne peux faire que 32000 de décalage , 2 fois moins qu'ave l'autoscroll!

    Ensuite je suis parti dans l'evenemetn PictureBox.Paint dans lequel j'essaye de faire un DrawImage de la partie qui m'intéresse, mais lors du scroll tout disparait, et le rafraichissement a postériori est assez long....

    Pourriez vous me guider, m'orienter vers des explication pour un néophyte en graphique .net  Merci

    • Partager sur Facebook
    • Partager sur Twitter
      22 février 2021 à 17:07:43

      Un entier en .NET (VB.NET ou C#) est un entier 32bits, pas 16bits (la limitation au environ de 32K, c'est dans le domaine des 16 bits signés, pas dans les 32bits).

      Vous n'indiquez pas la librairie graphique que vous utilisez (Winform, WPF, ...).

      Les possibilités techniques sont totalement différentes entre ces librairies graphiques.

      WPF est largement plus adapté à des applications lourdes graphiquement.

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        23 février 2021 à 10:22:08

        Merci pour votre réponse, je suis en winform. Je ne connais pas WPF.  connaissez vous un tutorilel pour m'apprendre les bases de cette librairie? est ce que je peux l'appeler depuis une application Winform?

        La limite de la position est tout de meme 32000 et quelquyes même si je lui demande plus. La limitation doit être ailleurs.

        • Partager sur Facebook
        • Partager sur Twitter
          23 février 2021 à 10:54:24

          >Je ne connais pas WPF.  connaissez vous un tutorilel

          WPF est une librairie assez complexe/différente des autres et un simple tutoriel ne suffira pas.

          >La limitation doit être ailleurs.

          Winform est un simple carrossage de l'API Windows avec des bouts datant des années 80, il y a peut-être encore des limitations à des "short" (16-bits) dedans. Mais généralement, il existe des versions mise à jour que des composants moins "basiques" devrait utiliser.

          Si vous comptez invertir du temps sur un projet hautement graphique, je vous conseillerai d'investir du temps sur WPF qui est largement plus récent et moins limité que Winforms.

          Mais il y a des chances que des solutions "ad hoc" pour Winform existent sur le Net.

          Mais comme WPF a pris le relais depuis près de 15 ans, les solutions les plus abouties risquent fort d'être sous WPF, si WPF ne le fait pas de base.

          Faire "à la main" demande une grosse connaissance des mécanismes d'affichage de Windows, c'est pour cela que je vous conseille d'écumer les solutions sur le Net, quitte à faire votre propre solution, mais en ayant les bases de solutions qui "fonctionnent ou presque" (état habituel des trucs trouvé sur Internet, en plus des trucs qui n'ont jamais vraiment fonctionnés ou qui ne fonctionnent plus).

          Pour ce qui est du clignotement en utilisant DrawImage, c'est un problème classique qu'on gère facilement soit en désactivant l'écrasement par la couleur de fond (quand on réaffiche tout à chaque fois), soit en utilisant le "double buffering".

          • Partager sur Facebook
          • Partager sur Twitter
          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
            23 février 2021 à 11:15:19

            Merci, je ne pense pas investir dans le WPF pour l'instant.

            Pour el double buffering c'est activé dans la form

            Pour l'écrasement, je ne trouve pas.

            Voici mon code de l'event paint:

            Private Sub MainPictureBox_Paint(sender As Object, e As PaintEventArgs) Handles MainPictureBox.Paint
            
            
                    Dim displayedWidth = MainPictureBox.Width
            
                    'Création lovale du graphics pour dessiner 
                    Dim g As Graphics = e.Graphics
                    Dim units As GraphicsUnit = GraphicsUnit.Pixel
                    Dim position As Single = HScrollBar1.Value * 4
                    Dim srcRect As RectangleF = New RectangleF(position, 0, displayedWidth, imageAffichee.Size.Height)
            
                    ' On dessine l'image  à la position 0.0   srect c'est la taille de l'image qu'on prends
                    g.DrawImage(imageAffichee, 0, 0, srcRect, units)
             End Sub

            Contrairement à l'utilisation de l'autoscroll la picturebox fait la taille du panel, et de la form! C'est peut être la l'erreur?

            En refaisant un test, c'est la couleur du panel qu'on apercoit pendant le scroll! Y'a t il moyen de l'empecher? si oui comment?

            -
            Edité par ericgck 23 février 2021 à 12:11:50

            • Partager sur Facebook
            • Partager sur Twitter
              23 février 2021 à 12:47:18

              Regarde si la picturebox a autosize à true ou pas. Met-le à true et teste.
              • Partager sur Facebook
              • Partager sur Twitter
                23 février 2021 à 13:29:53

                Non elle est a false et c'est fait exprès,  sinon je ne peux pas afficher toute l'image qui est plus grande que ce que peux afficher la picturebox!
                • Partager sur Facebook
                • Partager sur Twitter
                  23 février 2021 à 15:16:21

                  >Pour el double buffering c'est activé dans la form

                  Ok, mais le panel ?

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    23 février 2021 à 15:25:07

                    Je ne vois pas de double buffering pour le panel.

                    J'ai mis son fond transparent et maintenant c'est le fond de la form qui apparait avant que je redessine ( un breakpoint au début de MainPictureBox_Paint me montre le fond de la form, comme si l'appel a Paint avait déja effacé la form.  Peux t'on supprimer cela?

                    • Partager sur Facebook
                    • Partager sur Twitter
                      23 février 2021 à 15:33:50

                      >comme si l'appel a Paint avait déja effacé la form

                      C'est probablement le cas.

                      Winform est réputé pour sa "non" gestion correcte de la transparence.

                      Là, on va commencer à jouer contre le système, faudrait commencer à sortir la clé à molette.

                      Mais je suis de l'avis de @umfred, on commence par faire simple.

                      "autorise" de la picturebox, c'est basé sur l'image ou son contenant ?

                      -
                      Edité par bacelar 23 février 2021 à 15:35:22

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                        23 février 2021 à 16:00:00

                        Je ne comprneds pas ta remaque sur le "autorise" de la picturebox

                        Voici le contenu du designer:

                         '
                                'Panel1
                                '
                                Me.Panel1.AutoScroll = True
                                Me.Panel1.BackColor = System.Drawing.Color.Transparent
                                Me.Panel1.Controls.Add(Me.HScrollBar1)
                                Me.Panel1.Controls.Add(Me.MainPictureBox)
                                Me.Panel1.Dock = System.Windows.Forms.DockStyle.Fill
                                Me.Panel1.Location = New System.Drawing.Point(0, 0)
                                Me.Panel1.Name = "Panel1"
                                Me.Panel1.Size = New System.Drawing.Size(819, 818)
                                Me.Panel1.TabIndex = 1
                                '
                                'HScrollBar1
                                '
                                Me.HScrollBar1.Dock = System.Windows.Forms.DockStyle.Bottom
                                Me.HScrollBar1.Location = New System.Drawing.Point(0, 801)
                                Me.HScrollBar1.Name = "HScrollBar1"
                                Me.HScrollBar1.Size = New System.Drawing.Size(819, 17)
                                Me.HScrollBar1.TabIndex = 1
                                '
                                'ImageForm
                                '
                                Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None
                                Me.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink
                                Me.BackColor = System.Drawing.Color.Red
                                Me.ClientSize = New System.Drawing.Size(819, 818)
                                Me.Controls.Add(Me.Panel1)
                                Me.DoubleBuffered = True
                                Me.KeyPreview = True
                                Me.Name = "ImageForm"
                                Me.Text = "Images"
                                CType(Me.MainPictureBox, System.ComponentModel.ISupportInitialize).EndInit()
                                Me.Panel1.ResumeLayout(False)
                                Me.ResumeLayout(False)

                        Avecautosize ca ne change rien. Mais c'est nroaml car la picturebox ne dépasse plus du panel.

                        C'est ce que j'avais avant, la picutebox de 65000 pixel dans un panel de 1300 avec autosize.

                        CA fonctionne nickel, meme si une image si gnrade commence a prendre de la place en RAM. Mais la mon image en fait 200000 et donc elle est tronquée a 65000. L'idée etait de calquer le focntionnement du panel° picturebox, mais en scrollant manuellement l'image . CE qui focntionne presque, sauf qu'il redessine tout et c'est donc inutilisable (l'image est grise pendant le scroll tellement c'est long a redessiner)

                        Je viens d'essayer de n'appeler Paint qu'une fois

                         If a > 0 Then Return
                                a = 1

                        dans ce cas, lorsque je déplace mon scroll, l'image s'efface au fur et a mesure..... de la gauche vers la droite!

                        Je commence a avoir peur que la clé à molette ne suffise pas :magicien:


                        • Partager sur Facebook
                        • Partager sur Twitter
                          23 février 2021 à 16:20:04

                          si la picturebox est dans le panel:

                          propriétés de la picturebox: dock=None, size=autosize; (tu la positionnes dans le coin haut gauche du panel)

                          propriétés du panel: autoscroll=true

                          et ça devrait faire l'affaire en principe.

                          Edit sans image de la taille que tu as, je ne peux pas vérifier (avec des grandes images de mon acabit, je me retrouve avec un overflow ^^)

                          -
                          Edité par umfred 23 février 2021 à 16:36:59

                          • Partager sur Facebook
                          • Partager sur Twitter
                            23 février 2021 à 20:42:39

                            • Partager sur Facebook
                            • Partager sur Twitter
                            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                              Il y a environ 21 heures

                              Oui merci a vous deux, mais l'autoscroll ne focntionne qu'avec des images jusqu'a 65535 

                              et l'exemple sur codeproject tronque l'image a 32767 pixel, que j'avais déjà eu. En revanche l'animation est plus fluide. elle est faite directemetn dans le controle, sans passer par un picutrebox!

                              Je vais peut être essayer de saucissoner mon image!

                              ....

                              Sur le chemin ce petit post explique un peu les limitations https://stackoverflow.com/questions/2596457/c-graphics-drawimage-has-a-size-limit-how-to-deal-with-it

                              Je pense que je suis en plein dedans!

                              Bon résultat de mes analyses,

                              Le problème viens de la fonction  g.DrawImage(image, DestRect, SrcRect, GraphicsUnit.Pixel)

                              qui apparemment ne sait pas allez chercher plus loin que 32000 dans le bitmap passé en parametre. 

                              J'ai donc découpé l'image en tranche de 32000 et gardé autant de bitmap.

                              Puis dans le paint (apparement il ne faut pas utiliser l'vent mais surcharger OnPaint) J'affiche la partie correspondate.

                              Je vous met ici les modification approtées à l'exemple  https://www.codeproject.com/Articles/15743/Pan-and-Zoom-Very-Large-Images

                              sur le drawing board, qui va donc remplacet ma picturebox dans mon projet

                                Public Shadows Property Image() As System.Drawing.Image
                                      Get
                                          Return m_OriginalImage
                                      End Get
                                      Set(ByVal Value As System.Drawing.Image)
                                          If Not m_OriginalImage Is Nothing Then
                                              m_OriginalImage.Dispose()
                                              m_Select_Rect = Nothing
                                              m_Origin = New Point(0, 0)
                                              m_ApparentImageSize = New Size(0, 0)
                                              m_ZoomFactor = 1
                                              GC.Collect()
                                          End If
                              
                                          If Value Is Nothing Then
                                              m_OriginalImage = Nothing
                                              Me.Invalidate()
                                              Exit Property
                                          End If
                              
                              
                              
                                          m_OriginalImage = New Bitmap(Value)
                                          '  Dim bmpData As New BitmapData
                                          m_ImageRect = New List(Of System.Drawing.Bitmap)
                                          Dim pos As Integer = 0
                                          For pos = 0 To Value.Width Step tranche
                                              Dim taille = tranche + recouvrement
                                              If (taille + pos) > Value.Width Then
                                                  taille = Value.Width - pos
                                              End If
                                              m_ImageRect.Add(m_OriginalImage.Clone(New Rectangle(pos, 0, taille, Value.Height), Imaging.PixelFormat.Format32bppPArgb))
                                          Next
                              
                                          ' on sauvegarde cette syntaxe au cas ou ca joue sur la RAM m_ImageRect.Add(New Bitmap(DirectCast(m_OriginalImage.Clone(New Rectangle(30000, 0, 32000, Value.Height), Imaging.PixelFormat.Format32bppPArgb), Bitmap)))
                                          'Force a paint
                                          Me.Invalidate()
                                      End Set
                                  End Property
                              
                                 Private Sub DrawImage(ByRef g As Graphics)
                                      If m_OriginalImage Is Nothing Then Exit Sub
                              
                                      g.PixelOffsetMode = Drawing2D.PixelOffsetMode.Half
                                      g.SmoothingMode = Drawing2D.SmoothingMode.None
                                      g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
                                      Dim oX = m_Origin.X
                                      Dim indice As Integer = Math.Floor(oX / tranche)
                                      oX = oX Mod tranche
                              
                                      If m_StretchImageToFit Then
                                          SrcRect = New System.Drawing.Rectangle(0, 0, m_OriginalImage.Width, m_OriginalImage.Height)
                                      Else
                                          SrcRect = New System.Drawing.Rectangle(oX, m_Origin.Y, m_DrawWidth, m_DrawHeight)
                                      End If
                              
                                      g.DrawImage(m_ImageRect(indice), DestRect, SrcRect, GraphicsUnit.Pixel)
                              
                                      If Not PanMode Then
                                          g.DrawRectangle(m_Select_Pen, Selected_Rectangle)
                                      End If
                              
                                      RaiseEvent SetScrollPositions()
                              
                                  End Sub
                                 Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
                                      e.Graphics.Clear(Me.BackColor)
                                      DrawImage(e.Graphics)
                                      MyBase.OnPaint(e)
                                  End Sub

                              Merci a tous pour votre aide, vous m'avez bien mis sur la voie.

                              -
                              Edité par ericgck il y a environ 14 heures

                              • Partager sur Facebook
                              • Partager sur Twitter

                              vb. affichage et scroll de grandes images panorama

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              • Editeur
                              • Markdown