2012-02-21 582 views
16

我想將位圖打印到移動藍牙打印機(Bixolon SPP-R200)--SDK不提供用於打印內存的direkt方法圖片。所以我想這樣轉換一個位圖:Android:將位圖轉換爲單色位圖(每像素1位)

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

到單色位圖。我使用Canvas在上面給出的位圖上繪製黑色文本,效果很好。但是,當我將上述位圖轉換爲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 - 是否有意義簡單地通過寬度「大步」的說法?
  • 我想我必須評估每個像素的顏色信息,並將其切換爲黑色或白色(並且我會將此值寫入新的目標字節數組,我將最終傳遞給打印機)?
  • 如何最好地評估每個像素顏色信息以決定它應該是黑色還是白色? (呈現的位圖在白色背景上是黑色的疼痛)

這種方法是否有意義?有更容易的方法嗎?僅將位圖黑色化爲白色是不夠的,主要問題是將每個像素的顏色信息減少到一位。

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如果這有助於人們,請給我發電子郵件和我會爲這個問題提出一個合適的答案。 – 2013-12-28 09:16:01

+0

爲什麼使用GetPixels將所有像素加載到單個數組中......然後通過位圖AGAIN調用單個GetPixel調用(可能效率最低的方式)嵌套循環?只需循環訪問原始數組,然後使用SetPixels將整個陣列重新推回到位圖中。 – 2016-03-14 16:17:06

+0

@ClintStLaurent好點 - 代碼真的很老xD - 我甚至不認爲我們已經以這種形式使用它了,但正如你指出的那樣,它寫在那裏的方式效率很低。隨意根據您的建議進行編輯。 – AgentKnopf 2016-03-15 19:20:29

回答

18

您可以將圖像轉換爲單色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); 

這簡化了顏色 - >單色轉換。現在你可以做一個getPixels()並讀取每個32位像素的最低字節。如果是< 128這是一個0,否則它是1.

+0

非常感謝您的回答!爲了澄清像素評估,我基本上更新了我的問題(在UPDATE下面):我是通過這樣做得到32位int的最低字節:int lowestByte = pixel & 0xff;? – AgentKnopf 2012-02-21 13:12:10

+1

是的。實際上,最低字節的第7位恰好就是你想要的1bpp像素的位。表達式'(pixel&0x80)>> 7'會給你一個'0'或'1'。 – 2012-02-21 13:26:53

+0

哇謝謝:)! – AgentKnopf 2012-02-21 13:33:05

10

嗯,我認爲它現在很晚回覆此線程,但我也有時回來這個東西,並決定建立我自己的庫,將轉換任何JPG或PNG圖像到1bpp .bmp。大多數需要1bpp圖像的打印機都會支持這個圖像(在其中一個:)上進行測試)。 在這裏您可以找到圖書館以及使用它製作單色單通道圖像的測試項目。隨意更改它..:)

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

享受.. !! :)

+0

感謝您的努力!我確信它會對其他人有所幫助,我會去看看你發佈的項目:)。 – AgentKnopf 2013-03-20 10:02:04

5

轉換爲與原始位圖完全相同大小的單色是不夠要打印。

打印機只能將每個「像素」(點)打印爲單色,因爲每個墨點只有一種顏色,因此它們必須使用的點多於足夠多,並且要調整它們的大小,密度......以模擬灰度 - 喜歡的感覺。這種技術被稱爲halftoning。您可以看到打印機的分辨率通常至少爲600dpi,通常爲1200-4800dpi,而顯示屏幕通常在200-300ppi之間。

Halftone

所以,你的單色位圖應該是至少3倍原始分辨率的兩側。

+0

你是指任何偶然的抖動?我已經抖動已經集成到我的代碼:) – AgentKnopf 2013-08-02 08:26:56

+0

號抖動是一個完全不同的業務。在8位或更多灰度位圖中,有255個(或更多,取決於您使用多少位)灰度級,所以原始分辨率很好。但是如果你使用單色位圖,那麼幾乎所有的細節都會因爲你從1670萬色減少到2而大幅丟失。半色調增加了分辨率,並使用額外的像素來提供灰度效果作爲通過這個限制的方法。你可以參考我上面給出的鏈接。 – 2013-08-02 09:12:14

+0

啊,謝謝你清理:)。在我的特殊用例中,我已經畫出了黑白畫布。然而,它也可能發生,我們打印照片,所以這些情況下半色調可能真的很方便 - 再次感謝:)! – AgentKnopf 2013-08-02 10:02:02

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;