Bitmap转为单色位图,打印电子签名

背景

项目中使用手写板,用户在上面签名后,将电子签名传到后台,同时将签名连同别的信息打印出来。

手写板已经有很多优秀的开源库,也可以动手撸一个。

手写板签名后可以得到签名的Bitmap,而所用的硬件是有打印接口的,可以接收Bitmap为参数打印图片,这样看似需求就能实现了。

问题

但打印接口接收的Bitmap必须是单色位图,类似于二维码,每个像素点非黑即白,非1即0。

其实我们在使用zxing生成二维码时,也利用zxing的api对每个像素点进行了判断,赋予其黑或白。

而在带有签名的Bitmap中,很明显有笔迹的像素点应该是黑色,其余应该是白色的,这样打印出来就没问题了。

那怎样判断某个像素点是否有笔迹呢?

突破口

这就要靠下面这个神奇的方法:Bitmap.getPixel(x, y)

    /**
     * Returns the {@link Color} at the specified location. Throws an exception
     * if x or y are out of bounds (negative or >= to the width or height
     * respectively). The returned color is a non-premultiplied ARGB value.
     *
     * @param x    The x coordinate (0...width-1) of the pixel to return
     * @param y    The y coordinate (0...height-1) of the pixel to return
     * @return     The argb {@link Color} at the specified coordinate
     * @throws IllegalArgumentException if x, y exceed the bitmap's bounds
     */
    @ColorInt
    public int getPixel(int x, int y) {
        checkRecycled("Can't call getPixel() on a recycled bitmap");
        checkPixelAccess(x, y);
        return nativeGetPixel(mNativePtr, x, y);
    }

该方法返回坐标x, y处的颜色,当返回值为背景色时,即表示空白;否则表示有笔迹。

注意:不同Bitmap的背景色可能不同!一般为白色或透明。

Bitmap还有一个setPixels方法,能重新设置每个像素点的颜色。

    /**
     * <p>Replace pixels in the bitmap with the colors in the array. Each element
     * in the array is a packed int prepresenting a non-premultiplied ARGB
     * {@link Color}.</p>
     *
     * @param pixels   The colors to write to the bitmap
     * @param offset   The index of the first color to read from pixels[]
     * @param stride   The number of colors in pixels[] to skip between rows.
     *                 Normally this value will be the same as the width of
     *                 the bitmap, but it can be larger (or negative).
     * @param x        The x coordinate of the first pixel to write to in
     *                 the bitmap.
     * @param y        The y coordinate of the first pixel to write to in
     *                 the bitmap.
     * @param width    The number of colors to copy from pixels[] per row
     * @param height   The number of rows to write to the bitmap
     *
     * @throws IllegalStateException if the bitmap is not mutable
     * @throws IllegalArgumentException if x, y, width, height are outside of
     *         the bitmap's bounds.
     * @throws ArrayIndexOutOfBoundsException if the pixels array is too small
     *         to receive the specified number of pixels.
     */
    public void setPixels(@ColorInt int[] pixels, int offset, int stride,
            int x, int y, int width, int height) {
        checkRecycled("Can't call setPixels() on a recycled bitmap");
        if (!isMutable()) {
            throw new IllegalStateException();
        }
        if (width == 0 || height == 0) {
            return; // nothing to do
        }
        checkPixelsAccess(x, y, width, height, offset, stride, pixels);
        nativeSetPixels(mFinalizer.mNativeBitmap, pixels, offset, stride,
                        x, y, width, height);
    }

解决方案

结合这两个方法,将Bitmap转为单色位图的思路就是:

  1. 遍历Bitmap上的每个像素点
  2. 每次遍历时,先将像素点赋值白色。
  3. 利用getPixel方法判断是否有笔迹,有的话再赋值黑色。
  4. 遍历结束后,利用setPixels方法使颜色设置作用于Bitmap上。

按照这个思路,可以写出下面的转换方法:

    private Bitmap getSingleColorBitmap(Bitmap bitmap, @ColorInt int bgColor) {
        int[] pix = new int[bitmap.getWidth() * bitmap.getHeight()];
        boolean isBitmapEmpty = true;
        for (int y = 0; y < bitmap.getHeight(); y++) {
            for (int x = 0; x < bitmap.getWidth(); x++) {
                int index = y * bitmap.getWidth() + x;
                pix[index] = WHITE;
                if (bitmap.getPixel(x, y) != bgColor) {
                    isBitmapEmpty = false;
                    pix[index] = BLACK;
                }
            }
        }
        if (isBitmapEmpty) {
            return null;
        }
        bitmap.setPixels(pix, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
        return bitmap;
    }

同时该方法使用标志位isBitmapEmpty判断图片是否空白。

猜你喜欢

转载自blog.csdn.net/recordGrowth/article/details/78503449
今日推荐