Thursday, 02 October 2008
Blending Two Images Using GDIPlusX

After seeing a post on the Micrsoft forums. I set out to try and solve how to blend two images using GDI+. I could find little information on the web on how to solve this particular problem, so I came up with my own technique (with some excellent help from Craig Boyd).

Here is a sample blended image and the VFP / GDIPlusX code that I used to create it.

 

Paste this code into a PRG and run it. This code requires the GDIPlusX library from VFPX.

Local lcPict1, lcPict2

 

m.lcPict1 = Getpict()

If File(m.lcPict1)

   m.lcPict2 = Getpict()

   If File(m.lcPict2)

      ImageAlphaBlend(m.lcPict1, m.lcPict2)

   Endif

Endif

 

**********************************************************

Function ImageAlphaBlend(tcPictLeft, tcPictRight)

**********************************************************

 

   Local loColorMatrix As xfcCOlorMatrix

   Local loImageLeft As xfcImage

   Local loImageRight As xfcImage

   Local loBitmapPart As xfcBitmap

   Local loBitmapLeft As xfcBitmap

   Local laImageAttribs[1]

   Local loGfxLeft As xfcGraphics

   Local loGfxPart As xfcGraphics

   Local loGfxScreen As xfcGraphics

   Local lnAlphaSteps, lnBlendPercentage, lnWidthOpaque, lnStep, lnHeightImage, lnLeftStart

 

** Sets the number of Alpha blend steps used to render the blend.

** The max is 256. lower steps equals lower quality, but higher speed

   m.lnAlphaSteps = 128

** Sets the percentage of the image that is blended

   m.lnPercentageBlend = .75

 

   Dimension laImageAttribs[m.lnAlphaSteps]

 

** Requires the GDIPlusX library (version 1.20 beta)

** http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=15083

   Do (Locfile("SYSTEM.APP"))

   With _Screen.System.Drawing

 

      m.loImageRight = .Image.FromFile(m.tcPictLeft)

      m.loImageLeft = .Image.FromFile(m.tcPictRight)

 

** Force the left image to be the same size as the right image

      m.loBitmapLeft = .Bitmap.New(m.loImageRight.Width, m.loImageRight.Height)

      m.loGfxLeft=.Graphics.FromImage(m.loBitmapLeft)

      m.loGfxLeft.Clear(.Color.Transparent)

      m.loGfxLeft.DrawImage(m.loImageLeft,0,0,m.loBitmapLeft.Width,m.loBitmapLeft.Height)

 

      m.lnWidthOpaque = m.loImageRight.Width * (1 - m.lnPercentageBlend) / 2

      m.lnWidthPart = Ceiling((m.loBitmapLeft.Width-m.lnWidthOpaque*2)/m.lnAlphaSteps)

      m.loBitmapPart = .Bitmap.New(m.lnWidthPart, m.loBitmapLeft.Height)

      m.loGfxPart=.Graphics.FromImage(m.loBitmapPart)

      m.loGfxPart.Clear(.Color.Transparent)

 

** Pre-fill ImageAttributes with Alpha ColorMatrix blend for performance

** The biggest advantage to doing this is if you were processing multiple

** set of images at a time, which we aren't doing here.

      m.loColorMatrix=.Imaging.ColorMatrix.New()

 

      For m.lnCurrentStep = 1 To m.lnAlphaSteps

         laImageAttribs[m.lnCurrentStep] = .Imaging.ImageAttributes.New()

         m.loColorMatrix.Matrix33 = m.lnCurrentStep/m.lnAlphaSteps

         laImageAttribs[m.lnCurrentStep].SetColorMatrix(m.loColorMatrix)

      Endfor

 

** Adjust these for preferred image quality vs. speed

*m.loGfxLeft.InterpolationMode = .Drawing2D.InterpolationMode.Default

*m.loGfxLeft.CompositingQuality = .Drawing2D.CompositingQuality.Default

*m.loGfxLeft.SmoothingMode = .Drawing2D.SmoothingMode.Default

 

** Use integers instead of floats for performance

      m.loGfxLeft.UsePrecision = .F.

** Minor speed increase accessing this property once

      m.lnHeightImage = m.loImageRight.Height

 

      For m.lnCurrentStep = 1 To m.lnAlphaSteps

         m.lnLeftStart = m.lnCurrentStep*m.lnWidthPart + m.lnWidthOpaque

 

** Draw partial right image to part

         m.loGfxPart.DrawImage(m.loImageRight, ;

            0,0,m.lnWidthPart,m.lnHeightImage, ;

            m.lnLeftStart,0,m.lnWidthPart,m.lnHeightImage, ;

            .GraphicsUnit.Pixel)

 

** Draw part to left image with Alpha blend

         m.loGfxLeft.DrawImage(m.loBitmapPart, ;

            m.lnLeftStart,0,m.lnWidthPart,m.lnHeightImage, ;

            0,0,m.lnWidthPart,m.lnHeightImage, ;

            .GraphicsUnit.Pixel, ;

            laImageAttribs[m.lnCurrentStep])

 

      Endfor

 

** Draw last opaque part of right image

      m.loGfxLeft.DrawImage(m.loImageRight, ;

         m.loImageRight.Width-m.lnWidthOpaque, 0, m.lnWidthOpaque, m.lnHeightImage, ;

         m.loImageRight.Width-m.lnWidthOpaque, 0, m.lnWidthOpaque, m.lnHeightImage, ;

         .GraphicsUnit.Pixel)

 

** Render to the screen

      m.loGfxScreen = .Graphics.FromHWnd(_Screen.HWnd)

      m.loGfxScreen.Clear(.Color.White)

      m.loGfxScreen.DrawImage(m.loBitmapLeft,0,0,1024,768)

 

** Or you can save it to a file

**m.loBitmapLeft.Save("MyBlendedImage.png")

 

   Endwith

 

   Return

Endfunc

 

 


Thursday, 02 October 2008 15:43:52 (Eastern Daylight Time, UTC-04:00)  #     Comments [12]   |