Wednesday, January 14, 2009

Changing the Color and Orientation of Images

Recently, I needed to change the color of an image. I have a container that includes an image and depending on the user's color choices, the container's background color might change. That means certain colors in the image must also change so the image blends in with the container properly, and rather than creating a number of images with pre-defined colors, I wanted to change the colors programmatically. One other wrinkle: because the orientation of the container might also change under some circumstances, I also wanted to rotate the image.

Fortunately, the VFPX GDIPlusX project makes this a snap and thanks to a recent blog posting by Cesar, it didn't take too long to figure out what to do. The following code reads the color of the upper left pixel in the image whose file name is in the lcImageFile variable and converts that color to the one specified in This.BackColor. It also rotates the image if it's wide and short but the container is narrow and tall. It then writes the new image directly to the PictureVal property of the imgImage object so there's no additional disk I/O.

* Create the GDIPlusX objects if necessary.

if type('_screen.System.Name') <> 'O'
do System.APP
endif type('_screen.System.Name') <> 'O'
with _screen.System.Drawing

* Load the image.

loBmp = .Bitmap.FromFile(lcImageFile)

* Get the color of the upper left pixel.

loColor = loBmp.GetPixel(0, 0)

* Create a color map and tell it to convert from the color of
* the pixel to our background color.

loColorMap = .Imaging.ColorMap.New()
loColorMap.OldColor = loColor
loColorMap.NewColor = .Color.FromRGB(This.BackColor)

* Create an attributes object and make it use the color map.

loAttr = .Imaging.ImageAttributes.New()
loAttr.SetRemapTable(loColorMap)

* Create a new image and draw the old image onto it using the new
* color mapping.

loDestBmp = .Bitmap.New(loBmp.Width, loBmp.Height, ;
.Imaging.PixelFormat.Format24bppRGB)
loGfx = .Graphics.FromImage(loDestBmp)
loRect = loBmp.GetBounds()
loGfx.DrawImage(loBmp, loRect, loRect, .GraphicsUnit.Pixel, loAttr)

* Flip the image if its orientation doesn't match ours.

if This.Width > This.Height and loBmp.Height > loBmp.Width
loDestBmp.RotateFlip(.RotateFlipType.Rotate90FlipNone)
endif This.Height > This.Width ...

* Write the image directly to the PictureVal property of our image
* object.

loDestBmp.Save(This.imgImage, .Imaging.ImageFormat.Bmp)
endwith

No comments: