Android: преобразование растрового изображения в монохромное растровое изображение (1 бит на пиксель)
Я хочу напечатать растровое изображение на мобильном Bluetooth-принтере (Bixolon SPP-R200). SDK не предлагает директивные методы для печати изображения в памяти. Поэтому я подумал о преобразовании Bitmap следующим образом:
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
К монохромному растровому изображению. Я рисую черный текст выше, указанный битмап, используя Canvas, который хорошо работает. Однако, когда я конвертирую вышеуказанный Bitmap в 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"?
- Я предполагаю, что мне придется оценивать информацию о цветах каждого пикселя и переключать его на черный или белый (и я бы записал это значение в новом массиве целевых байтов, который я бы, в конечном счете, перешел на принтер)?
- Как лучше всего оценить информацию о цвете каждого пикселя, чтобы решить, что он должен быть черным или белым? (Полученный растровый рисунок - черная боль на белом фоне).
Этот подход имеет смысл вообще? Есть ли более простой способ? Недостаточно просто сделать растровое изображение черно-белым, основная проблема заключается в том, чтобы уменьшить информацию о цвете для каждого пикселя в один бит.
UPDATE
Как было предложено Рубеном, я сначала преобразую 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);
}
}
Теперь Рубен предложил "прочитать младший байт каждого 32-битного пикселя" - это будет связано с моим вопросом о том, как оценить цвет пикселя. Мой последний вопрос в этом отношении: я получаю младший байт, просто делая это:
// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
Ответы
Ответ 1
Вы можете преобразовать изображение в монохромный 32bpp с помощью ColorMatrix.
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);
Это упрощает преобразование цвета → монохромное. Теперь вы можете просто сделать getPixels() и прочитать младший байт каждого 32-битного пикселя. Если оно < 128 равно 0, в противном случае оно равно 1.
Ответ 2
Ну, я думаю, что уже довольно поздно ответить на эту тему, но иногда я работал над этим материалом и решил создать свою собственную библиотеку, которая будет конвертировать любые jpg или png-изображения в 1bpp.bmp. Большинство принтеров, которым требуются изображения 1bpp, будут поддерживать это изображение (проверено на одном из них:)).
Здесь вы можете найти библиотеку, а также тестовый проект, который использует его для создания монохромного одноканального изображения. Не стесняйтесь его менять..:)
https://github.com/acdevs/1bpp-monochrome-android
Наслаждайтесь..!!:)
Ответ 3
Преобразование в монохромный с тем же размером, что и исходное растровое изображение, недостаточно для печати.
Принтеры могут печатать каждый "пиксель" (точка) как монохромный, потому что каждое пятно чернил имеет только 1 цвет, поэтому они должны использовать гораздо больше точек, чем их, и регулировать их размер, плотность... для эмуляции оттенков серого Чувствовать. Этот метод называется halftoning. Вы можете видеть, что принтеры часто имеют разрешение не менее 600 точек на дюйм, обычно 1200-4800 точек на дюйм, а экран дисплея часто достигает 200-300 пикселей.
![Halftone]()
Таким образом, ваше монохромное растровое изображение должно быть не менее 3 раз исходным разрешением в каждой стороне.
Ответ 4
Вы должны преобразовать каждый пиксель в пространство 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;