views:

818

answers:

6

We have a piece of code which saves a .Net System.Drawing.Bitmap to file. The Save call is specifying the file location as well as the ImageFormat which we are expecting to save the image data as a Jpeg so out code looks like this:

public MediaFile IngestImage(System.Drawing.Bitmap imgSrc, string name){
     ... // left out because it is not relevant to this question
     imgSrc.Save(fullPath, System.Drawing.Imaging.ImageFormat.Jpeg);
     ... // left out because it is not relevant to this question
}

For some reason every now and then this method generates PNG images as .jpg files. Most of the time it is not a big deal however another piece of the project has issues with these files not being actual jpegs (Windows Media Services).

Any help is appreciated, has anyone ever seen this?

Note: full path is something like "\servcer\share\file.jpg". We are saving jpg's with the extension "jpg". Hence the issue... Later we are creating publishing points on a Windows Media Server to play a SMIL playlist we then have to "Announce" the files and formats to the publishing point when the publishing point starts playing it expects a Jpg file because that is the extension of the file and the content is actually a PNG

Here is the actual code creating the BitpMap object that is passed into the above method...

        public static Bitmap CreateBitmap(string text, int height, int width, Color foregroundColor, Color backgroundColor, string fontName, int fontSize, bool antialias)
    {
        // Initialize graphics
        Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
        using (Graphics g = Graphics.FromImage(bmp))
        {
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            if (antialias)
            {
                g.SmoothingMode = SmoothingMode.AntiAlias;
                g.TextRenderingHint = TextRenderingHint.AntiAlias;
            }

            // Set colors
            SolidBrush fgBrush = new SolidBrush(foregroundColor);
            SolidBrush bgBrush = new SolidBrush(backgroundColor);

            // paint background
            RectangleF rectF = new RectangleF(0, 0, width, height);
            g.FillRectangle(bgBrush, rectF);

            // Load font
            FontFamily fontFamily = FontFamily.GenericSerif;
            Font font = new Font(fontFamily, fontSize, FontStyle.Regular, GraphicsUnit.Pixel);
            try
            {
                fontFamily = new FontFamily(fontName);
                font = new Font(fontFamily, fontSize, FontStyle.Regular, GraphicsUnit.Pixel);
            }
            catch { }

            // Set font direction & alignment
            StringFormat format = new StringFormat();
            format.Alignment = StringAlignment.Center;
            format.LineAlignment = StringAlignment.Center;

            // Finally, draw the text
            g.DrawString(text, font, fgBrush, rectF, format);

            return bmp;
        }
    }
A: 

It looks like your fullPath might be saving the file with a png extension, and you're telling imgSrc to compress the image using Jpeg compression.

I would verify that the fullPath's extension is jpeg or jpg, and not png.

Here's the msdn doc on the Save.

Joseph
No the full path is something like "\\servcer\share\file.jpg". We are saving jpg's with the extension "jpg". Hence the issue... Later we are creating publishing points on a Windows Media Server to play a SMIL playlist we then have to "Announce" the files and formats to the publishing point when the publishing point starts playing it expects a Jpg file because that is the extension of the file and the content is actually a PNG
RyanFetz
@RyanFetz Well in that case: A) The code you posted is not the issue and it's somewhere else. or B) You have bad data coming in and you can't rely on the extension of the file when determining the compression used.
Joseph
@Joseph See the above edit, This is the code that creates the bitmap object. I was not trying to be rude in the above comment, it is just I had assumed you would think i am actually saving a file with a jpg extension considering we are saving with that format. I apologize.
RyanFetz
@Ryan No worries, I was just doing the best with what you gave me and that was the only conclusions I could come up with that might help you. I'll take a look at your edits and see if I can be of help!
Joseph
+3  A: 

I'd approach this by:

  1. paring down CreateBitmap(). For instance, does the problem appear if you remove everything except line that calls new and the return line? I'd assume it would, but it's worth checking. If on the odd chance the problem disappears with this modification, then use a binary search to see if you can track it down to a particular line.

  2. wrapping the Save call with try/catch to see if somewhere a ExternalException is being silently eaten. Bitmap.Save() (inherited from Image.Save()) says the following about ExternalException:

The image was saved with the wrong image format.

-or-

The image was saved to the same file it was created from.

Is is possible that the files that fail already exist at fullPath in PNG format with the .jpg extension?

JeffH
+1  A: 

Well, I gave it shot and tried to repro the issue with the code given above. Here is roughly what I did:

 Random r = new Random();
 for (int i = 0; i < max; i++)
 {
  System.Diagnostics.Debugger.Break()
  int size = 1 + i;
  int width = 1 + i;
  SaveBitmap(@"C:\Projects\test.jpg", ImageFormat.Jpeg, "hello", size, width, Color.Black, Color.White, "Arial", size, true);
  SaveBitmap(@"C:\Projects\test.png", ImageFormat.Jpeg, "hello", size, width, Color.Black, Color.White, "Arial", size, true);
  SaveBitmap(@"C:\Projects\test.jpg", ImageFormat.Jpeg, "hello", size, width, Color.Black, Color.White, "Arial", size, false);
  SaveBitmap(@"C:\Projects\test.png", ImageFormat.Jpeg, "hello", size, width, Color.Black, Color.White, "Arial", size, false);
 }

 public static void SaveBitmap(string filename, ImageFormat format, string text, int height, int width, Color foregroundColor, Color backgroundColor, string fontName, int fontSize, bool antialias)
 {
  using (Image source = CreateBitmap(text, height, width, foregroundColor, backgroundColor, fontName, fontSize, antialias))
   source.Save(filename, format);

  using (Image imgLoaded = Bitmap.FromFile(filename))
  {
   if (imgLoaded.RawFormat.Guid != format.Guid)
    throw new InvalidOperationException();
  }
 }

This runs without issue and the test for if (imgLoaded.RawFormat.Guid != format.Guid) never breaks into the debugger. I'm guessing you have a little more code than the CreateBitmap routine posted above.

My Recommendation:

Modify your code and insert the verification statement in the above SaveBitmap() just after your call to Image.Save(). Then go break it as see how you got there...

csharptest.net
A: 

Maybe this is an issue with the filename you or the user is specifiing. it could be that if it ends with .png then jpegformat is ignored and a PNG file is generated.

codymanix
A: 

I am also experiencing this issue in a cropping application. The source image file is a JPG. I have attempted several different ImageFormat types, and in all instances the format saved is a PNG with a JPG file extension. Photoshop then complains 'Invalid JPEG marker type'. If I rename the file to .png it opens fine in Photoshop.

Attempting this with a different image, produces a correct JPG format with JPG extension.

I suspect the format of the original file could possibly be to blame. I will post my findings when this issue is resolved.

A: 

Have you tried setting the ImageCodecInfo explicitly?

Dim enc = ImageCodecInfo.GetImageEncoders().ToList().Find(Function(e) e.MimeType = "image/png")
objBitMap.Save(stream, enc, params)
H. Abraham Chavez