using System; using System.Collections.Generic; using System.Text; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; namespace TextDesignerCSLibrary { /// /// Class to store the font info to pass as parameter to the drawing methods. /// public class TextContext { public TextContext() { fontFamily = new System.Drawing.FontFamily("Arial"); fontStyle = System.Drawing.FontStyle.Regular; nfontSize = 20; pszText = null; ptDraw = new System.Drawing.Point(0, 0); strFormat = new System.Drawing.StringFormat(); } /// /// fontFamily is the font family /// public System.Drawing.FontFamily fontFamily; /// /// fontStyle is the font style, eg, bold, italic or bold /// public System.Drawing.FontStyle fontStyle; /// /// nfontSize is font size /// public int nfontSize; /// /// pszText is the text to be displayed /// public string pszText; /// /// ptDraw is the point to draw /// public System.Drawing.Point ptDraw; /// /// strFormat is the string format /// public System.Drawing.StringFormat strFormat; } /// /// Class to draw text outlines /// public class Canvas { /// /// Generate Text Glow strategy /// /// is the color of the text /// is the color of the glow outline /// is the thickness of the outline in pixels /// valid ITextStrategy pointer if successful public static ITextStrategy TextGlow( System.Drawing.Color clrText, System.Drawing.Color clrOutline, int nThickness) { TextGlowStrategy strat = new TextGlowStrategy(); strat.Init(clrText, clrOutline, nThickness); return strat; } /// /// Generate Text Glow strategy /// /// is the brush of the text /// is the color of the glow outline /// is the thickness of the outline in pixels /// valid ITextStrategy pointer if successful public static ITextStrategy TextGlow( System.Drawing.Brush brushText, System.Drawing.Color clrOutline, int nThickness) { TextGlowStrategy strat = new TextGlowStrategy(); strat.Init(brushText, clrOutline, nThickness); return strat; } /// /// Generate Text Outline strategy /// /// is the color of the text /// is the color of the outline /// is the thickness of the outline in pixels /// valid ITextStrategy pointer if successful public static ITextStrategy TextOutline( System.Drawing.Color clrText, System.Drawing.Color clrOutline, int nThickness) { TextOutlineStrategy strat = new TextOutlineStrategy(); strat.Init(clrText, clrOutline, nThickness); return strat; } /// /// Generate Text Outline strategy /// /// is the brush of the text /// is the color of the outline /// is the thickness of the outline in pixels /// valid ITextStrategy pointer if successful public static ITextStrategy TextOutline( System.Drawing.Brush brushText, System.Drawing.Color clrOutline, int nThickness) { TextOutlineStrategy strat = new TextOutlineStrategy(); strat.Init(brushText, clrOutline, nThickness); return strat; } /// /// Setting Gradient Outlined Text effect /// /// is the text color /// is the inner outline color /// is the outer outline color /// is the outline thickness /// valid ITextStrategy pointer if successful public static ITextStrategy TextGradOutline( System.Drawing.Color clrText, System.Drawing.Color clrOutline1, System.Drawing.Color clrOutline2, int nThickness) { TextGradOutlineStrategy strat = new TextGradOutlineStrategy(); strat.Init(clrText, clrOutline1, clrOutline2, nThickness); return strat; } /// /// Setting Gradient Outlined Text effect /// /// is the text brush /// is the inner outline color /// is the outer outline color /// is the outline thickness /// valid ITextStrategy pointer if successful public static ITextStrategy TextGradOutline( System.Drawing.Brush brushText, System.Drawing.Color clrOutline1, System.Drawing.Color clrOutline2, int nThickness) { TextGradOutlineStrategy strat = new TextGradOutlineStrategy(); strat.Init(brushText, clrOutline1, clrOutline2, nThickness); return strat; } /// /// Setting just Text effect with no outline /// /// is the text color /// valid ITextStrategy pointer if successful public static ITextStrategy TextNoOutline( System.Drawing.Color clrText) { TextNoOutlineStrategy strat = new TextNoOutlineStrategy(); strat.Init(clrText); return strat; } /// /// Setting just Text effect with no outline /// /// is the text brush /// valid ITextStrategy pointer if successful public static ITextStrategy TextNoOutline( System.Drawing.Brush brushText) { TextNoOutlineStrategy strat = new TextNoOutlineStrategy(); strat.Init(brushText); return strat; } /// /// Setting Outlined Text effect with no text fill /// /// is the outline color /// is the outline thickness /// specifies rounded or sharp edges /// valid ITextStrategy pointer if successful public static ITextStrategy TextOnlyOutline( System.Drawing.Color clrOutline, int nThickness, bool bRoundedEdge) { TextOnlyOutlineStrategy strat = new TextOnlyOutlineStrategy(); strat.Init(clrOutline, nThickness, bRoundedEdge); return strat; } /// /// Generate a canvas image based on width and height /// /// is the image width /// is the image height /// a valid canvas image if successful public static System.Drawing.Bitmap GenImage(int width, int height) { return new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb); } /// /// Generate a canvas image based on width and height /// /// is the image width /// is the image height /// is the list of colors for the gradient /// specifies whether the gradient is horizontal /// a valid canvas image if successful public static System.Drawing.Bitmap GenImage(int width, int height, List colors, bool horizontal) { System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb); DrawGradient.Draw(bmp, colors, horizontal); return bmp; } /// /// Generate a canvas image based on width and height /// /// is the image width /// is the image height /// is the color to paint the image /// a valid canvas image if successful public static System.Drawing.Bitmap GenImage(int width, int height, System.Drawing.Color clr) { System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapData = new BitmapData(); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); bmp.LockBits( rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, bitmapData); unsafe { uint* pixels = (uint*)bitmapData.Scan0; if (pixels == null) return null; uint col = 0; int stride = bitmapData.Stride >> 2; uint color = (uint)(clr.A << 24 | clr.R << 16 | clr.G << 8 | clr.G); for (uint row = 0; row < bitmapData.Height; ++row) { for (col = 0; col < bitmapData.Width; ++col) { uint index = (uint)(row * stride + col); pixels[index] = color; } } } bmp.UnlockBits(bitmapData); return bmp; } /// /// Generate a canvas image based on width and height /// /// is the image width /// is the image height /// is the color to paint the image /// is alpha of the color /// a valid canvas image if successful public static System.Drawing.Bitmap GenImage(int width, int height, System.Drawing.Color clr, byte alpha) { System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb); BitmapData bitmapData = new BitmapData(); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); bmp.LockBits( rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, bitmapData); unsafe { uint* pixels = (uint*)bitmapData.Scan0; if (pixels == null) return null; uint col = 0; int stride = bitmapData.Stride >> 2; uint color = (uint)(alpha << 24 | clr.R << 16 | clr.G << 8 | clr.G); for (uint row = 0; row < bitmapData.Height; ++row) { for (col = 0; col < bitmapData.Width; ++col) { uint index = (uint)(row * stride + col); pixels[index] = color; } } } bmp.UnlockBits(bitmapData); return bmp; } /// /// Generate mask image of the text strategy. /// /// is text strategy /// is the mask image width /// is the mask image height /// offsets the text (typically used for shadows) /// is text context /// a valid mask image if successful public static System.Drawing.Bitmap GenMask( ITextStrategy strategy, int width, int height, System.Drawing.Point offset, TextContext textContext) { if (strategy == null || textContext == null) return null; System.Drawing.Bitmap pBmp = new System.Drawing.Bitmap(width, height, PixelFormat.Format32bppArgb); using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(pBmp)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; strategy.DrawString(graphics, textContext.fontFamily, textContext.fontStyle, textContext.nfontSize, textContext.pszText, new System.Drawing.Point(textContext.ptDraw.X + offset.X, textContext.ptDraw.Y + offset.Y), textContext.strFormat); } return pBmp; } /// /// Measure the mask image based on the mask color. /// /// is the mask image to be measured /// is mask color used in mask image /// returns the topmost Y /// returns the leftmost X /// returns the bottommost Y /// returns the rightmost X /// true if successful public static bool MeasureMaskLength( System.Drawing.Bitmap mask, System.Drawing.Color maskColor, ref uint top, ref uint left, ref uint bottom, ref uint right) { top = 30000; left = 30000; bottom = 0; right = 0; if (mask == null) return false; BitmapData bitmapDataMask = new BitmapData(); Rectangle rect = new Rectangle(0, 0, mask.Width, mask.Height); mask.LockBits( rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, bitmapDataMask); unsafe { uint* pixelsMask = (uint*)bitmapDataMask.Scan0; if (pixelsMask == null) return false; uint col = 0; int stride = bitmapDataMask.Stride >> 2; for (uint row = 0; row < bitmapDataMask.Height; ++row) { for (col = 0; col < bitmapDataMask.Width; ++col) { uint index = (uint)(row * stride + col); byte nAlpha = 0; if (MaskColor.IsEqual(maskColor, MaskColor.Red)) nAlpha = (Byte)((pixelsMask[index] & 0xff0000) >> 16); else if (MaskColor.IsEqual(maskColor, MaskColor.Green)) nAlpha = (Byte)((pixelsMask[index] & 0xff00) >> 8); else if (MaskColor.IsEqual(maskColor, MaskColor.Blue)) nAlpha = (Byte)(pixelsMask[index] & 0xff); if (nAlpha > 0) { if (col < left) left = col; if (row < top) top = row; if (col > right) right = col; if (row > bottom) bottom = row; } } } } mask.UnlockBits(bitmapDataMask); return true; } /// /// Apply image to mask onto the canvas /// /// is the image to be used /// is the mask image to be read /// is the destination image to be draw upon /// is mask color used in mask image /// true if successful public static bool ApplyImageToMask( System.Drawing.Bitmap image, System.Drawing.Bitmap mask, System.Drawing.Bitmap canvas, System.Drawing.Color maskColor) { if (image == null || mask == null || canvas == null) return false; BitmapData bitmapDataImage = new BitmapData(); BitmapData bitmapDataMask = new BitmapData(); BitmapData bitmapDataCanvas = new BitmapData(); Rectangle rectCanvas = new Rectangle(0, 0, canvas.Width, canvas.Height); Rectangle rectMask = new Rectangle(0, 0, mask.Width, mask.Height); Rectangle rectImage = new Rectangle(0, 0, image.Width, image.Height); image.LockBits( rectImage, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, bitmapDataImage); mask.LockBits( rectMask, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, bitmapDataMask); canvas.LockBits( rectCanvas, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, bitmapDataCanvas); unsafe { uint* pixelsImage = (uint*)bitmapDataImage.Scan0; uint* pixelsMask = (uint*)bitmapDataMask.Scan0; uint* pixelsCanvas = (uint*)bitmapDataCanvas.Scan0; if (pixelsImage == null || pixelsMask == null || pixelsCanvas == null) return false; uint col = 0; int stride = bitmapDataCanvas.Stride >> 2; for (uint row = 0; row < bitmapDataCanvas.Height; ++row) { for (col = 0; col < bitmapDataCanvas.Width; ++col) { if (row >= bitmapDataImage.Height || col >= bitmapDataImage.Width) continue; if (row >= bitmapDataMask.Height || col >= bitmapDataMask.Width) continue; uint index = (uint)(row * stride + col); uint indexMask = (uint)(row * (bitmapDataMask.Stride >> 2) + col); uint indexImage = (uint)(row * (bitmapDataImage.Stride >> 2) + col); byte maskByte = 0; if (MaskColor.IsEqual(maskColor, MaskColor.Red)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff0000) >> 16); else if (MaskColor.IsEqual(maskColor, MaskColor.Green)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff00) >> 8); else if (MaskColor.IsEqual(maskColor, MaskColor.Blue)) maskByte = (Byte)(pixelsMask[indexMask] & 0xff); if (maskByte > 0) pixelsCanvas[index] = Alphablend(pixelsCanvas[index], pixelsImage[indexImage], (Byte)(pixelsMask[indexMask] >> 24), (Byte)(pixelsMask[indexMask] >> 24)); } } } canvas.UnlockBits(bitmapDataCanvas); mask.UnlockBits(bitmapDataMask); image.UnlockBits(bitmapDataImage); return true; } /// /// Apply color to mask onto the canvas /// /// is the color to be used /// is the mask image to be read /// is the destination image to be draw upon /// is mask color used in mask image /// true if successful public static bool ApplyColorToMask( System.Drawing.Color clr, System.Drawing.Bitmap mask, System.Drawing.Bitmap canvas, System.Drawing.Color maskColor) { if (mask == null || canvas == null) return false; BitmapData bitmapDataMask = new BitmapData(); BitmapData bitmapDataCanvas = new BitmapData(); Rectangle rectCanvas = new Rectangle(0, 0, canvas.Width, canvas.Height); Rectangle rectMask = new Rectangle(0, 0, mask.Width, mask.Height); mask.LockBits( rectMask, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, bitmapDataMask); canvas.LockBits( rectCanvas, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, bitmapDataCanvas); unsafe { uint* pixelsMask = (uint*)bitmapDataMask.Scan0; uint* pixelsCanvas = (uint*)bitmapDataCanvas.Scan0; if (pixelsMask == null || pixelsCanvas == null) return false; uint col = 0; int stride = bitmapDataCanvas.Stride >> 2; for (uint row = 0; row < bitmapDataCanvas.Height; ++row) { for (col = 0; col < bitmapDataCanvas.Width; ++col) { if (row >= bitmapDataMask.Height || col >= bitmapDataMask.Width) continue; uint index = (uint)(row * stride + col); uint indexMask = (uint)(row * (bitmapDataMask.Stride >> 2) + col); byte maskByte = 0; if (MaskColor.IsEqual(maskColor, MaskColor.Red)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff0000) >> 16); else if (MaskColor.IsEqual(maskColor, MaskColor.Green)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff00) >> 8); else if (MaskColor.IsEqual(maskColor, MaskColor.Blue)) maskByte = (Byte)(pixelsMask[indexMask] & 0xff); uint color = (uint)(0xff << 24 | clr.R << 16 | clr.G << 8 | clr.B); if (maskByte > 0) pixelsCanvas[index] = Alphablend(pixelsCanvas[index], color, (Byte)(pixelsMask[indexMask] >> 24), (Byte)(pixelsMask[indexMask] >> 24)); } } } canvas.UnlockBits(bitmapDataCanvas); mask.UnlockBits(bitmapDataMask); return true; } /// /// Apply color to mask onto the canvas /// /// is the color to be used /// is the mask image to be read /// is the destination image to be draw upon /// is mask color used in mask image /// determine how much to offset the mask /// true if successful public static bool ApplyColorToMask( System.Drawing.Color clr, System.Drawing.Bitmap mask, System.Drawing.Bitmap canvas, System.Drawing.Color maskColor, System.Drawing.Point offset) { if (mask == null || canvas == null) return false; BitmapData bitmapDataMask = new BitmapData(); BitmapData bitmapDataCanvas = new BitmapData(); Rectangle rectCanvas = new Rectangle(0, 0, canvas.Width, canvas.Height); Rectangle rectMask = new Rectangle(0, 0, mask.Width, mask.Height); mask.LockBits( rectMask, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb, bitmapDataMask); canvas.LockBits( rectCanvas, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb, bitmapDataCanvas); unsafe { uint* pixelsMask = (uint*)bitmapDataMask.Scan0; uint* pixelsCanvas = (uint*)bitmapDataCanvas.Scan0; if (pixelsMask == null || pixelsCanvas == null) return false; uint col = 0; int stride = bitmapDataCanvas.Stride >> 2; for (uint row = 0; row < bitmapDataCanvas.Height; ++row) { for (col = 0; col < bitmapDataCanvas.Width; ++col) { if ((row - offset.Y) >= bitmapDataMask.Height || (col - offset.X) >= bitmapDataMask.Width || (row - offset.Y) < 0 || (col - offset.X) < 0) continue; uint index = (uint)(row * stride + col); uint indexMask = (uint)((row - offset.Y) * (bitmapDataMask.Stride >> 2) + (col - offset.X)); byte maskByte = 0; if (MaskColor.IsEqual(maskColor, MaskColor.Red)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff0000) >> 16); else if (MaskColor.IsEqual(maskColor, MaskColor.Green)) maskByte = (Byte)((pixelsMask[indexMask] & 0xff00) >> 8); else if (MaskColor.IsEqual(maskColor, MaskColor.Blue)) maskByte = (Byte)(pixelsMask[indexMask] & 0xff); uint color = (uint)(0xff << 24 | clr.R << 16 | clr.G << 8 | clr.B); if (maskByte > 0) pixelsCanvas[index] = Alphablend(pixelsCanvas[index], color, (Byte)(pixelsMask[indexMask] >> 24), (Byte)(pixelsMask[indexMask] >> 24)); } } } canvas.UnlockBits(bitmapDataCanvas); mask.UnlockBits(bitmapDataMask); return true; } /// /// Draw outline on image /// /// is text strategy /// is the image to be draw upon /// offsets the text (typically used for shadows) /// is text context /// true if successful public static bool DrawTextImage( ITextStrategy strategy, System.Drawing.Bitmap image, System.Drawing.Point offset, TextContext textContext) { if (strategy == null || image == null || textContext == null) return false; bool bRet = false; using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(image)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; bRet = strategy.DrawString(graphics, textContext.fontFamily, textContext.fontStyle, textContext.nfontSize, textContext.pszText, new System.Drawing.Point(textContext.ptDraw.X + offset.X, textContext.ptDraw.Y + offset.Y), textContext.strFormat); } return bRet; } /// /// Set alpha to color /// /// is destination color in ARGB /// is source color in ARGB /// is nAlpha is alpha channel /// private static UInt32 AddAlpha(UInt32 dest, UInt32 source, Byte nAlpha) { if (0 == nAlpha) return dest; if (255 == nAlpha) return source; Byte nSrcRed = (Byte)((source & 0xff0000) >> 16); Byte nSrcGreen = (Byte)((source & 0xff00) >> 8); Byte nSrcBlue = (Byte)((source & 0xff)); Byte nRed = (Byte)(nSrcRed); Byte nGreen = (Byte)(nSrcGreen); Byte nBlue = (Byte)(nSrcBlue); return (UInt32)(nAlpha << 24 | nRed << 16 | nGreen << 8 | nBlue); } /// /// Performs Alphablend /// /// is destination color in ARGB /// is source color in ARGB /// is nAlpha is alpha channel /// sets alpha channel of the returned UInt32 /// destination color private static UInt32 Alphablend(UInt32 dest, UInt32 source, Byte nAlpha, Byte nAlphaFinal) { if (0 == nAlpha) return dest; if (255 == nAlpha) return source; Byte nInvAlpha = (Byte)(~nAlpha); Byte nSrcRed = (Byte)((source & 0xff0000) >> 16); Byte nSrcGreen = (Byte)((source & 0xff00) >> 8); Byte nSrcBlue = (Byte)((source & 0xff)); Byte nDestRed = (Byte)((dest & 0xff0000) >> 16); Byte nDestGreen = (Byte)((dest & 0xff00) >> 8); Byte nDestBlue = (Byte)(dest & 0xff); Byte nRed = (Byte)((nSrcRed * nAlpha + nDestRed * nInvAlpha) >> 8); Byte nGreen = (Byte)((nSrcGreen * nAlpha + nDestGreen * nInvAlpha) >> 8); Byte nBlue = (Byte)((nSrcBlue * nAlpha + nDestBlue * nInvAlpha) >> 8); return (UInt32)(nAlphaFinal << 24 | nRed << 16 | nGreen << 8 | nBlue); } /// /// Performs Alphablend /// /// is destination color in ARGB /// is source color in ARGB /// destination color private static UInt32 PreMultipliedAlphablend(UInt32 dest, UInt32 source) { Byte Alpha = (Byte)((source & 0xff000000) >> 24); Byte nInvAlpha = (Byte)(255 - Alpha); Byte nSrcRed = (Byte)((source & 0xff0000) >> 16); Byte nSrcGreen = (Byte)((source & 0xff00) >> 8); Byte nSrcBlue = (Byte)((source & 0xff)); Byte nDestRed = (Byte)((dest & 0xff0000) >> 16); Byte nDestGreen = (Byte)((dest & 0xff00) >> 8); Byte nDestBlue = (Byte)(dest & 0xff); Byte nRed = (Byte)(nSrcRed + ((nDestRed * nInvAlpha) >> 8)); Byte nGreen = (Byte)(nSrcGreen + ((nDestGreen * nInvAlpha) >> 8)); Byte nBlue = (Byte)(nSrcBlue + ((nDestBlue * nInvAlpha) >> 8)); return (UInt32)(0xff << 24 | nRed << 16 | nGreen << 8 | nBlue); } } }