Search code examples
c#asp.net-mvcbitmapdrawstring

Bitmap graphics: when saving on disk no drawed strings - works when memorystream


I am creating a PNG picture, using the Bitmap object, using Drawing.Graphics . I create a Bitmap, insert a background image and draw some strings.

Now, when I save the image on the disk, the files does not have my strings!

I am doing this in ASP.NET MVC, where this is my controllers signature:

    [AcceptVerbs(HttpVerbs.Get)]
    public string GetNewsletterPicture(string headline, string tagline)

When I don't save the image on the disk and instead returns a FileStreamResult from a MemoryStream, the image looks perfectly.

So there is some problem that when I save the image to the disk, the strings are "forgotten" somehow.

Any ideas?

My code:

ColorConverter converter = new ColorConverter();
        Color textColor = (Color)converter.ConvertFromString("#FF58595B");
        int width = 598;
        int height = 77;
        int offSet = 40;
        int shadowOffset = 1;

        var bmp = new Bitmap(width, height);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.Clear(Color.LightGray);
            Image backgroundImg = new Bitmap(Server.MapPath("~/Static/Images/bgimg.png"));
            g.DrawImage(backgroundImg,0,0);

            StringFormat sf= new StringFormat();
            sf.Alignment = StringAlignment.Center;

            var rectangleTop = new RectangleF(0, 0, width, height);
            var rectangleTopShadowHack = new RectangleF(shadowOffset, shadowOffset, width + shadowOffset, height + shadowOffset);
            g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

            // only show headline and center it
            if (!string.IsNullOrEmpty(tagline))
            {
                var rectangleBottomShadowHack = new RectangleF(shadowOffset, offSet + shadowOffset, width + shadowOffset, height - offSet + shadowOffset);
                var rectangleBottom = new RectangleF(0, offSet, width, height - offSet);

                g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(Color.White), rectangleBottomShadowHack, sf);
                g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(textColor), rectangleBottom, sf);
            }
            else
            {
                sf.LineAlignment = StringAlignment.Center;
            }
            g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(Color.White), rectangleTopShadowHack, sf);
            g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(textColor), rectangleTop, sf);

            g.Save();

            var fileName = Guid.NewGuid().ToString() + ".png";
            var path = Server.MapPath("~/Static/Previews/" + fileName);
            bmp.Save(path, ImageFormat.Png);

            return fileName;

If in doubt, it is the g.DrawString which is not being saved on the picture.

NEW atttempt (still not working):

[AcceptVerbs(HttpVerbs.Get)]
        public string GetNewsletterPicture(string headline, string tagline)
        {
            ColorConverter converter = new ColorConverter();
            Color textColor = (Color)converter.ConvertFromString("#FF58595B");
            int width = 598;
            int height = 77;
            int offSet = 40;
            int shadowOffset = 1;

            var bmp = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.Clear(Color.LightGray);
                Image backgroundImg = new Bitmap(Server.MapPath("~/Static/Images/bgimg.png"));
                g.DrawImage(backgroundImg,0,0);

                StringFormat sf= new StringFormat();
                sf.Alignment = StringAlignment.Center;

                var rectangleTop = new RectangleF(0, 0, width, height);
                var rectangleTopShadowHack = new RectangleF(shadowOffset, shadowOffset, width + shadowOffset, height + shadowOffset);
                g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

                // only show headline and center it
                if (!string.IsNullOrEmpty(tagline))
                {
                    var rectangleBottomShadowHack = new RectangleF(shadowOffset, offSet + shadowOffset, width + shadowOffset, height - offSet + shadowOffset);
                    var rectangleBottom = new RectangleF(0, offSet, width, height - offSet);

                    g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(Color.White), rectangleBottomShadowHack, sf);
                    g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(textColor), rectangleBottom, sf);
                }
                else
                {
                    sf.LineAlignment = StringAlignment.Center;
                }
                g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(Color.White), rectangleTopShadowHack, sf);
                g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(textColor), rectangleTop, sf);

                g.Flush(FlushIntention.Sync);
            }

            var fileName = Guid.NewGuid().ToString() + ".png";
            var path = Server.MapPath("~/Static/Previews/" + fileName);
            bmp.Save(path, ImageFormat.Png);

            return fileName;


            //MemoryStream stm = new MemoryStream();
            //bmp.Save(stm,System.Drawing.Imaging.ImageFormat.Png);
            //stm.Position = 0;

            //return new FileStreamResult(stm, "image/png");
        }

Solution

  • I can't tell for sure, but it looks like you might be confusing g.Save() with g.Flush().

    You need to call g.Flush(FlushIntention.Sync) instead of g.Save(). You should probably also call bmp.Save() outside of the using block:

    var bmp = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(bmp))
    {
      //...
      g.Flush(FlushIntention.Sync);
    }
    
    var fileName = Guid.NewGuid().ToString() + ".png";
    var path = Server.MapPath("~/Static/Previews/" + fileName);
    
    bmp.Save(path, ImageFormat.Png)
    

    Save() is used to save the current graphics state so that you can modify it and then restore it later.:

    GraphicsState oldState = g.Save();
    
    // Make some changes to the graphics state...
    
    g.Restore(oldState);
    

    Flush() on the other hand, is used to force the graphics object to complete any pending operations. By passing FlushIntention.Sync as a parameter, Flush() won't return until the flushing is complete.