调用字体时图像上受保护的内存异常

时间:2015-08-07 20:30:49

标签: c# fonts gdi+

编辑:所以,我知道发生了什么,我只是不明白为什么。我的Dictionary<string, object>存储的字体很好,但是有一个特定的函数可以运行,当它运行时,字典会被部分删除。

在: enter image description here

在: enter image description here

这些图片之间运行的代码是:

    public static int countLines(string a)
    {
        int count = 0;
        string line;
        System.IO.StreamReader file;

        try
        {
            file = new System.IO.StreamReader(@a);
        }

        catch (Exception ex)
        {
            MessageBox.Show("Missing " + a + "\n\n" + ex.ToString(), "Exception");
            return 0;
        }

        while ((line = file.ReadLine()) != null)
        {

            if (line.Substring(0, 2) == "10") { count++; }

        }

        file.Close();

        return count;
    }

---结束编辑---

当我使用太多自定义字体时,我得到this tracedump。我使用相同的solution listed here,并尝试了投票修复(删除dispose和一个编组调用),这会立即导致GDI +错误。实际上,我有该代码的修改版本,以便我可以调用并获取不同的字体:

    #region Font setup
    //Setup code for custom fonts
    [DllImport("gdi32.dll")]
    private static extern IntPtr AddFontMemResourceEx(byte[] pbFont, int cbFont, IntPtr pdv, out uint pcFonts);

    [DllImport("gdi32.dll")]
    internal static extern bool RemoveFontMemResourceEx(IntPtr fh);

    static private IntPtr m_fh = IntPtr.Zero;
    static private PrivateFontCollection m_pfc = null;

    public static Font getFont(string fonttype, float size)
    {
        m_pfc = null;

        Font fnt = null;

        if (null == m_pfc)
        {
            Stream stmFont = null;

            // First load the font as a memory stream

            switch (fonttype)
            {
                case "MICR":
                    stmFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("QATestFileGenTools.Fonts.MICR.ttf");
                    break;

                case "HAND":
                    Random rnd = new Random(DateTime.Now.Millisecond);
                    int rr = rnd.Next(0, 3);

                    if (rr == 0)
                    {
                        stmFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("QATestFileGenTools.Fonts.hand1.ttf");
                        size += rnd.Next(0, 4);
                    }

                    if (rr == 1)
                    {
                        stmFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("QATestFileGenTools.Fonts.hand2.ttf");
                        size += rnd.Next(2, 6);
                    }

                    if (rr == 2)
                    {
                        stmFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("QATestFileGenTools.Fonts.hand3.ttf");
                        size += rnd.Next(6, 10);
                    }

                    break;

                case "SIG":
                    stmFont = Assembly.GetExecutingAssembly().GetManifestResourceStream("QATestFileGenTools.Fonts.signature.ttf");
                    break;

                default:
                    MessageBox.Show("Bad call to getFont()", "Error");
                    break;
            }

            if (null != stmFont)
            {

                // 
                // GDI+ wants a pointer to memory, GDI wants the memory.
                // We will make them both happy.
                //

                // First read the font into a buffer
                byte[] rgbyt = new Byte[stmFont.Length];
                stmFont.Read(rgbyt, 0, rgbyt.Length);

                // Then do the unmanaged font (Windows 2000 and later)
                // The reason this works is that GDI+ will create a font object for
                // controls like the RichTextBox and this call will make sure that GDI
                // recognizes the font name, later.
                uint cFonts;
                AddFontMemResourceEx(rgbyt, rgbyt.Length, IntPtr.Zero, out cFonts);


                // Now do the managed font
                IntPtr pbyt = Marshal.AllocCoTaskMem(rgbyt.Length);
                if (null != pbyt)
                {
                    Marshal.Copy(rgbyt, 0, pbyt, rgbyt.Length);

                    m_pfc = new PrivateFontCollection();
                    m_pfc.AddMemoryFont(pbyt, rgbyt.Length);
                    Marshal.FreeCoTaskMem(pbyt);
                }
            }
        }

        if (m_pfc.Families.Length > 0)
        {
            // Handy how one of the Font constructors takes a
            // FontFamily object, huh? :-)
            fnt = new Font(m_pfc.Families[0], size);
        }

        m_pfc.Dispose();
        return fnt;
    }
    //End setup for fonts
    #endregion

如果删除dispose()和FreeCoTaskMem()is this,我不可避免地会遇到GDI +错误。

这两个问题都不会立即发生。看起来我可以在抛出任何异常之前平均运行20-25次。

任何想法都将不胜感激。当我只使用单一字体时,我从未遇到过错误(每次都可能产生1000+)。至少,有趣的是,如果我只调用两种字体,它也不是问题。但当&#34; HAND&#34;被抛入混合物中,这似乎是个问题。

调用它的方法是:

public static byte[] GenCheckImage(string outputPath, string frontBack, string MICRline, string amount, string[] imageOptions, Dictionary<string, object> dictCfgIn, string names = "John Smith", string date = null, string lar = null)//, string payeeName, string date)
    {

        System.Reflection.Assembly thisExe;
        thisExe = System.Reflection.Assembly.GetExecutingAssembly();

        if (date == null)
        {
            date = DateTime.Now.AddDays(-4).ToString("d");
        }

        if (lar == null)
        {
            lar = "Some Dollars & xx/100";
        }

        if (frontBack == "F")
        {
            //Open the front image to frontImage Image source from embedded resource

            System.IO.Stream file;

            Random rnd = new Random(DateTime.Now.Millisecond);
            int a = rnd.Next(imageOptions.Length);

           // if (a == 0)  {file = thisExe.GetManifestResourceStream("QATestFileGenTools.checkFront1.bmp");}
           // else if (a == 1)  {file = thisExe.GetManifestResourceStream("QATestFileGenTools.checkFront2.bmp");}
            file = thisExe.GetManifestResourceStream(imageOptions[a]);
            Bitmap b;

            using (System.Drawing.Image frontImage = System.Drawing.Image.FromStream(file))//;
            {


            byte[] binaryData = new Byte[file.Length];
            long bytesRead = file.Read(binaryData, 0,
                                    (int)file.Length);

            Bitmap b2 = new Bitmap(frontImage);

            file.Close();

            Font micrFont = getFont("MICR", 18);

            Font objFont;
            if ((bool)dictCfgIn["Handwriting"])
                objFont = getFont("HAND", 20);
            else
                objFont = new System.Drawing.Font("Arial", 20);

            Font sigFont = getFont("SIG", 30);
            string[] sigName = NSCreateRAW.CreateRaw.genName();
            string sigString = sigName[0] + sigName[1] + rnd.Next(1, 6).ToString();

            amount = amount.TrimStart('0'); //Insert(2, "XYZ")
            amount = amount.Insert((amount.Length - 2), ".");
            //Draw something
            //Bitmap b = new Bitmap(frontImage);
            b = new Bitmap(frontImage);
            Graphics graphics = Graphics.FromImage(b);

            if (imageOptions[a] == "QATestFileGenTools.checkFront1.bmp")  // ProfitStars Check Template
            {
                graphics.DrawString(date, objFont, Brushes.Black, 690, 150);
                graphics.DrawString(lar, objFont, Brushes.Black, 150, 280);
                graphics.DrawString(names, objFont, Brushes.Black, 200, 215);
                graphics.DrawString(MICRline, micrFont, Brushes.Black, 200, 490);
                graphics.DrawString(amount, objFont, Brushes.Black, 985, 230);
                graphics.DrawString(sigString, sigFont, Brushes.Black, 680, 400);
            }

            else if (imageOptions[a] == "QATestFileGenTools.checkFront2.bmp")  // TWS Check Template
            {
                graphics.DrawString(date, objFont, Brushes.Black, 735, 105);
                graphics.DrawString(lar, objFont, Brushes.Black, 160, 250);
                graphics.DrawString(names, objFont, Brushes.Black, 200, 165);
                graphics.DrawString(MICRline, micrFont, Brushes.Black, 200, 490);
                graphics.DrawString(amount, objFont, Brushes.Black, 1020, 185);
                graphics.DrawString(sigString, sigFont, Brushes.Black, 690, 380);
            }

            else if (imageOptions[a] == "QATestFileGenTools.checkFront3.bmp")  // "Blank" Check Template
            {
                graphics.DrawString(date, objFont, Brushes.Black, 935, 110);
                graphics.DrawString(lar, objFont, Brushes.Black, 180, 275);
                graphics.DrawString(names, objFont, Brushes.Black, 220, 210);
                graphics.DrawString(MICRline, micrFont, Brushes.Black, 220, 470);
                graphics.DrawString(amount, objFont, Brushes.Black, 1000, 210);
                graphics.DrawString(sigString, sigFont, Brushes.Black, 690, 395);
            }

            else
            {
                //graphics.DrawString(MICRline, micrFont, Brushes.Black, 200, 490);
                //graphics.DrawString(amount, objFont, Brushes.Black, 985, 230);
            }

            if ((bool)dictCfgIn["Bad Images"] && (bool)dictCfgIn["Skew Images"])
            {
                Point[] destinationPoints = {
                    new Point(0, 50),   // destination for upper-left point of  
                  // original 
                    new Point(1170, 0),  // destination for upper-right point of  
                  // original 
                    new Point(30, 585)};
                graphics.DrawImage(b, destinationPoints);
            }

            if ((bool)dictCfgIn["Bad Images"] && (bool)dictCfgIn["Bar Images"])
            {
                Pen penWide = new Pen(Color.Black, 45);
                Pen penNarrow = new Pen(Color.Black, 2);
                Point[] points1 =
                {
                     new Point(0   , 250),
                     new Point(1200, 250)
                };
                Point[] points2 =
                {
                    new Point (0   , 280),
                    new Point (1200, 280)
                };
                graphics.DrawLines(penWide, points1);
                graphics.DrawLines(penNarrow, points2);
            }
            }
            //Convert to TIF - requires BitMiracle.LibTiff.Classic
            byte[] tiffBytes = GetTiffImageBytes(b, false);

            //File.WriteAllBytes("checkfront.tif", tiffBytes);

            //Encoding enc = Encoding.GetEncoding(1252);
            //string result = enc.GetString(tiffBytes);

            //File.Write("check2.tif", result);

            return tiffBytes;
        }

第二位代码中的using包装器是新的 - 我认为它可能有所帮助,但它根本没有改变结果。

1 个答案:

答案 0 :(得分:0)

最后,事实证明,非托管内存只是一个坏主意。其他进程需要内存,指针变得无效。

我最终使用的是PrivateFontCollection。我仍然使用该集合中的字典只是因为它使访问更容易,并使我的许多代码以类似的方式工作。我开始使用的代码示例在处理大型数据集时太不稳定了。

我在这里修改了解决方案:http://www.emoticode.net/c-sharp/load-custom-ttf-font-file-and-use-it-on-any-winform-controls.html