using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace POSV.Utils { /// /// /// NinePatch ninePatch = new NinePatch(image); // 9-patch /// Image newImage = ninePatch.ImageSizeOf(500, 500); /// /// public class NinePatch { private Image image; public Bitmap OriginalImage { get { using (Bitmap baseBitmap = new Bitmap(this.image)) { Rectangle rect = new Rectangle(1 , 1 , baseBitmap.Width - 2 , baseBitmap.Height - 2); Bitmap result = baseBitmap.Clone(rect , baseBitmap.PixelFormat); return result; } } } private Dictionary cache; private List topPatches; private List leftPatches; private List bottomPatches; private List rightPatches; private const int BYTES_PER_PIXEL = 4; public NinePatch(Image image) { this.image = image; cache = new Dictionary(); FindPatchRegion(); } public void ClearCache() { foreach (KeyValuePair pair in cache) { pair.Value.Dispose(); } cache.Clear(); } public Image ImageSizeOf(int w , int h) { if (cache.ContainsKey(String.Format("{0}x{1}" , w , h))) { return cache[String.Format("{0}x{1}" , w , h)]; } using (Bitmap src = this.OriginalImage) { int sourceWidth = src.Width; int sourceHeight = src.Height; int targetWidth = w; int targetHeight = h; targetWidth = System.Math.Max(sourceWidth , targetWidth); targetHeight = System.Math.Max(sourceHeight , targetHeight); if (sourceWidth == targetWidth && sourceHeight == targetHeight) { return src; } BitmapData srcData = src.LockBits( new Rectangle(0 , 0 , sourceWidth , sourceHeight) , ImageLockMode.ReadOnly , src.PixelFormat ); byte[] srcBuf = new byte[sourceWidth * sourceHeight * BYTES_PER_PIXEL]; Marshal.Copy(srcData.Scan0 , srcBuf , 0 , srcBuf.Length); Bitmap dst = new Bitmap(targetWidth , targetHeight); byte[] dstBuf = new byte[dst.Width * dst.Height * BYTES_PER_PIXEL]; List xMapping = XMapping(targetWidth - sourceWidth , targetWidth); List yMapping = YMapping(targetHeight - sourceHeight , targetHeight); for (int y = 0; y < targetHeight; y++) { int sourceY = yMapping[y]; for (int x = 0; x < targetWidth; x++) { int sourceX = xMapping[x]; for (int z = 0; z < BYTES_PER_PIXEL; z++) { dstBuf[y * targetWidth * BYTES_PER_PIXEL + x * BYTES_PER_PIXEL + z] = srcBuf[sourceY * sourceWidth * BYTES_PER_PIXEL + sourceX * BYTES_PER_PIXEL + z]; } } } BitmapData dstData = dst.LockBits( new Rectangle(0 , 0 , dst.Width , dst.Height) , ImageLockMode.WriteOnly , src.PixelFormat ); IntPtr dstScan0 = dstData.Scan0; Marshal.Copy(dstBuf , 0 , dstScan0 , dstBuf.Length); src.UnlockBits(srcData); dst.UnlockBits(dstData); cache.Add(String.Format("{0}x{1}" , w , h) , dst); return dst; } } private void FindPatchRegion() { topPatches = new List(); leftPatches = new List(); bottomPatches = new List(); rightPatches = new List(); using (Bitmap src = new Bitmap(image)) { BitmapData srcData = src.LockBits( new Rectangle(0 , 0 , src.Width , src.Height) , ImageLockMode.ReadOnly , src.PixelFormat ); byte[] srcBuf = new byte[src.Width * src.Height * BYTES_PER_PIXEL]; Marshal.Copy(srcData.Scan0 , srcBuf , 0 , srcBuf.Length); // top for (int x = 1; x < srcData.Width - 1; x++) { int index = x * BYTES_PER_PIXEL; byte b = srcBuf[index]; byte g = srcBuf[index + 1]; byte r = srcBuf[index + 2]; byte alpha = srcBuf[index + 3]; if (r == 0 && g == 0 && b == 0 && alpha == 255) { topPatches.Add(x - 1); } } // left for (int y = 1; y < srcData.Height - 1; y++) { int index = y * BYTES_PER_PIXEL * srcData.Width; byte b = srcBuf[index]; byte g = srcBuf[index + 1]; byte r = srcBuf[index + 2]; byte alpha = srcBuf[index + 3]; if (r == 0 && g == 0 && b == 0 && alpha == 255) { leftPatches.Add(y - 1); } } // bottom for (int x = 1; x < srcData.Width - 1; x++) { int index = (srcData.Height - 1) * BYTES_PER_PIXEL * srcData.Width + x * BYTES_PER_PIXEL; byte b = srcBuf[index]; byte g = srcBuf[index + 1]; byte r = srcBuf[index + 2]; byte alpha = srcBuf[index + 3]; if (r == 0 && g == 0 && b == 0 && alpha == 255) { bottomPatches.Add(x - 1); } } // right for (int y = 1; y < srcData.Height - 1; y++) { int index = y * BYTES_PER_PIXEL * srcData.Width + (srcData.Width - 1) * BYTES_PER_PIXEL; byte b = srcBuf[index]; byte g = srcBuf[index + 1]; byte r = srcBuf[index + 2]; byte alpha = srcBuf[index + 3]; if (r == 0 && g == 0 && b == 0 && alpha == 255) { rightPatches.Add(y - 1); } } } } private List XMapping(int diffWidth , int targetWidth) { List result = new List(targetWidth); int src = 0; int dst = 0; while (dst < targetWidth) { int foundIndex = topPatches.IndexOf(src); if (foundIndex != -1) { int repeatCount = (diffWidth / topPatches.Count) + 1; if (foundIndex < diffWidth % topPatches.Count) { repeatCount++; } for (int j = 0; j < repeatCount; j++) { result.Insert(dst++ , src); } } else { result.Insert(dst++ , src); } src++; } return result; } private List YMapping(int diffHeight , int targetHeight) { List result = new List(targetHeight); int src = 0; int dst = 0; while (dst < targetHeight) { int foundIndex = leftPatches.IndexOf(src); if (foundIndex != -1) { int repeatCount = (diffHeight / leftPatches.Count) + 1; if (foundIndex < diffHeight % leftPatches.Count) { repeatCount++; } for (int j = 0; j < repeatCount; j++) { result.Insert(dst++ , src); } } else { result.Insert(dst++ , src); } src++; } return result; } } }