将24位bmp转换为16位?

11

我知道.NET Framework自带一个图像转换类(System.Drawing.Image.Save方法)。

但我需要将24位(R8G8B8)的位图图像转换为16位(X1R5G5B5),对于这种类型的转换,我真的一无所知,并且在bmp标头中进行24位到16位的更改也行不通(因为我们需要转换整个图像数据)。

此外,我想知道是否可以控制图片的抖动等参数。

有什么好的建议吗?任何形式的帮助都将不胜感激。


有点晚了,但对于 System.Drawing.Image,您可以使用我绘图库中的 ConvertPixelFormat。它支持抖动,实际上不仅可以用于 GDI+ 图像,而且可以用于任何托管或非托管像素缓冲区。 - György Kőszeg
3个回答

20

格式为Format16bppRgb1555的像素格式被声明了,但GDI+实际上并不支持它。没有主流的视频驱动程序或图像编解码器曾使用过这种像素格式。这是GDI+设计人员猜测可能会发生的事情,他们的时光机不够精确。否则就是从System.Drawing中工作的程序员进行了相当粗糙的复制/粘贴。

Rgb555是可用硬件和编解码器的最接近匹配:

public static Bitmap ConvertTo16bpp(Image img) {
    var bmp = new Bitmap(img.Width, img.Height,
                  System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
    using (var gr = Graphics.FromImage(bmp))
        gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
    return bmp;
}

1

您需要使用编码器参数指定颜色深度来保存位图。

    myEncoder = Encoder.ColorDepth;
    myEncoderParameters = new EncoderParameters(1);

    // Save the image with a color depth of 24 bits per pixel.
    myEncoderParameter = new EncoderParameter(myEncoder, 24L);
    myEncoderParameters.Param[0] = myEncoderParameter;

    myBitmap.Save("MyBitmap.bmp", myImageCodecInfo, myEncoderParameters);

7
我测试了这个,但它不起作用。无论我传递24、8还是32,输出格式都不会改变。我甚至可以传递无效的值,如-8,但颜色深度永远不会改变。 - Elmue
取决于MIME类型。已使tif格式正常工作,没有注意到不同格式的更改。 - e-frank

1
一个非常简单的方法是循环遍历旧位图数据,并将每对r8-g8-b8值转换为x1-r5-g5-b5,类似于这个函数:
char condense(char i)
{ 
  return (char)(i*255.0f/31.0f);
}

short transform(long input)// note that the last 8 bytes are ignored
{
  return condense(input&0xff) || (condense((input&0xff00)>>8)<<5)
    || (condense((intput&0xff0000)>>16)<<10);
}

// and somewhere in your program
{
  int len; // the length of your data in pixels
  char *data; // your data
  char *newdata; // this is where you store the new data; make sure it's allocated

  for(char *p=data; p<data+len*3; p+=3)
    *(short *)newdata=transform(*(long *)data);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接