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

C++Builder Discussion :

probl�me avec GetDIB


Sujet :

C++Builder

  1. #1
    Membre confirm�

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    137
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 137
    Par d�faut probl�me avec GetDIB
    Bonjour,

    Mon but est d'imprimer une TBitmap sur le Canvas de TPrinter.
    J'utilise donc les m�thodes GetDIBSizes et GetDIB pour convertir le bitmap en DIB (puis j'utilise la fonction StretchDIBits, comme recommand� ici)

    Cependant, sur Windows XP (et Window 2000 je crois) la fonction GetDIB �choue de mani�re assez al�atoire (assez rarement quand m�me). Ca fait un moment que je traine ce probl�me, et je ne suis pas le seul, mais je n'ai jamais trouv� LA solution... HELP !

  2. #2
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    J'ai beaucoup souffert avec les DIBs, je pense que le probl�me vient de la gestion de la m�moire par la carte vid�o (car c'est elle qui prends en charge le chargement conversion des images). Cela explique que cela fonctionne et parfois pas.
    Ce qui ne va pas dans l'exemple c'est GetMem, FreeMem.
    Voici ce que je fais � la place:
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
     
    pBitmapHeader = (BITMAPINFO*)::HeapAlloc(::GetProcessHeap(),NULL,iMemNeeded);
    ...
    ::HeapFree(::GetProcessHeap(),NULL,pBitmapHeader);
    ps Je n'utilise pas de TBitmap mais le principe est le m�me.

    yarp
    www.senosoft.com

  3. #3
    Membre confirm�

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    137
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 137
    Par d�faut
    Ok merci beaucoup pour la r�ponse Yarp.
    Je vais essayer t'int�grer ton astuce. Je serais tr�s �tonn� si �a fonctionne mais tu as l'air de bien connaitre ce domaine.

    Sinon une autre solution serait de charger le DIB � partir d'un fichier BMP (sans passer par un TBitmap donc)...
    Et quelle classe utilises tu au lieu de TBitmap ?

    Encore merci

  4. #4
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    Une classe perso (mon appli traite les images et je me suis inspir� � l'origine de PaintLib) mais qui revient in fine � charger un BITMAPINFO (je charge le BITMPAINFOHEADER et les Bits et apr�s je reconstruit les Dibs seulement quand j'en ai besoin pour ne pas laisser le gourmand Windows g�rer lui-m�me les Handles . D'ou j'avais besoin de construire les Dibs.

    Comme je te le disais le caract�re pseudo al�atoire provient de la diff�rence de gestion de m�moire entre ton appli et celle de la carte vid�o, car quand tu alloue la m�moire pour un Dib c'est la carte vid�o qui prends en charge la conversion. Or les drivers de carte sont assez capricieux, pour le moins. HeapAlloc r�soud le probl�me, car la m�moire "is not movable" et est Thread Safe (cf. Msdn), en bref �a fixe les drivers.
    http://msdn2.microsoft.com/en-us/library/aa366597.aspx

    Vu ce matin sur CodeGear et qui pourrait t'int�resser, "Printing a TImage":
    http://dn.codegear.com/article/22018

    Il y a du GetDiBits et du GlobalAlloc (que je te conseille de remplacer par les HeapAlloc comme ci-dessus), on touche au coeur du sujet.

    yarp
    www.senosoft.com

  5. #5
    Membre confirm�

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    137
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 137
    Par d�faut
    J'ai donc mis en place les HeapAlloc...

    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
    bool __fastcall DrawBitmapToPrinterCanvas(Graphics::TBitmap *pBitmap, TCanvas *pCanvas, TRect rect)
    {
        unsigned int headerSize, imageSize;
        BITMAPINFO *pBitmapHeader = NULL;
        void *pBitmapImage = NULL;
        int result = GDI_ERROR;
        try
            {
            GetDIBSizes(pBitmap->Handle, headerSize, imageSize);
            //pBitmapHeader = (BITMAPINFO *)malloc(HeaderSize);
            //??? pBitmapImage = (void *)malloc(ImageSize);
            pBitmapHeader = (BITMAPINFO*)::HeapAlloc(::GetProcessHeap(), NULL, headerSize);
            pBitmapImage = (void *)::HeapAlloc(::GetProcessHeap(), NULL, imageSize);
            if (GetDIB(pBitmap->Handle, pBitmap->Palette, pBitmapHeader, pBitmapImage))
                {
                pCanvas->Lock();
                result = StretchDIBits(pCanvas->Handle, rect.Left, rect.Top, rect.Width(), rect.Height(),
                              0, 0, pBitmap->Width, pBitmap->Height,
                              pBitmapImage, pBitmapHeader,
                              DIB_RGB_COLORS, SRCCOPY);
                pCanvas->Unlock();
                }
            }
        catch(...)
            {
            }
        //if (pBitmapHeader != NULL) free(pBitmapHeader);
        //if (pBitmapImage != NULL) free(pBitmapImage);
        if (pBitmapHeader != NULL) ::HeapFree(::GetProcessHeap(), NULL, pBitmapHeader);
        if (pBitmapImage != NULL) ::HeapFree(::GetProcessHeap(), NULL, pBitmapImage);
        return (result != GDI_ERROR);
    }
    Pour l'instant, je ne sais pas si le probl�me est r�solu. En fait, je n'arrive pas � reproduire le probl�me sur mon PC avec l'ancien ou le nouveau code.

    Par contre j'aurai rapidement le retour de mes clients... En tout cas, merci �norm�ment Yarp pour ton aide. J'ai pass� pas mal d'heure � chercher une solution sur Internet et � retourner le probl�me dans tous les sens (fuite de m�moire ? probl�me de cerveau ?). Alors si ta solution fonctionne...

    A+

  6. #6
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    Imho I think so. Je distribue mon appli � des milliers d'exemplaires et si probl�me est en effet al�atoire (car d�pends des cartes graphiques) je n'en ait plus entendu parl� depuis que j'utilise HeapAlloc. Si cela ne fonctionnait pas je te conseille en tout cas de travailler sur cette partie allocation de m�moire.
    Il est vrai que le probl�me est rarement �voqu�, voire pas du tout, et la connaissance que j'en ait est purement empirique. J'ai remarqu� que � chaque sortie d'un nouveau mod�le de la NVidia GeForce le ph�nom�ne se produisait, et que d�s leurs premiers patchs il �tait r�solu => ma d�duction.

    yarp
    www.senosoft.com

  7. #7
    Membre confirm�

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    137
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 137
    Par d�faut
    Bon eh bien un client (qui a assez souvent ce probl�me d'impression d'image) a eu un gros probl�me avec la nouvelle version lors de l'impression : Son PC a compl�tement plant�... Il a d� couper l'alimentation pour pouvoir red�marrer

    Il s'agit s�rement des HeapAlloc (je n'ai jamais eu ce genre de bug auparavant).
    C'est bizarre car c'est le seul a avoir eu ce probl�me et c'est celui qui �tait le plus "touch�" par le probl�me d'impression d'image.

    Je pense qu'il y a quand un petit probl�me sur son PC : Et maintenant que j'y pense, lorsque je suis all� lui installer le logiciel, j'avais vu un message bizarre de windows : "Votre carte graphique ne dispose pas d'assez de m�moire" ou un truc dans le genre...

    Au fait, est ce que mon code (message pr�c�dent) te semble bon yarp ?

  8. #8
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    Je vais le tester demain et te r�pondre. Le cas m'int�resse aussi

    A ma connaissance HeapAlloc n'est pas li� � la carte graphique mais encore faut-il que celle-ci ait la capacit� de faire les op�rations. GetDeviceCaps permet de savoir ce tu peux faire ou pas, mais l� je ne pourrais pas t'aider beaucoup car je m'en suit peu servi.

    Par contre je peux d�ja te dire que je n'avais pas mis les test de base qu'il faut appliquer chaque fois que tu appelles une fonction de l'API, donc d�ja �a manque. Il faut toujours tester la valeur de retour, en cas d'�chec il faut mieux faire return que d'avoir un plantage.

    Je pense de toute fa�on qu'il faut s'inspirer de l'article de CodeGear que j'ai cit� dans ma premi�re r�ponse, avec allocation de m�moire Heap.

    Je regarde demain.

    yarp
    www.senosoft.com

  9. #9
    Membre confirm�

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    137
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 137
    Par d�faut
    Bon eh bien voil� un code qui fonctionne � tous les coups (pour l'instant plus de probl�me ) ... Un grand merci � yarp pour m'avoir mis sur la voie.

    Je pense que ce code m�rite de figurer dans la FAQ ou dans les sources. (j'ai cherch� pendant plusieurs jours cette solution).

    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
    bool __fastcall DrawBitmapToPrinterCanvas(Graphics::TBitmap *pBitmap, TCanvas *pCanvas, TRect rect)
    {
        int w = pBitmap->Width;
        int h = pBitmap->Height;
        HDC h_dc = pBitmap->Canvas->Handle;
        HDC h_mem_dc = ::CreateCompatibleDC(h_dc);
        HBITMAP h_mem_bmp = ::CreateCompatibleBitmap(h_dc, w, h);
        HBITMAP h_old_bmp = ::SelectObject(h_mem_dc, h_mem_bmp);
        int result = GDI_ERROR;
     
        //copy the image on the memory dc
        ::BitBlt(h_mem_dc, 0, 0, w, h, h_dc, 0, 0, SRCCOPY);
     
        //delete the mem dc
        ::SelectObject(h_mem_dc, h_old_bmp);
        ::DeleteDC(h_mem_dc);
     
        //get memory for a BITMAPIFO structure
        HANDLE h_bmp_info = ::GlobalAlloc(GHND, sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * 256));
        BITMAPINFO* bmp_info = static_cast<BITMAPINFO*> (::GlobalLock(h_bmp_info));
        //set up the structure
        memset(bmp_info, NULL, sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * 255));
        bmp_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmp_info->bmiHeader.biPlanes = 1;
        bmp_info->bmiHeader.biBitCount = 16; //ou 32
        bmp_info->bmiHeader.biWidth = w;
        bmp_info->bmiHeader.biHeight = h;
        bmp_info->bmiHeader.biCompression = BI_RGB;
     
        //find out how much memory for the bits
        if (::GetDIBits(h_dc, h_mem_bmp, 0, h, NULL, bmp_info, DIB_RGB_COLORS))
            {
            //Allocate memory for the bits
            HANDLE h_bits = ::GlobalAlloc(GHND, bmp_info->bmiHeader.biSizeImage);
            void *bits = ::GlobalLock(h_bits);
            //this time get the bits
            if (::GetDIBits(h_dc, h_mem_bmp, 0, h, bits, bmp_info, DIB_RGB_COLORS) != 0)
                {
                //send the bits to the printer
                result = StretchDIBits(pCanvas->Handle, rect.Left, rect.Top, rect.Width(), rect.Height(),
                              0, 0, w, h,
                              bits, bmp_info,
                              DIB_RGB_COLORS, SRCCOPY);
                }
            ::GlobalUnlock(bits);
            ::GlobalFree(h_bits);
            }
        //clean up
        ::DeleteObject(h_mem_bmp);
        ::GlobalUnlock(bmp_info);
        ::GlobalFree(h_bmp_info);
        return (result != GDI_ERROR);
    }

  10. #10
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    Bravo, et d�sol� de ne pas avoir donn�e suite, pas mal de boulot et de soucis moi aussi.

    Par contre je suis surpris que GlobalAlloc fonctionne mieux que HeapAlloc (j'avais utilis� GlobalAlloc dans une version interm�diaire puis je suis pass� � HeapAlloc).

    Ce qui est sur, c'est que ce code m�rite de figuer dans la FAQ.

    yarp
    www.senosoft.com

  11. #11
    Membre exp�riment�

    Profil pro
    Inscrit en
    Janvier 2003
    Messages
    288
    D�tails du profil
    Informations personnelles :
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Janvier 2003
    Messages : 288
    Par d�faut
    Je me suis pench� sur le probl�me HeapAlloc/GlobalAlloc aujourd'hui. La doc du MSDN est claire � ce sujet.

    "Les fonctions globales sont plus lentes que les autres fonctions de gestion de la m�moire et n'ont pas autant de possibilit�s. Par cons�quent, les nouvelles applications doivent utiliser les fonctions Heap. cependant, les fonctions Globales sont encore utilis�es par DDE et le clipboard".

    J'en d�duit que pour une imprimante, ou pour certaines imprimantes, le protocole de communication devait �tre similaire � DDE/clipboard et ne supportait que GlobalAlloc.

    Moralit�: Le Msdn dit que �a marche mieux avec HeapAlloc sauf quand �a ne marche pas. Mais ne nous dit pas (du moins pas ici) comment reconnaitre les p�riph�riques (cartes vid�os, imprimantes) qui ne supportent pas HeapAlloc.

+ R�pondre � la discussion
Cette discussion est r�solue.

Discussions similaires

  1. VC++ Direct3D8, probl�me avec LPD3DXFONT et LPD3DTEXTURE8
    Par Magus (Dave) dans le forum DirectX
    R�ponses: 3
    Dernier message: 03/08/2002, 11h10
  2. Probl�me avec [b]struct[/b]
    Par Bouziane Abderraouf dans le forum CORBA
    R�ponses: 2
    Dernier message: 17/07/2002, 10h25
  3. Probl�me avec le type 'Corba::Any_out'
    Par Steven dans le forum CORBA
    R�ponses: 2
    Dernier message: 14/07/2002, 18h48
  4. Probl�me avec la m�moire virtuelle
    Par Anonymous dans le forum CORBA
    R�ponses: 13
    Dernier message: 16/04/2002, 16h10

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