2012-02-21 3 views
16

Desidero stampare una bitmap su una stampante Bluetooth mobile (Bixolon SPP-R200) ​​- l'SDK non offre metodi direkt per stampare una memoria in memoria Immagine. Quindi ho pensato di convertire una bitmap in questo modo:Android: conversione di una bitmap in bitmap monocromatica (1 bit per pixel)

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

In bitmap monocromatica. Sto disegnando un testo nero sopra Bitmap dato usando una tela, che funziona bene. Tuttavia, quando converto la bitmap di cui sopra in un ByteArray, la stampante sembra non essere in grado di gestire quei byte. Sospetto di aver bisogno di una matrice con un bit per pixel (un pixel potrebbe essere bianco = 1 o nero = 0).

quanto non sembra esserci alcun comoda, fuori dalla scatola modo per farlo, un'idea che avevo era di utilizzare:

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

ottenere i pixel. I assumere, avrei dovuto usarla come segue:

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

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

Tuttavia - non sono sicuro di un paio di cose:

  • In getPixels - ha senso far passare semplicemente la larghezza l'argomento "Stride"?
  • Suppongo che dovrei valutare le informazioni sul colore di ciascun pixel e impostarlo su bianco o nero (e scriverei questo valore in un nuovo array di byte di destinazione che alla fine passerei alla stampante)?
  • Come valutare al meglio ciascuna informazione sul colore dei pixel per decidere che dovrebbe essere in bianco o nero? (La bitmap renderizzata è un dolore nero su sfondo bianco)

Questo approccio ha senso? C'è un modo più semplice? Non è sufficiente rendere bianco il bitmap nero &, il problema principale è ridurre le informazioni sul colore per ciascun pixel in un solo bit.

UPDATE

Come suggerito da Ruben io prima convertire il bitmap in una bitmap in bianco e nero. e poi ti iterare su ogni pixel:

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

Ora Ruben ha suggerito di "leggere il byte più basso di ogni pixel a 32 bit" - che si riferiscono alla mia domanda su come valutare il colore dei pixel. La mia ultima domanda a questo proposito: faccio ad avere il byte più basso semplicemente facendo questo:

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

ho questa QA recitato perché stavo lavorando su un concetto simile per quanto riguarda la manipolazione di matrici a livello di codice per diventare bitmap monocromatiche. Ho una domanda e la sua risposta finale qui: http://stackoverflow.com/questions/17918978/plot-an-array-into-bitmap-in-cc-for-thermal-printer Se questo aiuta le persone, per favore scrivimi e Verrò con una risposta adatta a questa domanda. –

+0

Perché stai utilizzando GetPixels per caricare tutti i pixel in un singolo array ... Quindi annidare il ciclo attraverso la bitmap AGAIN che chiama le singole chiamate GetPixel (il modo meno efficiente possibile)? Basta scorrere l'array originale, quindi utilizzare SetPixels per reinserire l'intero array nella bitmap. –

+0

@ClintStLaurent buon punto - il codice è davvero vecchio xD - Non penso nemmeno che lo stiamo usando in questa forma più, ma come hai sottolineato correttamente, è molto inefficiente il modo in cui è scritto lì. Sentiti libero di modificarlo secondo il tuo suggerimento. – AgentKnopf

risposta

18

È possibile convertire l'immagine in monocromatica 32bpp utilizzando un 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); 

Questo semplifica la conversione colore-> monocromatica. Ora puoi semplicemente eseguire getPixels() e leggere il byte più basso di ciascun pixel a 32 bit. Se è < 128 è uno 0, altrimenti è un 1.

+0

Grazie mille per la risposta! Giusto per chiarire la valutazione dei pixel ho aggiornato la mia domanda (sotto UPDATE) essenzialmente: ottengo il byte più basso di un int a 32 bit facendo così: int lowerByte = pixel & 0xff;? – AgentKnopf

+1

Sì. In realtà il bit 7 del byte più basso è esattamente il bit che vuoi per il tuo pixel 1bpp. L'espressione '(pixel & 0x80) >> 7' ti darà uno '0' o '1' per quello. –

+0

Wow grazie :)! – AgentKnopf

10

Beh, penso che sia abbastanza tardi ora per rispondere a questo thread ma stavo lavorando anche su questo materiale a volte indietro e ho deciso di costruire la mia libreria che convertirà qualsiasi immagine jpg o png in 1bpp .bmp. La maggior parte delle stampanti che richiedono immagini 1bpp supporteranno questa immagine (testata su una di quelle :)). Qui puoi trovare la libreria e un progetto di test che lo usa per creare un'immagine monocromatica a canale singolo. Sentiti libero di cambiarlo ..:)

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

Godetevi .. !! :)

+0

Grazie per lo sforzo! Sono sicuro che sarà utile per gli altri e darò un'occhiata al progetto che hai postato anche :). – AgentKnopf

5

Conversione in bianco e nero con la stessa dimensione della bitmap originale è non sufficiente da stampare.

Le stampanti possono stampare ciascun "pixel" (punto) come monocromatico perché ogni macchia d'inchiostro ha solo 1 colore, quindi devono usare molti più punti di abbastanza e regolare le loro dimensioni, densità ... per emulare la scala di grigi- come sentire Questa tecnica è chiamata halftoning. È possibile vedere che le stampanti hanno spesso una risoluzione di almeno 600 dpi, normalmente 1200-4800 dpi, mentre lo schermo spesso supera 200-300ppi.

Halftone

Così bitmap in bianco e nero dovrebbe essere almeno 3 volte la risoluzione originale in ogni lato.

+0

Vuoi dire dithering per caso? Avevo già inserito il dithering nel mio codice :) – AgentKnopf

+0

No. Il dithering è un'attività completamente diversa. In bitmap a 8 bit o più in scala di grigi ci sono 255 (o più, a seconda di quanti bit si usano) livelli di grigio, quindi la risoluzione originale va bene. Ma se utilizzi bitmap monocromatica, quasi tutti i dettagli andranno persi in modo significativo perché stai riducendo da più di 16,7 milioni di colori a solo 2. La mezzitoni aumenta la risoluzione e utilizza i pixel aggiuntivi per dare l'effetto della scala di grigi come mezzo per superare questa limitazione. Puoi fare riferimento al link che ho dato sopra. –

+0

Ah, grazie per averlo chiarito :)! Nel mio caso d'uso particolare, disegno già su una tela in bianco e nero. Tuttavia può anche accadere che stampiamo fotografie, quindi per questi casi la mezza tonalità potrebbe tornare utile - grazie ancora :)! – AgentKnopf

1

Si dovrebbe convertire ogni pixel nello spazio HSV e utilizzare il valore per determinare se il pixel l'immagine di destinazione sulla dovrebbe essere nero o bianco:

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;