使用C#调整透明图像大小

有没有人有秘密的公式来调整透明图像(主要是GIF), 没有任何质量损失 – 这是怎么回事?

我尝试了很多东西,我得到的最接近的东西还不够好。

看看我的主要形象:

http://sofzh.miximages.com/c%23/main.gif

然后缩放图像:

http://sofzh.miximages.com/c%23/ScaledImage.gif

//Internal resize for indexed colored images void IndexedRezise(int xSize, int ySize) { BitmapData sourceData; BitmapData targetData; AdjustSizes(ref xSize, ref ySize); scaledBitmap = new Bitmap(xSize, ySize, bitmap.PixelFormat); scaledBitmap.Palette = bitmap.Palette; sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); try { targetData = scaledBitmap.LockBits(new Rectangle(0, 0, xSize, ySize), ImageLockMode.WriteOnly, scaledBitmap.PixelFormat); try { xFactor = (Double)bitmap.Width / (Double)scaledBitmap.Width; yFactor = (Double)bitmap.Height / (Double)scaledBitmap.Height; sourceStride = sourceData.Stride; sourceScan0 = sourceData.Scan0; int targetStride = targetData.Stride; System.IntPtr targetScan0 = targetData.Scan0; unsafe { byte* p = (byte*)(void*)targetScan0; int nOffset = targetStride - scaledBitmap.Width; int nWidth = scaledBitmap.Width; for (int y = 0; y < scaledBitmap.Height; ++y) { for (int x = 0; x < nWidth; ++x) { p[0] = GetSourceByteAt(x, y); ++p; } p += nOffset; } } } finally { scaledBitmap.UnlockBits(targetData); } } finally { bitmap.UnlockBits(sourceData); } } 

我正在使用上面的代码,进行索引resize。

有没有人有改进的想法?

如果在缩放后没有要求保留文件类型,我建议采用以下方法。

 using (Image src = Image.FromFile("main.gif")) using (Bitmap dst = new Bitmap(100, 129)) using (Graphics g = Graphics.FromImage(dst)) { g.SmoothingMode = SmoothingMode.AntiAlias; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.DrawImage(src, 0, 0, dst.Width, dst.Height); dst.Save("scale.png", ImageFormat.Png); } 

结果将具有非常好的抗锯齿边缘

  • 删除已被广告替换的图像小屋图像

如果您必须以gif格式导出图像,那么您就可以使用; GDI +与gif不兼容。 有关更多信息,请参阅此博客文章

编辑:我忘了处理示例中的位图; 它已得到纠正

这是我用于一些利用GDI +的应用程序的基本resize函数

 ///  /// Resize image with GDI+ so that image is nice and clear with required size. ///  /// Image to resize /// New height to resize to. /// New width to resize to. /// Image object resized to new dimensions. ///  public static Image ImageResize(Image SourceImage, Int32 NewHeight, Int32 NewWidth) { System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(NewWidth, NewHeight, SourceImage.PixelFormat); if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format1bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format4bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format8bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Undefined | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.DontCare | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppArgb1555 | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppGrayScale) { throw new NotSupportedException("Pixel format of the image is not supported."); } System.Drawing.Graphics graphicsImage = System.Drawing.Graphics.FromImage(bitmap); graphicsImage.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality; graphicsImage.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; graphicsImage.DrawImage(SourceImage, 0, 0, bitmap.Width, bitmap.Height); graphicsImage.Dispose(); return bitmap; } 

如果它可以与GIF配合使用,我不记得我的头脑,但你可以尝试一下。

注意:我不能完全赞成这个function。 我从网上的其他一些样品拼凑了一些东西,并使它符合我的需求8 ^ D.

我认为问题在于你正在进行基于扫描线的resize,无论你多么努力地调整它都会导致锯齿状。 良好的图像resize质量要求您做一些工作来计算resize的像素覆盖的预resize的像素的平均颜色。

经营这个网站的人有一篇博文,讨论了一些图像大小调整算法。 您可能需要双三次图像缩放算法。

更好的图像大小调整

对于任何可能尝试使用Markus Olsson的解决方案来动态调整图像大小并将其写入响应流的人。

这不起作用:

 Response.ContentType = "image/png"; dst.Save( Response.OutputStream, ImageFormat.Png ); 

但这会:

 Response.ContentType = "image/png"; using (MemoryStream stream = new MemoryStream()) { dst.Save( stream, ImageFormat.Png ); stream.WriteTo( Response.OutputStream ); } 

虽然PNG肯定比GIF更好,但偶尔会有一个需要保留GIF格式的用例。

使用GIF或8位PNG,您必须解决量化问题。

量化是您选择最佳保留和表示图像的256种(或更少)颜色,然后将RGB值转换回索引的位置。 当您执行resize操作时,理想的调色板会更改,因为您正在混合颜色和更改余额。

对于轻微的resize,如10-30%,您可以保留原始调色板。

但是,在大多数情况下,您需要重新量化。

可供选择的主要两种算法是Octree和nQuant。 Octree非常快,并且做得非常好,特别是如果你可以叠加智能抖动算法。 nQuant需要至少80MB的RAM来执行编码(它构建完整的直方图),并且通常慢20-30倍(平均图像上每个编码1-5秒)。 但是,它有时会产生比Octree更高的图像质量,因为它不会“舍入”值以保持一致的性能。

在imageresizing.net项目中实现透明GIF和动画GIF支持时,我选择了Octree。 一旦您控制了图像调色板,透明度支持就不那么难了。