Announcement

Collapse
No announcement yet.

Easiest way to convert a JPG to a DIB (BMP file) in memory?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Easiest way to convert a JPG to a DIB (BMP file) in memory?

    I've searched through the forums, but haven't really found what I'm looking for.

    Basically, I need to convert a JPG file that has been loaded into a memory buffer (the entire file, copied to a buffer in memory) into a DIB bitmap I can use for various purposes.

    I would prefer a solution that doesn't require an external DLL of any type, works with Win98 and up, and can be used freely (no restrictions on distribution).

    I've seen bits and pieces of GDI+ code that "seems" like it would do what I need, but I'd really like to see a full standalone sample source code if possible.

    Thanks,

    Anthony
    Anthony Watson, Mountain Software
    www.mountainsoftware.com

  • #2
    Anthony, when you load any image into a DIB, the DIB is in a BMP format, so then all you have to do is save the DIB and conversion is done for you,

    search for "OLE Picture Viewer" for ways to load the DIB, and then "Save Bitmap" for the save code,there's tons of examples here

    Comment


    • #3
      Brad,

      I spent the day searching through the OLE picture viewers in the forums. Unfortunately, the samples I found wouldn't copy into PowerBASIC and run correctly. Don't know if the forum corrupted them or what, but with a bit cleaning and reediting, I have a couple of working samples.

      Unfortunately, I don't really understand what is taking place, so I'm still trying to figure out how I would get a bitmap handle that I could use for blitting and other purposes in my software.

      While studying the example source codes, I ran across what I believe is a command called "muldiv"? It's not listed anywhere in the PowerBASIC documentation, but it's used in many programs here on the forum. What is "muldiv" and what does it do? Is there a modern equivalent command?

      Thanks,

      Anthony
      Anthony Watson, Mountain Software
      www.mountainsoftware.com

      Comment


      • #4
        Anthony,


        MulDiv is an API function,

        The MulDiv function multiplies two 32-bit values and then divides the 64-bit result by a third 32-bit value. The return value is rounded up or down to the nearest integer.



        I'm still using PBWin ver 7.2, (been primarily learning web stuff so I havn't upgraded yet) so I'm not sure why the examples don't run ?

        but, I know what you are after, I'll put together a sample sometime tonight

        Comment


        • #5
          Convert JPG to BITMAP from memory

          This is (somewhat) the code i use in Egrid32. PLease test it toroughly
          because i didnt tested it much after i extracted it from it (i removed a
          bunch of features from the Egrid32 library and i dont know if this example
          has something broken). No reading from file is strictly required, i just used the
          read thing to make the example.

          Step 1: Read the image from file, but it can be read from anywhere.

          Step 2: Convert the JPG to a bitmap handle IN MEMORY. No writing to file.

          I left some resizing features that Egrid32 uses.

          Code:
          #INCLUDE "WIN32API.INC"
          
          $IMAGEFILE  = "C:\foto.jpg"    '<------------------CHANGE TO YOUR PIC
          
          TYPE IPicture DWORD
            QueryInterface   AS DWORD
            AddRef           AS DWORD
            Release          AS DWORD
            get_Handle       AS DWORD
            get_Hpal         AS DWORD
            get_Type         AS DWORD
            get_Width        AS DWORD
            get_Height       AS DWORD
            RENDER           AS DWORD
            set_Hpal         AS DWORD
            get_CurDC        AS DWORD
            SelectPicture    AS DWORD
            get_KeepOriginal AS DWORD
            put_KeepOriginal AS DWORD
            PictureChanged   AS DWORD
            SaveAsFile       AS DWORD
            get_Attributes   AS DWORD
          END TYPE 'IPicture
          
          TYPE IStream DWORD
            QueryInterface  AS DWORD
            AddRef          AS DWORD
            Release         AS DWORD
            SRead           AS DWORD
            SWrite          AS DWORD
            SSeek           AS DWORD
            SetSize         AS DWORD
            CopyTo          AS DWORD
            Commit          AS DWORD
            Revert          AS DWORD
            LockRegion      AS DWORD
            UnlockRegion    AS DWORD
            Stat            AS DWORD
            Clone           AS DWORD
          END TYPE 'IStream
          
          $PicID = CHR$(&H80, &H09, &HF8, &H7B, &H32, &HBF, &H1A, &H10, &H8B, &HBB, &H00, &HAA, &H00, &H30, &H0C, &HAB)
          
          DECLARE FUNCTION RelCall(pStrm AS DWORD) AS DWORD
          DECLARE FUNCTION CreateStreamOnHGlobal LIB "Ole32.dll" ALIAS "CreateStreamOnHGlobal" _
                           (hGlobalMem AS DWORD, DelOnRel AS DWORD, pStrm AS DWORD) AS DWORD
          DECLARE FUNCTION OleLoadPicture LIB "Olepro32.dll" ALIAS "OleLoadPicture" _
                           (BYVAL pStream AS DWORD, BYVAL PicSz AS DWORD, BYVAL fRunmode AS DWORD, _
                           pPicID AS ASCIZ * 17, ppvObj AS DWORD) AS DWORD
          DECLARE FUNCTION RendCall(hDC AS DWORD, x AS DWORD, y AS DWORD, cx AS DWORD, _
                           cy AS DWORD, nul AS DWORD, pic_height AS DWORD, pic_width _
                           AS DWORD, pic_height AS DWORD, nul AS DWORD, rct AS ANY) AS DWORD
          DECLARE FUNCTION DimenCall(pIStrmPtr AS DWORD, PicDimen AS DWORD) AS DWORD
          
          
          FUNCTION Load_ImageFromMemory(ImagePtr AS DWORD, ImageSize AS DWORD, Xsize AS LONG, YSize AS LONG, KeepRatio AS LONG) AS DWORD
          
          LOCAL hFile       AS DWORD        'picture's file handle
          LOCAL hMem        AS DWORD        'handle to globally alocated memory
          LOCAL pMem        AS DWORD        'pointer to globally alocated memory
          LOCAL a           AS DWORD
          LOCAL HDC         AS DWORD
          LOCAL DDC         AS DWORD
          LOCAL HBMP        AS DWORD
          LOCAL HBM         AS DWORD
          LOCAL rct         AS Rect
          LOCAL pIStrmPtr   AS IStream PTR  'ptr to IStream interface ptr
          LOCAL pIPicPtr    AS IPicture PTR 'ptr to IPicture interface ptr
          LOCAL PicWd       AS DWORD        'picture's HIMETRIC width
          LOCAL PicHt       AS DWORD        'picture's HIMETRIC height
          LOCAL PicWdPix    AS DWORD        'picture's width in pixels
          LOCAL PicHtPix    AS DWORD        'picture's height in pixels
          LOCAL DX          AS SINGLE
          LOCAL DY          AS SINGLE
          LOCAL PicSz       AS DWORD        'size of picture file in bytes
          LOCAL DataCorrect AS DWORD
          LOCAL Imagestring AS STRING
          
           IF Xsize < 0 THEN Xsize = 0
           IF Ysize < 0 THEN Ysize = 0
          
           IF ISTRUE(ImagePtr) AND ISTRUE(ImageSize) THEN
            ImageString = PEEK$(ImagePtr, ImageSize)
            hMem = GlobalAlloc(%GMEM_MOVEABLE, LEN(ImageString))
            IF hMem THEN
             pMem = GlobalLock(hMem)
             POKE$ pMem, ImageString
             DataCorrect = %TRUE
            END IF
           ELSE
            EXIT FUNCTION
           END IF
            
           IF ISTRUE(pMem) AND ISTRUE(DataCorrect) THEN
            IF (CreateStreamOnHGlobal(BYVAL hMem, BYVAL 1&, BYREF pIStrmPtr)) THEN EXIT IF
            IF OleLoadPicture(pIStrmPtr, PicSz, 0&,BYREF $PicID, pIPicPtr) THEN EXIT IF
            CALL DWORD @@pIStrmPtr.Release USING RelCall(BYVAL pIStrmPtr)
            CALL DWORD @@pIPicPtr.Get_Width USING DimenCall(BYVAL pIPicPtr,BYREF PicWd)
            CALL DWORD @@pIPicPtr.Get_Height USING DimenCall(BYVAL pIPicPtr,BYREF PicHt)
            DDC = GetDC(%HWND_DESKTOP)
             PicWdPix = CDBL((PicWd * GetDeviceCaps(DDC, %LOGPIXELSX)) / 2540)
             PicHtPix = CDBL((PicHt * GetDeviceCaps(DDC, %LOGPIXELSY)) / 2540)
             IF ISTRUE(Xsize) AND ISTRUE(ISTRUE(Ysize)) THEN
              IF KeepRatio THEN
               DX = (PicWdPix/Xsize)
               DY = (PicHtPix/Ysize)
               IF (DX > DY) THEN
                PicWdPix = (PicWdPix/DX)
                PicHtPix = (PicHtPix/DX)
               ELSE
                PicWdPix = (PicWdPix/DY)
                PicHtPix = (PicHtPix/DY)
               END IF
              ELSE
               PicWdPix = Xsize
               PicHtPix = Ysize
              END IF
             END IF
             HDC  = CreateCompatibleDC(DDC)
             HBMP = CreateCompatibleBitmap(DDC, PicWdPix, PicHtPix)
             IF GetStretchBltMode(HDC) <> %STRETCH_HALFTONE THEN
              CALL SetStretchBltMode(HDC, %STRETCH_HALFTONE)
              CALL SetBrushOrgEx(HDC, 0, 0, BYVAL %Null)
             END IF
             HBM  = SelectObject(HDC, HBMP)
             CALL ReleaseDC(%HWND_DESKTOP, DDC)
             SetRect RCT, 1, 1, PicWdPix, PicHtPix
             CALL DWORD @@pIPicPtr.Render USING RendCall(BYVAL pIPicPtr, BYVAL HDC, _
                  BYVAL 0, BYVAL 0, BYVAL PicWdPix, BYVAL PicHtPix, BYVAL 0&, BYVAL PicHt, BYVAL PicWd,  _
                  BYVAL -PicHt, BYVAL VARPTR(rct))
             CALL DWORD @@pIPicPtr.Release USING RelCall(BYVAL pIPicPtr)
             SelectObject HDC, HBM
             DeleteDC HDC
            FUNCTION = HBMP
            IF pMem  THEN CALL GlobalUnlock(hMem)
            IF hMem  THEN CALL GlobalFree(Hmem)
           END IF
          
          END FUNCTION
          
          
          
          FUNCTION PBMAIN AS LONG
          
          LOCAL ImageContents AS STRING
          LOCAL hBitmap AS DWORD
          LOCAL FF AS LONG
          
          ' get the image fom file.
          FF = FREEFILE
          OPEN $IMAGEFILE FOR BINARY AS #FF
           ImageContents = SPACE$(LOF(FF))
           GET #ff,,ImageContents
          CLOSE #FF
          
              
              
          ' Convert JPG to Bitmap from memory
          hBitmap = Load_ImageFromMemory(STRPTR(ImageContents), LEN(ImageContents), 0, 0, 0)
          
          IF HBitmap THEN
           MSGBOX "Success. Bitmap Handle is: " & STR$(hBitmap)
           DeleteObject hBitmap
          ELSE
           MSGBOX "Failure, Check JPG file."
          END IF
              
          END FUNCTION
          Last edited by Elias Montoya; 20 Mar 2008, 04:28 PM.

          Comment


          • #6
            Brad,

            Yep, I discovered the muldiv API on MSDN shortly after posting my message. Figures...

            I look forward to seeing your sample...

            Elias,

            Thanks for the sample code. It looks closer to what I'm needing, so I'll examine it in more detail this afternoon when I can find the time. Thanks!

            Anthony
            Anthony Watson, Mountain Software
            www.mountainsoftware.com

            Comment


            • #7
              Elias,

              With a little modification your sample appears to be working perfectly in my program. Thank you!

              One question though, it appears to load JPG, BMP, and GIF files without difficulty. Is there any way to get it to load PNG files as well (now I'm just being greedy... )?

              Very much appreciated!

              Anthony
              Anthony Watson, Mountain Software
              www.mountainsoftware.com

              Comment


              • #8
                Originally posted by Anthony Watson View Post
                ...Is there any way to get it to load PNG files as well (now I'm just being greedy... )?
                Unfortunately, Not without the need of third party dll's (as far as i know).
                I think you will need GDI+ for this one.

                Comment


                • #9
                  Elias,

                  I don't really need PNG support for my application, I just thought I'd ask.

                  My application is now loading JPG's fine, but I have run into a couple of issues.

                  It appears the code you supplied results in an image with a 32-bit color depth. This wouldn't be a problem for viewing, but I need to load and save the image in a database. A 16 color BMP or a 256 color GIF file ends up being huge once loaded.

                  I thought I'd work around that problem and tackle my resizing needs at once by creating a bitmap in memory and stretchblt'ing from one bitmap to the other. This works great to get down to 16-bit or 24-bit DIB's, but I've run into a problem if I try reducing it further to 256 colors or less. I can't figure out how to get a color table when reducing it to 256 colors. No matter what I do, the RGBQUAD data is zero.

                  Here's a clip from my program. I don't know how understandable it will be without all the subroutines it relies on, but hopefully you can get the basic idea of what I'm doing.

                  Code:
                          '** Get bitmap dimensions
                          a=GetObject(hBitmap,SIZEOF(bm),bm)
                          old_wide=bm.bmwidth
                          old_high=bm.bmheight
                          bpp=bm.bmbitspixel
                          old_sz=bm.bmheight*bm.bmwidthbytes
                  
                          '** Scale image down if too large
                          new_wide=old_wide
                          new_high=old_high
                          IF new_wide>640 OR new_high>480 THEN
                            a#=480/new_high
                            b#=640/new_wide
                            IF a#>b# THEN
                              a#=b#
                            END IF
                            new_wide=new_wide*a#
                            new_high=new_high*a#
                          END IF
                  
                          '** Define the new bitmap
                          new_bpp=16
                          rgb_size=0
                          IF new_bpp<16 THEN
                            rgb_size=(2^new_bpp)*4   '** 1, 16, or 256 color
                          END IF
                  
                          '** Create a header for the new bitmap
                          CALL create_buffer(40+rgb_size,bitmap_header)
                          CALL memfill(bitmap_header,0,40+rgb_size,0)
                          CALL put_long(bitmap_header,0,40)
                          CALL put_long(bitmap_header,4,new_wide)
                          CALL put_long(bitmap_header,8,new_high)
                          CALL put_word(bitmap_header,12,1)
                          CALL put_word(bitmap_header,14,new_bpp)
                          CALL put_long(bitmap_header,16,%BI_RGB)
                  
                          '** Create the bitmap
                          temp_bmp=CreateDIBSection(screen,BYVAL bitmap_header,%DIB_RGB_COLORS,BYVAL VARPTR(ppvBits),0,0)
                  
                          '** Set Device Contexts and copy old bitmap to new one
                          src_dc=CreateCompatibleDC(screen)
                          src_old=SelectObject(src_dc,hBitmap)
                          dst_dc=CreateCompatibleDC(screen)
                          dst_old=SelectObject(dst_dc,temp_bmp)
                          CALL SetStretchBltMode(dst_dc,%COLORONCOLOR)
                          CALL StretchBlt(dst_dc,0,0,new_wide,new_high,src_dc,0,0,old_wide,old_high,%SRCCOPY)
                  
                          '** Get the color table for the bitmap
                          IF rgb_size>0 THEN
                            CALL create_buffer(rgb_size,color_table)
                            a=GetDibColorTable(dst_dc,0,rgb_size/4,BYVAL color_table)
                          END IF
                  
                          CALL SelectObject(src_dc,src_old)
                          CALL SelectObject(dst_dc,dst_old)
                          CALL DeleteDC(src_dc)
                          CALL DeleteDC(dst_dc)
                  
                          '** Get the data bits for the bitmap
                          a=GetObject(temp_bmp,SIZEOF(bm),bm)
                          data_size=bm.bmheight*bm.bmwidthbytes
                  
                          '** Create memory buffer for the new bitmap
                          bmp_size=54+rgb_size+data_size
                          CALL create_buffer(bmp_size,address)
                          CALL memfill(address,0,bmp_size,0)
                  
                          '** Set the file header
                          CALL put_word(address,0,CVI("BM"))
                          CALL put_long(address,2,bmp_size)
                          CALL put_long(address,10,bmp_size-data_size)  '** start of bitmap data
                  
                          '** Copy bitmap header
                          CALL bmove(bitmap_header,0,address,14,40)
                  
                          '** Copy the color table
                          CALL bmove(color_table,0,address,54,rgb_size)
                  
                          '** Get the bitmap data
                          di=getdibits(screen,temp_bmp,0,new_high,BYVAL address+54+rgb_size,BYVAL bitmap_header,%DIB_RGB_COLORS)
                  
                          CALL free_buffer(bitmap_header)
                          CALL free_buffer(color_table)
                  
                          CALL DeleteObject(temp_bmp)
                          CALL DeleteObject(hBitmap)
                  From what I could make out on MSDN, the CreateDIBSection should create the palette table itself? But it doesn't, even though everything else works fine.

                  I tried calling the GetDIBColorTable to get the RGB palette, but while the call returns successfully with no errors, the color table is still zero'd out.

                  What am I missing?

                  For now I'll make do with 16-bit bitmaps, and loading smaller BMP files directly (bypassing your code). But it would be nice to get the GIF's down to 256 color bitmaps since that's all they have to start with.

                  Thanks,

                  Anthony
                  Anthony Watson, Mountain Software
                  www.mountainsoftware.com

                  Comment


                  • #10
                    Anthony, I need to stop promising to do things, I simply have very little time right now, and all my PB code is on another machine, but it appears that Elias has provided some good help!

                    his code is based on Semen's iPicture code if your interested,

                    also, you really might want to look into the GDI+ stuff it does a lot more!

                    about palettes, there was an old thread here that very extensively explained the "palette table"/s, as well as a different Bmp2Gif solution - B

                    Comment


                    • #11
                      I suggest you to listen to Brad's advice. Having dependency on a DLL is
                      a low price you have to pay compared to all the functionality you can get
                      from it. Specially when GDI+ is free.

                      Comment


                      • #12
                        Brad,

                        No problem, I understand being busy... The code Elias provided is serving my needs well.

                        Regarding the palettes, I did some quick searching this morning here and on Google, and think I have found the information I need to build the color table.

                        Elias,

                        While I try to avoid external support files in general, I just prefer to know how and why things are functioning in my programs and not rely on the work of others. That's why I got into programming in the first place.

                        I really don't do much work with graphics, so GDI+ is probably overkill for my situation. But I'll keep it in mind if my needs change.

                        Thanks,

                        Anthony
                        Anthony Watson, Mountain Software
                        www.mountainsoftware.com

                        Comment


                        • #13
                          Originally posted by Anthony Watson View Post
                          ...not rely on the work of others. That's why I got into programming in the first place....
                          Sometimes that is nearly impossible. Examples are a very important part on
                          the learning. As brad points out, this code is based on Semen's iPicture,
                          without it, it would be very hard to learn about that.

                          But cheer up, the PB comunity is full of helping hands.

                          Comment

                          Working...
                          X