C# 生成低位深度的图像文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/483014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generate image file with low bit depths?
提问by TheFlash
bpp= bits per pixel, so 32bpp means 8/8/8/8 for R/G/B/A.
bpp= 每像素位数,因此 32bpp 表示 R/G/B/A 的 8/8/8/8。
Like .NET has an enum for these "System.Drawing.Imaging.PixelFormat".
就像 .NET 对这些“System.Drawing.Imaging.PixelFormat”有一个枚举。
Now once I have a Bitmapor Imageobject with my graphics, how would I save itto a file / what format would I use?
现在,一旦我的图形有了位图或图像对象,我将如何将其保存到文件中/我将使用什么格式?
What image file format (JPEG/GIF/PNG) supports low bit-depths like 16bpp or 8bpp (instead of the usual 32bpp or 24bpp)
什么图像文件格式 (JPEG/GIF/PNG) 支持低位深度,如 16bpp 或 8bpp (而不是通常的 32bpp 或 24bpp)
采纳答案by Vojislav Stojkovic
Try this:
尝试这个:
ImageCodecInfo pngCodec = ImageCodecInfo.GetImageEncoders().Where(codec => codec.FormatID.Equals(ImageFormat.Png.Guid)).FirstOrDefault();
if (pngCodec != null)
{
EncoderParameters parameters = new EncoderParameters();
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
myImage.Save(myStream, pngCodec, parameters);
}
回答by Dead account
Untested code -
未经测试的代码 -
Image myImage = new Image();
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
myImage.Save(somestream, ImageFormat.Png, parameters);
Look at the System.Drawing.Imaging namespace and have a play with the Encoder.xxx parameter settings and the image.Save method. HTH.
查看 System.Drawing.Imaging 命名空间并尝试使用 Encoder.xxx 参数设置和 image.Save 方法。哈。
Updatealso worth noting that if you want a small image (low byte count) you can try saving as JPEG an using Encoder.Compression compression but at image quality cost.
更新还值得注意的是,如果您想要一个小图像(低字节数),您可以尝试使用 Encoder.Compression 压缩将其保存为 JPEG,但要以图像质量为代价。
回答by MSalters
All image formats effectively support low bit depths. You just leave the last bits unused, if not needed. GIF only supports low-color; you're restricted to 256 colors.
所有图像格式都有效地支持低位深度。如果不需要,您只需保留最后一位不使用。GIF 仅支持低色;你被限制为 256 种颜色。
回答by Rick Minerich
I don't think the other's answering tested their code as GDI+ PNG does not support the Encoder.BitDepth EncoderParameter. In fact, the only Codec which does is TIFF.
我不认为对方的回答测试了他们的代码,因为 GDI+ PNG 不支持 Encoder.BitDepth EncoderParameter。事实上,唯一能做的编解码器是 TIFF。
You need to change your image's PixelFormat before saving in order to have any effect out the output. This won't always produce the PixelFormat you expect. See my post herefor more information on which PixelFormats turn into what.
您需要在保存之前更改图像的 PixelFormat,以便对输出产生任何影响。这不会总是产生您期望的 PixelFormat。有关哪些 PixelFormats 变成什么的更多信息,请参阅我的帖子。
As for PixelFormat conversions, something like the following will work:
至于 PixelFormat 转换,类似以下内容将起作用:
private Bitmap ChangePixelFormat(Bitmap inputImage, PixelFormat newFormat)
{
Bitmap bmp = new Bitmap(inputImage.Width, inputImage.Height, newFormat);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(inputImage, 0, 0);
}
return bmp;
}
Unfortunately, these conversions can produce some really bad output. This is especially true in the case where you are performing a lossy conversion (high bit depth to lower).
不幸的是,这些转换会产生一些非常糟糕的输出。在您执行有损转换(高位深到低位)的情况下尤其如此。
回答by FastAl
One bit per pixel
每像素一位
This produces the smallest possible PNG from .Net only. Note that it is b&w - not even grayscale. Useful for documents.
这仅从 .Net 生成尽可能小的 PNG。请注意,它是黑白的 - 甚至不是灰度。对文档有用。
Consumer code:
消费者代码:
Dim src = (the original bitmap)
Using img = New Bitmap(src.Width, src.Height, PixelFormat.Format16bppRgb555) ' Provided Make1bpp function requires this
img.SetResolution(src.HorizontalResolution, src.VerticalResolution)
Using g = Graphics.FromImage(img)
g.Clear(Color.White) ' remove transparancy
g.DrawImage(src, 0, 0, src.Width, src.Height)
End Using
Using img2 As Bitmap = Make1bpp(img)
img2.SetResolution(src.HorizontalResolution, src.VerticalResolution)
Dim myencoder = (From parm In ImageCodecInfo.GetImageEncoders() Where parm.MimeType = "image/png").First()
Dim encoderParams = New EncoderParameters(1)
encoderParams.Param(0) = New EncoderParameter(Encoder.ColorDepth, 8L)
If IO.File.Exists(pngName) Then
IO.File.Delete(pngName)
End If
img2.Save(pngName, myencoder, encoderParams)
End Using
End Using
Make1bpp
制作1bpp
This is what the PNG encoder cares about
这就是PNG编码器关心的
Function Make1bpp(ByVal bmpIN As Bitmap) As Bitmap
Dim bmpOUT As Bitmap
bmpOUT = NewBitmap(bmpIN.Width, bmpIN.Height, PixelFormat.Format1bppIndexed)
bmpOUT.SetResolution(bmpIN.HorizontalResolution, bmpIN.VerticalResolution)
' seems like I've got this crap in this program about 100x.
If bmpIN.PixelFormat <> PixelFormat.Format16bppRgb555 Then
Throw New ApplicationException("hand-coded routine can only understand image format of Format16bppRgb555 but this image is " & _
bmpIN.PixelFormat.ToString & ". Either change the format or code this sub to handle that format, too.")
End If
' lock image bytes
Dim bmdIN As BitmapData = bmpIN.LockBits(New Rectangle(0, 0, bmpIN.Width, bmpIN.Height), _
Imaging.ImageLockMode.ReadWrite, bmpIN.PixelFormat)
' lock image bytes
Dim bmdOUT As BitmapData = bmpOUT.LockBits(New Rectangle(0, 0, bmpOUT.Width, bmpOUT.Height), _
Imaging.ImageLockMode.ReadWrite, bmpOUT.PixelFormat)
' Allocate room for the data.
Dim bytesIN(bmdIN.Stride * bmdIN.Height) As Byte
Dim bytesOUT(bmdOUT.Stride * bmdOUT.Height) As Byte
' Copy the data into the PixBytes array.
Marshal.Copy(bmdIN.Scan0, bytesIN, 0, CInt(bmdIN.Stride * bmpIN.Height))
' > this val = white pix. (each of the 3 pix in the rgb555 can hold 32 levels... 2^5 huh.)
Dim bThresh As Byte = CByte((32 * 3) * 0.66)
' transfer the pixels
For y As Integer = 0 To bmpIN.Height - 1
Dim outpos As Integer = y * bmdOUT.Stride
Dim instart As Integer = y * bmdIN.Stride
Dim byteval As Byte = 0
Dim bitpos As Byte = 128
Dim pixval As Integer
Dim pixgraylevel As Integer
For inpos As Integer = instart To instart + bmdIN.Stride - 1 Step 2
pixval = 256 * bytesIN(inpos + 1) + bytesIN(inpos) ' DEPENDANT ON Format16bppRgb555
pixgraylevel = ((pixval) And 31) + ((pixval >> 5) And 31) + ((pixval >> 10) And 31)
If pixgraylevel > bThresh Then ' DEPENDANT ON Format16bppRgb555
byteval = byteval Or bitpos
End If
bitpos = bitpos >> 1
If bitpos = 0 Then
bytesOUT(outpos) = byteval
byteval = 0
bitpos = 128
outpos += 1
End If
Next
If bitpos <> 0 Then ' stick a fork in any unfinished busines.
bytesOUT(outpos) = byteval
End If
Next
' unlock image bytes
' Copy the data back into the bitmap.
Marshal.Copy(bytesOUT, 0, _
bmdOUT.Scan0, bmdOUT.Stride * bmdOUT.Height)
' Unlock the bitmap.
bmpIN.UnlockBits(bmdIN)
bmpOUT.UnlockBits(bmdOUT)
' futile attempt to free memory.
ReDim bytesIN(0)
ReDim bytesOUT(0)
' return new bmp.
Return bmpOUT
End Function