XBM

XBM stands for X BitMap , and is a file format created by the X Consortium (http://www.x.org/ ) to represent monochrome images, i.e bitmaps.

xbm is supported by Tk.

In the 1980s XBM files occasionally had the .bmp extension, leading to confusions with the current MS image format.

See also strimj to XBM


D. McC XBM is a simple format by which monochrome bitmaps are represented in ASCII text. It consists of

  1. a short header specifying image height and width, and
  2. a series (enclosed in braces) of "big-endian" hexadecimal codes, separated by semicolons and spaces, representing "little-endian" binary data.

For example, " 0x1a; " (hexadecimal) represents " 01011000 " (binary).

So what? Well, by a fairly simple two-step process, an XBM file can be transformed into a textual rendering of the image in a pattern of 1's and 0's (or any other two characters). Once the image has been rendered as text, it can be *analyzed* as text, and the analysis can be quickly checked against a detailed visual representation (in a text widget). This would appear to have some possible use in optical character recognition (OCR) -- or so I (1) hope or (2) vainly imagine; I'll find out which sometime.

Step one is to strip away the inessentials (0x , ; , { } ,etc.) from the hexadecimal image data and to arrange the hex codes in accordance with the width of the image, producing a very compact representation of the image.


# Procedure to extract X Bitmap Data (XBD) from .xbm file:

 proc xbmtoxbd {xbm} {
        global xbd_data
        set xbd_data ""

        # Open XBM file:
        set fileid [open $xbm "r"]
        set newxbm [read $fileid]
        close $fileid

        # Get image width and height from XBM header:
        set onbrace [string first "\{" $newxbm]
        set onrang [string range $newxbm 0 $onbrace]
        set onlines [split $onrang "\n"]
        set goxbox 0
        foreach line $onlines {
                set deflin [split $line {" "_}]
                if { [lindex $deflin 0] == "#define" } {
                        set widorhi [lindex $deflin "end-1"]
                        if { $widorhi == "width" } {
                                set bimwid [lindex $deflin end]
                                set eighthwid [expr $bimwid / 8.0]
                                set eighto [split $eighthwid "."]
                                if { [lindex $eighto end] == 0 } {
                                        set xbd_half [lindex $eighto 0]
                                } else {
                                        set xbd_half [expr [lindex $eighto 0] + 1]
                                }
                                set xbd_width [expr $xbd_half*2]
                        } elseif { $widorhi == "height" } {
                                set img_ht [lindex $deflin end]
                        }
                }
                if { [string equal $xbd_width ""] < 1 && [string equal \
                        $img_ht ""] < 1 } {
                        break
                }
        }

        # Strip away inessentials from bitmap data:
        set firstox [string first "0x" $newxbm]
        set xbmtext [string range $newxbm $firstox end]
        set xbmtext [string map {
                "0x" "" "," "" " " "" "\}" "" ";" "" "\n" ""
                } $xbmtext]
        for { set x 0 } { $x <= $img_ht } { incr x } {
                set linestar [expr $xbd_width * $x]
                set linend [expr $linestar + $xbd_width -1]
                set xbdlin [string range $xbmtext $linestar $linend]
                append xbd_data "$xbdlin\n"
        }
 }

# Do this on specified file:

 xbmtoxbd ocrtest.xbm

Step two is to turn the big-endian hex codes into strings of 1's and 0's representing binary data in little-endian order.

# Procedure to convert XBD to X Bitmap Text (XBT):

 proc xbdtoxbt {xbd} {
        global xbt_text
        set xbt_text [string map {
                00 00000000 01 10000000 02 01000000 03 11000000 \
                04 00100000 05 10100000 06 01100000 07 11100000 \
                08 00010000 09 10010000 0a 01010000 0b 11010000 \
                0c 00110000 0d 10110000 0e 01110000 0f 11110000 \
                10 00001000 11 10001000 12 01001000 13 11001000 \
                14 00101000 15 10101000 16 01101000 17 11101000 \
                18 00011000 19 10011000 1a 01011000 1b 11011000 \
                1c 00111000 1d 10111000 1e 01111000 1f 11111000 \
                20 00000100 21 10000100 22 01000100 23 11000100 \
                24 00100100 25 10100100 26 01100100 27 11100100 \
                28 00010100 29 10010100 2a 01010100 2b 11010100 \
                2c 00111100 2d 10110100 2e 01110100 2f 11110100 \
                30 00001100 31 10001100 32 01001100 33 11001100 \
                34 00101100 35 10101100 36 01101100 37 11101100 \
                38 00011100 39 10011100 3a 01011100 3b 11011100 \
                3c 00111100 3d 10111100 3e 01111100 3f 11111100 \
                40 00000010 41 10000010 42 01000010 43 11000010 \
                44 00100010 45 10100010 46 01100010 47 11100010 \
                48 00010010 49 10010010 4a 01010010 4b 11010010 \
                4c 00110010 4d 10110010 4e 01110010 4f 11110010 \
                50 00001010 51 10001010 52 01001010 53 11001010 \
                54 00101010 55 10101010 56 01101010 57 11101010 \
                58 00011010 59 10011010 5a 01011010 5b 11011010 \
                5c 00111010 5d 10111010 5e 01111010 5f 11111010 \
                60 00000110 61 10000110 62 01000110 63 11000110 \
                64 00100110 65 10100110 66 01100110 67 11100110 \
                68 00010110 69 10010110 6a 01010110 6b 11010110 \
                6c 00110110 6d 10110110 6e 01110110 6f 11111110 \
                70 00001110 71 10001110 72 01001110 73 11001110 \
                74 00101110 75 10101110 76 01101110 77 11101110 \
                78 00011110 79 10011110 7a 01011110 7b 11011110 \
                7c 00111110 7d 10111110 7e 01111110 7f 11111110 \
                80 00000001 81 10000001 82 01000001 83 11000001 \
                84 00100001 85 10100001 86 01100001 87 11100001 \
                88 00010001 89 10010001 8a 01010001 8b 11010001 \
                8c 00110001 8d 10110001 8e 01110001 8f 11110001 \
                90 00001001 91 10001001 92 01001001 93 11001001 \
                94 00101001 95 10101001 96 01101001 97 11101001 \
                98 00011001 99 10011001 9a 01011001 9b 11011001 \
                9c 00111001 9d 10111001 9e 01111001 9f 11111001 \
                a0 00000101 a1 10000101 a2 01000101 a3 11000101 \
                a4 00100101 a5 10100101 a6 01100101 a7 11100101 \
                a8 00010101 a9 10010101 aa 01010101 ab 11010101 \
                ac 00110101 ad 10110101 ae 01110101 af 11110101 \
                b0 00001101 b1 10001101 b2 01001101 b3 11001101 \
                b4 00101101 b5 10101101 b6 01101101 b7 11101101 \
                b8 00011101 b9 10011101 ba 01011101 bb 11011101 \
                bc 00111101 bd 10111101 be 01111101 bf 11111101 \
                c0 00000011 c1 10000011 c2 01000011 c3 11000011 \
                c4 00100011 c5 10100011 c6 01100011 c7 11100011 \
                c8 00010011 c9 10010011 ca 01010011 cb 11010011 \
                cc 00110011 cd 10110011 ce 01110011 cf 11110011 \
                d0 00001011 d1 10001011 d2 01001011 d3 11001011 \
                d4 00101011 d5 10101011 d6 01101011 d7 11101011 \
                d8 00011011 d9 10011011 da 01011011 db 11011011 \
                dc 00111011 dd 10111011 de 01111011 df 11111011 \
                e0 00000111 e1 10000111 e2 01000111 e3 11000111 \
                e4 00100111 e5 10100111 e6 01100111 e7 11100111 \
                e8 00010111 e9 10010111 ea 01010111 eb 11010111 \
                ec 00110111 ed 10110111 ee 01110111 ef 11110111 \
                f0 00001111 f1 10001111 f2 01001111 f3 11001111 \
                f4 00101111 f5 10101111 f6 01101111 f7 11101111 \
                f8 00011111 f9 10011111 fa 01011111 fb 11011111 \
                fc 00111111 fd 10111111 fe 01111111 ff 11111111 \
        } $xbd]
 }

# Do this on the XBD data obtained in step one:

 xbdtoxbt $xbd_data

# Insert 1's and 0's into empty text widget called ".texto" (with no word or character wrap, # and with horizontal and vertical scrollbars!) and see the result:

 .texto insert 1.0 $xbt_text