Announcement

Collapse
No announcement yet.

GDI+ Question

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

  • GDI+ Question

    I was using some GDI+ code from the forums to read in a JPG image and had some trouble with larger images.

    The code reads the jpg with GDI+ and places the image in a DDT memory bitmap for subsequent processing. For example, this image (2492x1944) appears to be resized and placed in the upper left quadrant of the bitmap.

    seems to be read in as this:

    I've tried the code on a dozen images and it works fine. Only on a couple of large ones (like this one) do I see the problem. I can't say for sure that there's a cutoff size, because I don't have a string of successively sized images to test.

    Here's the test code I used.
    Code:
    'Compilable Example:
    #Compile Exe
    #Dim All
    #Include "Win32API.inc"
    
    Type GdiplusStartupInput Dword
       GdiplusVersion           As Dword
       DebugEventCallback       As Dword
       SuppressBackgroundThread As Long
       SuppressExternalCodecs   As Long
    End Type
    
    Type GdiplusStartupOutput Dword
       NotificationHook   As Dword
       NotificationUnhook As Dword
    End Type
    
    Declare Function GdiplusStartup Lib "gdiplus.dll" Alias "GdiplusStartup" (ByRef token As Dword, ByRef Input As GdiplusStartupInput, ByRef Output As GdiplusStartupOutput) As Long
    Declare Sub      GdiplusShutdown Lib "gdiplus.dll" Alias "GdiplusShutdown" (ByVal token As Dword)
    Declare Function GdipGetImageWidth Lib "GDIPLUS.DLL" Alias "GdipGetImageWidth" (ByVal Image As Dword, ByRef Width As Dword) As Long
    Declare Function GdipGetImageHeight Lib "GDIPLUS.DLL" Alias "GdipGetImageHeight" (ByVal Image As Dword, ByRef height As Dword) As Long
    Declare Function GdipCreateFromHDC Lib "gdiplus.dll" Alias "GdipCreateFromHDC" (ByVal hdc As Dword, ByRef graphics As Dword) As Long
    Declare Function GdipLoadImageFromFile Lib "gdiplus.dll" Alias "GdipLoadImageFromFile" (ByVal filename As Dword, ByRef Image As Dword) As Long
    Declare Function GdipDrawImage Lib "gdiplus.dll" Alias "GdipDrawImage"(ByVal graphics As Dword, ByVal Image As Dword, ByVal x As Single, ByVal y As Single) As Long                                              ' GpStatus
    Declare Function GdipDisposeImage Lib "gdiplus.dll" Alias "GdipDisposeImage" (ByVal Image As Dword) As Long
    Declare Function GdipDeleteGraphics Lib "gdiplus.dll" Alias "GdipDeleteGraphics" (ByVal graphics As Dword) As Long
    
    Function PBMain() As Long
       Local fName As String, w,h As Long
       Local pGraphics, pImage,hBMP,hBMPtemp, hBMPDC As Dword, strFileName As String
       Local token As Dword, StartupInput As GdiplusStartupInput
    
       fName = "wide.jpg"    '2592 x 1944
    
       'initialize GDIPlus
       StartupInput.GdiplusVersion = 1
       GdiplusStartup(token, StartupInput, ByVal %NULL)
    
       'load/display image onto Graphic control
       strFileName = UCode$(fName)                         'image source file
       GdipLoadImageFromFile(StrPtr(strFileName), pImage)  'pImage - image object
       GdipGetImageWidth(pImage,w)
       GdipGetImageHeight(pImage,h)
    
       'place to put the image
       Graphic Bitmap New w,h To hBMP
       Graphic Attach hBMP, 0
       Graphic Get DC To hBMPDC
    
       GdipCreateFromHDC(hBMPDC, pGraphics)          'pGraphics - graphic object
       GdipDrawImage(pGraphics, pImage, 0, 0)        'draw on graphic object - hBMP now contains image from file
    
       'cleanup
       If pImage Then GdipDisposeImage(pImage)         'delete image object
       If pGraphics Then GdipDeleteGraphics(pGraphics) 'delete graphic object
       GdiplusShutdown token                           ' Shutdown GDI+
    
       Graphic Save "verify.bmp"
    
    End Function
                   
    Last edited by Gary Beene; 20 Jun 2011, 05:37 PM.

  • #2
    It's a while since I had much to do with photos but is it possible that dimensioning a DDT bitmap doesn't allow enough bytes per pixel? The photo is probably ARGB and the default GDI desktop-compatible bitmap RGB?

    **added: maybe if you added 1/3 to each side it would work out - or would that be too easy?
    Last edited by Chris Holbrook; 20 Jun 2011, 04:04 PM.

    Comment


    • #3
      Hi Chris(H)!

      According to my photo editor, the photo is 24bpp.

      Comment


      • #4
        Try using GdipDrawImageRectI instead of GdipDrawImage, like:
        Code:
        DECLARE FUNCTION GdipDrawImageRectI LIB "gdiplus.dll" ALIAS "GdipDrawImageRectI" (BYVAL hGraphics???, BYVAL nImage???, BYVAL x&,BYVAL y&, BYVAL nWidth&, BYVAL nHeight&) AS LONG
        
        '   GdipDrawImage(pGraphics, pImage, 0, 0)        'draw on graphic object - hBMP now contains image from file
           GdipDrawImageRectI pGraphics, pImage, 0, 0, w-1, h-1

        Comment


        • #5
          Borje,

          Thank you, that does work. Can you clarify why?

          I can see that the API you suggested explicitly calls out the w,h. But the API I was using normally writes the whole image without having to explicitly call out the w,h - except in the cases where it doesn't . I don't see in MSDN where it clarifies the issue one way or another.

          Comment


          • #6
            Gary,

            This article may shed some light... http://msdn.microsoft.com/en-us/library/ms969894.aspx

            I think GdipDrawImage() GDI+ calculates the h,w based on the screen’s DPI and the image’s DPI."

            HTH
            Jules
            Best regards
            Jules
            www.rpmarchildon.com

            Comment


            • #7
              Hi Jules,

              Thanks for that link. When I look at image properties dialog, the resolution is given as 180. That may clarify why I had the problem (along with the quote you gave from the article).



              The link you gave was a good reminder that an image contains a resolution. I can't say that I've ever had to worry about the resolution value contained in the file.

              ... added ... the MSDN page on the API would have been a great place for MSDN to put the resolution comments! I looked again and didn't find an hint.
              Last edited by Gary Beene; 20 Jun 2011, 09:13 PM.

              Comment


              • #8
                Yes, "Normal" screen resolution in Windows is 96 DPI, so 96/180 explains the almost half width and height result. Can also use something like the following to calculate difference, in case a zoom factor is needed for whatever purpose (like a Print Preview, etc.):
                Code:
                #COMPILE EXE
                #DIM ALL
                #INCLUDE "Win32API.inc"
                
                DECLARE FUNCTION GdipGetImageHorizontalResolution LIB "gdiplus.dll" ALIAS "GdipGetImageHorizontalResolution" (BYVAL pImage AS DWORD, BYREF resolution AS SINGLE) AS LONG
                DECLARE FUNCTION GdipGetImageVerticalResolution LIB "gdiplus.dll" ALIAS "GdipGetImageVerticalResolution" (BYVAL pImage AS DWORD, BYREF resolution AS SINGLE) AS LONG
                
                FUNCTION PBMAIN() AS LONG
                   LOCAL picDpiH, picDpiV AS SINGLE
                   GdipGetImageHorizontalResolution pImage, picDpiH
                   GdipGetImageVerticalResolution pImage, picDpiV
                
                   LOCAL hDC, scrDpiH, scrDpiV AS LONG
                   hDC = GetDc(0) ' desktop DC
                   scrDpiH = GetDeviceCaps(hDC, %LOGPIXELSX)
                   scrDpiV = GetDeviceCaps(hDC, %LOGPIXELSY)
                   ReleaseDC 0, hDC
                
                   ? "Picture DPI:" + STR$(picDpiH) + " x" + STR$(picDpiV) + $CRLF + _
                     "Screen DPI:" + STR$(scrDpiH) + " x" + STR$(scrDpiV) + $CRLF + _
                     "Difference: " + FORMAT$(scrDpiH / picDpiH, "0.000") + " x " + _
                                      FORMAT$(scrDpiV / picDpiV, "0.000")
                END FUNCTION

                Comment


                • #9
                  Borje,
                  Thanks for the additional code. It would seem that using GDIPDrawRectI would be best for not leaving anything to chance.

                  I'm not sure when GDIPDrawImage would be a better choice. It requires fewer arguments, but may have uncertain results unless the DPI is checked. I suppose if you know the image DPI is 96, then GDIPDrawImage would be the easier choice.

                  Comment


                  • #10
                    Originally posted by Gary Beene View Post
                    Borje,
                    Thanks for the additional code. It would seem that using GDIPDrawRectI would be best for not leaving anything to chance.

                    I'm not sure when GDIPDrawImage would be a better choice. It requires fewer arguments, but may have uncertain results unless the DPI is checked. I suppose if you know the image DPI is 96, then GDIPDrawImage would be the easier choice.
                    You would use GDIDrawImage when you wanted your print output to be sized according to the DPI of the image. For screen output it isn't relevant, as you have already discovered. When you print the image, though, the additional clarity of a higher DPI is often desirable. It's more of the automatic behind the scenes stuff that confuses when its original intent is not considered. If you are creating content for print output, you would be in control of the DPI for all images to be included as a matter of course.
                    The world is strange and wonderful.*
                    I reserve the right to be horrifically wrong.
                    Please maintain a safe following distance.
                    *wonderful sold separately.

                    Comment


                    • #11
                      Borje,
                      As a followup to the code you posted:
                      Code:
                      GdipDrawImageRectI pGraphics, pImage, 0, 0, w-1, h-1
                      The w-1,h-1 should be w,h. MSDN says the arguments are width/height, rather than right/bottom coordinates.

                      When I used your w-1/h-1 arguments in the larger picture the error wasn't visibly obvious, so I didn't catch it when I tried it out the day of your post.

                      But today, I was doing some pixel sampling and kept getting some values as black along the right/bottom edges. That let me catch the need to change to w,h.

                      Comment


                      • #12
                        Good to know - thanks!

                        Comment

                        Working...
                        X