【问题标题】:Bitmap Save in .Net is saving the image in an incorrect format?.Net 中的位图保存是否以不正确的格式保存图像?
【发布时间】:2010-11-23 18:37:13
【问题描述】:

我们有一段代码可以将 .Net System.Drawing.Bitmap 保存到文件中。 Save 调用指定了文件位置以及我们期望将图像数据保存为 Jpeg 的 ImageFormat,因此代码如下所示:

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
}

出于某种原因,此方法不时将 PNG 图像生成为 .jpg 文件。大多数时候这没什么大不了的,但是项目的另一部分存在这些文件不是实际 jpeg(Windows 媒体服务)的问题。

感谢您的帮助,有人见过吗?

注意: 完整路径类似于“\servcer\share\file.jpg”。我们正在使用扩展名“jpg”保存 jpg。因此问题...稍后我们在 Windows Media Server 上创建发布点以播放 SMIL 播放列表,然后我们必须在发布点开始播放时将文件和格式“宣布”到发布点它需要一个 Jpg 文件,因为是文件的扩展名,内容实际上是PNG

这是创建传递给上述方法的 BitpMap 对象的实际代码...

        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;
        }
    }

【问题讨论】:

  • 你能多贴一点代码吗?我认为问题出在调用 CreateBitmap 的方法中,或者在 IngestImage 方法中。
  • 问题不在您发布的代码中。如果你可以发布一个单独编译的类并且可以重现行为,我会再看一次......在反射器中查看 Image 类时,有一些路径看起来很奇怪(比如原始格式的缓存图像和一些技巧,以便在某些情况下原始格式从 jpeg 切换到 png),但是当新生成的图像只保存一次时,它们都无法解释问题......

标签: c# .net png bitmap jpeg


【解决方案1】:

我会通过以下方式解决这个问题:

  1. 削减CreateBitmap()。例如,如果您删除除了调用newreturn 行之外的所有内容,是否会出现问题?我认为它会,但值得检查。如果此修改后问题消失了,请使用binary search 来查看是否可以将其追踪到特定行。

  2. try/catch 包装Save 调用,以查看ExternalException 是否在某处被默默吃掉。 Bitmap.Save()(继承自Image.Save())关于ExternalException的说法如下:

图片保存错误 图片格式。

-或-

图像被保存到同一个文件 它是从创建的。

失败的文件是否可能已经存在于fullPath,格式为PNG格式,扩展名为.jpg?

【讨论】:

    【解决方案2】:

    我在裁剪应用程序中也遇到了这个问题。 源图像文件是 JPG。 我尝试了几种不同的 ImageFormat 类型,在所有情况下,保存的格式都是带有 JPG 文件扩展名的 PNG。 Photoshop 然后抱怨“无效的 JPEG 标记类型”。 如果我将文件重命名为 .png,它将在 Photoshop 中正常打开。

    尝试使用不同的图像,生成带有 JPG 扩展名的正确 JPG 格式。

    我怀疑原始文件的格式可能是罪魁祸首。 解决此问题后,我将发布我的发现。

    【讨论】:

      【解决方案3】:

      好吧,我试了一下,并尝试用上面给出的代码重现问题。这大致是我所做的:

          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();
              }
          }
      

      这运行没有问题,并且 if (imgLoaded.RawFormat.Guid != format.Guid) 的测试永远不会进入调试器。我猜你的代码比上面发布的 CreateBitmap 例程多一点。

      我的建议:

      在调用 Image.Save() 之后,修改您的代码并在上述 SaveBitmap() 中插入验证语句。然后去打破它,看看你是怎么到那里的......

      【讨论】:

        【解决方案4】:

        这可能是您或用户指定的文件名的问题。如果它以 .png 结尾,则可能会忽略 jpegformat 并生成 PNG 文件。

        【讨论】:

          【解决方案5】:

          您是否尝试过明确设置 ImageCodecInfo?

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

          【讨论】:

            【解决方案6】:

            你可以试试这个来保存文件

            public bool ResizeImage(string OriginalFilepath, string NewFilepath)
                {
                    Bitmap original = (Bitmap)Image.FromFile(OriginalFilepath);
                    Bitmap resized = new Bitmap(original, new Size(width,height));
                    resized.Save(NewFilepath.jpeg);
            
                }
            

            【讨论】:

              【解决方案7】:

              C# Win7(64bit) VS 2010 Bitmap.Save("wnd.bmp") 以 png 格式保存。 MainWnd 是我捕获并尝试以位图形式保存到文件的 C# 表单。

                      Bitmap bmp = new Bitmap(MainWnd.ActiveForm.Width, MainWnd.ActiveForm.Height);
                      Rectangle crec = MainWnd.ActiveForm.ClientRectangle;
                      Rectangle r = this.ClientRectangle;
                      MainWnd.ActiveForm.DrawToBitmap(bmp, r);
                      bmp.Save("wnd.bmp");  // saves as PNG not BMP !!
              

              00000000 89 50 4E 47 0D 0A 1A 0A - 00 00 00 0D 49 48 44 52 ‰PNG........IHDR 00000010 00 00 04 0B 00 00 02 E6 - 08 06 00 00 00 24 30 1D ..........$0。 00000020 D1 00 00 00 01 73 52 47 - 42 00 AE CE 1C E9 00 00 Ñ....sRGB.®Î.é..

              【讨论】:

                【解决方案8】:

                看起来您的 fullPath 可能正在使用 png 扩展名保存文件,并且您告诉 imgSrc 使用 Jpeg 压缩来压缩图像。

                我会验证 fullPath 的扩展名是 jpeg 或 jpg,而不是 png。

                这是存档中的msdn doc

                【讨论】:

                • 没有完整路径类似于“\\servcer\share\file.jpg”。我们正在使用扩展名“jpg”保存 jpg。因此问题...稍后我们在 Windows Media Server 上创建发布点以播放 SMIL 播放列表,然后我们必须在发布点开始播放时将文件和格式“宣布”到发布点它需要一个 Jpg 文件,因为是文件的扩展名,内容实际上是一个PNG
                • @RyanFetz 那么在这种情况下:A)您发布的代码不是问题,它在其他地方。或 B) 您有错误的数据传入,并且在确定使用的压缩时不能依赖文件的扩展名。
                • @Joseph 参见上面的编辑,这是创建位图对象的代码。我并不想在上面的评论中粗鲁,只是我假设你会认为我实际上是在保存一个带有 jpg 扩展名的文件,因为我们正在使用该格式保存。我很抱歉。
                • @Ryan 不用担心,我只是用你给我的东西做得最好,这是我能得出的唯一可能对你有帮助的结论。我会看看你的编辑,看看我能不能帮上忙!
                猜你喜欢
                • 1970-01-01
                • 2023-04-07
                • 2019-02-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-06-25
                相关资源
                最近更新 更多