|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Text; |
| 5 | + |
| 6 | +using ST.Library.UI.STTextBox; |
| 7 | +using ST.Library.Drawing.SvgRender; |
| 8 | + |
| 9 | +using System.IO; |
| 10 | +using System.Drawing; |
| 11 | +using System.Drawing.Imaging; |
| 12 | +using System.Runtime.InteropServices; |
| 13 | +using System.Text.RegularExpressions; |
| 14 | + |
| 15 | +namespace ST.Library.Drawing |
| 16 | +{ |
| 17 | + public class EmojiRender : IEmojiRender, IDisposable |
| 18 | + { |
| 19 | + private Dictionary<string, string> m_dic_xml = new Dictionary<string, string>(); |
| 20 | + private Dictionary<string, CacheInfo> m_dic_cache = new Dictionary<string, CacheInfo>(); |
| 21 | + |
| 22 | + private struct CacheInfo |
| 23 | + { |
| 24 | + public int Size; |
| 25 | + public Image Image; |
| 26 | + public Image SelectedImage; |
| 27 | + } |
| 28 | + |
| 29 | + private ImageAttributes m_img_attr_normal; |
| 30 | + private ImageAttributes m_img_attr_selected; |
| 31 | + |
| 32 | + public EmojiRender(string strFile) { |
| 33 | + ColorMatrix m = new ColorMatrix(new float[][]{ |
| 34 | + new float[]{1, 0, 0, 0, 0}, |
| 35 | + new float[]{0, 1, 0, 0, 0}, |
| 36 | + new float[]{0, 0, 1, 0, 0}, |
| 37 | + new float[]{0, 0, 0, 1, 0}, |
| 38 | + new float[]{0, 0, 0, 0, 1}, |
| 39 | + }); |
| 40 | + m_img_attr_normal = new ImageAttributes(); |
| 41 | + m_img_attr_normal.SetColorMatrix(m); |
| 42 | + m[3, 3] = 0.5F; |
| 43 | + m_img_attr_selected = new ImageAttributes(); |
| 44 | + m_img_attr_selected.SetColorMatrix(m); |
| 45 | + this.InitSvgFromPackage(strFile); |
| 46 | + } |
| 47 | + |
| 48 | + public bool IsEmoji(string strChar) { |
| 49 | + return this.GetEmojiString(strChar) != null; |
| 50 | + } |
| 51 | + |
| 52 | + private string GetEmojiString(string strText) { |
| 53 | + if (m_dic_xml.ContainsKey(strText)) { |
| 54 | + return strText; |
| 55 | + } |
| 56 | + // http://www.unicode.org/charts/PDF/UFE00.pdf |
| 57 | + // FE00 - FE0F is the Variation Selectors |
| 58 | + // FE0E -> text variation selector |
| 59 | + // FE0F -> emoji variation selector |
| 60 | + if (strText.IndexOf('\uFE0F') == -1) { |
| 61 | + return null; |
| 62 | + } |
| 63 | + strText = strText.Replace("\uFE0F", "");// strText.Substring(0, strText.Length - 1); |
| 64 | + if (m_dic_xml.ContainsKey(strText)) { |
| 65 | + return strText; |
| 66 | + } |
| 67 | + return null; |
| 68 | + } |
| 69 | + |
| 70 | + public void DrawEmoji(ISTTextBoxRender render, string strChar, int nX, int nY, int nWidth, bool bSelected) { |
| 71 | + strChar = this.GetEmojiString(strChar); |
| 72 | + CacheInfo ci; |
| 73 | + if (string.IsNullOrEmpty(strChar)) { |
| 74 | + strChar = "none"; |
| 75 | + } |
| 76 | + if (m_dic_cache.ContainsKey(strChar)) { |
| 77 | + ci = m_dic_cache[strChar]; |
| 78 | + if (ci.Size != nWidth) { |
| 79 | + ci.Image.Dispose(); |
| 80 | + ci.Image = this.GetEmojiImage(strChar, nWidth); |
| 81 | + m_dic_cache[strChar] = ci; |
| 82 | + } |
| 83 | + } else { |
| 84 | + ci.Size = nWidth; |
| 85 | + ci.Image = this.GetEmojiImage(strChar, nWidth); |
| 86 | + ci.SelectedImage = this.SetAlpha((Bitmap)ci.Image.Clone()); |
| 87 | + m_dic_cache.Add(strChar, ci); |
| 88 | + } |
| 89 | + Rectangle rect = new Rectangle(nX, nY, nWidth, nWidth); |
| 90 | + render.DrawImage(bSelected ? ci.SelectedImage : ci.Image, rect); |
| 91 | + //if (!bSelected) { |
| 92 | + // render.DrawImage(ci.Image, rect); |
| 93 | + //} else { |
| 94 | + // using (Bitmap bmp = (Bitmap)ci.Image.Clone()) { |
| 95 | + // var bmpData = bmp.LockBits(new Rectangle(0, 0, nWidth, nWidth), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); |
| 96 | + // byte[] byClr = new byte[bmpData.Stride * bmpData.Height]; |
| 97 | + // Marshal.Copy(bmpData.Scan0, byClr, 0, byClr.Length); |
| 98 | + // for (int x = 0; x < bmp.Width; x++) { |
| 99 | + // for (int y = 0; y < bmp.Height; y++) { |
| 100 | + // int nIndex = y * bmpData.Stride + x * 4 + 3; |
| 101 | + // byClr[nIndex] = (byte)(byClr[nIndex] >> 1); |
| 102 | + // } |
| 103 | + // } |
| 104 | + // Marshal.Copy(byClr, 0, bmpData.Scan0, byClr.Length); |
| 105 | + // bmp.UnlockBits(bmpData); |
| 106 | + // render.DrawImage(bmp, rect); |
| 107 | + // } |
| 108 | + //} |
| 109 | + } |
| 110 | + |
| 111 | + public Image GetEmojiImage(string strChar, int nSize) { |
| 112 | + strChar = this.GetEmojiString(strChar); |
| 113 | + if (strChar == null) { |
| 114 | + return null; |
| 115 | + } |
| 116 | + Bitmap bmp = new Bitmap(nSize, nSize); |
| 117 | + using (Graphics g = Graphics.FromImage(bmp)) { |
| 118 | + using (SvgDocument svg = SvgDocument.FromXml(m_dic_xml[strChar])) { |
| 119 | + svg.Draw(g, new RectangleF(0, 0, nSize, nSize)); |
| 120 | + } |
| 121 | + } |
| 122 | + return bmp; |
| 123 | + } |
| 124 | + |
| 125 | + public Image SetAlpha(Bitmap bmp) { |
| 126 | + var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); |
| 127 | + byte[] byClr = new byte[bmpData.Stride * bmpData.Height]; |
| 128 | + Marshal.Copy(bmpData.Scan0, byClr, 0, byClr.Length); |
| 129 | + for (int x = 0; x < bmp.Width; x++) { |
| 130 | + for (int y = 0; y < bmp.Height; y++) { |
| 131 | + int nIndex = y * bmpData.Stride + x * 4 + 3; |
| 132 | + byClr[nIndex] = (byte)(byClr[nIndex] >> 1); |
| 133 | + } |
| 134 | + } |
| 135 | + Marshal.Copy(byClr, 0, bmpData.Scan0, byClr.Length); |
| 136 | + bmp.UnlockBits(bmpData); |
| 137 | + return bmp; |
| 138 | + } |
| 139 | + |
| 140 | + private int InitSvgFromPackage(string strFile) { |
| 141 | + int nCounter = 0; |
| 142 | + Dictionary<string, string> dic = new Dictionary<string, string>(); |
| 143 | + using (StreamReader reader = new StreamReader(strFile, Encoding.UTF8)) { |
| 144 | + string strLine = string.Empty; |
| 145 | + while ((strLine = reader.ReadLine()) != null) { |
| 146 | + int nIndex = strLine.IndexOf(','); |
| 147 | + string strXml = strLine.Substring(nIndex + 1); |
| 148 | + dic.Add(this.GetString(strLine.Substring(0, nIndex)), strXml); |
| 149 | + } |
| 150 | + } |
| 151 | + if (!dic.ContainsKey("none")) { |
| 152 | + dic.Add("none", "<svg viewBox='0,0,20,20'><rect stroke='red' fill='yellow' x='4' y='2' width='12' height='16'/><path stroke='red' fill='none' d='M8,8 v-2 h4 v4 h-2 v2'/><line stroke='red' x1='8' y1='14' x2='12' y2='14'/></svg>"); |
| 153 | + } |
| 154 | + m_dic_xml = dic; |
| 155 | + return nCounter; |
| 156 | + } |
| 157 | + |
| 158 | + public string GetString(string strText) { |
| 159 | + StringBuilder sb = new StringBuilder(); |
| 160 | + for (int i = 0; i < strText.Length; i += 4) { |
| 161 | + sb.Append((char)(Convert.ToInt32(strText.Substring(i, 4), 16))); |
| 162 | + } |
| 163 | + return sb.ToString(); |
| 164 | + } |
| 165 | + /// <summary> |
| 166 | + /// Package all svg files to one file |
| 167 | + /// </summary> |
| 168 | + /// <param name="strSvgFilesPath">The svg path</param> |
| 169 | + /// <param name="strFileOut">The out file</param> |
| 170 | + /// <returns>Svg count</returns> |
| 171 | + public static int PackageSvgFiles(string strSvgFilesPath, string strFileOut) { |
| 172 | + int nCounter = 0; |
| 173 | + Regex reg_start = new Regex(@"^\s+|\s+$", RegexOptions.Multiline); |
| 174 | + using (StreamWriter writer = new StreamWriter(strFileOut, false, Encoding.UTF8)) { |
| 175 | + foreach (var v in Directory.GetFiles(strSvgFilesPath, "*.svg")) { |
| 176 | + string strName = Path.GetFileNameWithoutExtension(v); |
| 177 | + string strText = EmojiRender.FileNameToUnicode(strName); |
| 178 | + string strXml = File.ReadAllText(v).Trim(); |
| 179 | + strXml = reg_start.Replace(strXml, "").Replace("\r", "").Replace("\n", ""); |
| 180 | + writer.WriteLine(strText + "," + strXml); |
| 181 | + nCounter++; |
| 182 | + } |
| 183 | + } |
| 184 | + return nCounter; |
| 185 | + } |
| 186 | + |
| 187 | + private static string FileNameToUnicode(string strName) { |
| 188 | + //((strText[nIndex] & 0x03FF) << 10) + (strText[nIndex + 1] & 0x03FF) + 0x10000; |
| 189 | + strName.ToLower(); |
| 190 | + if (strName[0] == 'u') { |
| 191 | + strName = strName.Substring(1); |
| 192 | + } |
| 193 | + string strRet = string.Empty; |
| 194 | + foreach (var v in strName.Split('-', '_')) { |
| 195 | + int number = Convert.ToInt32(v, 16); |
| 196 | + if (number < 0x10000) { |
| 197 | + strRet += number.ToString("X4"); |
| 198 | + } else { |
| 199 | + number &= 0xFFFF; |
| 200 | + int nH = (number >> 10) | 0xD800; //D800-DBFF -> hight |
| 201 | + int nL = (number & 0x03FF) | 0xDC00; //DC00-DEFF -> low |
| 202 | + strRet += nH.ToString("X4"); |
| 203 | + strRet += nL.ToString("X4"); |
| 204 | + } |
| 205 | + } |
| 206 | + return strRet; |
| 207 | + } |
| 208 | + |
| 209 | + public void Dispose() { |
| 210 | + if (m_img_attr_normal != null) { |
| 211 | + m_img_attr_normal.Dispose(); |
| 212 | + } |
| 213 | + if (m_img_attr_selected != null) { |
| 214 | + m_img_attr_selected.Dispose(); |
| 215 | + } |
| 216 | + } |
| 217 | + } |
| 218 | +} |
0 commit comments