Android:将位图转换为单色位图(每像素 1 位)
我想将位图打印到移动蓝牙打印机 (Bixolon SPP-R200) - SDK 不提供打印内存中图像的直接方法。所以我考虑像这样转换位图:
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
转换为单色位图。我使用画布在上面给定的位图上绘制黑色文本,效果很好。但是,当我将上面的位图转换为 ByteArray 时,打印机似乎无法处理这些字节。我怀疑我需要一个每个像素一位的数组(一个像素要么是白色 = 1,要么是黑色 = 0)。
由于似乎没有方便的、开箱即用的方法来做到这一点,我的一个想法是使用:
bitmap.getPixels(pixels, offset, stride, x, y, width, height)
获取像素。我想,我必须按如下方式使用它:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int [] pixels = new int [width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
但是 - 我不确定一些事情:
- 在 getPixels 中 - 简单地将宽度作为“Stride”参数传递是否有意义?
- 我想我必须评估每个像素的颜色信息并将其切换为黑色或白色(并且我会将这个值写入一个新的目标字节数组中,最终将其传递给打印机)?
- 如何最好地评估每个像素的颜色信息,以决定它应该是黑色还是白色? (渲染的位图是白色背景上的黑色痛苦)
这种方法有意义吗?有更简单的方法吗?仅将位图设为黑色和黑色是不够的。白色,主要问题是将每个像素的颜色信息减少为一位。
更新
根据 Reuben 的建议,我首先将位图转换为单色位图。然后我将迭代每个像素:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// Iterate over height
for (int y = 0; y < height; y++) {
int offset = y * height;
// Iterate over width
for (int x = 0; x < width; x++) {
int pixel = bitmap.getPixel(x, y);
}
}
现在 Reuben 建议“读取每个 32 位像素的最低字节”——这与我关于如何评估像素颜色的问题有关。我在这方面的最后一个问题:我是否可以通过简单地这样做来获得最低字节:
// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
I want to print a Bitmap to a mobile Bluetooth Printer (Bixolon SPP-R200) - the SDK doesn't offer direkt methods to print an in-memory image. So I thought about converting a Bitmap like this:
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
To a Monochrome Bitmap. I am drawing black text on above given Bitmap using a Canvas, which works well. However, when I convert the above Bitmap to a ByteArray, the printer seems to be unable to handle those bytes. I suspect I need an Array with one Bit per Pixel (a Pixel would be either white = 1 or black = 0).
As there seems to be no convenient, out of the box way to do that, one idea I had was to use:
bitmap.getPixels(pixels, offset, stride, x, y, width, height)
to Obtain the pixels. I assume, I'd have to use it as follows:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int [] pixels = new int [width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
However - I am not sure about a few things:
- In getPixels - does it make sense to simply pass the width as the "Stride" argument?
- I guess I'd have to evaluate the color information of each pixel and either switch it to black or white (And I'd write this value in a new target byte array which I would ultimately pass to the printer)?
- How to best evaluate each pixel color information in order to decide that it should be black or white? (The rendered Bitmap is black pain on a white background)
Does this approach make sense at all? Is there an easier way? It's not enough to just make the bitmap black & white, the main issue is to reduce the color information for each pixel into one bit.
UPDATE
As suggested by Reuben I'll first convert the Bitmap to a monochrome Bitmap. and then I'll iterate over each pixel:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// Iterate over height
for (int y = 0; y < height; y++) {
int offset = y * height;
// Iterate over width
for (int x = 0; x < width; x++) {
int pixel = bitmap.getPixel(x, y);
}
}
Now Reuben suggested to "read the lowest byte of each 32-bit pixel" - that would relate to my question about how to evaluate the pixel color. My last question in this regard: Do I get the lowest byte by simply doing this:
// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以使用 ColorMatrix 将图像转换为单色 32bpp。
这简化了彩色→单色转换。现在您只需执行 getPixels() 并读取每个 32 位像素的最低字节。如果<128则为0,否则为1。
You can convert the image to monochrome 32bpp using a ColorMatrix.
That simplifies the color->monochrome conversion. Now you can just do a getPixels() and read the lowest byte of each 32-bit pixel. If it's <128 it's a 0, otherwise it's a 1.
好吧,我认为现在回复这个帖子已经很晚了,但我有时也在研究这些东西,并决定构建我自己的库,将任何 jpg 或 png 图像转换为 1bpp .bmp。大多数需要 1bpp 图像的打印机都支持此图像(已在其中之一上进行测试:))。
在这里您可以找到库以及使用它来制作单色单通道图像的测试项目。请随意更改它..:)
https://github.com/acdevs/1bpp-monochrome- android
享受..!! :)
Well I think its quite late now to reply to this thread but I was also working on this stuff sometimes back and decided to build my own library that will convert any jpg or png image to 1bpp .bmp. Most printers that require 1bpp images will support this image (tested on one of those :)).
Here you can find library as well as a test project that uses it to make a monochrome single channel image. Feel free to change it..:)
https://github.com/acdevs/1bpp-monochrome-android
Enjoy..!! :)
您应该将每个像素转换为 HSV 空间,并使用该值来确定目标图像上的像素应该是黑色还是白色:
You should convert each pixel into HSV space and use the value to determine if the Pixel on the target image should be black or white:
转换为与原始位图大小完全相同的单色不足以进行打印。
打印机只能将每个“像素”(点)打印为单色,因为每个墨水点只有一种颜色,因此它们必须使用足够多的点并调整其大小、密度……以模拟灰度般的感觉。这种技术称为半色调。您可以看到,打印机的分辨率通常至少为 600dpi,通常为 1200-4800dpi,而显示屏的分辨率通常最高为 200-300ppi。
所以你的单色位图应该是 <每侧至少为原始分辨率的 3 倍。
Converting to monochrome with exact the same size as the original bitmap is not enough to print.
Printers can only print each "pixel" (dot) as monochrome because each spot of ink has only 1 color, so they must use much more dots than enough and adjust their size, density... to emulate the grayscale-like feel. This technique is called halftoning. You can see that printers often have resolution at least 600dpi, normally 1200-4800dpi, while display screen often tops at 200-300ppi.
So your monochrome bitmap should be at least 3 times the original resolution in each side.
我认为保留颜色会产生更好的 1 位像素图像;我已经评论了高对比度滤镜和灰色矩阵,如果想尝试的话。
我没有对速度进行基准测试,目标是将数据发送到 POS 打印机,
如果您在图像上添加 BMP 标头(62 字节)前缀,则 96 像素(屏幕)可以转换为 203 像素(打印机),也许可以转换为 BMP 格式。
我将 C# 与 SkiaSharp 一起使用,但对于 java 代码也很有用。
[
]
I think that keep the color will produce better 1 bit pixel image; I have commented the high contract filter and gray matrix, if want to try.
I don't have benchmark the code for speed, the objective is sending data to POS printer, 96 pixel (screen) can be converted to 203 pixel (printer)
if you prefix the image with BMP header (62 bytes), maybe can be converted to BMP format.
I'm using C# with SkiaSharp, but can be useful for java code.
[
]