如何将图像保存为位图图像文件?
How can I save an image as Bitmap Image File?
我做了一个自动图像阈值功能,想把它保存为位图文件。
但是,当我使用C# GDI+的Bitmap.Save
功能时,虽然我将ImageFormat设置为BMP,但它始终是RGB彩色图像文件而不是位图图像文件。
我必须将它保存为位图图像文件,因为打印机只能读取位图图像文件。
也许你会问我位图图像文件是什么。我不是图像处理专家,很抱歉很难解释清楚。但是我可以举个例子:在Photoshop中,有几种颜色模式,比如RGB mode/CMYK mode/Index mode/Grayscale mode/Bitmap 模式,我想将图像保存为Bitmap C#中的模式。
这是 Adobe explain about the Bitmap mode in their website:
Bitmap mode uses one of two color values (black or white) to represent the pixels in an image. Images in Bitmap mode are called bitmapped 1‑bit images because they have a bit depth of 1.
我用谷歌搜索但没有找到任何相关信息。我怎样才能在 C# 中做到这一点?谢谢。
这是我的代码:
Thread T = new Thread(() => {
Bitmap processedBitmap = new Bitmap(@"G:\0001.jpg");
BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
int bytesPerPixel = Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
int byteCount = bitmapData.Stride * processedBitmap.Height;
byte[] pixels = new byte[byteCount];
IntPtr ptrFirstPixel = bitmapData.Scan0;
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
for (int y = 0; y < heightInPixels; y++)
{
int currentLine = y * bitmapData.Stride;
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
int oldBlue = pixels[currentLine + x];
int oldGreen = pixels[currentLine + x + 1];
int oldRed = pixels[currentLine + x + 2];
double averageColor = (oldBlue + oldGreen + oldRed) / 3;
int NewC;
if (averageColor > 200)
{
NewC = 255;
}
else
{
NewC = 0;
}
// calculate new pixel value
pixels[currentLine + x] = (byte)NewC;
pixels[currentLine + x + 1] = (byte)NewC;
pixels[currentLine + x + 2] = (byte)NewC;
}
}
// copy modified bytes back
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
processedBitmap.UnlockBits(bitmapData);
processedBitmap.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Sucess!");
});
T.Start();
要将 BMP 对象保存到文件,您只需这样做:
bmp.Save("c:\Path\To\File\image.bmp, ImageFormat.Bmp);
你还有别的事吗?
我相信 OP 指的是此 adobe link 中的最后一种图像
位图只是数据的容器,您存储的数据格式由 PixelFormat 设置定义。可以看出"Adobe"Bitmap模式是2色格式模式,对应C#Bitmap中的PixelFormat.Format1bppIndexed
您有几个以 PixelFormat 作为参数的位图构造函数。
public Bitmap (int width, int height, System.Drawing.Imaging.PixelFormat format);
public Bitmap (int width, int height, int stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0);
您的源图像是 24 位图像。
当您进行颜色平均时,您将使用以下代码写回图像缓冲区:
pixels[currentLine + x] = (byte)NewC;
pixels[currentLine + x + 1] = (byte)NewC;
pixels[currentLine + x + 2] = (byte)NewC;
你又写回了 24 位。
因此,例如,如果您的 RGB 原始值为 (202, 203, 249),则 NewC 将为 218,然后您将其阈值返回到 255,因此您写回 (255,255,255) 仍然是一个 RGB 值,它仅用于白色的。
然后使用
保存该图像
processedBitmap.Save("G:\aaa.bmp", ImageFormat.Bmp);
ImageFormat class 只是设置图像的类型,如 jpeg、png 等。
正如您所发现的,您仍然输出 24 位图像。
所以你想要的是将图像保存为纯每像素 1 位的黑白图像。
为此,您需要指定要保存的图像的 PixelFormat,特别是您需要 PixelFormat Format1bppIndexed.
如果您改为将代码的相关位更改为:
...
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
processedBitmap.UnlockBits(bitmapData);
Bitmap clone = processedBitmap.Clone(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), PixelFormat.Format1bppIndexed);
clone.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Success!");
现在您的输出克隆将是 1bpp 图像。
但是,您可以进一步简化代码,因为这个克隆函数实际上可以为您完成所有工作,您可以将代码简化为以下内容。
Bitmap processedBitmap = new Bitmap(@"G:[=13=]01.jpg");
Bitmap clone = processedBitmap.Clone(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), PixelFormat.Format1bppIndexed);
clone.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Success!");
请注意输出略有不同。
这是输出的一些测试样本。
这是我的输入图像:
使用阈值代码输出图像:
并且仅使用克隆方法输出图像:
我做了一个自动图像阈值功能,想把它保存为位图文件。
但是,当我使用C# GDI+的Bitmap.Save
功能时,虽然我将ImageFormat设置为BMP,但它始终是RGB彩色图像文件而不是位图图像文件。
我必须将它保存为位图图像文件,因为打印机只能读取位图图像文件。
也许你会问我位图图像文件是什么。我不是图像处理专家,很抱歉很难解释清楚。但是我可以举个例子:在Photoshop中,有几种颜色模式,比如RGB mode/CMYK mode/Index mode/Grayscale mode/Bitmap 模式,我想将图像保存为Bitmap C#中的模式。
这是 Adobe explain about the Bitmap mode in their website:
Bitmap mode uses one of two color values (black or white) to represent the pixels in an image. Images in Bitmap mode are called bitmapped 1‑bit images because they have a bit depth of 1.
我用谷歌搜索但没有找到任何相关信息。我怎样才能在 C# 中做到这一点?谢谢。
这是我的代码:
Thread T = new Thread(() => {
Bitmap processedBitmap = new Bitmap(@"G:\0001.jpg");
BitmapData bitmapData = processedBitmap.LockBits(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), ImageLockMode.ReadWrite, processedBitmap.PixelFormat);
int bytesPerPixel = Bitmap.GetPixelFormatSize(processedBitmap.PixelFormat) / 8;
int byteCount = bitmapData.Stride * processedBitmap.Height;
byte[] pixels = new byte[byteCount];
IntPtr ptrFirstPixel = bitmapData.Scan0;
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
for (int y = 0; y < heightInPixels; y++)
{
int currentLine = y * bitmapData.Stride;
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
int oldBlue = pixels[currentLine + x];
int oldGreen = pixels[currentLine + x + 1];
int oldRed = pixels[currentLine + x + 2];
double averageColor = (oldBlue + oldGreen + oldRed) / 3;
int NewC;
if (averageColor > 200)
{
NewC = 255;
}
else
{
NewC = 0;
}
// calculate new pixel value
pixels[currentLine + x] = (byte)NewC;
pixels[currentLine + x + 1] = (byte)NewC;
pixels[currentLine + x + 2] = (byte)NewC;
}
}
// copy modified bytes back
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
processedBitmap.UnlockBits(bitmapData);
processedBitmap.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Sucess!");
});
T.Start();
要将 BMP 对象保存到文件,您只需这样做:
bmp.Save("c:\Path\To\File\image.bmp, ImageFormat.Bmp);
你还有别的事吗?
我相信 OP 指的是此 adobe link 中的最后一种图像 位图只是数据的容器,您存储的数据格式由 PixelFormat 设置定义。可以看出"Adobe"Bitmap模式是2色格式模式,对应C#Bitmap中的PixelFormat.Format1bppIndexed
您有几个以 PixelFormat 作为参数的位图构造函数。
public Bitmap (int width, int height, System.Drawing.Imaging.PixelFormat format);
public Bitmap (int width, int height, int stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0);
您的源图像是 24 位图像。 当您进行颜色平均时,您将使用以下代码写回图像缓冲区:
pixels[currentLine + x] = (byte)NewC;
pixels[currentLine + x + 1] = (byte)NewC;
pixels[currentLine + x + 2] = (byte)NewC;
你又写回了 24 位。
因此,例如,如果您的 RGB 原始值为 (202, 203, 249),则 NewC 将为 218,然后您将其阈值返回到 255,因此您写回 (255,255,255) 仍然是一个 RGB 值,它仅用于白色的。
然后使用
processedBitmap.Save("G:\aaa.bmp", ImageFormat.Bmp);
ImageFormat class 只是设置图像的类型,如 jpeg、png 等。 正如您所发现的,您仍然输出 24 位图像。
所以你想要的是将图像保存为纯每像素 1 位的黑白图像。 为此,您需要指定要保存的图像的 PixelFormat,特别是您需要 PixelFormat Format1bppIndexed.
如果您改为将代码的相关位更改为:
...
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
processedBitmap.UnlockBits(bitmapData);
Bitmap clone = processedBitmap.Clone(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), PixelFormat.Format1bppIndexed);
clone.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Success!");
现在您的输出克隆将是 1bpp 图像。
但是,您可以进一步简化代码,因为这个克隆函数实际上可以为您完成所有工作,您可以将代码简化为以下内容。
Bitmap processedBitmap = new Bitmap(@"G:[=13=]01.jpg");
Bitmap clone = processedBitmap.Clone(new Rectangle(0, 0, processedBitmap.Width, processedBitmap.Height), PixelFormat.Format1bppIndexed);
clone.Save("G:\aaa.bmp", ImageFormat.Bmp);
MessageBox.Show("Success!");
请注意输出略有不同。 这是输出的一些测试样本。
这是我的输入图像:
使用阈值代码输出图像:
并且仅使用克隆方法输出图像: