2012-02-21 13 views
16

Chcę wydrukować mapę bitową na przenośnej drukarce Bluetooth (Bixolon SPP-R200) ​​- SDK nie oferuje metod direkt do drukowania w pamięci obraz. Tak więc pomyślałem o konwersji bitmapy w następujący sposób:Android: Konwertowanie mapy bitowej na monochromatyczną bitmapę (1 bit na piksel)

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

Do monochromatycznej bitmapy. Rysuję czarny tekst na powyższej bitmapie za pomocą płótna, które działa dobrze. Jednak po konwersji powyższej bitmapy na ByteArray, drukarka wydaje się nie być w stanie obsłużyć tych bajtów. Podejrzewam, że potrzebuję tablicy z jednym bitem na piksel (piksel będzie albo biały = 1 albo czarny = 0).

Ponieważ nie wydaje się być wygodne, z drogi, pola do zrobienia, że ​​jeden pomysł miałam używać:

bitmap.getPixels(pixels, offset, stride, x, y, width, height) 

uzyskać pikseli. Przypuszczam, że będę musiał go używać w następujący sposób:

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

int [] pixels = new int [width * height]; 
bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 

jednak - nie jestem pewien, o kilka rzeczy:

  • W getPixels - czy to ma sens, aby po prostu przejść jak szerokość argument "krok"?
  • Chyba będę musiał ocenić informacje o kolorze każdego piksela i albo przełączyć go na czarny lub biały (I napisałbym tę wartość w nowej docelowej tablicy bajtów, którą ostatecznie przekazałbym do drukarki)?
  • Jak najlepiej ocenić informacje o kolorach poszczególnych pikseli, aby można było wybrać kolor czarny lub biały? (Renderowana bitmapa to czarny ból na białym tle)

Czy to podejście ma sens? Czy istnieje prostszy sposób? Nie wystarczy tylko sprawić, by bitmapa była czarna, a główną kwestią jest zredukowanie informacji o kolorach dla każdego piksela w jeden bit.

UPDATE

Jak sugeruje Rubena będę najpierw przekonwertować bitmapę do bitmap monochromatycznych. i wtedy będę iterować każdego piksela:

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); 
     } 
    } 

Teraz Reuben zasugerował „czytać najniższą bajt każdego piksela 32-bit” - które odnoszą się do mojego pytania o tym, jak ocenić kolor piksela. Moje ostatnie pytanie w tej kwestii: Czy dostanę najniższą bajt po prostu w ten sposób:

// Using the pixel from bitmap.getPixel(x,y) 
int lowestByte = pixel & 0xff; 
+0

mam to QA wystąpił bo byłem w pracy na podobnym koncepcji w odniesieniu do programowego manipulowania tablicami, aby stać się monochromatycznymi mapami bitowymi. Mam pytanie i jego ostateczną odpowiedź tutaj: http://stackoverflow.com/questions/17918978/plot-an-array-into-bitmap-in-cc-for-thermal-printer Jeśli to pomaga ludziom, napisz do mnie i Wymyślę odpowiednią odpowiedź na to pytanie. –

+0

Dlaczego używasz GetPixels do załadowania wszystkich pikseli do pojedynczej tablicy ... Następnie zagnieżdżona pętla poprzez bitmapę PONOWNIE wywołując poszczególne wywołania GetPixel (najmniej efektywny sposób)? Po prostu przeprowadź pętlę przez oryginalną tablicę, a następnie użyj SetPixels, aby przesunąć całą tablicę z powrotem do bitmapy. –

+0

@ClintStLaurent dobry punkt - kod jest naprawdę stary xD - nie sądzę, że używamy go już w tej formie, ale jak wskazałeś poprawnie, jest to bardzo nieefektywne, jak jest napisane. Możesz go edytować zgodnie z sugestią. – AgentKnopf

Odpowiedz

18

można przekonwertować obraz na monochromatyczny 32bpp użyciu 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); 

Upraszcza konwersję kolorów-> monochromatycznych. Teraz możesz po prostu zrobić getPixels() i odczytać najniższy bajt każdego 32-bitowego piksela. Jeśli jest to < 128 to 0, w przeciwnym razie jest to 1.

+0

Dziękuję bardzo za odpowiedź! Aby wyjaśnić ocenę pikseli, zaktualizowałem zasadniczo moje pytanie (poniżej UPDATE): czy otrzymam najniższy bajt 32-bitowej int, wykonując to: int lowestByte = pixel & 0xff;? – AgentKnopf

+1

Tak. Właściwie bit 7 najniższego bajtu jest dokładnie tym, którego potrzebujesz dla piksela 1bpp. Wyrażenie "(pixel i 0x80) >> 7" da ci za to "0" lub "1". –

+0

Wow, dziękuję :)! – AgentKnopf

10

Cóż, wydaje mi się, że jest już dość późno, aby odpowiedzieć na ten wątek, ale czasami pracowałem nad tymi rzeczami i postanowiłem zbudować własną bibliotekę, która zmieni każdą z nich. obraz jpg lub png na 1bpp .bmp. Większość drukarek, które wymagają obrazów 1 pz, obsługuje ten obraz (testowany na jednym z nich :)). Tutaj można znaleźć bibliotekę, a także projekt testowy, który wykorzystuje ją do utworzenia jednokanałowego monochromatycznego obrazu. Możesz to zmienić ...:)

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

Ciesz .. !! :)

+0

Dzięki za wysiłek! Jestem pewien, że będzie to pomocne dla innych osób. Przyjrzę się również projektowi, który napisaliście :). – AgentKnopf

5

Konwersja na monochromatyczną z dokładnie tego samego rozmiaru co oryginalna mapa bitowa to niewystarczająca do wydrukowania.

Drukarki mogą drukować każdy "piksel" (kropka) w trybie monochromatycznym, ponieważ każdy punkt atramentu ma tylko 1 kolor, więc muszą używać o wiele więcej punktów niż wystarczające i dopasować ich rozmiar, gęstość ..., aby emulować skalę szarości- jak czuć. Ta technika nazywa się halftoning. Widać, że drukarki mają często rozdzielczość co najmniej 600dpi, zwykle 1200-4800dpi, a ekrany często sięgają 200-300ppi.

Halftone

Więc monochromatyczny bitmapy powinny być co najmniej 3 razy oryginalnej rozdzielczości z każdej strony.

+0

Masz na myśli dithering przez przypadek? Miałem już dithering już zintegrowany z moim kodem :) – AgentKnopf

+0

Nr Dithering to zupełnie inna sprawa. W mapie bitowej 8-bitowej lub większej w skali szarości istnieje 255 (lub więcej, w zależności od liczby używanych bitów) poziomów szarości, więc oryginalna rozdzielczość jest dobra. Ale jeśli użyjesz monochromatycznej bitmapy, prawie wszystkie szczegóły zostaną utracone, ponieważ redukujesz z ponad 16,7 miliona kolorów do zaledwie 2. Półtonowanie zwiększa rozdzielczość i wykorzystuje dodatkowe piksele, aby nadać efekt skali szarości jako sposób na pokonanie tego ograniczenia. Możesz odwołać się do linku podanego powyżej. –

+0

Ah, dzięki za wyczyszczenie tego :)! W moim konkretnym przypadku użycia rysuję już na płótnie w czerni i bieli. Może się jednak zdarzyć, że drukujemy fotografie, więc w takich przypadkach może się przydać półtonowanie - jeszcze raz dziękujemy :)! – AgentKnopf

1

należy przekonwertować każdego piksela w przestrzeni HSV i użyć wartości w celu określenia, czy pikseli na obrazie docelowym powinien być czarny lub biały:

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; 
Powiązane problemy