bpp是每像素位数,所以32bpp意味着R/G/B/A的值为8/8/8/8。
就像.NET中有一个枚举用于表示这些“System.Drawing.Imaging.PixelFormat”。
现在,一旦我有了包含我的图形的 Bitmap 或 Image 对象,我该如何将其保存到文件中,我应该使用什么格式?
哪种图像文件格式(JPEG/GIF/PNG)支持低位深度,例如16bpp或8bpp (而非通常的32bpp或24bpp)
bpp是每像素位数,所以32bpp意味着R/G/B/A的值为8/8/8/8。
就像.NET中有一个枚举用于表示这些“System.Drawing.Imaging.PixelFormat”。
现在,一旦我有了包含我的图形的 Bitmap 或 Image 对象,我该如何将其保存到文件中,我应该使用什么格式?
哪种图像文件格式(JPEG/GIF/PNG)支持低位深度,例如16bpp或8bpp (而非通常的32bpp或24bpp)
我认为其他回答者没有测试他们的代码,因为GDI+ PNG不支持Encoder.BitDepth EncoderParameter。实际上,唯一支持它的编解码器是TIFF。
在保存图像之前,您需要更改图像的PixelFormat以产生输出的效果。但这并不总是会产生您期望的像素格式。有关哪些像素格式会转化成什么的更多信息,请参见我的这篇文章。
至于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;
}
不幸的是,这些转换可能会产生一些非常糟糕的输出。特别是在执行有损转换(高位深度到低位深度)的情况下,这一点尤为明显。
这是从.Net中产生最小可能的PNG格式。请注意,它是黑白的 - 甚至不是灰度。对于文档非常有用。
使用者代码:
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
这是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
所有的图像格式都有效地支持低位深度。如果不需要,您可以将最后几位留空。GIF仅支持低色彩;您只能使用256种颜色。
试试这个:
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);
}
未经测试的代码 -
Image myImage = new Image();
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8);
myImage.Save(somestream, ImageFormat.Png, parameters);