Android:将位图转换为单色位图(每像素1位)

Age*_*opf 21 android monochrome bitmap

我想将Bitmap打印到移动蓝牙打印机(Bixolon SPP-R200) - SDK不提供direkt方法来打印内存中的图像.所以我想过转换像这样的Bitmap:

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Run Code Online (Sandbox Code Playgroud)

到单色位图.我使用Canvas在上面给出的Bitmap上绘制黑色文本,效果很好.但是,当我将上面的位图转换为ByteArray时,打印机似乎无法处理这些字节.我怀疑我需要一个每像素一位的数组(一个像素将是白色= 1或黑色= 0).

由于似乎没有方便的,开箱即用的方式,我有一个想法是使用:

bitmap.getPixels(pixels, offset, stride, x, y, width, height)
Run Code Online (Sandbox Code Playgroud)

获取像素.我假设,我必须按如下方式使用它:

int width = bitmap.getWidth();
int height = bitmap.getHeight();

int [] pixels = new int [width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
Run Code Online (Sandbox Code Playgroud)

但是 - 我不确定一些事情:

  • 在getPixels中 - 简单地将宽度作为"Stride"参数传递是否有意义?
  • 我想我必须评估每个像素的颜色信息,并将其切换为黑色或白色(我将这个值写入一个新的目标字节数组,我最终会传递给打印机)?
  • 如何最好地评估每个像素颜色信息,以确定它应该是黑色还是白色?(渲染的位图在白色背景上是黑色疼痛)

这种方法有意义吗?有没有更简单的方法?仅仅将位图设置为黑白是不够的,主要问题是将每个像素的颜色信息减少为一位.

UPDATE

根据Reuben的建议,我首先将Bitmap转换为单色Bitmap.然后我将迭代每个像素:

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在Reuben建议"读取每个32位像素的最低字节" - 这与我关于如何评估像素颜色的问题有关.我在这方面的最后一个问题是:通过简单地执行此操作,我得到的是最低字节:

// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
Run Code Online (Sandbox Code Playgroud)

Reu*_*ton 26

您可以使用ColorMatrix将图像转换为单色32bpp.

Bitmap bmpMonochrome = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpMonochrome);
ColorMatrix ma = new ColorMatrix();
ma.setSaturation(0);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(ma));
canvas.drawBitmap(bmpSrc, 0, 0, paint);
Run Code Online (Sandbox Code Playgroud)

这简化了颜色 - >单色转换.现在你可以做一个getPixels()并读取每个32位像素的最低字节.如果它<128则为0,否则为1.

  • 首先,Android不支持1bpp位图,其次是BitmapFactory.decode*用于解码PNG和JPEG格式.您需要参考打印机的文档并准确确定其支持的内容. (2认同)

小智 10

好吧,我认为现在回复这个帖子已经很晚了,但我有时还会回来处理这个问题并决定构建我自己的库,将任何jpg或png图像转换为1bpp .bmp.大多数需要1bpp图像的打印机都支持此图像(在其中一个上测试:)).在这里,您可以找到库以及使用它来制作单色单通道图像的测试项目.随意改变它.. :)

https://github.com/acdevs/1bpp-monochrome-android

请享用..!!:)


phu*_*clv 5

转换为与原始位图完全相同的单色并不足以 打印.

打印机只能将每个"像素"(点)打印为单色,因为每个墨点只有1种颜色,因此它们必须使用足够多的点并调整它们的大小,密度......以模拟灰度级的感觉.这种技术称为半色调.您可以看到打印机的分辨率通常至少为600dpi,通常为1200-4800dpi,而显示屏的分辨率通常为200-300ppi.

半色调

因此,您的单色位图应至少为每侧的原始分辨率的3倍.


Mor*_*itz 5

您应该将每个像素转换为HSV空间并使用该值来确定目标图像上的像素是黑色还是白色:

  Bitmap bwBitmap = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565 );
  float[] hsv = new float[ 3 ];
  for( int col = 0; col < bitmap.getWidth(); col++ ) {
    for( int row = 0; row < bitmap.getHeight(); row++ ) {
      Color.colorToHSV( bitmap.getPixel( col, row ), hsv );
      if( hsv[ 2 ] > 0.5f ) {
        bwBitmap.setPixel( col, row, 0xffffffff );
      } else {
        bwBitmap.setPixel( col, row, 0xff000000 );
      }
    }
  }
  return bwBitmap;
Run Code Online (Sandbox Code Playgroud)