Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. Creating image file from pointer to HGLOBAL

Creating image file from pointer to HGLOBAL

Scheduled Pinned Locked Moved Managed C++/CLI
csharpc++data-structureshelpquestion
7 Posts 3 Posters 2 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    alleyes 0
    wrote on last edited by
    #1

    In an app that is used to capture images, the information used to store the image data is referenced by a pointer to HGLOBAL. That is then used to re-create the image so it can be written to disk with a call to GlobalFree. I have two problems: I need to attach a file header so I can write the image to a file. The image data is of native type DWORD so I cant use the .NET classes without massaging the image data. What I have done thus far: BITMAPINFOHEADER* imgHeader = (BITMAPINFOHEADER*)GlobalLock(gPtrImage); array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage); if (!imgHeader) { GlobalFree(gPtrImage); return; } BITMAPFILEHEADER* bfh = new BITMAPFILEHEADER(); bfh->bfType = 0x4d42; //BM bfh->bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + imgHeader->biSize + imgHeader->biSizeImage); bfh->bfReserved1 = 0; bfh->bfReserved2 = 0; bfh->bfOffBits = (DWORD) (bfh->bfSize - imgHeader->biSizeImage); LPDWORD Pixels = (LPDWORD)((LPBYTE)imgHeader + sizeof(BITMAPINFOHEADER)); Marshal::Copy(static_cast<IntPtr>(bfh), imgArray, 0, sizeof(BITMAPFILEHEADER)); Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, (sizeof(BITMAPFILEHEADER) + 1), imgHeader->biSizeImage); GlobalUnlock(gPtrImage); System::Environment::SpecialFolder saveFolder = System::Environment::SpecialFolder::MyDocuments; SaveFileDialog^ sfd = gcnew SaveFileDialog(); sfd->InitialDirectory = System::Environment::GetFolderPath(saveFolder); sfd->Filter = "Device Independent Bitmaps |*.bmp|All files|*.*"; if (sfd->ShowDialog() == System::Windows::Forms::DialogResult::OK) { System::IO::Stream^ imgFileStream = sfd->OpenFile(); if (imgFileStream != nullptr) { imgFileStream->Write(imgArray, 0, imgArray->Length); imgFileStream->Close(); } } GlobalFree(gPtrImage); gPtrImage = NULL; The file size is a lot larger than I would expect for a 640*480 32 bit BMP and it can't be displayed. The image is fine when written to a picturebox, the data is then unlocked but NOT freed. As a test, I save the image of the picturebox i.e PictureBox->Image and that is fine. The data needs to to be handed off to another application that requires native code so I need to re-create the image from the pointer to HGLOBAL and that's where it falls down What might be wrong with this? Thanks for any help

    M 1 Reply Last reply
    0
    • A alleyes 0

      In an app that is used to capture images, the information used to store the image data is referenced by a pointer to HGLOBAL. That is then used to re-create the image so it can be written to disk with a call to GlobalFree. I have two problems: I need to attach a file header so I can write the image to a file. The image data is of native type DWORD so I cant use the .NET classes without massaging the image data. What I have done thus far: BITMAPINFOHEADER* imgHeader = (BITMAPINFOHEADER*)GlobalLock(gPtrImage); array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage); if (!imgHeader) { GlobalFree(gPtrImage); return; } BITMAPFILEHEADER* bfh = new BITMAPFILEHEADER(); bfh->bfType = 0x4d42; //BM bfh->bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + imgHeader->biSize + imgHeader->biSizeImage); bfh->bfReserved1 = 0; bfh->bfReserved2 = 0; bfh->bfOffBits = (DWORD) (bfh->bfSize - imgHeader->biSizeImage); LPDWORD Pixels = (LPDWORD)((LPBYTE)imgHeader + sizeof(BITMAPINFOHEADER)); Marshal::Copy(static_cast<IntPtr>(bfh), imgArray, 0, sizeof(BITMAPFILEHEADER)); Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, (sizeof(BITMAPFILEHEADER) + 1), imgHeader->biSizeImage); GlobalUnlock(gPtrImage); System::Environment::SpecialFolder saveFolder = System::Environment::SpecialFolder::MyDocuments; SaveFileDialog^ sfd = gcnew SaveFileDialog(); sfd->InitialDirectory = System::Environment::GetFolderPath(saveFolder); sfd->Filter = "Device Independent Bitmaps |*.bmp|All files|*.*"; if (sfd->ShowDialog() == System::Windows::Forms::DialogResult::OK) { System::IO::Stream^ imgFileStream = sfd->OpenFile(); if (imgFileStream != nullptr) { imgFileStream->Write(imgArray, 0, imgArray->Length); imgFileStream->Close(); } } GlobalFree(gPtrImage); gPtrImage = NULL; The file size is a lot larger than I would expect for a 640*480 32 bit BMP and it can't be displayed. The image is fine when written to a picturebox, the data is then unlocked but NOT freed. As a test, I save the image of the picturebox i.e PictureBox->Image and that is fine. The data needs to to be handed off to another application that requires native code so I need to re-create the image from the pointer to HGLOBAL and that's where it falls down What might be wrong with this? Thanks for any help

      M Offline
      M Offline
      Mark Salsbery
      wrote on last edited by
      #2

      BITMAPINFOHEADER.biSizeImage is allowed to be 0... I would personally feel better about checking for that unless you know for sure it's never going to be 0...maybe something like

      if (imgHeader->biSizeImage == 0)
      imgHeader->biSizeImage = (((imgHeader->biWidth * (long)imgHeader->biBitCount + 31L) & (~31L)) / 8L) * abs(imgHeader->biHeight);

      Al_S wrote:

      array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage);

      Your array isn't big enough. What about the size of the BITMAPFILEHEADER and the BITMAPINFOHEADER?

      Al_S wrote:

      Marshal::Copy(static_cast(Pixels), imgArray, (sizeof(BITMAPFILEHEADER) + 1), imgHeader->biSizeImage);

      Array indexes are 0-based... That should be Marshal::Copy(static_cast(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage); Also I'm not sure about those static_casts... why not just use IntPtr(bfh)/IntPtr(Pixels)

      Al_S wrote:

      The file size is a lot larger than I would expect for a 640*480 32 bit BMP

      Should be a little over 1MB - just how big is it? You're the one calculating the size - what do you see in the debugger?

      Mark Salsbery Microsoft MVP - Visual C++ :java:

      A 1 Reply Last reply
      0
      • M Mark Salsbery

        BITMAPINFOHEADER.biSizeImage is allowed to be 0... I would personally feel better about checking for that unless you know for sure it's never going to be 0...maybe something like

        if (imgHeader->biSizeImage == 0)
        imgHeader->biSizeImage = (((imgHeader->biWidth * (long)imgHeader->biBitCount + 31L) & (~31L)) / 8L) * abs(imgHeader->biHeight);

        Al_S wrote:

        array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage);

        Your array isn't big enough. What about the size of the BITMAPFILEHEADER and the BITMAPINFOHEADER?

        Al_S wrote:

        Marshal::Copy(static_cast(Pixels), imgArray, (sizeof(BITMAPFILEHEADER) + 1), imgHeader->biSizeImage);

        Array indexes are 0-based... That should be Marshal::Copy(static_cast(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage); Also I'm not sure about those static_casts... why not just use IntPtr(bfh)/IntPtr(Pixels)

        Al_S wrote:

        The file size is a lot larger than I would expect for a 640*480 32 bit BMP

        Should be a little over 1MB - just how big is it? You're the one calculating the size - what do you see in the debugger?

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        A Offline
        A Offline
        alleyes 0
        wrote on last edited by
        #3

        Hi Mark. Since the original image is from a global pointer to HGLOBAL, which was previously created and displayed, I am aware of all the fields of the BITMAPINFOHEADER. They are all set from grabbing an image in other code. I am trying to re-create the image after handing off the pointer to HGLOBAL elsewhere With that: biSizeImage = 0x12c000 (about 1.2M) biBitCount = 0x20 ... ... I saw that the array size was goofy so I fixed that - I think. array^ imgArray = gcnew array(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER)); I also fixed copying to the array: Marshal::Copy(static_cast<IntPtr>(bfh), imgArray, 0, sizeof(BITMAPFILEHEADER)); Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage); All this washes out to a correct file size. When viewed in a hex editor, the BITMAPFILEHEADER appears where it belongs correctly. The rest of the data is different though. The resultant image can not be viewed X| As far as the use of the static_cast, I don't have any problems with that and I think I've used it properly. Thanks for responding.

        M 1 Reply Last reply
        0
        • A alleyes 0

          Hi Mark. Since the original image is from a global pointer to HGLOBAL, which was previously created and displayed, I am aware of all the fields of the BITMAPINFOHEADER. They are all set from grabbing an image in other code. I am trying to re-create the image after handing off the pointer to HGLOBAL elsewhere With that: biSizeImage = 0x12c000 (about 1.2M) biBitCount = 0x20 ... ... I saw that the array size was goofy so I fixed that - I think. array^ imgArray = gcnew array(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER)); I also fixed copying to the array: Marshal::Copy(static_cast<IntPtr>(bfh), imgArray, 0, sizeof(BITMAPFILEHEADER)); Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage); All this washes out to a correct file size. When viewed in a hex editor, the BITMAPFILEHEADER appears where it belongs correctly. The rest of the data is different though. The resultant image can not be viewed X| As far as the use of the static_cast, I don't have any problems with that and I think I've used it properly. Thanks for responding.

          M Offline
          M Offline
          Mark Salsbery
          wrote on last edited by
          #4

          alleyes wrote:

          I saw that the array size was goofy so I fixed that - I think. array^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER));

          Still not big enough :) array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

          alleyes wrote:

          Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage);

          You're not writing the BITMAPINFOHEADER to the output array... I missed that one the first time, sorry :) Marshal::Copy(static_cast<IntPtr>(imgHeader), imgArray, sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER) + imgHeader->biSizeImage);

          Mark Salsbery Microsoft MVP - Visual C++ :java:

          modified on Tuesday, January 12, 2010 4:47 PM

          A 2 Replies Last reply
          0
          • M Mark Salsbery

            alleyes wrote:

            I saw that the array size was goofy so I fixed that - I think. array^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER));

            Still not big enough :) array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

            alleyes wrote:

            Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage);

            You're not writing the BITMAPINFOHEADER to the output array... I missed that one the first time, sorry :) Marshal::Copy(static_cast<IntPtr>(imgHeader), imgArray, sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER) + imgHeader->biSizeImage);

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            modified on Tuesday, January 12, 2010 4:47 PM

            A Offline
            A Offline
            alleyes 0
            wrote on last edited by
            #5

            array size change plus the proper copy nails it. Thanks very much! :-D

            1 Reply Last reply
            0
            • M Mark Salsbery

              alleyes wrote:

              I saw that the array size was goofy so I fixed that - I think. array^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER));

              Still not big enough :) array<BYTE>^ imgArray = gcnew array<BYTE>(imgHeader->biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));

              alleyes wrote:

              Marshal::Copy(static_cast<IntPtr>(Pixels), imgArray, sizeof(BITMAPFILEHEADER), imgHeader->biSizeImage);

              You're not writing the BITMAPINFOHEADER to the output array... I missed that one the first time, sorry :) Marshal::Copy(static_cast<IntPtr>(imgHeader), imgArray, sizeof(BITMAPFILEHEADER), sizeof(BITMAPINFOHEADER) + imgHeader->biSizeImage);

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              modified on Tuesday, January 12, 2010 4:47 PM

              A Offline
              A Offline
              alleyes 0
              wrote on last edited by
              #6

              Hi Mark, Is there a way to do the reverse of this? That is, one HGLOBAL to store different images, where it normally is one HGLOBAL relating to one image. Thanks for the valuable help!

              M 1 Reply Last reply
              0
              • A alleyes 0

                Hi Mark, Is there a way to do the reverse of this? That is, one HGLOBAL to store different images, where it normally is one HGLOBAL relating to one image. Thanks for the valuable help!

                M Offline
                M Offline
                Mouzam Basheer
                wrote on last edited by
                #7

                Hi Developers. i am going to wrap lib(static library ) file in c++. one function return HGLOBAL DIB. how can i access Byte Array or Bitmap Image from this and pass this Byte Array or bitmap to My C# Project. please help me. thanks in advance. Here is function that return HGLOBAL DIB Type.

                HGLOBAL m_hDib;
                int retval = XRaySensorIsImageAvailable();

                    if ( 0 < retval )
                    {
                        if (m\_hDib ) ::GlobalFree(m\_hDib);
                        m\_hDib = XRaySensorGetDIB();
                
                	}
                
                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups