PyXR

c:\projects\bitpim\src \ brewcompressedimage.py



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