Android Question Convert to monochrome bitmap

EvgenyB4A

Active Member
Licensed User
Longtime User
How to convert a regular RGB bitmap to monochrome bitmap with 1 bit per pixel?
I need it to print an image to BT monochrome printer printer.
 

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
Do you need to save it at 1 bit/pixel bitmap? Or just calculate the 1/0 bit for each original pixel in order to send them to the printer?
 
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
There are different ways to do it
(I assume that if your first pixels (once processed) are for instance: BWBBWWBB WWWWWWWB .... you want to get 4Ch, FEh,.....to send to the printer)

In order to convert a 24bit pixel to 1 bit, you would need to get its luminance and then compare to a threshold in order to decide if it is 0 or 1. These operations are costly, so a possible "faster" approach would be to

  • First convert the bitmap to monochrome using some existing library. Still would have 24bits/pixel but would be easier for your purposes.
  • Once you have it, the following should work (not tested: may contain from 0 to N errors). If instead of a monochroe bitmap you pass a color bitmap, the routine is still valid but its inner line would have to be modified accordingly

B4X:
' Klaus's routine from somewhere in this forum. Faster than getting pixels one by one
Sub getPixels(bmp AsBitmap, offset As Int, stride As Int, x As Int, y As Int, width As Int, height As Int) As Int()
    Dim jo = bmp AsJavaObject
    Dim pixels(width * height) As Int
    jo.RunMethod("getPixels", ArrayAs Object(pixels, offset, width, x, y, width, height))
    Return pixels
End Sub

'Call this routine once you have your bitmap converted to monochrome with whatever library you use
Sub Get1bitPerPixelArrayFromMyMonochromeBitmap(mb as Bitmap) as Byte()
    Dim size as int = mb.width*mb.height
    Dim myPixels() as int = getPixels(mb,0,mb.width,0,0,mb.width,mb.height)
    Dim myPrinterArray(size/8 + 1) as byte
    Dim myThreshold as int = 128 'or whatever
    Dim val as int
    Dim index as int=0
    for row=0 to mb.height-1
        for col=0 to (mb.width/8)-1  'assume mb.width is multiple of 8 otherwise we will need padding
            val=0
            for numBit=0 to 7
                if Bit.And(mypixels(mb.width*row + 8*col + num_bit),0xFF)>myThreshold Then
                    val = Bir.Or(val,Bit.ShiftRight(0x80,numBit))
                end if
            next
            myPrinterArray(index)=val
            index=index+1
        next
    next
    Return(myPrinterArray)
End Sub

If you have to send special control codes between each row and/or the bitmap width is not an exact multiple of 8, perhaps you will need to modifiy the "for" loops
 
Upvote 0

EvgenyB4A

Active Member
Licensed User
Longtime User
There are different ways to do it
(I assume that if your first pixels (once processed) are for instance: BWBBWWBB WWWWWWWB .... you want to get 4Ch, FEh,.....to send to the printer)

In order to convert a 24bit pixel to 1 bit, you would need to get its luminance and then compare to a threshold in order to decide if it is 0 or 1. These operations are costly, so a possible "faster" approach would be to

  • First convert the bitmap to monochrome using some existing library. Still would have 24bits/pixel but would be easier for your purposes.
  • Once you have it, the following should work (not tested: may contain from 0 to N errors). If instead of a monochroe bitmap you pass a color bitmap, the routine is still valid but its inner line would have to be modified accordingly

B4X:
' Klaus's routine from somewhere in this forum. Faster than getting pixels one by one
Sub getPixels(bmp AsBitmap, offset As Int, stride As Int, x As Int, y As Int, width As Int, height As Int) As Int()
    Dim jo = bmp AsJavaObject
    Dim pixels(width * height) As Int
    jo.RunMethod("getPixels", ArrayAs Object(pixels, offset, width, x, y, width, height))
    Return pixels
End Sub

'Call this routine once you have your bitmap converted to monochrome with whatever library you use
Sub Get1bitPerPixelArrayFromMyMonochromeBitmap(mb as Bitmap) as Byte()
    Dim size as int = mb.width*mb.height
    Dim myPixels() as int = getPixels(mb,0,mb.width,0,0,mb.width,mb.height)
    Dim myPrinterArray(size/8 + 1) as byte
    Dim myThreshold as int = 128 'or whatever
    Dim val as int
    Dim index as int=0
    for row=0 to mb.height-1
        for col=0 to (mb.width/8)-1  'assume mb.width is multiple of 8 otherwise we will need padding
            val=0
            for numBit=0 to 7
                if Bit.And(mypixels(mb.width*row + 8*col + num_bit),0xFF)>myThreshold Then
                    val = Bir.Or(val,Bit.ShiftRight(0x80,numBit))
                end if
            next
            myPrinterArray(index)=val
            index=index+1
        next
    next
    Return(myPrinterArray)
End Sub

If you have to send special control codes between each row and/or the bitmap width is not an exact multiple of 8, perhaps you will need to modifiy the "for" loops
Thank you very much.
I will try later.
 
Upvote 0
Top