2012-02-21 1 views
16

Я хочу распечатать растровое изображение на мобильный Bluetooth-принтер (Bixolon SPP-R200) ​​- SDK не предлагает директивные методы для печати в памяти образ. Поэтому я подумал о преобразовании Bitmap следующим образом:Android: преобразование растрового изображения в монохромное растровое изображение (1 бит на пиксель)

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 

To Monochrome Bitmap. Я рисую черный текст выше, указанный битмап, используя 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

Как было предложено Рувима я сначала преобразовать растровое изображение в монохромное растровое изображение. и тогда я буду перебирать каждого пикселя:

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; 
+0

У меня есть этот QA снимался, потому что я работал на аналогичной концепции что касается программного манипулирования массивами, чтобы стать монохромными растровыми изображениями. У меня есть вопрос и его возможный ответ здесь: http://stackoverflow.com/questions/17918978/plot-an-array-into-bitmap-in-cc-for-thermal-printer Если это помогает людям, пожалуйста, напишите мне и Я придумаю подходящий ответ на этот вопрос. –

+0

Почему вы используете GetPixels для загрузки всех пикселей в один массив ... Затем вложенный цикл через битмап AGAIN вызывает индивидуальные вызовы GetPixel (наименее эффективным способом)? Просто запустите свой исходный массив, а затем используйте SetPixels, чтобы вернуть весь массив в растровое изображение. –

+0

@ClintStLaurent хорошая точка - код действительно старый xD - я даже не думаю, что мы используем его в этой форме больше, но, как вы указали правильно, это очень неэффективно, как там написано. Не стесняйтесь редактировать его в соответствии с вашим предложением. – AgentKnopf

ответ

18

Вы можете преобразовать изображение в монохромном 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.

+0

Большое спасибо за ваш ответ! Чтобы уточнить оценку пикселя, я обновил свой вопрос (ниже UPDATE) по существу: я получаю младший байт 32-битного int, делая это: int lowByte = pixel & 0xff;? – AgentKnopf

+1

Да. На самом деле бит 7 младшего байта - это именно тот бит, который вы хотите для своего 1bpp-пикселя. Выражение '(pixel & 0x80) >> 7' даст вам '0' или '1' для этого. –

+0

Wow thanks :)! – AgentKnopf

10

Ну, я думаю, что довольно поздно ответить на эту тему, но я тоже иногда работал над этим материалом и решил создать свою собственную библиотеку, которая будет конвертировать любые jpg или png изображение до 1bpp .bmp. Большинство принтеров, которым требуются изображения 1bpp, будут поддерживать это изображение (проверено на одном из них :)). Здесь вы можете найти библиотеку, а также тестовый проект, который использует его для создания монохромного одноканального изображения. Не стесняйтесь его менять.:)

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

Наслаждайтесь .. !! :)

+0

Спасибо за внимание! Я уверен, что это будет полезно для других, и я пойду посмотреть на проект, который вы также разместили :). – AgentKnopf

5

Преобразование в монохромное с точно таким же размером, что и исходное растровое изображение, недостаточно для печати.

Принтеры могут печатать каждый «пиксель» (точка) только в монохромном режиме, потому что каждое пятно чернил имеет только 1 цвет, поэтому они должны использовать гораздо больше точек, чем достаточно, и регулировать их размер, плотность ... для эмуляции оттенков серого, подобный ощущение. Этот метод называется halftoning. Вы можете видеть, что принтеры часто имеют разрешение не менее 600 точек на дюйм, обычно 1200-4800 точек на дюйм, в то время как экран дисплея часто достигает 200-300 пикселей.

Halftone

Таким образом, ваш монохромный растровый должен быть по крайней мере 3 раза оригинальное разрешение каждой стороны.

+0

Вы имеете в виду сглаживание? У меня уже было сглаживание, уже интегрированное в мой код :) – AgentKnopf

+0

Нет. Dithering - это совершенно другой бизнес. В 8-битовом или более градационном режиме в градациях серого есть 255 (или больше, в зависимости от того, сколько бит вы используете) уровней серого, поэтому исходное разрешение в порядке. Но если вы используете монохромное растровое изображение, то почти все детали будут значительно потеряны, потому что вы уменьшаете с более чем 16,7 миллионов цветов только до 2. Halftoning увеличивает разрешение и использует дополнительные пиксели, чтобы придать эффект оттенков серого как способ преодоления этого ограничения. Вы можете ссылаться на ссылку, указанную выше. –

+0

А, спасибо, что расчистили это :)! В моем конкретном случае я уже рисую на холсте черно-белым. Однако также может случиться так, что мы печатаем фотографии, поэтому для этих случаев полутонирование может действительно пригодиться - еще раз спасибо :)! – AgentKnopf

1

Вы должны преобразовать каждый пиксель в 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; 
Смежные вопросы