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

VB.NET Discussion :

[GDI+] Impression d'un document sur la base de PictureBox redessinnées


Sujet :

VB.NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de Miles Raymond
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2005
    Messages : 189
    Par défaut [GDI+] Impression d'un document sur la base de PictureBox redessinnées
    Bonjour,
    Je travaille sur un programme qui permet aux utilisateurs d'ajouter des informations sur des images chargées dans mon application. C'est à dire que j'affiche ces images (ici ce sont des pages scannées) sous la forme de picturebox (1 par page) comme dans un document Word. Ensuite l'utilisateur peut ajouter des textes par dessus.

    Mon problème est le suivant, à l'impression de mon document j'ai parfois (pour des gros documents) des messages d'erreur "Mémoire insuffisante". Je vois bien que même en disposant de tout mes objets, la mémoire allouée au programme grandis à chaque page envoyée à l'impression. Je procède comme suite pour imprimer ces picturebox :

    1. Je stock l'image actuelle de la Picturebox
    2. J'applique à ma picturebox la taille de l'image (stockée) à 300dpi et j'agrandis ma picturebox pour la mettre aux même dimensions.
    3. Je fais un "InvokePaint" sur ma PictureBox pour dessiner les textes sur l'image à 300dpi et dessiner directement sur mon control d'impression
    4. Je rétabli la taille et l'image de ma PictureBox
    5. Je dispose des images + graphics
    6. Et je passe à la page suivante.

    Voici un aperçu (un peu simplifié) de ma page d'impression (se trouve dans l'événement "PrintDocument.PrintPage").

    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
    Using g As Graphics = e.Graphics
                    'On récupère la page courante comme page à imprimer
                    Dim PageNumber As Integer = Form1.panel_scrollNavigator.Controls.GetChildIndex(PagesToPrint(nbSheets))
                    'On récupère le control
                    Dim ctrl As Page = Form1.panel_scroll.GetPage(PageNumber + 1)
                    'Niveau de détail du texte
                    g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
                    'On charge l'image en cours
                    Dim img As System.Drawing.Bitmap = CType(Image.FromFile(Form1.TempPath + "\" + ctrl.Name + ".png"), Bitmap)
                    'On récupère la taille actuel du control
                    Dim ctrlW As Integer = ctrl.Width
                    Dim ctrlH As Integer = ctrl.Height
                    'On défini les bordures de la page
                    Dim pageBorder As New Rectangle(e.PageBounds.Left, e.PageBounds.Top, e.PageBounds.Width, e.PageBounds.Height)
                    'On défini le nouveau ratio de la page pour l'impression des textes
                    Form1.ratio = CSng(System.Math.Sqrt(System.Math.Pow(img.Height, 2) + System.Math.Pow(img.Width, 2)) / _
                    System.Math.Sqrt(System.Math.Pow(ctrl.Height, 2) + System.Math.Pow(ctrl.Width, 2)))
                    'On défini la taille du control à la même taille que l'image (300 dpi)
                    ctrl.Width = img.Width
                    ctrl.Height = img.Height
                    'On lui applique l'image à 300 dpi comme image de fond
                    ctrl.Image = CType(img.Clone, Image)
                    'Ici on dessine l'image en 300 dpi redimenssionnée aux dimensions des pages
                    g.DrawImage(img, 0, 0, ctrl.Width, ctrl.Height)
                    'Ensuite on créé un bitmap et un graphics temporaire pour stocker le dessin du texte en 300 dpi
                    Dim bmp As New Bitmap(img.Width, img.Height)
                    Dim gimg As Graphics = Graphics.FromImage(bmp)
                    Dim PArgs As New PaintEventArgs(gimg, New Rectangle(img.Width, img.Height, img.Width, img.Height))
                    'On fait un InvokePaint sur le graphic temporaire pour dessiner le control
                    InvokePaint(ctrl, PArgs)
                    'Et on dessine le texte sur le page actuel
                    g.DrawImage(bmp, 0, 0, g.VisibleClipBounds.Width, g.VisibleClipBounds.Height)
     
                    'Puis on remet le control à sa taille d'origine
                    ctrl.Width = ctrlW
                    ctrl.Height = ctrlH
                    'Et on retrouve l'image de base
                    bmp = New Bitmap(ctrl.Width, ctrl.Height)
                    gimg = Graphics.FromImage(bmp)
                    'Et on l'applique au control
                    gimg.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
                    gimg.DrawImage(ctrl.Image, 0, 0, ctrl.Width, ctrl.Height)
                    ctrl.Image = CType(bmp.Clone, Image)
                    ctrl.SizeMode = PictureBoxSizeMode.Normal
                    'Puis on dispose de tout ce petit monde
                    gimg.Dispose()
                    img.Dispose()
                    bmp.Dispose()
                    gimg = Nothing
                    img = Nothing
                    bmp = Nothing
     
                    GC.Collect()
     
                    If nbSheets = pdi.PrinterSettings.ToPage - 1 Then
                        hasMorePages = False
                        e.HasMorePages = False
                    Else
                        nbSheets += 1
                        hasMorePages = True
                        e.HasMorePages = True
                    End If
     
    End Using
    Y a t'il des problèmes de fuites de mémoires sur les picturebox ? Logiquement le fait que je modifie ma Box pour prendre des valeurs supérieures pour l'impression et qu'ensuite je remet celle-ci à son état d'origine ne devrait pas augmenter la mémoire allouée au programme non ? (enfin si, pendant le processus, mais pas après)

    Merci de votre aide

  2. #2
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    je ne comprends pas ton histoire de passer par un controle pour imprimer ... ca ne me parait pas être une bonne idée
    quand on imprime il n'y a aucune raison de modifier les controles



    quelques remarques sur le code :

    using g = e.Graphics
    ca veut dire que tu vas disposer e.Graphics, alors qu'il t'es fournit par l'évènement print, s'il doit être supprimé c'est par celui qui l'a créé

    préférer DirectCast à CType

    une "fuite" trouvée :
    ligne 26 tu créé un new bitmap que tu ranges dans bmp
    ligne 38 tu créé un new bitmap que tu ranges dans bmp, l'ancien n'a plus de référence mais il reste en mémoire
    le bmp.dispose plus loin ne supprimera que le le bitmap qui est actuellement dans la variable
    idem avec gimp
    (info : ca peut faire pareil dans une propriété d'un control, si dans un picturebox tu mets une image, puis une autre, la 1ère existe toujours en ram)

    mettre une variable à nothing ne sert à rien

    le gc.collect, j'imagine que c'est pour voir si ca passait mieux
    enfin en théorie il essayer de ne pas l'appeler, c'est lent ; par contre lui il devrait choper les bmp laché dans la nature ... mais il doit pas aller assez vite ...
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre confirmé Avatar de Miles Raymond
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2005
    Messages : 189
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    je ne comprends pas ton histoire de passer par un controle pour imprimer ... ca ne me parait pas être une bonne idée
    quand on imprime il n'y a aucune raison de modifier les controles
    Je sais ça paraît stupide! Mais c'est ce que j'ai trouvé de plus simple en fait, vu que j'ai une fonction de dessin assez importante dans mon control personnalisé (PictureBox modifiée). Du coup plutôt que de récrire toute ma fonction de dessin, je me content de lister les picturebox et de balancer un invokepaint pour qu'il me sorte directement la pb dessinée correctement... C'est un peu le zouk mais c'est ce qu'il y a de plus simple!

    quelques remarques sur le code :

    using g = e.Graphics
    ca veut dire que tu vas disposer e.Graphics, alors qu'il t'es fournit par l'évènement print, s'il doit être supprimé c'est par celui qui l'a créé

    préférer DirectCast à CType

    une "fuite" trouvée :
    ligne 26 tu créé un new bitmap que tu ranges dans bmp
    ligne 38 tu créé un new bitmap que tu ranges dans bmp, l'ancien n'a plus de référence mais il reste en mémoire
    le bmp.dispose plus loin ne supprimera que le le bitmap qui est actuellement dans la variable
    idem avec gimp
    (info : ca peut faire pareil dans une propriété d'un control, si dans un picturebox tu mets une image, puis une autre, la 1ère existe toujours en ram)

    mettre une variable à nothing ne sert à rien

    le gc.collect, j'imagine que c'est pour voir si ca passait mieux
    enfin en théorie il essayer de ne pas l'appeler, c'est lent ; par contre lui il devrait choper les bmp laché dans la nature ... mais il doit pas aller assez vite ...
    Pour le GC.Collect : oui c'était pour les tests mais ça ne sers à rien.
    Pour les autres variables je vais jeter un oeil et faire des tests de performances, je reviens quand j'ai testé tout ça, merci de ton aide en tout cas ! Par contre petite question : c'est quoi la différence entre ctype et directcast ? Parce que je suis en option strict et visual studio me propose, par défaut, de modifier le type des variables avec ctype.

  4. #4
    Expert éminent Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 204
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    ctype sert à faire des conversions, directcast sert à boxer une variable
    image et bitmap ont un lien d'héritage donc le boxing est faisable
    pour transformer un integer en decimal par exemple on utilise ctype
    dans les cas d'héritage ou d'implémentation ca doit faire la même chose mais ctype est plus lent (même si le temps doit rester ridicule pour quelques appels)
    nb : toutes les classes héritent d'object, les cas les plus fréquents sont les évènements où sender est passé as object, si on est sur du type de sender on fait directement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    directcast(sender, button)
    pour savoir si on peut caster :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if typeof sender is button then

    sinon tu dis que ton control fait du dessin, auquel cas il suffirait de passer e.Graphics à ton control pour qu'il dessine dessus
    et tu peux avoir une méthode générique ou quasiment pour les 2 cas, cas de dessin du control ou cas de dessin pour impression
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre confirmé Avatar de Miles Raymond
    Profil pro
    Inscrit en
    Avril 2005
    Messages
    189
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Avril 2005
    Messages : 189
    Par défaut
    Merci beaucoup pour ton aide et pour ces précisions pol!
    Comme tu l'as dit, j'ai passé un peu de temps pour réecrire ma fonction de dessin, je lui passe juste mon Graphics avec l'image en fond et il récrit tout dessus, ça fait une vingtaine de lignes de codes en moins ! Mais du coup j'ai toujours un peu de perte de mémoire. Il faut encore que je regarde mais le gros du problème est résolu.

    Tes précisions m'ont bien aidé

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

Discussions similaires

  1. documentation sur la base de registre
    Par hacbao dans le forum Windows
    Réponses: 5
    Dernier message: 07/02/2014, 08h58
  2. Documentation sur une base de données RDF
    Par sarah-b dans le forum Web sémantique
    Réponses: 1
    Dernier message: 05/01/2014, 18h55
  3. Réponses: 1
    Dernier message: 18/09/2007, 22h53
  4. Réponses: 2
    Dernier message: 09/03/2007, 18h57
  5. documentation sur la restauration d'une base interbase 6.0
    Par devalender dans le forum InterBase
    Réponses: 1
    Dernier message: 03/09/2004, 17h56

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