--- /dev/null
+# -*- coding: utf-8 -*-\r
+"""\r
+bmp.py - module for constructing simple BMP graphics files\r
+\r
+ Permission is hereby granted, free of charge, to any person obtaining\r
+ a copy of this software and associated documentation files (the\r
+ "Software"), to deal in the Software without restriction, including\r
+ without limitation the rights to use, copy, modify, merge, publish,\r
+ distribute, sublicense, and/or sell copies of the Software, and to\r
+ permit persons to whom the Software is furnished to do so, subject to\r
+ the following conditions:\r
+\r
+ The above copyright notice and this permission notice shall be\r
+ included in all copies or substantial portions of the Software.\r
+\r
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\r
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\r
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\r
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+\r
+"""\r
+__version__ = "0.3"\r
+__about = "bmp module, version %s, written by Paul McGuire, October, 2003, updated by Margus Laak, September, 2009" % __version__ \r
+\r
+from math import ceil, hypot\r
+\r
+\r
+def shortToString(i):\r
+ hi = (i & 0xff00) >> 8\r
+ lo = i & 0x00ff\r
+ return chr(lo) + chr(hi)\r
+\r
+def longToString(i):\r
+ hi = (long(i) & 0x7fff0000) >> 16\r
+ lo = long(i) & 0x0000ffff\r
+ return shortToString(lo) + shortToString(hi)\r
+\r
+def long24ToString(i):\r
+ return chr(i & 0xff) + chr(i >> 8 & 0xff) + chr(i >> 16 & 0xff)\r
+\r
+def stringToLong(input_string, offset):\r
+ return ord(input_string[offset+3]) << 24 | ord(input_string[offset+2]) << 16 | ord(input_string[offset+1]) << 8 | ord(input_string[offset])\r
+\r
+def stringToLong24(input_string, offset):\r
+ return ord(input_string[offset+2]) << 16 | ord(input_string[offset+1]) << 8 | ord(input_string[offset])\r
+\r
+class Color(object):\r
+ """class for specifying colors while drawing BitMap elements"""\r
+ __slots__ = [ 'red', 'grn', 'blu' ]\r
+ __shade = 32\r
+ \r
+ def __init__( self, r=0, g=0, b=0 ):\r
+ self.red = r\r
+ self.grn = g\r
+ self.blu = b\r
+\r
+ def __setattr__(self, name, value):\r
+ if hasattr(self, name):\r
+ raise AttributeError, "Color is immutable"\r
+ else:\r
+ object.__setattr__(self, name, value)\r
+\r
+ def __str__( self ):\r
+ return "R:%d G:%d B:%d" % (self.red, self.grn, self.blu )\r
+ \r
+ def __hash__( self ):\r
+ return ( ( long(self.blu) ) + \r
+ ( long(self.grn) << 8 ) + \r
+ ( long(self.red) << 16 ) )\r
+ \r
+ def __eq__( self, other ):\r
+ return (self is other) or (self.toLong == other.toLong)\r
+\r
+ def lighten( self ):\r
+ return Color( \r
+ min( self.red + Color.__shade, 255), \r
+ min( self.grn + Color.__shade, 255), \r
+ min( self.blu + Color.__shade, 255) \r
+ )\r
+ \r
+ def darken( self ):\r
+ return Color( \r
+ max( self.red - Color.__shade, 0), \r
+ max( self.grn - Color.__shade, 0), \r
+ max( self.blu - Color.__shade, 0) \r
+ )\r
+ \r
+ def toLong( self ):\r
+ return self.__hash__()\r
+ \r
+ def fromLong( l ):\r
+ b = l & 0xff\r
+ l = l >> 8\r
+ g = l & 0xff\r
+ l = l >> 8\r
+ r = l & 0xff\r
+ return Color( r, g, b )\r
+ fromLong = staticmethod(fromLong)\r
+\r
+# define class constants for common colors\r
+Color.BLACK = Color( 0, 0, 0 )\r
+Color.RED = Color( 255, 0, 0 )\r
+Color.GREEN = Color( 0, 255, 0 )\r
+Color.BLUE = Color( 0, 0, 255 )\r
+Color.CYAN = Color( 0, 255, 255 )\r
+Color.MAGENTA = Color( 255, 0, 255 )\r
+Color.YELLOW = Color( 255, 255, 0 )\r
+Color.WHITE = Color( 255, 255, 255 )\r
+Color.DKRED = Color( 128, 0, 0 )\r
+Color.DKGREEN = Color( 0, 128, 0 )\r
+Color.DKBLUE = Color( 0, 0, 128 )\r
+Color.TEAL = Color( 0, 128, 128 )\r
+Color.PURPLE = Color( 128, 0, 128 )\r
+Color.BROWN = Color( 128, 128, 0 )\r
+Color.GRAY = Color( 128, 128, 128 )\r
+\r
+\r
+class BitMap(object):\r
+ """class for drawing and saving simple Windows bitmap files"""\r
+ \r
+ LINE_SOLID = 0\r
+ LINE_DASHED = 1\r
+ LINE_DOTTED = 2\r
+ LINE_DOT_DASH=3\r
+ _DASH_LEN = 12.0\r
+ _DOT_LEN = 6.0\r
+ _DOT_DASH_LEN = _DOT_LEN + _DASH_LEN\r
+ \r
+ def __init__( self, width, height, \r
+ bkgd = Color.WHITE, frgd = Color.BLACK ):\r
+ self.wd = int( ceil(width) )\r
+ self.ht = int( ceil(height) )\r
+ self.bgcolor = 0\r
+ self.fgcolor = 1\r
+ self.palette = []\r
+ self.palette.append( bkgd.toLong() )\r
+ self.palette.append( frgd.toLong() )\r
+ self.currentPen = self.fgcolor\r
+\r
+ tmparray = [ self.bgcolor ] * self.wd\r
+ self.bitarray = [ tmparray[:] for i in range( self.ht ) ]\r
+ self.currentPen = 1\r
+ \r
+\r
+ def plotPoint( self, x, y ):\r
+ if ( 0 <= x < self.wd and 0 <= y < self.ht ):\r
+ x = int(x)\r
+ y = int(y)\r
+ self.bitarray[y][x] = self.currentPen\r
+ \r
+\r
+ def _saveBitMapNoCompression( self ):\r
+ line_padding = (4 - (self.wd % 4)) % 4\r
+ \r
+ # write bitmap header\r
+ _bitmap = "BM"\r
+ _bitmap += longToString( 54 + self.ht*(self.wd*3 + line_padding) ) # DWORD size in bytes of the file\r
+ _bitmap += longToString( 0 ) # DWORD 0\r
+ _bitmap += longToString( 54 )\r
+ _bitmap += longToString( 40 ) # DWORD header size = 40\r
+ _bitmap += longToString( self.wd ) # DWORD image width\r
+ _bitmap += longToString( self.ht ) # DWORD image height\r
+ _bitmap += shortToString( 1 ) # WORD planes = 1\r
+ _bitmap += shortToString( 24 ) # WORD bits per pixel = 8\r
+ _bitmap += longToString( 0 ) # DWORD compression = 0\r
+ _bitmap += longToString( self.ht * (self.wd * 3 + line_padding) ) # DWORD sizeimage = size in bytes of the bitmap = width * height\r
+ _bitmap += longToString( 0 ) # DWORD horiz pixels per meter (?)\r
+ _bitmap += longToString( 0 ) # DWORD ver pixels per meter (?)\r
+ _bitmap += longToString( 0 ) # DWORD number of colors used = 256\r
+ _bitmap += longToString( 0 ) # DWORD number of "import colors = len( self.palette )\r
+\r
+ # write pixels\r
+ self.bitarray.reverse()\r
+ for row in self.bitarray:\r
+ for pixel in row:\r
+ c = self.palette[pixel]\r
+ _bitmap += long24ToString(c)\r
+ for i in range(line_padding):\r
+ _bitmap += chr( 0 )\r
+\r
+ return _bitmap\r
+\r
+ \r
+ \r
+ def saveFile( self, filename):\r
+ _b = self._saveBitMapNoCompression( )\r
+ \r
+ f = file(filename, 'wb')\r
+ f.write(_b)\r
+ f.close()\r
+ \r
+\r
+\r
+\r
+ \r
+ \r
+if __name__ == "__main__":\r
+ \r
+ bmp = BitMap( 10, 10 )\r
+ bmp.plotPoint( 5, 5 )\r
+ bmp.plotPoint( 0, 0 )\r
+ bmp.saveFile( "test.bmp" )\r
+\r