Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

GDI+ to PB's hBMP

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

  • GDI+ to PB's hBMP

    comments to: http://www.powerbasic.com/support/pb...ad.php?t=12506

    Code:
    this code imports images from files, resource or the clipboard using gdi+
    functions and converts them to powerbasic's bmp graphics so they can be
    manipulated using pb's functions.
     
    if the incoming image needs to be stretched to fit a particular size then
    i've found that the gdi+ functions do a bit better job of it than graphic
    stretch. this code is quite simple and will, most likely need some boosting
    to get it into a real program but as needs and requirements change in
    unforeseeable ways i've not attempted to create the end-all function but
    just a simple skeleton as a starting point.
     
    special thanks go to the following (and some i've most likely missed) for
    their input:
     
    general gdi+   patrice terrier
    resource code  ryan cross
    debugging      aslan babakhanov
     
    using fgdip_2hbmp
      the filename parameter is used to determine where the image is to be
      loaded from. an incoming null value indicates that it is on the clip-
      board. a string starting with the pound sign chr$(35) indicates a
      resource label and any other string is a file path\name.
     
      if hbmp's incoming value is non-zero then it is assumed that you wish
      the function to load the image into the existing graphic.
     
      the function returns:
        zero if it has failed or powerbasic's bmp handle
     
      the value of hinst??? in loadimagefromresouce can be left as zero if
      the resource data is in the current program.
     
     
    that should do it! i've set some constants for the file name and resource
    label. use the bit of code directly following to create the test pbr file
    with your favorite picture.
     
    don schullian
    don (at) dasoftvss (dot)com
    '
    '=====================================================
    '====== resource code ================================
    '=====================================================
    '
    #if 0
     
    #include "resource.h"
     
    #define jpgtest 1001
     
    jpgtest rcdata discardable "test.jpg"
     
    #endif
    '
    '=====================================================
    '====== test code ====================================
    '=====================================================
    '
    #compile exe
    #compiler pbwin 8
    #debug error on
    #dim all
     
    #resource "test.pbr"
    #include "win32api.inc"
    '
    '=====================================================
    '====== declarations =================================
    '=====================================================
    '
    type gdiplusstartupinput
      gdiplusversion as dword             '// must be 1
      debugeventcallback as dword         '// ignored on free builds
      suppressbackgroundthread as long    '// false unless you're prepared to call the hook/unhook functions properly
      suppressexternalcodecs as long      '// false unless you want gdi+ only to use its internal image codecs.
    end type
     
    type gdiplusstartupoutput
      notificationhook as dword
      notificationunhook as dword
    end type
     
    declare function gdiplusstartup              lib "gdiplus.dll" alias "gdiplusstartup"              (token???, inputbuf as gdiplusstartupinput, outputbuf as gdiplusstartupoutput) as long
    declare      sub gdiplusshutdown             lib "gdiplus.dll" alias "gdiplusshutdown"             (byval token???)
    declare function gdipdeletegraphics          lib "gdiplus.dll" alias "gdipdeletegraphics"          (byval hgraphics???) as long
    declare function gdipcreatefromhdc           lib "gdiplus.dll" alias "gdipcreatefromhdc"           (byval hdc???, hgraphics???) as long
    declare function gdiploadimagefromfile       lib "gdiplus.dll" alias "gdiploadimagefromfile"       (byval flname$, lpimage???) as long
    declare function gdipcreatebitmapfromhbitmap lib "gdiplus.dll" alias "gdipcreatebitmapfromhbitmap" (byval hbm&,byval hpal&, nbitmap&) as long
    declare function gdipcreatebitmapfromstream  lib "gdiplus.dll" alias "gdipcreatebitmapfromstream"  (byval pstream???,m_pbitmap&) as long
    declare function createstreamonhglobal       lib "ole32.dll"   alias "createstreamonhglobal"       (byval hglobal as dword, byval fdeleteonrelease as dword, pstm as dword) as long
    declare function gdipdisposeimage            lib "gdiplus.dll" alias "gdipdisposeimage"            (byval lpimage???) as long
    declare function gdipdrawimagerecti          lib "gdiplus.dll" alias "gdipdrawimagerecti"          (byval hgraphics???, byval nimage???, byval x&,byval y&, byval nwidth&, byval nheight&) as long
    declare function gdipgetimagewidth           lib "gdiplus.dll" alias "gdipgetimagewidth"           (byval lpimage???, nwidth???) as long
    declare function gdipgetimageheight          lib "gdiplus.dll" alias "gdipgetimageheight"          (byval lpimage???, nheight???) as long
    declare function gdipgetimagethumbnail       lib "gdiplus.dll" alias "gdipgetimagethumbnail"       (byval nimage&,byval thumbwidth&,byval thumbheight&, thumbnimage&, opt byval pcallback&, opt byval callbackdata&) as long
    '
    '-------------------------------------------
    '
    declare function pstreamrelease        (punk???) as long
    declare function loadimagefromresource (byval resourcename$,opt byval hinst???) as dword
    declare function fgdip_2hbmp           (byval filespec$,opt byval hbmp???) as dword
    '
    '=====================================================
    '====== test code ====================================
    '=====================================================
    '
    $from_rc     = "#1001"
    $from_file   = "mugshot.jpg"
    $from_cboard = "
     
    %gdi_stretch = 1
    $filespec    = $from_file
     
    function winmain ( byval hinstance   as dword, _
                       byval hprevinst   as dword, _
                       byval lpszcmdline as asciiz ptr, _
                       byval ncmdshow    as long ) as long
     
      dim  gditoken     as local dword
      dim  startupinput as local gdiplusstartupinput
      dim hbmp          as local dword
      dim  bmpx         as local single
      dim  bmpy         as local single
      dim hwnd          as local dword
      dim  xx           as local single
      dim  yy           as local single
     
      startupinput.gdiplusversion = 1
      if gdiplusstartup(gditoken, startupinput, byval %null) <> 0 then
        msgbox "no gdi+"
        exit function
      end if
     
    #if %gdi_stretch
      graphic bitmap new 300, 400 to hbmp
    #endif
     
      hbmp = fgdip_2hbmp($filespec,hbmp)
     
      if hbmp = 0 then
          msgbox "function failed"
        else
          graphic attach hbmp, 0
          graphic get client to bmpx, bmpy
          graphic window ", 50, 50, 500, 500 to hwnd
          graphic attach hwnd, 0
          graphic color %black, %yellow
          graphic clear
          if (bmpx > 500) or (bmpy > 500) then
              graphic stretch hbmp, 0, (0, 0)-(bmpx-1,bmpy-1) to (49,49)-(449,449)
            else
              xx = (500 - bmpx) \ 2
              yy = (500 - bmpy) \ 2
              graphic copy hbmp, 0 to (xx,yy)
          end if
          sleep 3000
          graphic attach hbmp, 0
          graphic bitmap end
          graphic attach hwnd, 0
          graphic window end
      end if
     
      gdiplusshutdown gditoken
     
    end function
    '
    '=====================================================
    '====== end test code ================================
    '=====================================================
    '
    function loadimagefromresource (byval resourcename as string, _
                                opt byval hinst        as dword   ) as dword
     
      dim hresource        as local dword
      dim  imagesize       as local dword
      dim presourcedata    as local dword
      dim m_hbuffer        as local dword
      dim pbuffer          as local dword
      dim pstream          as local dword ptr
      dim m_pbitmap        as local dword
      dim m_pbitmap_status as local long
      dim pname            as local asciiz * %max_path
     
      pname = resourcename
     
      hresource = findresource(hinst, pname, byval %rt_rcdata)
      if hresource = 0 then exit function
     
      imagesize = sizeofresource(hinst, hresource)
      if imagesize = 0 then exit function
     
      presourcedata = lockresource(loadresource(hinst, hresource))
      if presourcedata = 0 then exit function
     
      m_hbuffer = globalalloc(%gmem_moveable, imagesize)
      if m_hbuffer = 0 then exit function
     
      pbuffer = globallock(m_hbuffer)
      if pbuffer = 0 then goto exit_1
     
      copymemory pbuffer, presourcedata, imagesize
      if createstreamonhglobal(m_hbuffer, %false, pstream) <> 0 then goto exit_2
     
      m_pbitmap_status = gdipcreatebitmapfromstream(pstream, m_pbitmap)
      call dword @@pstream[2] using pstreamrelease(pstream)
      if (m_pbitmap       <> 0)  and _
         (m_pbitmap_status = 0) then
        function = m_pbitmap
      end if
     
      exit_2:
        globalunlock m_hbuffer
      exit_1:
        globalfree m_hbuffer
     
    end function
    '
    '------------------------------------------------------------------------------
    '
    function fgdip_2hbmp (     byval filespec as string, _
                           opt byval hbmp     as dword   ) as dword
     
      dim  bx       as local long
      dim  by       as local long
      dim hdc       as local dword
      dim hgraphics as local dword
      dim himage    as local dword
      dim  ix       as local long
      dim  iy       as local long
      dim htmp      as local dword
     
      select case asc(filespec)
        case -1   : if openclipboard(htmp) = 0 then exit function
                    htmp = getclipboarddata(%cf_bitmap)
                    if htmp <> 0 then
                      gdipcreatebitmapfromhbitmap htmp, byval %null, himage
                    end if
                    emptyclipboard
                    closeclipboard
                    if himage = 0 then exit function
        case 35   : himage = loadimagefromresource(filespec)
                    if himage = 0 then exit function
        case else : filespec = ucode$(filespec)
                    if gdiploadimagefromfile(filespec, himage) <> 0 then exit function
      end select
     
      gdipgetimagewidth  himage, ix
      gdipgetimageheight himage, iy
     
      if hbmp = 0 then
          bx = ix
          by = iy
          graphic bitmap new bx, by to hbmp
          graphic attach hbmp, 0
          gosub get_dc
        else
          graphic attach hbmp, 0
          graphic get client to bx, by
          gosub get_dc
          if (bx <> ix)   or _
             (by <> iy) then
            gdipgetimagethumbnail himage, bx, by, htmp
            swap himage, htmp
            gdipdisposeimage htmp
          end if
      end if
     
      gdipdrawimagerecti hgraphics, himage, 0, 0, bx-1, by-1
      gdipdeletegraphics hgraphics
      gdipdisposeimage himage
      function = hbmp
      exit function
      '
      '-------------------------------------
      '
      get_dc:
        graphic get dc to hdc
        gdipcreatefromhdc hdc, hgraphics
        if hgraphics <> 0 then return
        gdipdisposeimage himage
        graphic attach hbmp, 0
        graphic bitmap end
      return
     
    end function
    [this message has been edited by don schullian (edited september 29, 2005).]
    C'ya
    Don

    http://www.ImagesBy.me

  • #2
    Here's v2 with some extra parameters in fGDIp_2hBMP

    Don Schullian
    don (at) DASoftVSS (dot)com

    Code:
    '
    '=====================================================
    '====== RESOURCE CODE ================================
    '=====================================================
    '
    #IF 0
     
    #INCLUDE "resource.h"
     
    #define jpgtest 1001
     
    jpgtest RCDATA DISCARDABLE "test.jpg"
     
    #ENDIF
    '
    '=====================================================
    '====== TEST CODE ====================================
    '=====================================================
    '
    #COMPILE EXE
    #COMPILER PBWIN 8
    #DEBUG ERROR ON
    #DIM ALL
     
    #RESOURCE "test.pbr"
    #INCLUDE "win32api.inc"
    '
    '=====================================================
    '====== DECLARATIONS =================================
    '=====================================================
    '
    TYPE GdiplusStartupInput
      GdiplusVersion AS DWORD             '// Must be 1
      DebugEventCallback AS DWORD         '// Ignored on free builds
      SuppressBackgroundThread AS LONG    '// FALSE unless you're prepared to call the hook/unhook functions properly
      SuppressExternalCodecs AS LONG      '// FALSE unless you want GDI+ only to use its internal image codecs.
    END TYPE
     
    TYPE GdiplusStartupOutput
      NotificationHook AS DWORD
      NotificationUnhook AS DWORD
    END TYPE
     
    DECLARE FUNCTION GdiplusStartup              LIB "gdiplus.dll" ALIAS "GdiplusStartup"              (token???, inputbuf AS GdiplusStartupInput, outputbuf AS GdiplusStartupOutput) AS LONG
    DECLARE      SUB GdiplusShutdown             LIB "gdiplus.dll" ALIAS "GdiplusShutdown"             (BYVAL token???)
    DECLARE FUNCTION GdipDeleteGraphics          LIB "gdiplus.dll" ALIAS "GdipDeleteGraphics"          (BYVAL hGraphics???) AS LONG
    DECLARE FUNCTION GdipCreateFromHDC           LIB "gdiplus.dll" ALIAS "GdipCreateFromHDC"           (BYVAL hdc???, hGraphics???) AS LONG
    DECLARE FUNCTION GdipLoadImageFromFile       LIB "gdiplus.dll" ALIAS "GdipLoadImageFromFile"       (BYVAL flname$, lpImage???) AS LONG
    DECLARE FUNCTION GdipCreateBitmapFromHBITMAP LIB "gdiplus.dll" ALIAS "GdipCreateBitmapFromHBITMAP" (BYVAL hbm&,BYVAL hpal&, nBitmap&) AS LONG
    DECLARE FUNCTION GdipCreateBitmapFromStream  LIB "gdiplus.dll" ALIAS "GdipCreateBitmapFromStream"  (BYVAL pStream???,m_pBitmap&) AS LONG
    DECLARE FUNCTION CreateStreamOnHGlobal       LIB "ole32.dll"   ALIAS "CreateStreamOnHGlobal"       (BYVAL hGlobal AS DWORD, BYVAL fDeleteOnRelease AS DWORD, pstm AS DWORD) AS LONG
    DECLARE FUNCTION GdipDisposeImage            LIB "gdiplus.dll" ALIAS "GdipDisposeImage"            (BYVAL lpImage???) AS LONG
    DECLARE FUNCTION GdipDrawImageRectI          LIB "gdiplus.dll" ALIAS "GdipDrawImageRectI"          (BYVAL hGraphics???, BYVAL nImage???, BYVAL x&,BYVAL y&, BYVAL nWidth&, BYVAL nHeight&) AS LONG
    DECLARE FUNCTION GdipGetImageWidth           LIB "gdiplus.dll" ALIAS "GdipGetImageWidth"           (BYVAL lpImage???, nWidth???) AS LONG
    DECLARE FUNCTION GdipGetImageHeight          LIB "gdiplus.dll" ALIAS "GdipGetImageHeight"          (BYVAL lpImage???, nHeight???) AS LONG
    DECLARE FUNCTION GdipGetImageThumbnail       LIB "gdiplus.dll" ALIAS "GdipGetImageThumbnail"       (BYVAL nImage&,BYVAL thumbWidth&,BYVAL thumbHeight&, thumbnImage&, OPT BYVAL pCALLBACK&, OPT BYVAL callbackData&) AS LONG
    '
    '-------------------------------------------
    '
    DECLARE FUNCTION pStreamRelease        (pUnk???) AS LONG
    DECLARE FUNCTION LoadImageFromResource (BYVAL ResourceName$,OPT BYVAL hInst???) AS DWORD
    DECLARE FUNCTION fGDIp_2hBMP           (BYVAL FileSpec$,OPT BYVAL hBMP???,BYVAL KeepAspect&,BYVAL BkGrnd&) AS DWORD
    '
    '=====================================================
    '====== TEST CODE ====================================
    '=====================================================
    '
    $From_RC     = "#1001"
    $From_File   = "MugShot.jpg"
    $From_CBoard = ""
     
    %GDI_Stretch = 1
    $FileSpec    = $From_File
     
    FUNCTION WINMAIN ( BYVAL hInstance   AS DWORD, _
                       BYVAL hPrevInst   AS DWORD, _
                       BYVAL lpszCmdLine AS ASCIIZ PTR, _
                       BYVAL nCmdShow    AS LONG ) AS LONG
     
      DIM  GDItoken     AS LOCAL DWORD
      DIM  StartupInput AS LOCAL GDIplusStartupInput
      DIM hBMP          AS LOCAL DWORD
      DIM  BMPx         AS LOCAL SINGLE
      DIM  BMPy         AS LOCAL SINGLE
      DIM hWnd          AS LOCAL DWORD
      DIM  XX           AS LOCAL SINGLE
      DIM  YY           AS LOCAL SINGLE
     
      StartupInput.GDIplusVersion = 1
      IF GDIplusStartup(GDItoken, StartupInput, BYVAL %NULL) <> 0 THEN
        MSGBOX "No GDI+"
        EXIT FUNCTION
      END IF
     
    #IF %GDI_Stretch
      GRAPHIC BITMAP NEW 300, 400 TO hBMP
    #ENDIF
     
      hBMP = fGDIp_2hBMP($FileSpec,hBMP)
     
      IF hBMP = 0 THEN
          MSGBOX "Function failed"
        ELSE
          GRAPHIC ATTACH hBMP, 0
          GRAPHIC GET CLIENT TO BMPx, BMPy
          GRAPHIC WINDOW "", 50, 50, 500, 500 TO hWnd
          GRAPHIC ATTACH hWnd, 0
          GRAPHIC COLOR %BLACK, %YELLOW
          GRAPHIC CLEAR
          IF (BMPx > 500) OR (BMPy > 500) THEN
              GRAPHIC STRETCH hBMP, 0, (0, 0)-(BMPx-1,BMPy-1) TO (49,49)-(449,449)
            ELSE
              XX = (500 - BMPx) \ 2
              YY = (500 - BMPy) \ 2
              GRAPHIC COPY hBMP, 0 TO (XX,YY)
          END IF
          SLEEP 3000
          GRAPHIC ATTACH hBMP, 0
          GRAPHIC BITMAP END
          GRAPHIC ATTACH hWnd, 0
          GRAPHIC WINDOW END
      END IF
     
      GDIplusShutdown GDItoken
     
    END FUNCTION
    '
    '=====================================================
    '====== END TEST CODE ================================
    '=====================================================
    '
    FUNCTION LoadImageFromResource (BYVAL ResourceName AS STRING, _
                                OPT BYVAL hInst        AS DWORD   ) AS DWORD
     
      DIM hResource        AS LOCAL DWORD
      DIM  imageSize       AS LOCAL DWORD
      DIM pResourceData    AS LOCAL DWORD
      DIM m_hBuffer        AS LOCAL DWORD
      DIM pBuffer          AS LOCAL DWORD
      DIM pStream          AS LOCAL DWORD PTR
      DIM m_pBitmap        AS LOCAL DWORD
      DIM m_pBitmap_status AS LOCAL LONG
      DIM pName            AS LOCAL ASCIIZ * %MAX_PATH
     
      pName = ResourceName
     
      hResource = FindResource(hInst, pName, BYVAL %RT_RCDATA)
      IF hResource = 0 THEN EXIT FUNCTION
     
      imageSize = SizeofResource(hInst, hResource)
      IF imageSize = 0 THEN EXIT FUNCTION
     
      pResourceData = LockResource(LoadResource(hInst, hResource))
      IF pResourceData = 0 THEN EXIT FUNCTION
     
      m_hBuffer = GlobalAlloc(%GMEM_MOVEABLE, imageSize)
      IF m_hBuffer = 0 THEN EXIT FUNCTION
     
      pBuffer = GlobalLock(m_hBuffer)
      IF pBuffer = 0 THEN GOTO Exit_1
     
      CopyMemory pBuffer, pResourceData, imageSize
      IF CreateStreamOnHGlobal(m_hBuffer, %FALSE, pStream) <> 0 THEN GOTO Exit_2
     
      m_pBitmap_status = GdipCreateBitmapFromStream(pStream, m_pBitmap)
      CALL DWORD @@pStream[2] USING pStreamRelease(pStream)
      IF (m_pBitmap       <> 0)  AND _
         (m_pBitmap_status = 0) THEN
        FUNCTION = m_pBitmap
      END IF
     
      Exit_2:
        GlobalUnlock m_hBuffer
      Exit_1:
        GlobalFree m_hBuffer
     
    END FUNCTION
    '
    '------------------------------------------------------------------------------
    '
    FUNCTION fGDIp_2hBMP ALIAS "fGDIp_2hBMP" ( BYVAL FileSpec   AS STRING, _
                                           OPT BYVAL hBMP       AS DWORD , _
                                           OPT BYVAL KeepAspect AS LONG  , _
                                           OPT BYVAL Background AS LONG    ) EXPORT AS DWORD
     
      DIM  Bx       AS LOCAL LONG
      DIM  Bxx      AS LOCAL LONG
      DIM  By       AS LOCAL LONG
      DIM  Byy      AS LOCAL LONG
      DIM hDC       AS LOCAL DWORD
      DIM hGraphics AS LOCAL DWORD
      DIM  Iaspect  AS LOCAL CUX
      DIM hImage    AS LOCAL DWORD
      DIM  Ixx      AS LOCAL LONG
      DIM  Iyy      AS LOCAL LONG
      DIM hTmp      AS LOCAL DWORD
     
      SELECT CASE ASC(FileSpec)
        CASE -1   : IF OpenClipboard(hTmp) = 0 THEN EXIT FUNCTION
                    hTmp = GetClipboardData(%CF_BITMAP)
                    IF hTmp <> 0 THEN
                      GDIpCreateBitmapFromHBITMAP hTmp, BYVAL 0, hImage
                    END IF
                    EmptyClipboard
                    CloseClipboard
                    IF hImage = 0 THEN EXIT FUNCTION
        CASE 35   : hImage = LoadImageFromResource(FileSpec)
                    IF hImage = 0 THEN EXIT FUNCTION
        CASE ELSE : FileSpec = UCODE$(FileSpec)
                    IF GdipLoadImageFromFile(FileSpec, hImage) <> 0 THEN EXIT FUNCTION
      END SELECT
     
      GdipGetImageWidth  hImage, Ixx
      GdipGetImageHeight hImage, Iyy
     
      IF hBMP = 0 THEN
          Bxx = Ixx
          Byy = Iyy
          GRAPHIC BITMAP NEW Bxx, Byy TO hBMP
          GRAPHIC ATTACH hBMP, 0
          GOSUB Get_DC
        ELSE
          GRAPHIC ATTACH hBMP, 0
          GRAPHIC GET CLIENT TO Bxx, Byy
          GOSUB Get_DC
          IF KeepAspect = 0 THEN
              IF (Bxx <> Ixx)   OR _
                 (Byy <> Iyy) THEN
                GdipGetImageThumbnail hImage, Bxx, Byy, hTmp
                SWAP hImage, hTmp
                GdipDisposeImage hTmp
              END IF
            ELSE
              IF BackGround <> -2 THEN
                GRAPHIC CLEAR BackGround
              END IF
              Iaspect = Iyy / Ixx
              IF Byy => (Bxx * Iaspect) THEN
                  Iyy = MIN(Bxx,(Bxx * Iaspect))
                  By  = (Byy - Iyy) \ 2
                  Byy = Iyy
                ELSE
                  Iaspect = Ixx / Iyy
                  Ixx = MIN(Bxx,Byy * Iaspect)
                  Bx  = (Bxx - Ixx) \ 2
                  Bxx = Ixx
              END IF
          END IF
      END IF
     
      GdipDrawImageRectI hGraphics, hImage, Bx, By, Bxx, Byy
      GdipDeleteGraphics hGraphics
      GdipDisposeImage hImage
      FUNCTION = hBMP
      EXIT FUNCTION
      '
      '-------------------------------------
      '
      Get_DC:
        GRAPHIC GET DC TO hDC
        GdipCreateFromHDC hDC, hGraphics
        IF hGraphics <> 0 THEN RETURN
        GdipDisposeImage hImage
        GRAPHIC ATTACH hBMP, 0
        GRAPHIC BITMAP END
      RETURN
     
    END FUNCTION
    C'ya
    Don

    http://www.ImagesBy.me

    Comment


    • #3
      Memory Leak

      Hate to hijack an ancient thread, but since people still view the ancient threads... there seems to be a memory leak.

      I including this include file, which is at
      HTML Code:
      http://www.powerbasic.com/support/pbforums/showthread.php?t=24120
      . It's a great little include to help find memory leaks.

      Code:
      #include "process_memoryinfo.inc"
      I inserted this code in place of the single "hBMP = fGDIp_2hBMP($FileSpec,hBMP)" line...

      Code:
      LOCAL ll AS LONG
      FOR ll=1 TO 1000
        hBMP = fGDIp_2hBMP($FileSpec,hBMP)
        OPEN "pbforums_24723.txt" FOR APPEND SHARED AS #9
        PRINT #9, STR$(ll)
             LOCAL txt AS STRING
             getprocessmemorystatistics txt
        PRINT #9, txt
        CLOSE 9
      NEXT ll
      If you then examine the text file generated, it definitely is using increasing amounts of memory (it eventually fails).

      It's of interest to me, because I am experiencing a similar issue myself. SOMETHING isn't getting freed up, and it occurs whether loading an image from file or resource.

      It appears this code is using the same technique as Joe Woodbury's code at http://www.codeproject.com/Articles/...rces-using-GDI. I know little of C,C++,C#, so I've not tried compiling Joe's code to test it.

      Comment


      • #4
        If you then examine the text file generated, it definitely is using increasing amounts of memory (it eventually fails).
        Indeed. You aren't disposing the images.
        Forum: http://www.jose.it-berater.org/smfforum/index.php

        Comment


        • #5
          On each iteration of the loop, fGDIp_2hBMP is being repeatedly asked to put the same image into the same pb bitmap.

          Definitely something isn't being disposed of, but "GdipDisposeImage hImage" does appear in fGDIp_2hBMP.

          I think that something in LoadImageFromResouce (called be fGDIp_2hBMP) is leaking...


          Code:
          FUNCTION LoadImageFromResource (BYVAL ResourceName AS STRING, _
                                      OPT BYVAL hInst        AS DWORD   ) AS DWORD
          
            DIM hResource        AS LOCAL DWORD
            DIM  imageSize       AS LOCAL DWORD
            DIM pResourceData    AS LOCAL DWORD
            DIM m_hBuffer        AS LOCAL DWORD
            DIM pBuffer          AS LOCAL DWORD
            DIM pStream          AS LOCAL DWORD PTR
            DIM m_pBitmap        AS LOCAL DWORD
            DIM m_pBitmap_status AS LOCAL LONG
            DIM pName            AS LOCAL ASCIIZ * %MAX_PATH
          
            pName = ResourceName
          
            hResource = FindResource(hInst, pName, BYVAL %RT_RCDATA)
            IF hResource = 0 THEN EXIT FUNCTION
          
            imageSize = SizeofResource(hInst, hResource)
            IF imageSize = 0 THEN EXIT FUNCTION
          
            pResourceData = LockResource(LoadResource(hInst, hResource))
            IF pResourceData = 0 THEN EXIT FUNCTION
          
            m_hBuffer = GlobalAlloc(%GMEM_MOVEABLE, imageSize)
            IF m_hBuffer = 0 THEN EXIT FUNCTION
          
            pBuffer = GlobalLock(m_hBuffer)
            IF pBuffer = 0 THEN GOTO Exit_1
          
            CopyMemory pBuffer, pResourceData, imageSize
            IF CreateStreamOnHGlobal(m_hBuffer, %FALSE, pStream) <> 0 THEN GOTO Exit_2
          
            m_pBitmap_status = GdipCreateBitmapFromStream(pStream, m_pBitmap)
            CALL DWORD @@pStream[2] USING pStreamRelease(pStream)
            IF (m_pBitmap       <> 0)  AND _
               (m_pBitmap_status = 0) THEN
              FUNCTION = m_pBitmap
            END IF
          
            Exit_2:
              GlobalUnlock m_hBuffer
            Exit_1:
              GlobalFree m_hBuffer
          
              
          END FUNCTION
          Specifically the CreateStreamOnHGlobal(m_hBuffer, %FALSE, pStream) is where the memory usage increases. The MSDN documantation for CreateStreamOnHGlobal is at http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx . Of interest there is the description of the fDeleteOnRelease[in] parameter. It implies a "release" is necessary, but I find no documentation on releasing the stream. [setting the parameter to %true has no effect on the problem, and that parameter is often ignored per my research in various forums].

          Addl Info:
          I've researched the forums for quite some time ref "CreateStreamOnHGlobal release". It turns out that it's quite common to find posts speaking of "releasing" the stream (like https://www.powerbasic.com/support/p...ad.php?t=22428), but I've still yet to find exactly how one does that (in Powerbasic, anyway). Maybe it's a non-issue, but something's definitely going on using this code.
          Last edited by Philip Zeller; 2 Oct 2012, 03:13 PM. Reason: More Info

          Comment


          • #6
            Okay, I noticed that in the test code, I was overwriting hBMP with the return value from fGDIp_2hBMP, so I changed this:

            Code:
            hBMP = fGDIp_2hBMP($FileSpec,hBMP)
            to this:

            Code:
            fGDIp_2hBMP $FileSpec,hBMP
            This doesn't actually the problem in any way, though, but I thought I should correct it.

            The problem is that the simple act of calling the fGDIp_2hBMP still consumes increasing memory each time it's called (it seems like something in the fGDIp_2hBMP code isn't cleaning up after itself). It looks to me as though fGDIp_2hBMP does clean up after itself after putting the image into the specified pb bmp, though.

            I've confirmed that It does this regardless of whether a filename is specified, or a resource, which would tend to exonerate the LOADIMAGEFROMRESOURCE function. The memory usage increases in an amount roughly proportional to the size of the image file (size in bytes).

            This narrows it down to the fGDIp_2hBMP function:

            Code:
            FUNCTION fGDIp_2hBMP ALIAS "fGDIp_2hBMP" ( BYVAL FileSpec   AS STRING, _
                                                   OPT BYVAL hBMP       AS DWORD , _
                                                   OPT BYVAL KeepAspect AS LONG  , _
                                                   OPT BYVAL Background AS LONG    ) EXPORT AS DWORD
            
              DIM  Bx       AS LOCAL LONG
              DIM  Bxx      AS LOCAL LONG
              DIM  By       AS LOCAL LONG
              DIM  Byy      AS LOCAL LONG
              DIM hDC       AS LOCAL DWORD
              DIM hGraphics AS LOCAL DWORD
              DIM  Iaspect  AS LOCAL CUX
              DIM hImage    AS LOCAL DWORD
              DIM  Ixx      AS LOCAL LONG
              DIM  Iyy      AS LOCAL LONG
              DIM hTmp      AS LOCAL DWORD
            
              SELECT CASE ASC(FileSpec)
                CASE -1   : IF OpenClipboard(hTmp) = 0 THEN EXIT FUNCTION
                            hTmp = GetClipboardData(%CF_BITMAP)
                            IF hTmp <> 0 THEN
                              GDIpCreateBitmapFromHBITMAP hTmp, BYVAL 0, hImage
                            END IF
                            EmptyClipboard
                            CloseClipboard
                            IF hImage = 0 THEN EXIT FUNCTION
                CASE 35   : hImage = LoadImageFromResource(FileSpec)
                            IF hImage = 0 THEN EXIT FUNCTION
                CASE ELSE : FileSpec = UCODE$(FileSpec)
                            IF GdipLoadImageFromFile(FileSpec, hImage) <> 0 THEN EXIT FUNCTION
              END SELECT
            
              GdipGetImageWidth  hImage, Ixx
              GdipGetImageHeight hImage, Iyy
            
              IF hBMP = 0 THEN
                  Bxx = Ixx
                  Byy = Iyy
                  GRAPHIC BITMAP NEW Bxx, Byy TO hBMP
                  GRAPHIC ATTACH hBMP, 0
                  GOSUB Get_DC
                ELSE
                  GRAPHIC ATTACH hBMP, 0
                  GRAPHIC GET CLIENT TO Bxx, Byy
                  GOSUB Get_DC
                  IF KeepAspect = 0 THEN
                      IF (Bxx <> Ixx)   OR _
                         (Byy <> Iyy) THEN
                        GdipGetImageThumbnail hImage, Bxx, Byy, hTmp
                        SWAP hImage, hTmp
                        GdipDisposeImage hTmp
                      END IF
                    ELSE
                      IF BackGround <> -2 THEN
                        GRAPHIC CLEAR BackGround
                      END IF
                      Iaspect = Iyy / Ixx
                      IF Byy => (Bxx * Iaspect) THEN
                          Iyy = MIN(Bxx,(Bxx * Iaspect))
                          By  = (Byy - Iyy) \ 2
                          Byy = Iyy
                        ELSE
                          Iaspect = Ixx / Iyy
                          Ixx = MIN(Bxx,Byy * Iaspect)
                          Bx  = (Bxx - Ixx) \ 2
                          Bxx = Ixx
                      END IF
                  END IF
              END IF
            
              GdipDrawImageRectI hGraphics, hImage, Bx, By, Bxx, Byy
              GdipDeleteGraphics hGraphics
              GdipDisposeImage hImage
              FUNCTION = hBMP
              EXIT FUNCTION
              '
              '-------------------------------------
              '
              Get_DC:
                GRAPHIC GET DC TO hDC
                GdipCreateFromHDC hDC, hGraphics
                IF hGraphics <> 0 THEN RETURN
                GdipDisposeImage hImage
                GRAPHIC ATTACH hBMP, 0
                GRAPHIC BITMAP END
              RETURN
            
            END FUNCTION
            I can't see a case where gdipDisposeImage hImage would not be called, as none of the early EXIT FUNCTIONS should trigger if the image was successfully loaded.

            Comment


            • #7
              Moved

              Since this appears to be a general GDI+ issue, and not specifically relating to Don's code, I thought it best practice to move this discussion:

              http://www.powerbasic.com/support/pbforums/showthread.php?p=416727

              Comment

              Working...
              X