我正在创建一些将用作数据URI的占位符图像
Bitmap bitmap = new Bitmap(16, 10);
我做了一些研究,但找不到将这个位图保存为最小可能文件大小的好方法,这就是我想要一个8位PNG的原因。
我的问题是:如何将此位图作为8位PNG保存到文件/ bytearray /流中?任何好的图书馆?
答案 0 :(得分:2)
您可以使用 nQuant (您可以使用nuget安装,或参阅下面的参考资料)执行此操作。以下示例转换磁盘上的图像,并且可以很容易地进行调整以满足您的需求。
public static bool TryNQuantify(string inputFilename, string outputFilename)
{
var quantizer = new nQuant.WuQuantizer();
var bitmap = new Bitmap(inputFilename);
if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
ConvertTo32bppAndDisposeOriginal(ref bitmap);
}
try
{
using (var quantized = quantizer.QuantizeImage(bitmap))
{
quantized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch
{
return false;
}
finally
{
bitmap.Dispose();
}
return true;
}
private static void ConvertTo32bppAndDisposeOriginal(ref Bitmap img)
{
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var gr = Graphics.FromImage(bmp))
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
img.Dispose();
img = bmp;
}
有关详细信息,请参阅:
答案 1 :(得分:0)
我喜欢FreeImage项目,它重量轻,易于使用。下面是创建透明png的示例。您可以轻松地将其包装在方法中并设置宽度和高度以及透明度值。
//create a new bit map
FIBITMAP dib = new FIBITMAP();
//allocate a 16x10 bitmap with 8bit depth
dib = FreeImage.Allocate(16, 10, 8);
//set the transpareny
byte[] Transparency = new byte[1];
Transparency[0] = 0x00;
FreeImage.SetTransparencyTable(dib, Transparency);
//save the bitmap
FreeImage.Save(FREE_IMAGE_FORMAT.FIF_PNG, dib, "C:\\temp\\tp.png", FREE_IMAGE_SAVE_FLAGS.DEFAULT);
答案 2 :(得分:0)
如果您只需要一个小透明图像,为什么要停在8位?你可以直接下降到1位!无论如何你只需要一种颜色,它就会更小。
事实上,你甚至不需要做任何特别的事情。由于新索引位图上的像素都默认为0,这意味着它们引用了第一个调色板颜色,您需要做的就是制作一个新的1bpp图像,并将第一个调色板颜色设置为透明:
public static Bitmap MakePlaceholderImage(Int32 width, Int32 height)
{
Bitmap bm = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
// This colour can't be assigned directly since the .Palette getter actually makes a copy of the palette.
ColorPalette pal = bm.Palette;
pal.Entries[0] = Color.Transparent;
bm.Palette = pal;
return bm;
}
我对此进行了一些实验,并且保存为png,最终结果似乎始终比使用8bpp执行的相同代码的结果小8倍。对于5000x5000图像,文件大小为png几乎不超过3 KiB。
答案 3 :(得分:0)
Google 搜索让我找到了一个 6 年前的帖子,但我找不到我的解决方案。也应该是 6 年,因为它使用了 .Net Framework 的 System.Drawing 库。
此示例代码应该可以帮助任何想要编写 8 位索引 png 的人。
static class SaveImages
{
public static void SaveGrayImage(Bitmap srcImg, string name)
{
Bitmap grayImg = new Bitmap(srcImg.Width, srcImg.Height, PixelFormat.Format8bppIndexed);
var pal = grayImg.Palette;
foreach (int i in Enumerable.Range(0, 256))
pal.Entries[i] = Color.FromArgb(255, i, i, i);
grayImg.Palette = pal;
var data = grayImg.LockBits(new Rectangle(0, 0, srcImg.Width, srcImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
var bytes = new byte[data.Stride * data.Height];
foreach (int y in Enumerable.Range(0, srcImg.Height))
{
foreach (int x in Enumerable.Range(0, srcImg.Width))
{
var colour = srcImg.GetPixel(x, y);
var c = (int)colour.R + (int)colour.G + (int)colour.B;
c /= 3;
bytes[data.Stride * y + x] = (byte)c;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
grayImg.Save(name, ImageFormat.Png);
}
}
编辑:使用调色板添加透明度。
答案 4 :(得分:-1)
1)以每像素8位格式创建位图:
Bitmap bmp = new Bitmap(20, 20, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
有关更多格式,请参阅PixelFormat。
2)绘制到位图...
3)然后将其保存为PNG:
bmp.Save(@"c:\temp\xyz.png", System.Drawing.Imaging.ImageFormat.Png);
创建的文件将具有与bmp
(8位)