0

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");
        }
Lars Holdgaard
  • 9,496
  • 26
  • 102
  • 182

1 Answers1

1

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.

lfalin
  • 4,219
  • 5
  • 31
  • 57
  • I just tried to do that.. And I also tried without g.Save() - I have the same problem. Should I not use g.Save() ? There is no more to the snippet than you can see :-) Anyway, no strings still unfortunately – Lars Holdgaard Aug 07 '13 at 10:56
  • You should probably also call bmp.Save() outside of the using block. See my edits above. – lfalin Aug 07 '13 at 11:09
  • Thanks. I just tried this (see my new attempt in the original post). Still no luck though! Thanks so much for giving the understanding of save/flush though! – Lars Holdgaard Aug 07 '13 at 11:15
  • Just to clarify, the new file you're getting (and I'm assuming you're clearing out the Static/Previews folder so there's no danger of a mixup), still has every bit of graphics adjustment except the strings? – lfalin Aug 08 '13 at 09:35