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

Windows Discussion :

[C] Manipulation du format bitmap


Sujet :

Windows

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut [C] Manipulation du format bitmap
    Bonjour à tous,
    je voudrais savoir comment manipuler le format bitmap avec l'API Windows, donc :
    - passer d'un fichier à un espace mémoire (on a acces directement à l'image)
    - passer de l'espace mémoire à un objet bitmap (que l'on manipule avec un handle HBITMAP et qui peut être sélectionné avec un Device Context)

    Après, pour afficher le bitmap dans un DC et tout ça je crois avoir compris, mais je m'embrouille avec les structures comme BITMAPFILEHEADER, BITMAPINFOHEADER, RGBQUAD, BITMAPCOREINFO, BITMAPINFO, BITMAP...

    Et en passant, je voudrais savoir si il n'y a pas d'autre moyen d'afficher d'un bloc une image que l'on a en mémoire que le format bitmap (avec SetPixel c'est beaucoup trop lent).

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 572
    Points
    41 572
    Par défaut
    Le plus simple pour charger un bitmap en mémoire et y avoir directement accès:
    1. Charger le bitmap avec LoadImage() et les flags LR_LOADFROMFILE et LR_CREATEDIBSECTION
    2. Faire un GetObject() sur le bitmap pour récupérer un pointeur vers sa mémoire.


    Le plus simple pour créer un bitmap en mémoire avec un format donné, c'est utiliser la fonction CreateDIBSection(). Les formats 24 et 32 bits sont les plus simples à créer (pas de palette) et le format 32bits est le plus simple des deux à utiliser en mémoire.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut
    HBITMAP CreateDIBSection(
    HDC hdc, // handle to device context
    CONST BITMAPINFO *pbmi, // pointer to structure containing bitmap size, format, and color data
    UINT iUsage, // color data type indicator: RGB values or palette indices
    VOID *ppvBits, // pointer to variable to receive a pointer to the bitmap's bit values
    HANDLE hSection, // optional handle to a file mapping object
    DWORD dwOffset // offset to the bitmap bit values within the file mapping object
    );

    Pourquoi y a-t-il besion d'un device context alors qu'on est censé créer un device INDEPENDENT bitmap ??? Et à quoi servent toutes ces fonctions qui paraissent bien inutiles à première vue ?: CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDiscardableBitmap.......

    Et pourquoi dans ma doc qui doit faire une bonne vingtaine de pages sur le sujet, il n'y a aucune réference à CreateDIBSection? Ou est donc la mémoire du bitmap quand on a juste un handle et quel est l'interet que le programme ne puisse pas avoir accès à cette mémoire facilement ?

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut
    Je suppose que tu pensais à LoadImage à la place de LoadBitmap ?

  5. #5
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 572
    Points
    41 572
    Par défaut
    Pourquoi y a-t-il besion d'un device context alors qu'on est censé créer un device INDEPENDENT bitmap ???
    Ce paramètre n'est utilisé que si tu passes la valeur DIB_PAL_COLORS dans le paramètre iUsage. Normalement, on utilise la valeur DIB_RGB_COLORS et on passe un handle NULL.
    Et à quoi servent toutes ces fonctions qui paraissent bien inutiles à première vue ?: CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDIBitmap, CreateDiscardableBitmap.......
    • CreateBitmap() crée un DDB.
    • CreateBitmapIndirect() est pareil, mais avec une structure au lieu de directement les paramètres.
    • CreateCompatibleBitmap() crée aussi un DDB, mais avec le même format de couleur que le bitmap actuellement sélectionné dans le DC passé en paramètre.
    • CreateDIBitmap crée un DDB à partir d'un DIB.
    • CreateDiscardableBitmap() est un relicat de Win16.

    Donc en fait, toutes ces fonctions servent à créer des DDB, ce qui me parait inutile de nos jours. On peut les considérer toutes comme des reliquats de Win16 (les DIB n'étaient pas utilisables directement sous Win16, c'est pourquoi on faisait pratiquement tout avec des DDB).
    Et pourquoi dans ma doc qui doit faire une bonne vingtaine de pages sur le sujet, il n'y a aucune réference à CreateDIBSection?
    On ne sait pas de quand date ta doc. Si elle date de Win16, c'est normal.
    Ou est donc la mémoire du bitmap quand on a juste un handle et quel est l'interet que le programme ne puisse pas avoir accès à cette mémoire facilement ?
    L'intéret des DIB, c'est justement qu'on peut.
    Je suppose que tu pensais à LoadImage à la place de LoadBitmap ?
    Corrigé.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut
    C'est bien, maintenant je sais charger un bitmap, et même l'afficher (waou) mais comment faire pour le sauvegarder dans un autre fichier ?: Après un appel à GetObject, on ne retrouve qu'une parties des informations contenues au dépard dans le fichier.

    Je les réinvente comme elle sont pas trop dures à trouver (mais c'est embètant quand même, des valeurs comme la résolution paraissent pas évidentes).
    Ou alors je copie le début du fichier initial sans rien changer et après j'écris ma version de l'image que j'aurais modifiée.

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 572
    Points
    41 572
    Par défaut
    Cherche "Storing an Image" sur MSDN : Il y a tout un article là-dessus.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut
    J'ai déjà vu cet exemple, mais il me paraît plutot imbuvable, et l'est, à moins que quelqu'un ne m'explique les points techniques qui me paraissent un peu particuliers:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        // Convert the color format to a count of bits.
        cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
        if (cClrBits == 1)
            cClrBits = 1;
        else if (cClrBits <= 4)
            cClrBits = 4;
        else if (cClrBits <= 8)
            cClrBits = 8;
        else if (cClrBits <= 16)
            cClrBits = 16;
        else if (cClrBits <= 24)
            cClrBits = 24;
        else cClrBits = 32;
    Pourquoi utiliser le champ bmPlanes, alors qu'il est censé être toujours égal à 1 ?

    Toujours sur le même morceau, pourquoi utiliser les comparateurs <=, une simple égalité ne couvre pas tous les cas ??


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
         if (cClrBits != 24)
             pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                        sizeof(BITMAPINFOHEADER) +
                        sizeof(RGBQUAD) * (1<< cClrBits));
    
         // There is no RGBQUAD array for the 24-bit-per-pixel format.
    Et les bitmaps 32 bits ont une palette de couleur ?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
                                      * pbmi->bmiHeader.biHeight;
    Pourquoi ne pas utiliser le champ bmWidthBytes de la structure BITMAP, au lieu d'écrir : ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 ?


    Je m'aperçoit aussi que les champs biXPelsPerMeter et biYPelsPerMeter ne sont même pas traités; choix stratégique ou flemme de faire des docs potables ?

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 379
    Points : 41 572
    Points
    41 572
    Par défaut
    Citation Envoyé par _Michel Voir le message
    Pourquoi utiliser le champ bmPlanes, alors qu'il est censé être toujours égal à 1 ?
    Je ne sais pas. Au cas où, sans doute...
    Toujours sur le même morceau, pourquoi utiliser les comparateurs <=, une simple égalité ne couvre pas tous les cas ??
    Ce code sert à arrondir à la puissance de 2 (ou multiple de huit) supérieure.
    Normalement, on peut supposer que ça ne sert à rien. Mais ça ne coûte rien de valider les informations...
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
         if (cClrBits != 24)
             pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
                        sizeof(BITMAPINFOHEADER) +
                        sizeof(RGBQUAD) * (1<< cClrBits));
     
         // There is no RGBQUAD array for the 24-bit-per-pixel format.
    Et les bitmaps 32 bits ont une palette de couleur ?
    Non, ils n'en ont pas non plus. Je pens que c'est une erreur, moi, j'aurais mis < au lieu de !=.
    C'est peut-être lié au fait qu'on ne sauvegarde pratiquement jamais une image bmp en format 32 bits: C'est plus un format de travail que de stockage, généralement on stocke en 24.
    Edit: De toute façon, 1<<32 vaut zéro sous Visual sous Win32, donc ça revient un peu au même. Mais je serais pour remplacer quand meme le != par un <, plutôt que me reposer sur le comportement de l'opérateur de décalage.
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
                                      * pbmi->bmiHeader.biHeight;
    Pourquoi ne pas utiliser le champ bmWidthBytes de la structure BITMAP, au lieu d'écrir : ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8 ?
    Si je me souviens bien, la contrainte d'alignement n'est pas la même: Il me semble avoir lu quelque part que le bitmap en mémoire devait être aligné sur 16 bits, alors qu'ici on aligne sur 32...
    Je m'aperçoit aussi que les champs biXPelsPerMeter et biYPelsPerMeter ne sont même pas traités; choix stratégique ou flemme de faire des docs potables ?
    Je dirais flemme, mais ils ne servent pas à grand-chose. Moi, j'y mettrais zéro de toute façon. Après tout, comment peux-tu savoir combien de pixels par mettre il est censé y avoir dans l'image que tu crées ?

    Note: Si je retrouve mon code, je pourrais te faire profiter des modifs que j'avais faites pour sauvegarder dans d'autres formats que celui d'origine (par exemple, sauvegarder en 24 bits une image 32 bits, etc.). Mais c'est du vieux code à moi, il y avait des trucs maladroits dedans...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Expert éminent sénior
    Avatar de Mat.M
    Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2006
    Messages
    8 365
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2006
    Messages : 8 365
    Points : 20 401
    Points
    20 401
    Par défaut
    On peut passer aussi par des bitmpas COM notamment IPicture....
    Citation Envoyé par _Michel Voir le message
    J'ai déjà vu cet exemple, mais il me paraît plutot imbuvable, et l'est, à moins que quelqu'un ne m'explique les points techniques qui me paraissent un peu particuliers:

    Oui mais il permet un peu tous les cas de figures.
    Je l'ai copié collé pour me faire un petit utilitaire de capture d'écran et ça fonctionne impeccable.
    Si tu n'est pas à l'aise avec ce qui est compréhensible tu peux utiliser CxImage ou bien aller sur www.codeproject.com
    Mais je préfère le code bas-niveau du MSDN

    Re: pour les jpeg http://www.smalleranimals.com/jpegfile.htm

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    217
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 217
    Points : 105
    Points
    105
    Par défaut
    Non ça va, je crois m'en être bien tiré finalement (en tout cas ça marche avec les bitmaps 24 bbp non compressés) :

    Lecture :
    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
    unsigned char nom [256] = "\0";
    HBITMAP hBmp2;
    BITMAP Bmp2;
    
    ...
    
    // Obtient une structure BITMAP
    if (GetObject (hBmp2, sizeof (BITMAP), &Bmp2) != sizeof (BITMAP)){
            Message (hWnd, "Erreur dans l'obtention des informations sur le bitmap", 
                    "Ouverture", TRUE);
            DeleteObject (hBmp2);
            break;}
    					
    // Vérifie que le bitmap soit au bon format (24 bbp)
    if (Bmp2.bmBitsPixel != 24) {
            Message (hWnd, "Le bitmap n'a pas le format souhaité : \nseuls les bitmaps 24 bbp sont traités.",
    "Format incorrect", FALSE);
            DeleteObject (hBmp2);
            break;}
    Ecriture :
    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
    unsigned char nom [256];
    HANDLE hFichier;
    BITMAPFILEHEADER BFile;
    BITMAPINFOHEADER BInfo;
    long tmp;
    
    ...
    
    // Remplissage des données utiles :
    // 		BITMAPFILEHEADER
    BFile.bfType = 'B' + ('M' * 256);
    BFile.bfSize = sizeof (BITMAPFILEHEADER) + 
            sizeof (BITMAPINFOHEADER) + Bitmap.bmWidthBytes * Bitmap.bmHeight);
    BFile.bfReserved1 = 0;
    BFile.bfReserved2 = 0;
    BFile.bfOffBits = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER);
    					
    //		BITMAPINFOHEADER
    BInfo.biSize = sizeof (BITMAPINFOHEADER);
    BInfo.biWidth = Bitmap.bmWidth;
    BInfo.biHeight = Bitmap.bmHeight;
    BInfo.biPlanes = 1;
    BInfo.biBitCount = 24;
    BInfo.biCompression = BI_RGB;	// Peut-être un bug que de ne pas prendre en compte la compression ?..
    BInfo.biSizeImage = Bitmap.bmWidthBytes * Bitmap.bmHeight;
    BInfo.biXPelsPerMeter = 0;
    BInfo.biYPelsPerMeter = 0;
    BInfo.biClrUsed = 0;
    BInfo.biClrImportant = 0;
    
    // Création du fichier
    if ((hFichier = CreateFile (nom, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL))
            == INVALID_HANDLE_VALUE)
    {
            Message (hWnd, "Erreur dans la création du fichier.", "Création du fichier", FALSE);
            break;}
    					
    // Copie des infos dans le fichier
    if ((WriteFile (hFichier, &BFile, sizeof (BITMAPFILEHEADER), &tmp, NULL) == 0) ||
            (WriteFile (hFichier, &BInfo, sizeof (BITMAPINFOHEADER), &tmp, NULL) == 0) ||
            (WriteFile (hFichier, Bitmap.bmBits, Bitmap.bmWidthBytes * Bitmap.bmHeight, &tmp, NULL) == 0))
    {
            Message (hWnd, "Erreur dans l'écriture dans le fichier.", "Ecriture dans le fichier", TRUE);
            CloseHandle (hFichier);
            break;}
    
    // Fermeture du fichier
    if (CloseHandle (hFichier) == 0){
            Message (hWnd, "Erreur dans la fermeture du fichier.", "Fermeture du fichier", TRUE);
            break;}

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    89
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Mai 2007
    Messages : 89
    Points : 60
    Points
    60
    Par défaut
    bon il y a beaucoup plus simple! Le SDL !

    RDV sur les tutoriels SDL ! dans les cours et tutoriels C tu as le tutoriel pour apprendre le SDL^^

    et oui !

    comme include, tu ajoute #include <SDL.H>

    et après, tu fais un petit

    SDL_INIT(SDL_INIT_VIDEO); (ou un truc come ça^^)
    et après tu fais un LoadImage()

    beaucoup plus simple !
    Dans 1 km, y'a 1024 m... C'est simple non?

    Mon entreprise : Steel-Studio

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

Discussions similaires

  1. acquisition d'une image au format bitmap puis pgm
    Par MzelleBatz dans le forum Traitement d'images
    Réponses: 1
    Dernier message: 25/02/2008, 15h50
  2. Réponses: 4
    Dernier message: 14/02/2008, 14h18
  3. pb compact framework .NET : format BITMAP
    Par Guntreg dans le forum C#
    Réponses: 1
    Dernier message: 06/09/2007, 17h42
  4. [débutant]comment manipuler des fichiers bitmap
    Par caty_info dans le forum VB 6 et antérieur
    Réponses: 10
    Dernier message: 04/04/2007, 10h20
  5. Manipuler le format retourné pour une date.
    Par BlackMinou dans le forum Oracle
    Réponses: 3
    Dernier message: 05/04/2006, 18h01

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