Parsing Photos

(Part 3 of the Panzer General Portable Project)

When I created Panzer General Portable (PGP) for the windows phone, I had to deal with creating a game board based on a a single image file that looks like this:

image

There are 12 rows and 20 columns of images – each image is 60 pixels wide and 50 pixels wide.  Each image represents a hex on the game board.  When I did the Windows Phone app, I loaded this image each time in needed a hex – not the most efficient use of resources to be sure.  In addition to these game board images, there are similar composite images of units, country flags, etc..  The game board is a series of overlaid images for a given hex. The application keeps track of the correct image to be used via the x/y coordinates of the hex.  For example, the top left fix has a x/y of 0,0.

image

 

In other parts of the app, an index is used so the 0,0 hex is also index 0 with the 1,19 hex having an index value of 20.

image

 

You will also note that each image is a rectangle, and the area outside of the hex is a pink color.  Apparently, back in the old days, that color meant “transparent” to windows.  However, it does not to the iOS and Android, so that color needs to be converted into transparent

I fired up a new FSharp project in Visual Studio for Mac and created a F# script

I created a function that takes in the path to this composite image on my file system, a target directory where I want the small image to be written to, the name of that file, and the x y coordinates to locate the smaller image in the composite image:

1 let createHexImage sourcePath targetDirectory (fileName:string) x y = 2 let width = 60 3 let height = 50 4 let index = x + (y * 20) 5 use sourceImage = Image.FromFile(sourcePath) 6 use bitmap = new Bitmap(width,height) 7 use graphics = Graphics.FromImage(bitmap) 8 let targetRectangle = new Rectangle(0,0,width,height) 9 let sourceRectangle = new Rectangle(width*x,height*y,width,height) 10 graphics.DrawImage(sourceImage,targetRectangle,sourceRectangle,GraphicsUnit.Pixel) 11 graphics.Flush() 12 let transparentBitmap = createTransparentBitmap bitmap 13 let fileName = fileName.Replace("_",String.Empty) 14 let fileName' = targetDirectory + "//" + fileName + index.ToString() + ".jpeg" 15 transparentBitmap.Save(fileName') 16

The code is pretty straight forward File I/O and image creation.  Notice on line 12 a function called “createTransparentBitmap” is called to turn the pink into transparent.  That function is actually step 0 of a function chain like this (BTW: read from the bottom up in F# world):

1 let updateColor (color:Color) = 2 match color.R, color.G, color.B with 3 | 255uy,225uy,225uy -> Color.FromArgb(0x00FFFFFF) 4 | _,_,_ -> color 5 6 let getCoordinates index (bitmap:Bitmap) = 7 let y = index / bitmap.Width 8 let x = index % bitmap.Width 9 x,y 10 11 let adjustColor index (bitmap:Bitmap) = 12 let coordinates = getCoordinates index bitmap 13 let x = fst coordinates 14 let y = snd coordinates 15 let color = bitmap.GetPixel(x,y) 16 let updatedColor = updateColor color 17 bitmap.SetPixel(x,y,updatedColor) 18 19 let createTransparentBitmap (bitmap:Bitmap) = 20 let totalPixels = bitmap.Height * bitmap.Width 21 [0 .. totalPixels - 1] 22 |> Seq.iter(fun i -> adjustColor i bitmap) 23 bitmap

  • updateColor looks at a given pixel and if it is “pink”, it returns a new pixel of transparent, else it returns the pixel that came in (note that System drawing uses Pixel and Color interchangeably, which can be confusing)
  • getCordinates gets the pixel from the x,y coordinate of the bitmap
  • adjustColor takes in a bitmap and an index – it uses the index to locate the targeted pixel, updates the color if needed, and then sets a new pixel into the bitmap with the updated pixel.
  • createTransparentBitmap takes in the bitmap, calculates the total pixels, creates an array of integers, and then calls the adjustColor function

So after running this script, you can see my file system has a list of all of the images that the game needs:

image

The gist is here

 

 

 

 

g

One Response to Parsing Photos

  1. Pingback: F# Weekly #46, 2018 – One year of SAFE and pre-order of “Stylish F#” – Sergey Tihon's Blog

Leave a comment