Welcome, guest | Sign In | My Account | Store | Cart
#!/usr/bin/python
#-*- coding:utf-8 -*-

#brsyuksel.com

from tempfile import TemporaryFile

class BI_RLE(object):
       
def __init__(self,i,o):
               
self.i = open(i)
               
self.o = open(o,"w")
               
self.tmp = TemporaryFile()
               
               
if self.i.read(2) != 'BM':
                       
raise IOError, "Not BMP file"
               
               
self.i.seek(10)
                of
= self.i.read(4)#offset to start image data
               
self.offset = sum([ord(of[i])<<8*i for i in range(len(of))])

               
self.i.seek(18)
                w
= self.i.read(4)#image width
               
self.w = sum([ord(w[i])<<8*i for i in range(len(w))])

                h
= self.i.read(4)#image height
               
self.h = sum([ord(h[i])<<8*i for i in range(len(h))])

               
self.i.seek(28)
                b
= self.i.read(2)#channel:bit per pixel
               
self.bpp = sum([ord(b[i])<<8*i for i in range(len(b))])

               
if self.bpp != 4 and self.bpp != 8:
                       
raise IOError, "Not 4-Bit or 8-Bit BMP file"

                c
= self.i.read(4)#compression type
               
self.comp = sum([ord(c[i])<<8*i for i in range(len(c))])

               
if self.comp != 2 and self.comp != 1:
                       
raise IOError, "Not Compressed file"

               
self.tPix = self.w * self.h
               
self.rPix = 0
               
self.lns = 1

               
self.c = 0
               
self.EORLED = False#fix for EORLE

               
self.i.seek(self.offset)
               
self.enc = self.i.read()
               
self.dec = ""
               
self.buf = ""

       
def Decode(self):
                mrk
= {0:self.EOSL,1:self.EORLE,2:self.MOFF}#funcs for RLE Data markers

               
while((self.lns*self.w)<=self.tPix):
                        b
= self.enc[self.c:self.c+2]
                       
self.c += 2
                       
if len(b) != 2: break
                        b0
, b1 = ord(b[0]), ord(b[1])
                       
if b0 == 0:
                                mrk
.get(b1,self.UENCD)(b0,b1)
                       
else:
                               
self.DENCD(b0,b1)

       
def HPIX(self,pixel):
               
""" Half-Byte Packing for 4-Bit and Pixel Data Handler """
               
if self.bpp == 4:
                       
if self.buf == "":
                               
self.buf = chr(pixel<<4)
                       
else:
                               
self.buf = chr(ord(self.buf) | pixel)
                               
self.tmp.write(self.buf)
                               
self.buf = ""
               
else:
                       
self.tmp.write(chr(pixel))

       
def EOSL(self,*arg):
               
""" 00 00: End Of Scan Line """
                remain
= self.w - self.rPix
               
if not self.EORLED:
                       
self.rPix = 0
                       
self.lns += 1
               
if remain == 0: remain = 2#fix for EOSL
               
for i in range(remain):
                       
self.HPIX(0x00)

       
def MOFF(self,*arg):
               
""" 00 02: Move Offset """
                mov
= self.enc[self.c:self.c+2]
               
self.c += 2
                mov
= ord(mov[0]) + ord(mov[1])*self.w
               
for i in range(mov):
                       
self.HPIX(0x00)
               
self.rPix += mov
               
self.lns += self.rPix // mov
               
self.rPix %= mov

       
def UENCD(self,*arg):
               
""" 00 NN: Unencoded Data """
                p
= arg[1] #unencoded pixels data
               
if self.bpp == 4:
                       
#read bytes with padding byte for 4 bit
                        b
= int(round(p/2)) + (int(round(p/2))%2 | p%2)
               
else:
                       
#read bytes with padding byte for 8 bit
                        b
= p + p%2
                ue
= self.enc[self.c:self.c+b]
               
self.c += b
                delta
= self.rPix + p
               
for i in range(b):
                       
if self.rPix == delta: break
                       
if self.bpp == 4:
                               
for j in range(2):
                                       
if self.rPix == delta: break
                                       
self.HPIX((ord(ue[i])&(0x0F<<(4*((j+1)%2))))>>(4*((j+1)%2)))
                                       
self.rPix += 1
                       
else:
                               
self.HPIX(ord(ue[i]))
                               
self.rPix += 1

       
def DENCD(self,*arg):
               
""" NN PP: Decode Encoded Data """
                b0
, b1 = arg[0], arg[1] #piece, 2 pixels data
               
for i in range(b0):
                       
if self.bpp == 4:
                               
self.HPIX((b1&(0x0F<<(4*((i+1)%2))))>>(4*((i+1)%2)))
                       
else:
                               
self.HPIX(b1)
                       
self.rPix += 1

       
def EORLE(self,*arg):
               
""" 00 01: End Of RLE Data, Writing Decoded File """
               
self.EORLED = True
               
self.EOSL()
               
if not self.buf == "": self.tmp.write(self.buf)

               
self.tmp.seek(0)
               
self.dec = self.tmp.read()
               
self.tmp.close()

               
self.i.seek(0)
               
self.o.write(self.i.read(2)) #'BM' signature

                fs
= self.offset + len(self.dec) #FileSize: (Header + Color Palette) + ImageData
                fsize
= "" #filesize string value
               
for i in range(4): fsize+=chr((fs & (0xFF<<8*i))>>8*i)#ordering as little-endian
               
self.o.write(fsize)

               
self.i.seek(6)
               
self.o.write(self.i.read(24))#writing 24-byte same data from 6 offset

               
self.o.write('\x00\x00\x00\x00')#compression-type: none

                imgdsize
= ""#image data size string value
               
for i in range(4): imgdsize+=chr((len(self.dec)&(0xFF<<8*i))>>8*i)
               
self.o.write(imgdsize)

               
self.i.seek(38)
               
self.o.write(self.i.read(self.offset-38))#writing left same data from 38

               
self.o.write(self.dec)

               
self.o.close()
               
self.i.close()


#BI_RLE(inputfile,outputfile)
#obj = BI_RLE("/home/brs/m/4bitc.bmp","/home/brs/m/4bitc-dec.bmp")
#obj.Decode()

History