示例#1
0
文件: bmp.py 项目: mcgrew/pimp
def write( filename, width, height, data ):
    """
    Writes data out to a windows bitmap file.

    :Parameters:
        filename : string
            The name of the file to write to.
        width : int
            The width of the image in pixels
        height : int
            The height of the image in pixels
        data : string
            The data as a binary string.

    :rtype: boolean
    :returns: True on success
    """
    bpp = 24

    if bpp == 4:
        # 16 colors are reserved for this depth of images.
        colors = { "\x00\x00\x00": 0, "\x80\x00\x00": 1, "\x00\x80\x00": 2, "\x80\x80\x00": 3,
                   "\x00\x00\x80": 4, "\x80\x00\x80": 5, "\x00\x80\x80": 6, "\xc0\xc0\xc0": 7,
                   "\x80\x80\x80": 8, "\xff\x00\x00": 9, "\x00\xff\x00":10, "\xff\xff\x00":11,
                   "\x00\x00\xff":12, "\x00\xff\xff":13, "\x00\xff\xff":14, "\xff\xff\xff":15 }
        
        data = [ data[ i*width*3 : (i+1)*width*3 ] for i in range( height ) ]
        data.reverse( ) #reverse the bytes ( they are stored this way in bmp format )
        rawdata = ''.join( data )
        # I'm not sure of the easiest way to transform the raw data into the format I need here.
        # Color #7 is causing the problem, otherwise I could just bitmask it with 0xc0.
        # If I do that, I won't be able to tell the difference between 0xff and 0xc0.
        
    
    if bpp == 24:
        #swap the red and blue channels to make it easier to write this format
        data = swapChannels( width, height, data, 0, 2 )[ 2 ]
        
        # split data into a list of rows
        data = [ data[ i*width*3 : (i+1)*width*3 ] for i in range( height ) ]
        padding = "\x00" * ( ( -width * 3 ) % 4 ) # make each row an even multiple of 4.
        data.reverse( ) #reverse the bytes ( they are stored this way in bmp format )
        bmpdata = padding.join( data )
            
    # create the header (Windows V3)
    filesize = len( bmpdata ) + 54
    header = "BM"

    header += struct.pack( "IHHI", filesize, 0, 0, 54 ) # The main file header

    header += struct.pack( "IIIHHIIIIII", 40, width, height, 1, bpp, 0, len( bmpdata ), 3937, 3937, 0, 0 ) # Windows V3 header

    imageFile = open( filename, 'wb' )
    imageFile.write( header + bmpdata )
    imageFile.close( )
    return True
示例#2
0
def execute( width, height, data ):
    """
    Swaps the red and blue channels in an image.
        
    :Parameters:
        width : int
            The width of the image being converted
        height : int
            The height of the image being converted
        data : string
            A string containing the data for the image
    
    :rtype: tuple
    :returns: a tuple containing a width, height, and data as a binary string.
    """
    channels = len( data ) // ( width * height )
    if channels in ( 3, 4 ):
        return swapChannels( width, height, data, 0, 2 )
示例#3
0
文件: bmp.py 项目: mcgrew/pimp
def read( filename ):
    """
    Reads a windows bitmap file.

    :Parameters:
        filename : string
            the name of the file to be read.

    :rtype: tuple
    :returns: A tuple ( width, height, data ). Width and height are in pixels, data is a string containing chr(red) + chr(green) + chr(blue) for each pixel.
    """
    imageData = str( )
    imageFile = open( filename, 'rb' )
    #=========================== READ THE FILE HEADER ========================================    
    fileHeader = imageFile.read( 14 )
    if ( fileHeader[ :2 ] != 'BM' ):
        log( "Warning: Incorrectly formatted bitmap file" )
    dataAddress = struct.unpack( 'I', fileHeader[ 10: ] )[ 0 ]
    infoHeader = imageFile.read( dataAddress - 14 )
    infoHeaderSize = struct.unpack( 'I', infoHeader[ :4 ] )[ 0 ]

    #============================ READ THE INFOHEADER ==========================================    
    if ( infoHeaderSize == 24 ): # OS/2 V1 Header
        width, height, colorPlanes, bpp = struct.unpack( "HHHH", infoHeader[ 4:12 ] )
        
    elif ( infoHeaderSize == 40 ): # Windows V3 Header
        width, height, colorPlanes, bpp, compression = struct.unpack( 'IIHHI', infoHeader[ 4:20 ] )
        
    else:
        imageFile.close( )
        raise ImageFormatError( "Unable to parse header information" )
    #========================================================================================
    
    if compression:
        imageFile.close( )
        raise ImageReadError( "Compressed bitmap images are not currently supported" )

    if bpp == 4:
        # 16 colors are reserved for this depth of images. The following are the 20 reserved
        # Windows colors. The 4 commented out are omitted from this palette.
        colors = {   0: "\x00\x00\x00",   1: "\x80\x00\x00",   2: "\x00\x80\x00",   3: "\x80\x80\x00",
                     4: "\x00\x00\x80",   5: "\x80\x00\x80",   6: "\x00\x80\x80",   7: "\xc0\xc0\xc0",
                     #8: "\xc0\xdc\xc0",   9: "\xa6\xca\xf0", 246: "\xff\xfb\xf0", 247: "\xa0\xa0\xa4",
                   248: "\x80\x80\x80", 249: "\xff\x00\x00", 250: "\x00\xff\x00", 251: "\xff\xff\x00",
                   252: "\x00\x00\xff", 253: "\x00\xff\xff", 254: "\x00\xff\xff", 255: "\xff\xff\xff" }
        palette = colors.values( )

        data = imageFile.read( )
        try:
            translatedData = str( )
            for i in range( len( data ) ):
                pixels = ord( data[ i ] )
                translatedData += palette[ pixels >> 4 ] + palette[ pixels & 0xf ]
            imageData = [ translatedData[ i*width*3 : (i+1)*width*3 ] for i in range( height ) ]
            imageData.reverse( )
            imageData = ''.join( imageData )
        except IndexError:
            raise ImageReadError( "This image appears to be corrupted." )

    elif bpp == 24:
        eof = width * height * 3
        while ( len( imageData ) < eof ):
            data = imageFile.read( width * 3 )
            #throw away the extra \0 padding at the end of a line (if any)
            padding = ( -width * 3 ) % 4
            if padding:
                imageFile.seek( imageFile.tell( ) + padding )
            imageData = data + imageData
        # swap the red and blue channels, the channels are stored in reverse order
        # from what we need in the file
        imageData = swapChannels( width, height, imageData, 0, 2 )[ 2 ]
    else:
        imageFile.close( )
        raise ImageFormatError( "Images of %d bpp are not supported" % depth )
    imageFile.close( )

    return ( width, height, imageData )