0001 #!/usr/bin/env python 0002 0003 ### BITPIM 0004 ### 0005 ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 0006 ### 0007 ### This program is free software; you can redistribute it and/or modify 0008 ### it under the terms of the BitPim license as detailed in the LICENSE file. 0009 ### 0010 ### $Id: brewcompressedimage.py 2781 2006-01-30 23:18:32Z djpham $ 0011 0012 """Support for the BCI (Brew Compressed Image) format 0013 0014 Currently this code can read a BCI file. You should call the 0015 L{getimage} function. 0016 0017 """ 0018 0019 """ 0020 integers are lsb 0021 0022 0000 - 0003 BCI\0 0023 0004 - 0007 ? (x0844 = 2116) [length of file] 0024 0008 - 000b ? (x0434 = 1076) [offset to first image 0025 000c - 000d ? (1) 0026 000e - 000f width 0027 0010 - 0011 height 0028 0012 - 0013 ? (1) 2 0029 0014 - 0015 ? (1) 2 0030 0016 - 0017 ? (1) 2 0031 0018 - 0019 ? (0) 0032 001a - 001b ? (8) [bits per pixel?] 0033 001c - 001d ? (1) 0034 001e - 001f ? [0x100 = 256 ] # number of entries in palette 0035 0036 palette 0037 b,g,r,0 (32 bit entry) 0038 0039 next palette 0040 0000 - 0001 ? (2) palette number/id 0041 0002 - 0003 number of entries in palette 0042 0043 image 0044 0000 - 0001 data length 0045 0002 - 0003 ? (0) 0046 0004 - 0005 width 0047 0006 - 0007 height 0048 0008 - 0009 ? (1) 0049 000a - 000b ? (1) 0050 0051 """ 0052 0053 import common 0054 import zlib 0055 import cStringIO 0056 0057 import wx 0058 0059 class Display(wx.Frame): 0060 """Used for the builtin tester""" 0061 0062 def __init__(self, file, parent=None): 0063 bmp=wx.BitmapFromImage(wx.Image(file)) 0064 0065 wx.Frame.__init__(self, parent, -1, "Image Display") 0066 0067 b=wx.StaticBitmap(self, -1, bmp) 0068 0069 b.SetSize((bmp.GetWidth(), bmp.GetHeight())) 0070 self.Fit() 0071 self.Show(True) 0072 0073 0074 class MyImage: 0075 """An encapsulation of the image""" 0076 0077 def __init__(self, width, height, bytes, palette): 0078 self.width=width 0079 self.height=height 0080 offset=0 0081 import cStringIO 0082 data=cStringIO.StringIO() 0083 for row in range(height): 0084 # print "\r"+`row`, 0085 # 32 bit alignment 0086 while (offset%4)!=0: 0087 offset+=1 0088 for col in range(width): 0089 v=ord(bytes[offset]) 0090 offset+=1 0091 data.write(palette[v]) 0092 0093 self.data=data.getvalue() 0094 # print 0095 0096 def toImage(self, img=None): 0097 """Converts image to wxImage 0098 0099 @rtype: wxImage 0100 """ 0101 if img is None: 0102 img=wx.EmptyImage(self.width, self.height) 0103 else: 0104 img.Destroy() 0105 img.Create(self.width, self.height) 0106 img.SetData(self.data) 0107 return img 0108 0109 class BCIPalette: 0110 """An encapsulation of the palette""" 0111 def __init__(self, data=""): 0112 pal=[] 0113 for offset in range(0, len(data), 4): 0114 assert data[3]=="\x00" 0115 pal.append(data[offset+2]+data[offset+1]+data[offset]) 0116 self.pal=pal 0117 0118 def __getitem__(self,e): 0119 return self.pal[e] 0120 0121 class MemoryInputStream(wx.InputStream): 0122 def __init__(self, data): 0123 import cStringIO 0124 wx.InputStream.__init__(self,cStringIO.StringIO(data)) 0125 0126 class FileInputStream(wx.InputStream): 0127 def __init__(self, name): 0128 self.f=open(name, "rb") 0129 wx.InputStream.__init__(self, self.f) 0130 0131 def __del__(self): 0132 self.f.close() 0133 0134 def getimage(stream, intoImage=None): 0135 """Returns a wxImage of the stream specified""" 0136 0137 # try to read the entire thing in one gulp 0138 data=stream.read() 0139 # save hex version for debugging 0140 # f=open(file+".hex", "w") 0141 # f.write(common.datatohexstring(data)) 0142 # f.close() 0143 0144 palettes={} 0145 0146 ### verify format 0147 0148 # header 0149 assert data[0x00:0x04]=='BCI\x00' 0150 # file length 0151 assert readlsb(data[0x04:0x08])<=len(data) # this would be == but the bci tool doesn't truncate the file! 0152 # image offset 0153 imageoffset=readlsb(data[0x08:0x0b]) 0154 assert imageoffset<len(data) 0155 # ? (1) 0156 assert readlsb(data[0x0c:0x0e])==1 0157 # width, height 0158 width=readlsb(data[0x0e:0x10]) 0159 height=readlsb(data[0x10:0x12]) 0160 assert width>0 and height>0 0161 # number of objects/frames/palettes? no idea on order 0162 numitem1=readlsb(data[0x12:0x14]) 0163 numitem2=readlsb(data[0x14:0x16]) 0164 numitem3=readlsb(data[0x16:0x18]) 0165 # print "number of objects/frames/palettes? no idea on order: %d, %d, %d" % (numitem1, numitem2, numitem3) 0166 numpalettes=numitem1 # just a guess 0167 numotherthing=numitem2 # no idea what they are, possibly 'frames' as in the doc 0168 numimages=numitem3 # images, probably 'object' as in the doc 0169 # ? (0) 0170 assert readlsb(data[0x18:0x1a])==0 0171 # palette depth? 0172 bpp=readlsb(data[0x1a:0x1c]) 0173 # read the palettes 0174 offset=0x1c 0175 for _ in range(numpalettes): 0176 id=readlsb(data[offset:offset+2]) 0177 # print "palette id",id 0178 offset+=2 0179 numentries=readlsb(data[offset:offset+2]) 0180 # print "contains",numentries,"entries" 0181 offset+=2 0182 # f=open(file+".palette."+`id`+".hex", "w") 0183 # f.write(common.datatohexstring(data[offset:offset+numentries*4])) 0184 # f.close() 0185 pal=BCIPalette(data[offset:offset+numentries*4]) 0186 offset+=numentries*4 0187 palettes[id]=pal 0188 0189 0190 # some other type of object, possibly frames as in the doc 0191 for _ in range(numotherthing): 0192 # we just ignore the contents for the moment 0193 # print common.datatohexstring(data[offset:offset+0x14]) 0194 offset+=0x14 0195 0196 # images 0197 for _ in range(numimages): 0198 szdata=readlsb(data[offset:offset+4]) 0199 width=readlsb(data[offset+4:offset+6]) 0200 height=readlsb(data[offset+6:offset+8]) 0201 id1=readlsb(data[offset+8:offset+0xa]) # image id? 0202 id2=readlsb(data[offset+0xa:offset+0xc]) # palette id? 0203 offset+=0xc 0204 buf=data[offset:offset+szdata] 0205 res=zlib.decompress(buf) 0206 # f=open(file+".image."+`id1`+".hex", "w") 0207 # f.write(common.datatohexstring(res)) 0208 # f.close() 0209 0210 img=MyImage(width, height, res, palettes[id2]) 0211 0212 return img.toImage(intoImage) 0213 0214 def readlsb(data): 0215 """Read binary data in lsb""" 0216 res=0 0217 shift=0 0218 for i in data: 0219 res|=ord(i)<<shift 0220 shift+=8 0221 return res 0222 0223 BITMAP_TYPE_BCI=wx.BITMAP_TYPE_ANY+1 0224 0225 class BCIImageHandler(wx.PyImageHandler): 0226 0227 def __init__(self): 0228 super(BCIImageHandler, self).__init__() 0229 self.SetName("BREW Compressed Image") 0230 self.SetExtension("bci") 0231 self.SetType(BITMAP_TYPE_BCI) 0232 self.SetMimeType("image/x-brewcompressedimage") 0233 0234 def GetImageCount(self, _): 0235 # ::TODO:: return multiple images 0236 return 1 0237 0238 def LoadFile(self, image, stream, verbose, index): 0239 try: 0240 getimage(stream, image) 0241 return True 0242 except: 0243 return False 0244 0245 def SaveFile(self, image, stream, verbose): 0246 raise NotImplementedError 0247 0248 def DoCanRead(self, stream): 0249 # Check to see if the stream is a valid BCI stream, 0250 return stream.read(4)=='BCI\x00' 0251 0252 BITMAP_TYPE_LGBIT=BITMAP_TYPE_BCI+1 0253 class LGBITImageHandler(wx.PyImageHandler): 0254 def __init__(self): 0255 super(LGBITImageHandler, self).__init__() 0256 self.SetName('LG BIT Image') 0257 self.SetExtension('bit') 0258 self.SetType(BITMAP_TYPE_LGBIT) 0259 0260 def GetImageCount(self, _): 0261 return 1 0262 0263 def LoadFile(self, image, stream, verbose, index): 0264 return False 0265 def SaveFile(self, image, stream, verbose): 0266 return False 0267 def DoCanRead(self, stream): 0268 return False 0269 0270 wx.Image_AddHandler(BCIImageHandler()) 0271 0272 if __name__=='__main__': 0273 import sys 0274 0275 app=wx.PySimpleApp() 0276 if len(sys.argv)==2: 0277 f=Display(sys.argv[1]) 0278 elif len(sys.argv)==3: 0279 bciconvert(sys.argv[1], sys.argv[2]) 0280 f=Display(sys.argv[2]) 0281 else: 0282 assert Exception, "not enough params" 0283 0284 app.MainLoop() 0285
Generated by PyXR 0.9.4