2009-01-27 34 views
7

bpp =每像素的位數,所以32bpp表示R/G/B/A爲8/8/8/8。生成低位深度的圖像文件?

與.NET一樣,這些「System.Drawing.Imaging.PixelFormat」有一個枚舉。

現在,一旦我有一個位圖圖片對象與我的圖形,我將如何保存到一個文件/我會用什麼格式?

什麼圖像文件格式(JPEG/GIF/PNG)支持低比特深度像16bpp的或8bpp的(而不是通常的32bpp的或24 bpp的)

回答

3

試試這個:

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); 
} 
+3

這不實際工作時 - 請查看下 – benpage 2013-07-11 01:17:02

+1

裏克的答案似乎不PNG編解碼器使用Encoder.ColorDepth參數。 – psaxton 2017-09-19 17:43:36

-1

未經測試的代碼 -

Image myImage = new Image(); 
EncoderParameters parameters = new EncoderParameters(1); 
parameters.Param[0] = new EncoderParameter(Encoder.ColorDepth, 8); 
myImage.Save(somestream, ImageFormat.Png, parameters); 

看在System.Drawing.Imaging命名空間中播放,並使用Encoder.xxx參數設置和image.Save方法播放。 HTH。

更新 還值得注意的是,如果你想有一個小的圖像(低字節數),你可以嘗試保存爲JPEG的使用Encoder.Compression壓縮,但在圖像質量成本。

0

所有的圖像格式有效地支持低比特深度。如果不需要,您只需保留最後一些未使用的位。 GIF只支持低色彩;你只能使用256種顏色。

12

我不認爲對方的回答測試了他們的代碼,因爲GDI + PNG不支持Encoder.BitDepth EncoderParameter。事實上,唯一的編解碼器就是TIFF。

您需要在保存前更改圖像的PixelFormat,以便對輸出產生任何效果。這並不總是會產生你期望的PixelFormat。請參閱my post here瞭解有關哪些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; 
} 

不幸的是,這些轉換會產生一些非常糟糕的輸出。在執行有損轉換(高位深度降低)的情況下尤其如此。

1

每像素一位

這會從.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 

Make1bpp

這就是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