Trying get/convert raw rgba image data

Windows specific forum
LiK137
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Jun 23, 2010 5:13 pm

Trying get/convert raw rgba image data

Post by LiK137 »

Hi,
The dll procedure returns hDC raw image, image width and height.
Then I try to get that image to save to file.
1st I tried with CatchImage:

Code: Select all

  GetImage(*hDev, @w, @h, @*imgData)  ; get captured image
                                                        ; [in] h_dev - Object handle
                                                        ; [out] w - image cols
                                                        ; [out] h - image rows 
                                                        ; [out] bits - image data
                                                        ; System.Drawing.Bitmap img = new Bitmap(W, H, W, Imaging.PixelFormat.Format8bppIndexed, hDC)
                                                        ; System.Drawing.Imaging.ColorPalette gray = img.Palette  
  Debug h 
  Debug w
  Debug *imgData ; 
  imgMemSize = w*h
  ShowMemoryViewer(*imgData,imgMemSize)
  Img = CatchImage(#PB_Any, *imgData, imgMemSize)
  Debug Img
  If Img > 0
    SetGadgetState(ImGad_Prev, ImageID(Img))
  EndIf  
  SaveImage(ImageID(Img), "img.bmp", #PB_ImagePlugin_BMP)
Have searched forum and found following:
1.

Code: Select all

Structure PB_StructureDataBase 
  Bitmap.xl
  Width.xl
  Height.xl 
  Depth.xl 
  ColorArray.xl
EndStructure
Declare.xl Hbitmap2PBImage(hbitmap.xl)
Procedure.xl Hbitmap2PBImage(hbitmap.xl) 
  ; -    pbImg.xl = Hbitmap2PBImage(hbitmap.xl)  
  ; -    Returns pbImg Handle from hBitmap
  ; -    Manually Release hBitmap and pbImg
  Protected *idb.PB_StructureDataBase
  GetObject_(hbitmap, SizeOf(BITMAP), @bm.BITMAP)
  If bm\bmBits
    *idb = CreateImage(#PB_Any, bm\bmWidth, bm\bmHeight, bm\bmBitsPixel)
    If IsImage(*idb)
      DeleteObject_(*idb\Bitmap)
      *idb\Bitmap = hbitmap
    EndIf
  EndIf
  ProcedureReturn *idb
EndProcedure
No luck. Then with:

Code: Select all

Structure myBITMAPINFO 
  bmiHeader.BITMAPINFOHEADER 
  bmiColors.RGBQUAD[1] 
EndStructure 
Procedure CopyMemToImage(mem.xl, Img.xl)
  Protected bmi.myBITMAPINFO
  Protected w.xl, h.xl, hBmp.xl, hDC.xl
  w    = ImageWidth(Img)
  h    = ImageHeight(Img)
  hBmp = ImageID(Img)
  
  bmi\bmiHeader\biSize        = SizeOf(BITMAPINFOHEADER)
  bmi\bmiHeader\biWidth       =  w
  bmi\bmiHeader\biHeight      = -h
  bmi\bmiHeader\biPlanes      =  1
  bmi\bmiHeader\biBitCount    = 32
  bmi\bmiHeader\biCompression = #BI_RGB
  
  hDC  = StartDrawing( ImageOutput(Img) )
  If SetDIBits_(hDC, hBmp, 0, h, mem, bmi, #DIB_RGB_COLORS)
    StopDrawing()
    ProcedureReturn #True
  Else
    StopDrawing()
    ProcedureReturn #False
  EndIf
EndProcedure
And finally with this:

Code: Select all

Procedure displayBMP(hDIB)
  
  Define *pDIB.BITMAPINFOHEADER = GlobalLock_(hDIB)
  Define bmpFH.BITMAPFILEHEADER
  
  bitCount = *pDIB\biBitCount
  clrsUsed = *pDIB\biClrUsed
  
  If clrsUsed = 0 And bitCount <= 8
    clrsUsed = 1 << bitCount
  EndIf
  
  If *pDIB\biCompression = #BI_RGB
    bytesPerRow = (((*pDIB\biWidth * bitCount) + 31) / 32) * 4
    *pDIB\biSizeImage = bytesPerRow * *pDIB\biHeight
  ElseIf *pDIB\biSizeImage = 0
    ProcedureReturn -1
  EndIf
  
  With bmpFH
    \bfType = $4d42   ;ASCII for 'BM'
    \bfReserved1 = 0
    \bfReserved2 = 0
    \bfOffBits = SizeOf(BITMAPFILEHEADER) +
                 SizeOf(BITMAPINFOHEADER) +
                 SizeOf(RGBQUAD) * clrsUsed
    \bfSize = \bfOffBits + *pDIB\biSizeImage  
  EndWith 
  
  If bitCount < 24
    If clrsUsed = 0 And bitCount <= 8
      palletteSize = (1<<bitCount) * 4
    EndIf
  EndIf  
  
  bfhSize = SizeOf(bmpFH)
  
  bmpOffset = bfhSize + *pDIB\biSize + palletteSize
  bmpSize = bmpOffset + *pDIB\biSizeImage  
  If bmpSize <= 0
    ProcedureReturn -1
  EndIf  
  *bmpBuffer = AllocateMemory(bmpSize)
  CopyMemory(@bmpFH, *bmpBuffer, bfhSize)
  CopyMemory(*pDIB, *bmpBuffer + bfhSize, bmpSize - bfhSize)
  imgNo = CatchImage(#PB_Any, *bmpBuffer, bmpSize)  
;   SetGadgetState(#imgGadgetNo, ImageID(imgNo))
  
  GlobalUnlock_(hDIB)
  
;   FreeImage(imgNo)
  FreeMemory(*bmpBuffer)  
  
  ProcedureReturn imgNo
  
EndProcedure

After raw image is placed in memory it is handled and displayed by standard C# functions without any dll function calls.
How RAW image is converted to BMP?
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4663
Joined: Sun Apr 12, 2009 6:27 am

Re: Trying get/convert raw rgba image data

Post by RASHAD »

I am not sure about what you are doing
But if your first snippet return the correct width ,height ,img no.
So your statement to save the image is wrong
change

Code: Select all

SaveImage(ImageID(Img), "img.bmp", #PB_ImagePlugin_BMP)
to

Code: Select all

SaveImage(Img, "img.bmp", #PB_ImagePlugin_BMP)
And make sure you have Rights to the folder you are trying to save to
Egypt my love
LiK137
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Jun 23, 2010 5:13 pm

Re: Trying get/convert raw rgba image data

Post by LiK137 »

Thank You Rashad for reply.
I had been trying

Code: Select all

SaveImage(Img, "img.bmp", #PB_ImagePlugin_BMP)
and

Code: Select all

SaveImage(ImageId(Img), "img.bmp", #PB_ImagePlugin_BMP)
Both of them not applicable in this situation.
The dll function:
GetImage(*hDev, @w, @h, @*imgData) ; get captured image
; [in] h_dev - Object handle
; [out] w - image cols
; [out] h - image rows
; [out] bits - image data
specifically returns RGBA pixel data.
I do not know but in C# this RGBA pixel converted to Bitmap. Each pixel worked out in a loop.

the example of saving this raw data:

Code: Select all

         int W = 0;
         int H = 0;
         IntPtr data = IntPtr.Zero;
         GetImage(hDev, ref W, ref H, ref data);

         if (W > 0 && H > 0)
         {
            System.Drawing.Bitmap img = new System.Drawing.Bitmap(W, H, W, System.Drawing.Imaging.PixelFormat.Format8bppIndexed, data);
            System.Drawing.Imaging.ColorPalette gray = img.Palette;

            for (int i = 0; i < 255; i++)
            {
               gray.Entries[i] = System.Drawing.Color.FromArgb(i, i, i);
            }

            img.Palette = gray;
            SaveFileDialog dlg = new SaveFileDialog();

            if (dlg.ShowDialog() == DialogResult.OK)
            {
               img.Save(dlg.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
            }            
            img.Dispose();
         }
      }

Bitmap initialized based on pixel data

Code: Select all

public Bitmap (int width, int height, int stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0);
A 32-bit ARGB color has 8 bits each for alpha, red, green, and blue values.
Walking trough 255 entries by modifying the array of Color structure that make up this ColorPalette.

Can this be implemented in PureBasic?
fabulouspaul
User
User
Posts: 34
Joined: Sun Nov 23, 2014 1:18 pm

Re: Trying get/convert raw rgba image data

Post by fabulouspaul »

I am not sure if you just get a pointer to the pixel-data or a handle to the bitmap from the DLL.

If you just got the pixel-data, you should create a PB image with same size and color-depth as the raw image and copy the pixel-data to the PB image.

But if you get the handle of the bitmap, your first guess (Hbitmap2PBImage) should do the trick. I used that in a similar situation and experienced a failure every now and then. I could stabilize it by copying the image.

Code: Select all

Procedure.l Hbitmap2PBImage(hbitmap.l)
  Structure PB_StructureDataBase 
    Bitmap.l
    Width.w
    Height.w 
    Depth.w 
    ColorArray.l
  EndStructure
  
  Protected *idb.PB_StructureDataBase
  Protected bm.bitmap
  Protected img_nummer
  Protected buffer.l
  
  GetObject_(hbitmap, SizeOf(BITMAP), @bm.BITMAP)
  If bm\bmBits
    *idb = CreateImage(#PB_Any, bm\bmWidth, bm\bmHeight, bm\bmBitsPixel)
    If IsImage(*idb)
      buffer = *idb\Bitmap
      DeleteObject_(*idb\Bitmap)
      *idb\Bitmap = hbitmap
      
      img_nummer = CopyImage(*idb, #PB_Any)
      *idb\Bitmap = buffer
      FreeImage(*idb)
      ProcedureReturn img_nummer
    EndIf
  EndIf
  ProcedureReturn 0
EndProcedure
After either of those it should be possible to save the image as BMP by SaveImage().
Maybe you want to give it a try.
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4663
Joined: Sun Apr 12, 2009 6:27 am

Re: Trying get/convert raw rgba image data

Post by RASHAD »

Are you using Freeimage.dll or such?
I guess you need to use CreateDIBitmap_()
To creates a device-dependent bitmap (DDB) from a device-independent bitmap (DIB) and, optionally, sets the bitmap bits
You will get the image handle as a Return for that function
Egypt my love
LiK137
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Jun 23, 2010 5:13 pm

Re: Trying get/convert raw rgba image data

Post by LiK137 »

First Thank You
The library gives pixel data, not hBitmap. According to description function returns
const unsigned char** bits
"ram[out] bits - image data"

I receive data in this way:
define *bitsdata
GetImage(*hDev, @w, @h, @*bitsdata)

Even function completes successfully and give correct width and height of the bits image, when I want to get memory size by:
bitsdataMemSize = MemorySize(*bitsdata):Debug bitsdataMemSize

I receive "The specified MemoryID" is not valid and bitsdataMemSize should be Zero but strange that memoryviewer shows *bitsdata (I do not know whether it is correct address with correct data or not):
ShowMemoryViewer(*ppImgData,ppimgMemSize)

If my pointer to pointer implementation is correct I should not get any invalid memory error.

Thank You very much
LiK137
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Jun 23, 2010 5:13 pm

Re: Trying get/convert raw rgba image data

Post by LiK137 »

And in the following link
viewtopic.php?f=13&t=70809&hilit=argb
I saw Rashad's postreply which has

Code: Select all

Macro CopyImageToMemory(imagenumber, Memory)
Macro CopyMemoryToImage(Memory, imagenumber)
Procedure.l ARGB(rgb.l, a.b = 255)
ProcedureDLL ImageFromMem(Address, Length)
which I have to use after getting correct data from doublepointer.

Again many thanks
LiK137
Enthusiast
Enthusiast
Posts: 282
Joined: Wed Jun 23, 2010 5:13 pm

Re: Trying get/convert raw rgba image data

Post by LiK137 »

Thank You for replies.
the problem solved in another topic about pointers.
I should have to use PeekI to get memory pointer and PeekA to get Const Char data of w*h size.
Post Reply