rendered paste bodyfrom struct import *
import array , sys
import zlib
from os.path import getsize as ospath_getsize, splitext as ospath_splitext
try:
import imageop
except:
pass
'''
TODO:
Process the tRNS chunk
Imporve (make correct?) the adaptive filtering
'''
################################################################################
''' Class: Image_Error '''
################################################################################
class Image_Error(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class Color8888:
def __init__(self):
self.r = 0
self.g = 0
self.b = 0
self.a = 0xFF
class Color565:
def __init__(self):
self.nRed = 0
self.nGreen = 0
self.nBlue = 0
self.nAlpha = 0xFF
self.val = 0
def Assign_bits(self,d):
self.val = d
self.nRed = (d & 63488) >> 8
self.nGreen = (d & 2016) >> 3
self.nBlue = (d & 31) << 3
class Color1555:
def __init__(self,alpha=True):
self.alpha = alpha
self.nRed = 0
self.nGreen = 0
self.nBlue = 0
self.nAlpha = 0xFF
self.val = 0
def Assign_bits(self,d):
self.val = d
if self.alpha:
if (d >> 15):
self.nAlpha = 255
else:
self.nAlpha = 0
self.nRed = (d & 31744) >> 7
self.nGreen = (d & 992) >> 2
self.nBlue = (d & 31) << 3
def RGBA_value(self):
return unpack('L',chr(self.nRed) + chr(self.nGreen) + chr(self.nBlue) + chr(self.nAlpha))
class DXTAlphaBlockExplicit:
def __init__(self,data):
self.row = []
self.row.append(data[0])
self.row.append(data[1])
self.row.append(data[2])
self.row.append(data[3])
def GetBitsFromMask(Mask):
if Mask == 0: return 0,0
Temp = Mask
i=0
while i < 32:
if (Temp & 1):
break
i+=1
Temp = Temp >> 1
ShiftRight = i
# Temp is preserved, so use it again:
i=0
while i < 8:
if not (Temp & 1):
break
i+=1
Temp = Temp >> 1
ShiftLeft = 8 - i
return ShiftLeft,ShiftRight
################################################################################
''' Class: RGBA_data '''
################################################################################
class RGBA_data:
Bpp = 4
format = 'RGBA'
is_image = True
def __init__(self,width,height,data=None,mode='CHANNEL',fill=chr(0)):
self.Update_dimensions(width,height)
self.has_alpha = False
self.grey = False
self.mono = False
self.indexed = False
if not data:
if len(fill) == 1:
data = fill * (self.size_of_plane * 4)
else:
data = fill * self.size_of_plane
if isinstance(data,array.array):
self.data = data
if self.data.typecode == 'L':
self.mode = 'PIXEL'
else:
self.mode = 'CHANNEL'
else:
if mode.upper() == 'PIXEL':
self.data = array.array('L',data)
self.mode = 'PIXEL'
else:
self.data = array.array('B',data)
self.mode = 'CHANNEL'
def Pixel_mode(self):
if self.data.typecode == 'L': return
self.mode = 'PIXEL'
self.data = array.array('L',self.data.tostring())
def Channel_mode(self):
if self.data.typecode == 'B': return
self.mode = 'CHANNEL'
self.data = array.array('B',self.data.tostring())
def Data_length(self):
return len(self.data)
def Data_size(self):
return self.data.itemsize * len(self.data)
def Update_dimensions(self,width,height):
self.width = width
self.height = height
self.Bps = width * self.Bpp
self.size_of_plane = width * height
################################################################################
''' Class: Manipulator '''
################################################################################
class Manipulator:
def __init__(self,image=None):
if image: self.Set_image(image)
def Set_image(self,image):
if not image.is_image: image = image.RGBA
self.RGBA = image
self.width = self.RGBA.width
self.height = self.RGBA.height
self.Bpp = self.RGBA.Bpp
def Flip(self):
self.RGBA.Pixel_mode()
temp = self.RGBA.data[:]
y = self.height - 1
pos = 0
while y >= 0:
ls = y*self.width
ds = pos*self.width
self.RGBA.data[ds:ds+self.width] = temp[ls:ls+self.width]
pos +=1
y-=1
def FlipLR(self):
self.RGBA.Pixel_mode()
y = 0
while y < self.height:
ls = y*self.width
le = ls + self.width
line = self.RGBA.data[ls:le]
line.reverse()
self.RGBA.data[ls:le] = line
y+=1
return
def Rotate_90(self):
self.RGBA.Pixel_mode()
temp = self.RGBA.data[:]
width = self.height
height = self.width
pos = 0
x=0
while x < self.width:
y=self.height-1
while y > -1:
self.RGBA.data[pos] = temp[y*self.width+x]
pos+=1
y-=1
x+=1
self.width = width
self.height = height
self.Bps = self.width * self.Bpp
self.RGBA.Update_dimensions(width,height)
def Rotate_right(self): self.Rotate_90()
def Rotate_180(self):
self.RGBA.Pixel_mode()
self.RGBA.data.reverse()
def Rotate_270(self):
self.RGBA.Pixel_mode()
temp = self.RGBA.data[:]
width = self.height
height = self.width
pos = 0
x=self.width-1
while x > -1:
y=0
while y < self.height:
self.RGBA.data[pos] = temp[y*self.width+x]
pos+=1
y+=1
x-=1
self.width = width
self.height = height
self.Bps = self.width * self.Bpp
self.RGBA.Update_dimensions(width,height)
def Rotate_left(self): self.Rotate_270()
def Crop(self,top_x,top_y,bottom_x,bottom_y):
width = bottom_x - top_x
height = bottom_y - top_y
self.Bps = self.width * self.Bpp
self.RGBA.Pixel_mode()
temp = self.RGBA.data[:]
self.RGBA.data = array.array('L',chr(0)*(width*height*4))
self.RGBA.Update_dimensions(width,height)
pos = 0
y = top_y
while y < bottom_y:
new_row = pos*width
old_row = y*self.width
self.RGBA.data[new_row:new_row+width] = temp[old_row+top_x:old_row+bottom_x]
pos+=1
y+=1
self.width = width
self.height = height
self.Bps = self.width * self.Bpp
def Half(self,multiple=1):
while multiple > 0:
width = int(self.width/2)
height = int(self.height/2)
self.RGBA.Channel_mode()
t = self.RGBA.data[:]
self.RGBA.data = array.array('B',chr(0)*(width*height*4))
self.RGBA.Update_dimensions(width,height)
width_mult = self.width * 4
pos = 0
y=0
while y < height*2:
x=0
while x < width*8:
r1 = y*width_mult+x
r2 = (y+1)*width_mult+x
self.RGBA.data[pos] = (t[r1] + t[r1+4] + t[r2] + t[r2+4])/4
self.RGBA.data[pos+1] = (t[r1+1] + t[r1+5] + t[r2+1] + t[r2+5])/4
self.RGBA.data[pos+2] = (t[r1+2] + t[r1+6] + t[r2+2] + t[r2+6])/4
self.RGBA.data[pos+3] = (t[r1+3] + t[r1+7] + t[r2+3] + t[r2+7])/4
pos+=4
x+=8
y+=2
self.width = width
self.height = height
self.size_of_plane = self.width * self.height
self.Bps = self.width * self.Bpp
self.final_size = self.size_of_plane * self.Bpp
multiple-=1
def Double(self,multiple=1):
while multiple > 0:
width = self.width * 2
height = self.height * 2
self.RGBA.Channel_mode()
temp = self.RGBA.data[:]
t = array.array('B',chr(0)*(width*height*4))
self.RGBA.width = width
self.RGBA.height = height
pos = 0
y=0
while y < height:
x=0
while x < width*4:
r1 = y*width*4+x
r2 = (y+1)*width*4+x
t[r1] = t[r1+4] = t[r2] = t[r2+4] = temp[pos]
t[r1+1] = t[r1+5] = t[r2+1] = t[r2+5] = temp[pos+1]
t[r1+2] = t[r1+6] = t[r2+2] = t[r2+6] = temp[pos+2]
t[r1+3] = t[r1+7] = t[r2+3] = t[r2+7] = temp[pos+3]
pos+=4
x+=8
y+=2
self.RGBA.data = t
self.width = width
self.height = height
self.size_of_plane = self.width * self.height
self.Bps = self.width * self.Bpp
self.final_size = self.size_of_plane * self.Bpp
multiple-=1
def Scale(self,width,height):
import imageop
self.RGBA.data = array.array('L',imageop.scale(self.RGBA.data.tostring(),self.Bpp,self.width,self.height,width,height))
self.RGBA.mode = 'PIXEL'
self.RGBA.Update_dimensions(width,height)
self.width = width
self.height = height
self.size_of_plane = self.width * self.height
self.Bps = self.width * self.Bpp
self.final_size = self.size_of_plane * self.Bpp
del imageop
def Invert(self):
self.RGBA.Channel_mode()
x=0
l = len(self.RGBA.data)
while x < l:
self.RGBA.data[x] = 255 - self.RGBA.data[x]
self.RGBA.data[x+1] = 255 - self.RGBA.data[x+1]
self.RGBA.data[x+2] = 255 - self.RGBA.data[x+2]
x+=4
def Grey_image(self):
self.RGBA.grey = True
self.RGBA.Channel_mode()
x=0
l = len(self.RGBA.data)
while x < l:
avg = (self.RGBA.data[x] + self.RGBA.data[x+1] + self.RGBA.data[x+2])/3
self.RGBA.data[x] = avg
self.RGBA.data[x+1] = avg
self.RGBA.data[x+2] = avg
x+=4
def Alpha_to_color(self,color=(0,0,0)):
if not self.RGBA.has_alpha: return
self.RGBA.has_alpha = False
r=color[0]
g=color[1]
b=color[2]
self.RGBA.Channel_mode()
x=0
l = len(self.RGBA.data)
while x < l:
alpha = self.RGBA.data[x+3]
self.RGBA.data[x] = self.RGBA.data[x] + int((r - self.RGBA.data[x] )*((255-alpha)/255.0))
self.RGBA.data[x+1] = self.RGBA.data[x+1] + int((g - self.RGBA.data[x+1])*((255-alpha)/255.0))
self.RGBA.data[x+2] = self.RGBA.data[x+2] + int((b - self.RGBA.data[x+2])*((255-alpha)/255.0))
self.RGBA.data[x+3] = 255
x+=4
################################################################################
''' Class: Base_image '''
################################################################################
class Base_image:
def init(self):
self.grey = False
self.mono = False
self.flipped = False
self.has_alpha = False
self.is_image = False
self.is_image_bmp = False
self.pad = False
def Write_PNG(self,outfilename,type='RGBA8',filter=0,compression=6):
RGBA_to_PNG(self.RGBA,outfilename,type=type,filter=filter,compression=compression)
return 0
def Write_TGA(self,outfilename,type='BGR24',flip=False):
RGBA_to_TGA(self.RGBA,outfilename,type=type,flip=flip)
def Write_GIF(self,outfilename,colors=2,fg=(255,255,255),bg=(0,0,0),trans=False,invert=False):
if not self.RGBA.grey:
m = Manipulator()
m.Set_image(self.RGBA)
m.Grey_image()
del m
temp = array.array('B',self.RGBA.data.tostring())
out = array.array('B',chr(0)*(len(self.RGBA.data)/4))
l = len(self.RGBA.data)
pos=0
x=0
while x < l:
if invert:
out[pos] = 255 - temp[x]
else:
out[pos] = temp[x]
pos+=1
x+=4
import imageop
mono = imageop.dither2mono(out.tostring(),self.width,self.height)
from gif_image import make_gif
open(outfilename,'wb').write(make_gif(mono,self.width,self.height,fg,bg,trans))
def Write_BMP(self,outfilename,type='24'):
BGR_to_BMP(self.RGBA,outfilename,type)
def Write_XPM(self,outfilename):
RGBA_to_XPM(self.RGBA,outfilename)
def Write_XBM(self,outfilename):
RGBA_to_XBM(self.RGBA,outfilename)
def Read_image_data(self,element_size):
f = open(self.file,'rb')
f.seek(self.addr + self.data_offset)
self.unprocessed = array.array(element_size,f.read(self.data_size))
f.close()
################################################################################
### Function: Create_blank
################################################################################
def Create_blank(self):
self.file = None
self.mipmap = 0
self.addr = 0
self.height = 128
self.width = 128
self.size_of_plane = self.width * self.height
self.Bps = self.width * 4
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = RGBA_data(self.width,self.height)
################################################################################
''' Class: Base_Indexed_image '''
################################################################################
class Base_indexed_image:
def Read_palette(self,size,pixBytes=4):
f = open(self.file,'rb')
f.seek(self.palette_offset)
p_temp = array.array('B',f.read(size))
pix = array.array('B',chr(0)*4)
self.palette = array.array('L',chr(0)*((size/pixBytes)*4))
f.close()
i=0
p=0
pix[3] = 255
l = size/pixBytes
while i < l:
pix[0] = p_temp[p+2]
pix[1] = p_temp[p+1]
pix[2] = p_temp[p]
self.palette[i] = unpack('L',pix.tostring())[0]
p += pixBytes
i+=1
def Read_16bit_palette(self,size):
f = open(self.file,'rb')
f.seek(self.palette_offset)
p_temp = array.array('H',f.read(size))
self.palette = array.array('L',chr(0)*((size/2)*4))
f.close()
color = Color1555()
i=0
l = size/2
while i < l:
color.assign_bits(p_temp[i])
self.palette[i] = color.RGBA_value()
i+=1
################################################################################
''' Class: Indexed_image '''
################################################################################
class Indexed_image(Base_image,Base_indexed_image):
def Process1bit(self):
self.Read_image_data('B')
back = self.palette[1:].tostring()
self.RGBA = RGBA_data(self.width,self.height,fill=back,mode='PIXEL')
color = self.palette[0]
padsize = 0
if self.pad: padsize = ((32 - (self.width % 32)) / 8) % 4
pos = 0
if self.flipped:
compare = self.height
j = 0
it = 1
else:
compare = -1
j=self.height-1
it = -1
while j != compare:
i=0
while i < self.width:
c=0
k=128
while c < 8:
if not (self.unprocessed[pos] & k): self.RGBA.data[j * self.width + i] = color
k >>= 1
i+=1
if i >= self.width: break
c+=1
pos +=1
pos +=padsize
j+=it
def Process2bit(self):
self.Read_image_data('B')
back = self.palette[1:].tostring()
self.RGBA = RGBA_data(self.width,self.height,fill=back,mode='PIXEL')
padsize = 0
if self.pad: padsize = ((32 - (self.width % 32)) / 8) % 4
pos = 0
if self.flipped:
compare = self.height
j = 0
it = 1
else:
compare = -1
j=self.height-1
it = -1
while j != compare:
i=0
while i < self.width:
c=6
k=192
while c > -2:
color = (self.unprocessed[pos] & k) >> c
self.RGBA.data[j * self.width + i] = self.palette[color]
k >>= 2
i+=1
if i >= self.width: break
c-=2
pos +=1
pos +=padsize
j+=it
def Process4bit(self):
self.Read_image_data('B')
back = self.palette[0:1].tostring()
self.RGBA = RGBA_data(self.width,self.height,fill=back,mode='PIXEL')
padsize = 0
if self.pad: padsize = ((8 - (self.width % 8)) / 2) % 4
pos=0
j=0
if self.flipped:
compare = self.height
j = 0
it = 1
else:
compare = -1
j=self.height-1
it = -1
while j != compare:
i=0
while i < self.width:
bytedata = self.unprocessed[pos]
self.RGBA.data[j * self.width + i] = self.palette[bytedata >> 4]
i+=1
if i == self.width: break
self.RGBA.data[j * self.width + i] = self.palette[bytedata & 0x0F]
i+=1
pos+=1
pos+=padsize
j+=it
def Process8bit(self,read=True):
if read: self.Read_image_data('B')
back = self.palette[0:1].tostring()
self.RGBA = RGBA_data(self.width,self.height,fill=back,mode='PIXEL')
padsize = 0
if self.pad: padsize = (4 - (self.Bps % 4)) % 4
pos=0
j=0
if self.flipped:
compare = self.height
j = 0
it = 1
else:
compare = -1
j=self.height-1
it = -1
while j != compare:
i=0
while i < self.width:
bytedata = self.unprocessed[pos]
self.RGBA.data[j * self.width + i] = self.palette[bytedata]
i+=1
pos+=1
j+=it
################################################################################
''' Class: Indexed_RLE_image '''
################################################################################
class RLE_image(Base_image,Base_indexed_image):
def Process_RLE8(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,fill=self.palette[0:1].tostring(),mode='PIXEL')
pos = 0
bytes = array.array('B',chr(0)*2)
y=0
while y < self.height:
x=0
while True:
bytes[0] = self.unprocessed[pos]
bytes[1] = self.unprocessed[pos+1]
pos+=2
if bytes[0] == 0: #Escape
if bytes[1] == 0: break #EOL
elif bytes[1] == 1: #Bitmap End
y = self.height
break
elif bytes[1] == 2:
bytes[0] = self.unprocessed[pos]
bytes[1] = self.unprocessed[pos+1]
pos+=2
x += bytes[0]
y += bytes[1]
if y >= self.height: break
else: # Run of pixels
if self.width - x < bytes[1]: return False
r=0
while r < bytes[1]:
self.RGBA.data[y*self.width+x+r] = self.palette[self.unprocessed[pos+r]]
r+=1
pos+=r
x+=r
if bytes[1] % 2: pos +=1
else:
dc_loc = y * self.width + x
r=0
while r < bytes[0]:
self.RGBA.data[dc_loc+r] = self.palette[bytes[1]]
r+=1
x += bytes[0]
y+=1
if not self.flipped: Manipulator(image=self.RGBA).Flip()
def Process_RLE4(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,fill=self.palette[0:1].tostring(),mode='PIXEL')
pos = 0
bytes = array.array('B',chr(0)*2)
y=0
while y < self.height:
x=0
while True:
bytes[0] = self.unprocessed[pos]
bytes[1] = self.unprocessed[pos+1]
pos+=2
if bytes[0] == 0:
if bytes[1] == 0: break
elif bytes[1] == 1:
y = self.height
break
elif bytes[1] == 2:
bytes[0] = self.unprocessed[pos]
bytes[1] = self.unprocessed[pos+1]
pos+=2
x += bytes[0]
y += bytes[1]
if y >= self.height: break
else: # Run of pixels
r=0
while r < bytes[1] and x < self.width:
twopix = self.unprocessed[pos]
pos+=1
upper = twopix >> 4
lower = twopix & 15
x+=1
self.RGBA.data[y * self.width + x] = self.palette[upper]
x+=1
self.RGBA.data[y * self.width + x] = self.palette[lower]
r+=2
align = bytes[1] % 4
if align == 1 or align == 2: pos+=1
else:
dc_loc = y * self.width
upper = bytes[1] >> 4
lower = bytes[1] & 15
r=0
while r < bytes[0] and x < self.width-1:
x+=1
if r & 1:
self.RGBA.data[dc_loc+x] = self.palette[lower]
else:
self.RGBA.data[dc_loc+x] = self.palette[upper]
r+=1
y+=1
if not self.flipped: Manipulator(image=self.RGBA).Flip()
def Process_PacketRLE8(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,fill=self.palette[0:1].tostring(),mode='PIXEL')
pos = 0
x = 0
l = self.RGBA.Data_length()
dl = len(self.unprocessed)
while x < l:
head = self.unprocessed[pos]
pos+=1
#if not pos < dl: return
if head & 128:
rep = (head & 127) + x
#if not pos < dl: return
index = self.unprocessed[pos]
pos+=1
while x <= rep:
self.RGBA.data[x] = self.palette[index]
x+=1
else:
run = (head & 127) + x
while x <= run:
self.RGBA.data[x] = self.palette[self.unprocessed[pos]]
pos+=1
x+=1
#if not pos < dl: return
if not self.flipped: Manipulator(image=self.RGBA).Flip()
def Process_PacketRLE_BGR(self):
if self.sourceBpp == 2:
self.Process_PacketRLE_BGR16()
return
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
pos = 0
x = 0
l = self.RGBA.Data_length()
dl = len(self.unprocessed)
Bpp = self.sourceBpp
a = 255
while x < l:
head = self.unprocessed[pos]
pos+=1
if head & 128:
rep = (head & 127)*4 + x
r = self.unprocessed[pos+2]
g = self.unprocessed[pos+1]
b = self.unprocessed[pos]
if Bpp == 4: a = self.unprocessed[pos+3]
pos+=Bpp
while x <= rep:
self.RGBA.data[x] = r
self.RGBA.data[x+1] = g
self.RGBA.data[x+2] = b
self.RGBA.data[x+3] = a
x+=4
#if not x < l: break
else:
run = (head & 127)*4 + x
while x <= run:
self.RGBA.data[x] = self.unprocessed[pos+2]
self.RGBA.data[x+1] = self.unprocessed[pos+1]
self.RGBA.data[x+2] = self.unprocessed[pos]
if Bpp == 4: a = self.unprocessed[pos+3]
self.RGBA.data[x+3] = a
pos+=Bpp
x+=4
#if not x < l: break
if not self.flipped: Manipulator(image=self.RGBA).Flip()
def Process_PacketRLE_BGR16(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
l = self.RGBA.Data_length()
if self.alpha_bits: alpha=False #WHY???????????? -------------------------------------------------------FIX???
color = Color1555(alpha=alpha)
pos = 0
x = 0
while x < l:
head = self.unprocessed[pos]
pos+=1
if head & 128:
rep = (head & 127)*4 + x
bytes = (self.unprocessed[pos+1]<<8) | self.unprocessed[pos]
color.Assign_bits(bytes)
pos+=2
while x <= rep:
self.RGBA.data[x] = color.nRed
self.RGBA.data[x+1] = color.nGreen
self.RGBA.data[x+2] = color.nBlue
self.RGBA.data[x+3] = color.nAlpha
x+=4
#if not x < l: break
else:
run = (head & 127)*4 + x
while x <= run:
bytes = (self.unprocessed[pos+1]<<8) | self.unprocessed[pos]
color.Assign_bits(bytes)
self.RGBA.data[x] = color.nRed
self.RGBA.data[x+1] = color.nGreen
self.RGBA.data[x+2] = color.nBlue
self.RGBA.data[x+3] = color.nAlpha
pos+=2
x+=4
#if not x < l: break
if not self.flipped: Manipulator(image=self.RGBA).Flip()
################################################################################
''' Class: BGR_image '''
################################################################################
class BGR_image(Base_image):
def Process16bit(self,pad=True,alpha=False):
self.Read_image_data('H')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
color = Color1555(alpha=alpha)
padsize = 0
if pad: padsize = (4 - (self.width*2 % 4)) % 4
pos = 0
outbytewidth = self.width*4
offset = 0
if self.flipped:
offsetmult = self.width
origin = pos
offset -= offsetmult
else:
offsetmult = self.width * -1
origin = offsetmult * self.height * -1
i=0
while i < self.final_size:
offset += offsetmult
pos = origin + offset
j=0
while j < outbytewidth:
color.Assign_bits(self.unprocessed[pos])
self.RGBA.data[i] = color.nRed
self.RGBA.data[i+1] = color.nGreen
self.RGBA.data[i+2] = color.nBlue
self.RGBA.data[i+3] = color.nAlpha
j+=4
i+=4
pos +=1
pos+=padsize
def Process24bit(self,pad=True):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
pos = 0
padsize = 0
if pad:
padsize = (4 - (self.Bps % 4)) % 4
if padsize != 0:
padsize = (4 - (self.Bps % 4))
offset = 0
if self.flipped:
offsetmult = self.width * 3 + padsize
origin = pos
offset -= offsetmult
else:
offsetmult = self.width * -3 - padsize
origin = offsetmult * self.height * -1
self.Process_BGR_data(offset,offsetmult,origin)
def Process32bit(self,alpha=False):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
pos = 0
offset = 0
if self.flipped:
offsetmult = self.width * 4
origin = pos
offset -= offsetmult
else:
origin = pos + self.final_size
offsetmult = self.width * -4
if alpha:
self.Process_BGRA_data(offset,offsetmult,origin)
else:
self.Process_BGR_data(offset,offsetmult,origin)
def Process_BGR_data(self,offset,offsetmult,origin):
outbytewidth = self.width*4
i=0
while i < self.final_size:
offset += offsetmult
pos = origin + offset
j=0
print len(self.unprocessed)
while j < outbytewidth:
self.RGBA.data[i] = self.unprocessed[pos+2]
self.RGBA.data[i+1] = self.unprocessed[pos+1]
self.RGBA.data[i+2] = self.unprocessed[pos]
self.RGBA.data[i+3] = 0xFF
j+=4
i+=4
pos +=self.sourceBpp
def Process_BGRA_data(self,offset,offsetmult,origin):
outbytewidth = self.width*4
i=0
while i < self.final_size:
offset += offsetmult
pos = origin + offset
j=0
while j < outbytewidth:
self.RGBA.data[i] = self.unprocessed[pos+2]
self.RGBA.data[i+1] = self.unprocessed[pos+1]
self.RGBA.data[i+2] = self.unprocessed[pos]
self.RGBA.data[i+3] = self.unprocessed[pos+3]
j+=4
i+=4
pos +=self.sourceBpp
################################################################################
''' Class: Greyscale_image '''
################################################################################
class Greyscale_image:
def Process_greyA_16bit(self):
self.sourceBpp = 2
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
l=len(self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height,mode='PIXEL')
x=0
y=0
l=len(self.unprocessed)
while x < l:
self.RGBA.data[y] = self.unprocessed[x] * 65793 + self.unprocessed[x+1]*16777216
y+=1
x+=2
def Process_greyA_32bit(self):
self.sourceBpp = 4
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
l=len(self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height)
x=0
y=0
l=len(self.unprocessed)
while x < l:
self.RGBA.data[y] = self.unprocessed[x] * 65793 + self.unprocessed[x+2]*16777216
y+=1
x+=4
def Process_grey_16bit(self):
self.Create_grey_palette(256)
self.sourceBpp = 2
self.Bps = self.width * 2
x=0
y=0
self.Read_image_data('B')
l=len(self.unprocessed)
temp = array.array('B',chr(0)*(l/2))
while y < l:
temp[x] = self.unprocessed[y]
x+=1
y+=2
self.unprocessed = temp
self.Process8bit(read=False)
def Process_grey_8bit(self):
self.Create_grey_palette(256)
self.sourceBpp = 1
self.Bps = self.width
self.Process8bit()
def Process_grey_4bit(self):
self.sourceBpp = 0.5
self.Bps = (self.width + (2-self.width % 2)%2)/2
if self.interlaced:
self.Create_grey_palette(256)
self.Process8bit()
else:
self.Create_grey_palette(16)
self.Process4bit()
def Process_grey_2bit(self):
self.sourceBpp = 0.25
self.Bps = (self.width + (4-self.width % 4)%4)/4
if self.interlaced:
self.Create_grey_palette(256)
self.Process8bit()
else:
self.Create_grey_palette(4)
self.Process2bit()
def Process_grey_1bit(self):
self.sourceBpp = 0.125
self.Bps = (self.width + (8-self.width % 8)%8)/8
if self.interlaced:
self.Create_grey_palette(256)
self.Process8bit()
else:
self.Create_grey_palette(2) #Look at using imageop/mono2grey for this---------------------------------------------------------------------OPTIMIZE
self.Process1bit()
def Process_grey_PacketRLE8(self): #Needs RLE_image to work
self.Create_grey_palette(256)
self.sourceBpp = 1
self.Bps = self.width
self.Process_PacketRLE8()
def Process_grey_PacketRLE16(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='PIXEL')
pos = 0
x = 0
l = self.RGBA.Data_length()
dl = len(self.unprocessed)
while x < l:
head = self.unprocessed[pos]
pos+=1
#if not pos < dl: return
if head & 128:
rep = (head & 127) + x
#if not pos < dl: return
pixel = self.unprocessed[pos] * 65793 + self.unprocessed[pos+1]*16777216
pos+=2
while x <= rep:
self.RGBA.data[x] = pixel
x+=1
else:
run = (head & 127) + x
while x <= run:
pixel = self.unprocessed[pos] * 65793 + self.unprocessed[pos+1]*16777216
self.RGBA.data[x] = pixel
pos+=2
x+=1
#if not pos < dl: return
if not self.flipped: Manipulator(image=self.RGBA).Flip()
def Create_grey_palette(self,num):
self.palette = array.array('L',chr(0)*(num*4))
step = 255/(num-1)
p=0
for x in range(0,256,step):
self.palette[p] = long(long(65793 * x) + 4278190080)
p+=1
################################################################################
''' Class: Texture_image '''
################################################################################
class Texture_image(Base_image):
################################################################################
### Function: DecompressDXT1
################################################################################
def DecompressDXT1(self):
self.Read_image_data('H')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
#RGB Red 5 Green 6 Blue 5
color_0 = Color565()
color_1 = Color565()
# 32 bit RGBA
colors = []
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
three = long(3)
pos = 0
zoff = self.mipmap * self.size_of_plane
y=0
while y < self.height:
x=0
while x < self.width:
color_0.Assign_bits(self.unprocessed[pos])
color_1.Assign_bits(self.unprocessed[pos+1])
bitmask = (long(self.unprocessed[pos+2]) << 16) + self.unprocessed[pos+3]
pos += 4
colors[0].r = color_0.nRed
colors[0].g = color_0.nGreen
colors[0].b = color_0.nBlue
colors[1].r = color_1.nRed
colors[1].g = color_1.nGreen
colors[1].b = color_1.nBlue
if color_0.val > color_1.val:
colors[2].b = (2 * colors[0].b + colors[1].b + 1) / 3
colors[2].g = (2 * colors[0].g + colors[1].g + 1) / 3
colors[2].r = (2 * colors[0].r + colors[1].r + 1) / 3
colors[3].b = (colors[0].b + 2 * colors[1].b + 1) / 3
colors[3].g = (colors[0].g + 2 * colors[1].g + 1) / 3
colors[3].r = (colors[0].r + 2 * colors[1].r + 1) / 3
colors[3].a = 0xFF
else:
colors[2].b = (colors[0].b + colors[1].b) >> 1
colors[2].g = (colors[0].g + colors[1].g) >> 1
colors[2].r = (colors[0].r + colors[1].r) >> 1
colors[3].b = (colors[0].b + 2 * colors[1].b + 1) / 3
colors[3].g = (colors[0].g + 2 * colors[1].g + 1) / 3
colors[3].r = (colors[0].r + 2 * colors[1].r + 1) / 3
colors[3].a = 0x00
j=0
k=0
for j in (2,3,0,1):
i=0
yval = y + j
yoff = yval * self.Bps
while i < 4:
shift = k*2
select = (bitmask & (three << shift)) >> shift
col = colors[select]
xval = x + i
if xval < self.width and yval < self.height:
offset = zoff + yoff + (xval * self.Bpp)
self.RGBA.data[offset] = col.r
self.RGBA.data[offset+1] = col.g
self.RGBA.data[offset+2] = col.b
self.RGBA.data[offset+3] = col.a
i+=1
k+=1
x+=4
y+=4
del self.unprocessed
################################################################################
### Function: DecompressDXT2 - untested and unused - so far...
################################################################################
def DecompressDXT2(self):
self.DecompressDXT3()
self.CorrectPreMult()
def CorrectPreMult(self):
i=0
while i < self.final_size:
if not self.RGBA.data[i+3] == 0:
self.RGBA.data[i] = (int(self.RGBA.data[i]) << 8) / self.RGBA.data[i+3]
self.RGBA.data[i+1] = (int(self.RGBA.data[i+1]) << 8) / self.RGBA.data[i+3]
self.RGBA.data[i+2] = (int(self.RGBA.data[i+2]) << 8) / self.RGBA.data[i+3]
i+=4
################################################################################
### Function: DecompressDXT3
################################################################################
def DecompressDXT3(self):
self.Read_image_data('H')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
#RGB Red 5 Green 6 Blue 5
color_0 = Color565()
color_1 = Color565()
# 32 bit RGBA
colors = []
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
three = long(3)
pos = 0
zoff = self.mipmap * self.size_of_plane
y=0
while y < self.height:
x=0
while x < self.width:
alpha = DXTAlphaBlockExplicit(self.unprocessed[pos:pos+4])
pos += 4
color_0.Assign_bits(self.unprocessed[pos])
color_1.Assign_bits(self.unprocessed[pos+1])
bitmask = (long(self.unprocessed[pos+2]) << 16) + self.unprocessed[pos+3]
pos += 4
colors[0].r = color_0.nRed
colors[0].g = color_0.nGreen
colors[0].b = color_0.nBlue
colors[1].r = color_1.nRed
colors[1].g = color_1.nGreen
colors[1].b = color_1.nBlue
colors[2].b = (2 * colors[0].b + colors[1].b + 1) / 3
colors[2].g = (2 * colors[0].g + colors[1].g + 1) / 3
colors[2].r = (2 * colors[0].r + colors[1].r + 1) / 3
colors[3].b = (colors[0].b + 2 * colors[1].b + 1) / 3
colors[3].g = (colors[0].g + 2 * colors[1].g + 1) / 3
colors[3].r = (colors[0].r + 2 * colors[1].r + 1) / 3
k=0
j=0
for j in (2,3,0,1):
i=0
yval = y + j
yoff = yval * self.Bps
while i < 4:
shift = k*2
select = (bitmask & (three << shift)) >> shift
col = colors[select]
xval = x + i
if xval < self.width and yval < self.height:
offset = zoff + yoff + (xval * self.Bpp)
self.RGBA.data[offset] = col.r
self.RGBA.data[offset+1] = col.g
self.RGBA.data[offset+2] = col.b
i+=1
k+=1
j=0
while j < 4:
yval = y + j
yoff = yval * self.Bps
word = alpha.row[j]
i=0
while i < 4:
xval = x + i
if xval < self.width and yval < self.height:
offset = zoff + yval * self.Bps + (xval * self.Bpp) + 3
self.RGBA.data[offset] = word & 0x0F
self.RGBA.data[offset] = self.RGBA.data[offset] | (self.RGBA.data[offset] << 4)
word = word >> 4
i+=1
j+=1
x+=4
y+=4
del self.unprocessed
################################################################################
### Function: DecompressDXT4 - untested and unused - so far...
################################################################################
def DecompressDXT4(self):
self.DecompressDXT5()
self.CorrectPreMult()
################################################################################
### Function: DecompressDXT5
################################################################################
def DecompressDXT5(self):
self.Read_image_data('H')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
#RGB Red 5 Green 6 Blue 5
color_0 = Color565()
color_1 = Color565()
# 32 bit RGBA
colors = []
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
colors.append(Color8888())
alphas = [0,0,0,0,0,0,0,0]
three = long(3)
z=0
pos = 0
zoff = self.mipmap * self.size_of_plane
y=0
while y < self.height:
x=0
while x < self.width:
if y >= self.height or x >= self.width: break
alphas[0] = self.unprocessed[pos] >> 8
alphas[1] = self.unprocessed[pos] % (alphas[0] << 8)
alphamask = self.unprocessed[pos+1]
alphamask2 = self.unprocessed[pos+2]
pos += 4
color_0.Assign_bits(self.unprocessed[pos])
color_1.Assign_bits(self.unprocessed[pos+1])
bitmask = (long(self.unprocessed[pos+2]) << 16) + self.unprocessed[pos+3]
pos += 4
colors[0].r = color_0.nRed
colors[0].g = color_0.nGreen
colors[0].b = color_0.nBlue
colors[1].r = color_1.nRed
colors[1].g = color_1.nGreen
colors[1].b = color_1.nBlue
colors[2].b = (2 * colors[0].b + colors[1].b + 1) / 3
colors[2].g = (2 * colors[0].g + colors[1].g + 1) / 3
colors[2].r = (2 * colors[0].r + colors[1].r + 1) / 3
colors[3].b = (colors[0].b + 2 * colors[1].b + 1) / 3
colors[3].g = (colors[0].g + 2 * colors[1].g + 1) / 3
colors[3].r = (colors[0].r + 2 * colors[1].r + 1) / 3
k=0
j=0
for j in (2,3,0,1):
i=0
yval = y + j
yoff = yval * self.Bps
while i < 4:
shift = k*2
select = (bitmask & (three << shift)) >> shift
col = colors[select]
xval = x + i
if xval < self.width and yval < self.height:
offset = zoff + yoff + (xval * self.Bpp)
self.RGBA.data[offset] = col.r
self.RGBA.data[offset+1] = col.g
self.RGBA.data[offset+2] = col.b
i+=1
k+=1
j=0
if (alphas[0] > alphas[1]):
alphas[2] = (6 * alphas[0] + 1 * alphas[1] + 3) / 7
alphas[3] = (5 * alphas[0] + 2 * alphas[1] + 3) / 7
alphas[4] = (4 * alphas[0] + 3 * alphas[1] + 3) / 7
alphas[5] = (3 * alphas[0] + 4 * alphas[1] + 3) / 7
alphas[6] = (2 * alphas[0] + 5 * alphas[1] + 3) / 7
alphas[7] = (1 * alphas[0] + 6 * alphas[1] + 3) / 7
else :
alphas[2] = (4 * alphas[0] + 1 * alphas[1] + 2) / 5
alphas[3] = (3 * alphas[0] + 2 * alphas[1] + 2) / 5
alphas[4] = (2 * alphas[0] + 3 * alphas[1] + 2) / 5
alphas[5] = (1 * alphas[0] + 4 * alphas[1] + 2) / 5
alphas[6] = 0x00
alphas[7] = 0xFF
bits = alphamask
j=0
while j < 2:
i=0
while i < 4:
if (((x + i) < self.width) and ((y + j) < self.height)):
offset = z * self.size_of_plane + (y + j) * self.Bps + (x + i) * self.Bpp + 3
self.RGBA.data[offset] = alphas[bits & 0x07]
bits >>= 3
i+=1
j+=1
bits = alphamask2
j=2
while j < 4:
i=0
while i < 4:
if (((x + i) < self.width) and ((y + j) < self.height)):
offset = z * self.size_of_plane + (y + j) * self.Bps + (x + i) * self.Bpp + 3
self.RGBA.data[offset] = alphas[bits & 0x07]
bits >>= 3
i+=1
j+=1
x+=4
y+=4
del self.unprocessed
################################################################################
### Function: DecompressARGB32bit
################################################################################
def DecompressARGB32bit(self,alpha=True,rgb=True,swizzled=False):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
i=0
size = self.final_size
#account for BGR
self.hasError = 0
r=2 ; b=0
if not rgb: r=0 ; b=2
while i < size:
try:
self.RGBA.data[i] = self.unprocessed[i+r]
self.RGBA.data[i+1] = self.unprocessed[i+1]
self.RGBA.data[i+2] = self.unprocessed[i+b]
if alpha:
self.RGBA.data[i+3] = self.unprocessed[i+3]
else:
self.RGBA.data[i+3] = 0xFF
except:
self.hasError = 1
i+= 4
if swizzled:
self.RGBA.data = array.array('L',self.RGBA.data.tostring())
self.unswiz = array.array('L',chr(0)*self.final_size)
self.offset = 0
self.Unswizzle(0,0,self.width,self.height,self.width)
self.RGBA.data = array.array('B',self.unswiz.tostring())
##############################################################################
### Function: DecompressRGB16bit
############################################################################
def DecompressRGB16bit(self,a1555=False,alpha=False,swizzled=False):
self.Read_image_data('H')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
if a1555:
color = Color1555(alpha=alpha)
else:
color = Color565()
pos = 0
size = self.final_size
i=0
while i < size:
color.Assign_bits(self.unprocessed[pos])
pos+=1
self.RGBA.data[i] = color.nRed
self.RGBA.data[i+1] = color.nGreen
self.RGBA.data[i+2] = color.nBlue
self.RGBA.data[i+3] = color.nAlpha
i+=4
if swizzled:
self.RGBA.data = array.array('L',self.RGBA.data.tostring())
self.unswiz = array.array('L',chr(0)*self.final_size)
self.offset = 0
self.Unswizzle(0,0,self.width,self.height,self.width)
self.RGBA.data = array.array('B',self.unswiz.tostring())
############################################################################
### Function: DecompressRGB24bit
############################################################################
def DecompressRGB24bit(self,swizzled=False):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
i=0
pos = 0
size = self.final_size
while i < size:
self.RGBA.data[i] = self.unprocessed[pos+2]
self.RGBA.data[i+1] = self.unprocessed[pos+1]
self.RGBA.data[i+2] = self.unprocessed[pos]
self.RGBA.data[i+3] = 0xFF
pos+=3
i+=4
if swizzled:
self.RGBA.data = array.array('L',self.RGBA.data.tostring())
self.unswiz = array.array('L',chr(0)*self.final_size)
self.offset = 0
self.Unswizzle(0,0,self.width,self.height,self.width)
self.RGBA.data = array.array('B',self.unswiz.tostring())
############################################################################
### Function: Unswizzle
############################################################################
def Unswizzle(self,offset,offsetout,width,height,stride):
if width < 2 or height < 2:
length = width * height
self.unswiz[offsetout:offsetout+length] = self.RGBA.data[self.offset:self.offset+length]
offsetout = offsetout + (length)
elif width == 2 and height == 2:
self.unswiz[offsetout] = self.RGBA.data[self.offset]
self.unswiz[offsetout + 1] = self.RGBA.data[self.offset + 1]
self.unswiz[offsetout + stride] = self.RGBA.data[self.offset + 2]
self.unswiz[offsetout + stride + 1] = self.RGBA.data[self.offset + 3]
self.offset = self.offset + 4
else:
self.Unswizzle(self.offset, offsetout, width / 2, height / 2, stride)
self.Unswizzle(self.offset, offsetout + (width / 2), width / 2, height / 2, stride)
self.Unswizzle(self.offset, offsetout + (stride * (height / 2)), width / 2, height / 2, stride)
self.Unswizzle(self.offset, offsetout + (stride * (height / 2)) + (width / 2), width / 2, height / 2, stride)
################################################################################
''' Class: XPR0_image '''
################################################################################
class XPR0_image(Texture_image):
def __init__(self,mipmap=0,addr=0,size=None,file=None,process=True):
self.init()
self.type = 'XPR0'
if not file:
self.Create_blank()
return
if not size:
size = ospath_getsize(file)
self.file = file
self.mipmap = mipmap
self.addr = addr
self.size = size
self.Read_header()
self.Get_image_dimensions()
self.data_size = self.size - self.data_offset
self.size_of_plane = self.width * self.height
self.Bps = self.width * 4
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
if self.header['TextureFormat'] == 12:
self.DecompressDXT1()
elif self.header['TextureFormat'] == 14:
self.DecompressDXT3()
elif self.header['TextureFormat'] == 6:
self.DecompressARGB32bit(swizzled=True)
elif self.header['TextureFormat'] == 7:
self.DecompressARGB32bit(alpha=False,swizzled=True)
elif self.header['TextureFormat'] == 15:
self.DecompressDXT5()
else:
pass
#6 RGBA8 0x06
#12 DXT1 0x0C
#14 DXT3 0x0E
#15 DXT5 0x0F
#11 P8 0x0B
def Read_header(self):
format = '4s5L4B2L'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['XPRMagic'],\
self.header['TotalSize'],\
self.header['HeaderSize'],\
self.header['TextureCommon'],\
self.header['TextureData'],\
self.header['TextureLock'],\
self.header['TextureMisc1'],\
self.header['TextureFormat'],\
l_w,\
h_m,\
self.header['TextureSize'],\
self.header['EndOfHeader'] = unpack(format,f.read(calcsize(format)))
f.close()
# Get 4 bit values
l = l_w >> 4
self.header['TextureLevel'] = l
if l:
self.header['TextureWidth'] = l_w % (l << 4)
else:
self.header['TextureWidth'] = l_w
h = h_m >> 4
self.header['TextureHeight'] = h
if h:
self.header['TextureMisc2'] = h_m % (h << 4)
else:
self.header['TextureMisc2'] = h_m
def Get_image_dimensions(self):
levels = {8:(256,256),
7:(128,128),
6:(64,64),
5:(32,32),
4:(16,16),
3:(8,8),
2:(4,4),
1:(2,2),
0:(1,1)}
if levels.has_key(self.header['TextureLevel']):
self.width, self.height = levels[self.header['TextureLevel']]
else:
self.width, self.height = 128 , 128
self.data_offset = self.header['HeaderSize']
################################################################################
''' Class: DDS_image '''
################################################################################
class DDS_image(Texture_image):
def __init__(self,mipmap=0,addr=0,size=None,file=None,process=True):
self.init()
self.type = 'DDS'
if not file:
self.Create_blank()
return
if not size:
size = ospath_getsize(file)
self.file = file
self.mipmap = mipmap
self.addr = addr
self.size = size
self.Read_header(addr)
self.Get_image_dimensions()
self.data_size = self.size - self.data_offset
self.size_of_plane = self.width * self.height
self.Bps = self.width * 4
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
alpha = True
if self.header['pfFourCC'] == 'DXT1':
self.DecompressDXT1()
elif self.header['pfFourCC'] == 'DXT2':
self.DecompressDXT2()
elif self.header['pfFourCC'] == 'DXT3':
self.DecompressDXT3()
elif self.header['pfFourCC'] == 'DXT4':
self.DecompressDXT4()
elif self.header['pfFourCC'] == 'DXT5':
self.DecompressDXT5()
elif self.header['pfFourCC'] == '\x00\x00\x00\x00':
#Need to find out if image is swizzled?
if self.header['pfBpp'] == 32:
rgb = True
alpha = True
if not self.header['pfBlueMask'] == 0xFF: rgb=False
if not self.header['pfAlphaMask']: alpha = False
self.DecompressARGB32bit(alpha=alpha,rgb=rgb)
elif self.header['pfBpp'] == 16:
a1555 = False
alpha = False
if self.header['pfGreenMask'] == 992:
a1555 = True
if self.header['pfAlphaMask']: alpha = True
self.DecompressRGB16bit(a1555=a1555,alpha=alpha)
elif self.header['pfBpp'] == 24:
self.DecompressRGB24bit()
else:
pass
else:
pass
self.RGBA.has_alpha = alpha
def Read_header(self,addr):
format = '4s8L40s2L4s10L'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['magic'],\
self.header['size'],\
self.header['flags'],\
self.header['height'],\
self.header['width'],\
self.header['pitch'],\
self.header['depth'],\
self.header['mipMapLevels'],\
self.header['alphaBitDepth'],\
reserved,\
self.header['pfSize'],\
self.header['pfFlags'],\
self.header['pfFourCC'],\
self.header['pfBpp'],\
self.header['pfRedMask'],\
self.header['pfGreenMask'],\
self.header['pfBlueMask'],\
self.header['pfAlphaMask'],\
self.header['caps1'],\
self.header['caps2'],\
self.header['caps3'],\
self.header['caps4'],\
self.header['textureStage'] = unpack(format,f.read(calcsize(format)))
f.close()
def Get_image_dimensions(self):
self.width = self.header['width']
self.height = self.header['height']
self.data_offset = self.header['size'] + 4
################################################################################
''' Class: TGA_image '''
################################################################################
class TGA_image(Indexed_image,BGR_image,RLE_image,Greyscale_image):
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'TGA'
self.pallete = None
self.Read_header()
self.flipped = False
if self.header['ImageDescriptor'] & 32:
self.flipped = True
self.alpha_bits = self.header['ImageDescriptor'] & 15
self.Get_image_dimensions()
self.size_of_plane = self.width * self.height
self.sourceBpp = self.header['BitsPerPixel']/8
self.data_size = self.width * self.height * self.sourceBpp
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
self.Process()
def Process(self):
typecode = self.header['DataTypeCode']
bpp = self.header['BitsPerPixel']
index_pixel = self.header['ColorMapDepth'] / 8
if typecode == 2: #BGR
if bpp == 32:
print "32bit"
self.Process32bit(alpha=True)
elif bpp == 24:
self.Process24bit(pad=False)
elif bpp == 16:
self.Process16bit(pad=False)
elif typecode == 1: #Indexed
psize = self.header['ColorMapLength'] * index_pixel
self.pad = False
if index_pixel == 32:
self.Read_palette(psize,4)
if bpp == 8: self.Process8bit()
elif index_pixel == 24:
self.Read_palette(psize,3)
if bpp == 8: self.Process8bit()
elif index_pixel == 16:
self.Read_16bit_palette(psize)
if bpp == 8: self.Process8bit()
elif typecode == 9: #RLE Indexed
self.data_size = self.size - self.data_offset
psize = self.header['ColorMapLength'] * index_pixel
self.pad = False
if index_pixel == 4:
self.Read_palette(psize,4)
if bpp == 8: self.Process_PacketRLE8()
elif index_pixel == 3:
self.Read_palette(psize,3)
if bpp == 8: self.Process_PacketRLE8()
elif index_pixel == 2:
self.Read_16bit_palette(psize)
if bpp == 8: self.Process_PacketRLE8()
elif typecode == 10: #RLE
self.data_size = self.size - self.data_offset
self.Process_PacketRLE_BGR()
elif typecode == 3: # Grey
if bpp == 16:
self.Process_greyA_16bit()
if not self.flipped: Manipulator(image=self.RGBA).Flip()
elif bpp == 8:
self.Process_grey_8bit()
elif typecode == 11: #Grey RLE
self.data_size = self.size - self.data_offset
if bpp == 16:
self.Process_grey_PacketRLE16()
elif bpp == 8:
self.Process_grey_PacketRLE8()
if self.alpha_bits: self.RGBA.has_alpha = True
def Read_header(self):
format = '<3B2HB4H2B'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['IdLength'],\
self.header['ColorMapType'],\
self.header['DataTypeCode'],\
self.header['ColorMapOrigin'],\
self.header['ColorMapLength'],\
self.header['ColorMapDepth'],\
self.header['xOrigin'],\
self.header['yOrigin'],\
self.header['Width'],\
self.header['Height'],\
self.header['BitsPerPixel'],\
self.header['ImageDescriptor'] = unpack(format,f.read(calcsize(format)))
self.head_size = calcsize(format)
format = '<2L16sH'
f.seek(-26,2)
self.footer = {}
self.footer['ExtOffset'],\
self.footer['DevOffset'],\
self.footer['Signature'],\
self.footer['Unimportant'] = unpack(format,f.read(calcsize(format)))
f.close()
if self.footer['Signature'] == 'TRUEVISION-XFILE':
if self.footer['ExtOffset']:
self.size = self.footer['ExtOffset'] - 1
else:
self.size -= 26
else:
del self.footer
self.footer = None
return True
def Get_image_dimensions(self):
self.width = self.header['Width']
self.height = self.header['Height']
self.data_offset = 18 + self.header['IdLength'] + (self.header['ColorMapLength'] * (self.header['ColorMapDepth']/8))
self.palette_offset = 18 + self.header['IdLength']
################################################################################
''' Class: ICO_image '''
################################################################################
class ICO_image(Indexed_image,BGR_image,RLE_image):
def __init__(self,addr=0,size=None,file=None,process=True,options=None):
self.default_icon = None
if options:
if options.has_key('icon'):
self.default_icon = options['icon']
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'ICO'
self.Read_header()
self.final_size = self.width * self.height * 4
if process: self.Process()
def Process(self):
bitcount = self.icon_heads[self.default_icon]['Bitcount']
if bitcount == 32:
self.Process32bit()
elif bitcount == 24:
self.Process24bit()
elif bitcount == 16:
self.Process16bit()
elif bitcount == 8:
self.Read_palette(self.palette_size)
self.Process8bit()
elif bitcount == 4:
self.Read_palette(self.palette_size)
self.Process4bit()
elif bitcount == 1:
self.Read_palette(self.palette_size)
self.Process1bit()
self.RGBA.mono = True
self.Process_Mask()
self.RGBA.has_alpha = True
def Process_Mask(self):
f = open(self.file,'rb')
f.seek(self.mask_offset)
mask = array.array('B',f.read(self.mask_size))
f.close
self.RGBA.Channel_mode()
padsize = ((32 - (self.width % 32)) / 8) % 4
pos = 0
row_l = self.width * 4
j = (self.height-1)*row_l
while j >= 0:
i=0
while i < row_l:
c=0
k=128
while c < 8:
if (mask[pos] & k): self.RGBA.data[j+i+3] = 0
k >>= 1
i+=4
if i >= row_l: break
c+=1
pos +=1
pos +=padsize
j-=row_l
def Read_header(self):
format = '<3H'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['Reserved'],\
self.header['Type'],\
self.header['Count'] = unpack(format,f.read(calcsize(format)))
format = '<BBBBHHLL'
format2 = '<3i2h6i'
self.icon_heads = []
x = 0
last = 0
choice = 0
while x < self.header['Count']:
header = {}
header['Width'],\
header['Height'],\
header['ColorCount'],\
header['Reserved'],\
header['Planes'],\
header['Bitcount'],\
header['BytesInRes'],\
header['ImageOffset'] = unpack(format,f.read(calcsize(format)))
self.icon_heads.append(header)
#choose largest icon as default
test = header['Width'] * header['Height'] * header['Bitcount']
if test > last:
last = test
choice = x
x+=1
for h in range(0,len(self.icon_heads)):
f.seek(self.icon_heads[h]['ImageOffset'])
self.icon_heads[h]['HeaderSize'],\
width,\
height,\
self.icon_heads[h]['Planes'],\
self.icon_heads[h]['Bitcount'],\
self.icon_heads[h]['Compression'],\
self.icon_heads[h]['SizeImage'],\
self.icon_heads[h]['XPelsPerMeter'],\
self.icon_heads[h]['YPelsPerMeter'],\
self.icon_heads[h]['ClrUsed'],\
self.icon_heads[h]['ClrImportant'] = unpack(format2,f.read(calcsize(format2)))
#print self.icon_heads[h]
f.close()
if not self.default_icon == None:
if self.default_icon < len(self.icon_heads):
choice = self.default_icon
else:
self.default_icon = choice
else:
self.default_icon = choice
self.width = self.icon_heads[choice]['Width']
self.height = self.icon_heads[choice]['Height']
self.data_offset = self.icon_heads[choice]['ImageOffset'] + 40
self.sourceBpp = self.icon_heads[choice]['Bitcount'] / 8.0
if self.sourceBpp >= 1: self.sourceBpp = int(self.sourceBpp)
colors = self.icon_heads[choice]['ClrUsed']
if self.sourceBpp <= 1:
self.palette_size = colors * 4
if not self.palette_size:
if self.sourceBpp == 1:
self.palette_size = 1024
elif self.sourceBpp == 0.5:
self.palette_size = 64
elif self.sourceBpp == 0.125:
self.palette_size = 2
self.palette_offset = self.data_offset
self.data_offset = self.palette_offset + self.palette_size
self.Bps = self.width * self.sourceBpp
#Do I need to pad this? --------------------------------------------------------------------------------------------_FIX
self.data_size = int(self.width * self.height * self.sourceBpp)
#print self.data_size
#self.data_size =
#print self.icon_heads[choice]['SizeImage']
self.mask_offset = self.data_offset + self.data_size
self.mask_size = self.icon_heads[choice]['BytesInRes'] + self.icon_heads[choice]['ImageOffset'] - self.mask_offset
################################################################################
''' Class: Fake_BMP_image '''
################################################################################
class Fake_BMP_image(Indexed_image,BGR_image,RLE_image):
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'BMP'
self.pallete = None
self.pad = True
self.is_image_bmp = True
return
################################################################################
''' Class: BMP_image '''
################################################################################
class BMP_image(Indexed_image,BGR_image,RLE_image):
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'BMP'
self.pallete = None
self.pad = True
if not self.Read_header():
self.Process_OS2(process)
return
self.flipped = False
if self.header['Height'] < 0:
self.flipped = True
self.header['Height'] = self.header['Height'] * -1
self.palette_offset = self.addr + self.head_size
self.Get_image_dimensions()
self.size_of_plane = self.width * self.height
self.sourceBpp = self.header['BitCount']/8
self.data_size = self.header['SizeImage']
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
if not self.header['Compression'] or self.header['Compression'] == 3:
if self.header['BitCount'] == 24:
self.Process24bit()
elif self.header['BitCount'] == 16:
self.Process16bit()
elif self.header['BitCount'] == 32:
if self.header['Compression'] == 3:
self.Process32bitCompressed()
else:
self.Process32bit()
elif self.header['BitCount'] == 1:
self.Read_palette(8)
self.Process1bit()
self.RGBA.indexed = True
self.RGBA.mono = True
elif self.header['BitCount'] == 4:
self.Read_palette(64)
self.Process4bit()
self.RGBA.indexed = True
elif self.header['BitCount'] == 8:
self.Read_palette(1024)
self.Process8bit()
self.RGBA.indexed = True
else:
pass
else:
size = self.header['ClrUsed'] * 4
if self.header['Compression'] == 2:
if not size: size = 64
self.Read_palette(size)
self.Process_RLE4()
elif self.header['Compression'] == 1:
if not size: size = 1024
self.Read_palette(size)
self.Process_RLE8()
else:
pass
self.RGBA.indexed = True
def Process_OS2(self,process):
self.Read_OS2_header()
self.Get_image_dimensions()
self.size_of_plane = self.width * self.height
self.sourceBpp = self.header['BitCount']/8
self.size = self.header['FileSize']
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.flipped = False
self.RGBA = None
if not process: return
if self.header['BitCount'] == 1:
self.Read_palette(6,pixBytes=3)
self.Process1bit()
self.RGBA.indexed = True
self.RGBA.mono = True
elif self.header['BitCount'] == 4:
self.Read_palette(48,pixBytes=3)
self.Process4bit()
self.RGBA.indexed = True
elif self.header['BitCount'] == 8:
self.Read_palette(768,pixBytes=3)
self.Process8bit()
self.RGBA.indexed = True
else:
self.Process24bit()
def Read_palette(self,size,pixBytes=4):
f = open(self.file,'rb')
f.seek(self.addr + self.head_size)
p_temp = array.array('B',f.read(size))
pix = array.array('B',chr(0)*4)
self.palette = array.array('L',chr(0)*((size/pixBytes)*4))
f.close()
i=0
p=0
pix[3] = 255
while i < size/pixBytes:
pix[0] = p_temp[p+2]
pix[1] = p_temp[p+1]
pix[2] = p_temp[p]
self.palette[i] = unpack('L',pix.tostring())[0]
p += pixBytes
i+=1
def Read_header(self):
format = '<2siI4i2h6i'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['Magic'],\
self.header['FileSize'],\
self.header['Reserved'],\
self.header['DataOff'],\
self.header['HeaderSize'],\
self.header['Width'],\
self.header['Height'],\
self.header['Planes'],\
self.header['BitCount'],\
self.header['Compression'],\
self.header['SizeImage'],\
self.header['XPelsPerMeter'],\
self.header['YPelsPerMeter'],\
self.header['ClrUsed'],\
self.header['ClrImportant'] = unpack(format,f.read(calcsize(format)))
self.head_size = calcsize(format)
f.close()
if not self.header['HeaderSize'] == 40: return False
return True
def Read_OS2_header(self):
format = '<2sIhhII4H'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['Magic'],\
self.header['FileSize'],\
self.header['XHotSpot'],\
self.header['YHotspot'],\
self.header['DataOff'],\
self.header['Fix'],\
self.header['Width'],\
self.header['Height'],\
self.header['Planes'],\
self.header['BitCount'] = unpack(format,f.read(calcsize(format)))
self.head_size = calcsize(format)
f.close()
return True
def Get_image_dimensions(self):
self.width = self.header['Width']
self.height = self.header['Height']
self.data_offset = self.header['DataOff']
def Process32bitCompressed(self):
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
pos = 0
#Neet to test...... FIX----
pos = self.header['DataOff'] - 12
rMask = unpack('L',self.unprocessed[pos:pos+4].tostring())
pos += 4
gMask = unpack('L',self.unprocessed[pos:pos+4].tostring())
pos += 4
bMask = unpack('L',self.unprocessed[pos:pos+4].tostring())
pos += 4
rShiftL, rShiftR = GetShiftFromMask(rMask)
gShiftL, gShiftR = GetShiftFromMask(gMask)
bShiftL, bShiftR = GetShiftFromMask(bMask)
i=0
while i < self.final_size:
Read = unpack('L',self.unprocessed[pos:pos+4].tostring())
pos+=4
if Read != 1: return False
self.RGBA.data[i] = ((Read & bMask) >> bShiftR) << bShiftL
self.RGBA.data[i + 1] = ((Read & gMask) >> gShiftR) << gShiftL
self.RGBA.data[i + 2] = ((Read & rMask) >> rShiftR) << rShiftL
self.RGBA.data[i + 3] = 0xFF
i+=4
################################################################################
''' Class: JPEG_image NOT FINISHED - WIP =]'''
################################################################################
class JPEG_image(Base_image):
def __init__(self,addr=0,size=None,file=None,process=True):
import TonyJpegDecoder
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'JPG'
self.header = {}
self.decoder = TonyJpegDecoder.TonyJpegDecoder()
self.data = self.decoder.DecompressImage(open(file,'rb').read())
self.width = self.decoder.Width
self.height = self.decoder.Height
self.size_of_plane = self.width * self.height
self.sourceBpp = 3
self.size = size
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
self.Process_data()
def Process_data(self):
self.RGBA = RGBA_data(self.width,self.height,fill=chr(255),mode='CHANNEL')
pos=0
x=0
y=self.height-1
padding = (self.width % 2)*3
while y > 0:
x=0
while x < self.width*4:
row = y*self.width*4
self.RGBA.data[row+x] = self.data[pos+2]
self.RGBA.data[row+x+1] = self.data[pos+1]
self.RGBA.data[row+x+2] = self.data[pos]
self.RGBA.data[row+x+3] = 255
pos+=3
x+=4
pos+=padding
y-=1
################################################################################
''' Class: PNG_image '''
################################################################################
class PNG_image(Indexed_image,Greyscale_image):
def Filter_0(self,row,data): #None
self.over = data
return data
def Filter_1(self,row,data): #Left
l=len(data);x=0
#l=self.Bps;x=0
while x < l:
left = x - self.filterBpp
if left < 0:
left = 0
else:
left = data[left]
data[x] = (data[x] + left) % 256
x+=1
self.over = data
return data
def Filter_2(self,row,data): #Up
row_l = len(data)#self.Bps
x=0
while x < row_l:
data[x] = (data[x] + self.over[x]) % 256
x+=1
self.over = data
return data
def Filter_3(self,row,data): #Average
row_l = len(data)#self.Bps
x=0
while x < row_l:
left = x - self.filterBpp
if left < 0:
left = 0
else:
left = data[left]
above = self.over[x]
data[x] = (data[x] + ((left + above)/2)) % 256
x+=1
self.over = data
return data
def Filter_4(self,row,data): #Paeth
row_l = len(data)#self.Bps
x=0
while x < row_l:
left = x - self.filterBpp
if left < 0:
left = 0
above_left = 0
else:
left = data[left]
above_left = self.over[x - self.filterBpp]
above = self.over[x]
data[x] = (data[x] + self.PaethPredictor(left,above,above_left)) % 256
x+=1
self.over = data
return data
def PaethPredictor(self,l,a,ul):
p = l + a - ul # initial estimate
pa = abs(p - l) # distances to a, b, c
pb = abs(p - a)
pc = abs(p - ul)
# return nearest of a,b,c,
# breaking ties in order a,b,c.
if pa <= pb and pa <= pc:
return l
elif pb <= pc:
return a
else:
return ul
def Init_filter(self):
self.filterBpp = self.sourceBpp
if self.filterBpp < 1: self.filterBpp = 1
self.over = array.array('B',chr(0)*self.Bps)
def De_filter_rows(self):
row_l = self.Bps
x=0
l = self.height*row_l
self.Init_filter()
while x < l:
flt = self.unprocessed.pop(x)
if flt < 5: self.unprocessed[x:x+row_l] = self.filter[flt](self,x,self.unprocessed[x:x+row_l])
x+=row_l
filter = {}
filter[0] = Filter_0
filter[1] = Filter_1
filter[2] = Filter_2
filter[3] = Filter_3
filter[4] = Filter_4
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'PNG'
self.pad = False
self.data_offsets = {}
self.Read_header()
self.Get_image_dimensions()
self.interlaced = self.header['InterlaceType']
self.size_of_plane = self.width * self.height
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
self.Process()
def Process(self):
colortype = self.header['ColorType']
bitdepth = self.header['Bitdepth']
if colortype == 6:
if bitdepth == 8: #RGB with alpha
self.Process_RGBA_32bit()
else:
self.Process_RGBA_64bit()
self.RGBA.has_alpha = True
elif colortype == 4: #Greyscale with alpha
if bitdepth == 8:
self.Process_greyA_16bit()
else:
self.Process_greyA_32bit()
self.RGBA.has_alpha = True
self.RGBA.grey = True
elif colortype == 3: #Indexed (Palette)
self.flipped = True
if bitdepth == 8:
self.Process_indexed_8bit()
elif bitdepth == 4:
self.Process_indexed_4bit()
elif bitdepth == 2:
self.Process_indexed_2bit()
else:
self.Process_indexed_1bit()
self.RGBA.mono = True
self.RGBA.indexed = True
elif colortype == 2: #RGB
if bitdepth == 8:
self.Process_RGB_24bit()
else:
self.Process_RGB_48bit()
elif colortype == 0: #Greyscale
self.flipped = True
if bitdepth == 16:
self.Process_grey_16bit()
elif bitdepth == 8:
self.Process_grey_8bit()
elif bitdepth == 4:
self.Process_grey_4bit()
elif bitdepth == 2:
self.Process_grey_2bit()
else:
self.Process_grey_1bit()
self.RGBA.mono = True
self.RGBA.grey = True
if self.interlaced: self.DeInterlace()
def Process_palette(self,data):
l=len(data)
self.palette = array.array('L',chr(0)*((l/3)*4))
i=0
p=0
while p < l:
self.palette[i] = unpack('L',data[p:p+3] + chr(255))[0]
p+=3
i+=1
def DeInterlace(self):
# 1 6 4 6 2 6 4 6
# 7 7 7 7 7 7 7 7
# 5 6 5 6 5 6 5 6
# 7 7 7 7 7 7 7 7
# 3 6 4 6 3 6 4 6
# 7 7 7 7 7 7 7 7
# 5 6 5 6 5 6 5 6
# 7 7 7 7 7 7 7 7
# Good for testimg the De-Filtered data
self.RGBA.Pixel_mode()
data = self.RGBA.data[:]
pos = 0
for xi,y,xjump,yjump in ((0,0,8,8),
(4,0,8,8),
(0,4,4,8),
(2,0,4,4),
(0,2,2,4),
(1,0,2,2),
(0,1,1,2)):
while y < self.height:
x=xi
while x < self.width:
if pos >= len(data): break
self.RGBA.data[(y*self.width)+x] = data[pos]
x+=xjump
pos+=1
if pos >= len(data): break
y+=yjump
def DeFilter_interlaced_rows(self,data,width,height,row_l):
x=0
l = row_l*height
self.Init_filter()
while x < l:
flt = data.pop(x)
if flt < 5: data[x:x+row_l] = self.filter[flt](self,x,data[x:x+row_l])
x+=row_l
return data
def Read_interlaced_image_data(self):
f = open(self.file,'rb')
data = ''
s = self.data_offsets.keys()
s.sort()
for k in s:
f.seek(k,0)
data += f.read(self.data_offsets[k])
self.unprocessed = array.array('B',chr(0)*int(self.width*self.height*self.sourceBpp))
step = []
step.append( ( ((self.width+((8-self.width%8)%8))/8) , ((self.height+((8-self.height%8)%8))/8) ) )
step.append( ( ((self.width+((4-self.width%4)%4))/8) , ((self.height+((8-self.height%8)%8))/8) ) )
step.append( ( ((self.width+((4-self.width%4)%4))/4) , ((self.height+((4-self.height%4)%4))/8) ) )
step.append( ( ((self.width+((2-self.width%2)%2))/4) , ((self.height+((4-self.height%4)%4))/4) ) )
step.append( ( ((self.width+self.width%2)/2) , ((self.height+((2-self.height%2)%2))/4) ) )
step.append( ( (self.width/2) , ((self.height+self.height%2)/2) ) )
step.append( ( (self.width),(self.height/2) ) )
start = 0
d = array.array('B')
data = zlib.decompress(data)
sb=0
for width,height in step:
size = int(width*self.sourceBpp+1) * height
row_l = int(width*self.sourceBpp)
if self.sourceBpp == 0.125:
row_l = int((width + (8-width % 8)%8)/8)
size = (row_l+1) * height
elif self.sourceBpp == 0.250:
row_l = int((width + (4-width % 4)%4)/4)
size = (row_l+1) * height
elif self.sourceBpp == 0.5:
row_l = int((width + (2-width % 2)%2)/2)
size = (row_l+1) * height
tmp = array.array('B',data[start:start+size])
tmp = self.DeFilter_interlaced_rows(tmp,width,height,row_l)
if self.sourceBpp < 1:
d+= self.Byte_convert(tmp,width)
else:
d += tmp
start+=size
sb+=1
f.close()
self.unprocessed = d
def Byte_convert(self,data,wid):
byted = array.array('B')
l=len(data)
x=0
z=1
if self.sourceBpp == 0.125:
m = 256;ss=1
elif self.sourceBpp == 0.250:
m = 64;ss=2
elif self.sourceBpp == 0.5:
m = 16;ss=4
while x < l:
c=7
s=128
byte = data[x]
while c >= 0:
if z > wid and wid%8:
z=1
break
val = ((byte & s)>>c) * m
if val: val-=1
byted += array.array('B',chr(val))
s>>=ss
c-=ss
z+=1
x+=1
return byted
def Process_RGBA_32bit(self):
self.sourceBpp = 4
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
self.RGBA = RGBA_data(self.width,self.height,data=self.unprocessed)
del self.unprocessed
def Process_RGBA_64bit(self):
self.sourceBpp = 8
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
x=0
y=0
l=len(self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
while y < l:
self.RGBA.data[x] = self.unprocessed[y]
x+=1
y+=2
del self.unprocessed
def Process_indexed_8bit(self):
self.sourceBpp = 1
self.Bps = self.width
self.Process8bit()
def Process_indexed_4bit(self):
self.sourceBpp = 0.5
self.Bps = (self.width + (2-self.width % 2)%2)/2
self.Process4bit()
def Process_indexed_2bit(self):
self.sourceBpp = 0.25
self.Bps = (self.width + (4-self.width % 4)%4)/4
self.Process2bit()
def Process_indexed_1bit(self):
self.sourceBpp = 0.125
self.Bps = (self.width + (8-self.width % 8)%8)/8
self.Process1bit()
def Process_RGB_24bit(self):
self.sourceBpp = 3
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
x=0
y=0
l=len(self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
while y < l:
self.RGBA.data[x] = self.unprocessed[y]
self.RGBA.data[x+1] = self.unprocessed[y+1]
self.RGBA.data[x+2] = self.unprocessed[y+2]
x+=4
y+=3
del self.unprocessed
def Process_RGB_48bit(self):
self.sourceBpp = 6
self.Bps = self.width * self.sourceBpp
self.Read_image_data('B')
x=0
y=0
l=len(self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height,mode='CHANNEL')
while y < l:
self.RGBA.data[x] = self.unprocessed[y]
self.RGBA.data[x+1] = self.unprocessed[y+2]
self.RGBA.data[x+2] = self.unprocessed[y+4]
x+=4
y+=6
del self.unprocessed
def Get_image_dimensions(self):
self.width = self.header['Width']
self.height = self.header['Height']
def Read_header(self):
format = '>8sL4s2L5BL'
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
self.header['Magic'],\
self.header['HeadSize'],\
self.header['HeaderType'],\
self.header['Width'],\
self.header['Height'],\
self.header['Bitdepth'],\
self.header['ColorType'],\
self.header['FilterMethod'],\
self.header['CompressionType'],\
self.header['InterlaceType'],\
self.header['HeadCRC'] = unpack(format,f.read(calcsize(format)))
self.head_size = calcsize(format)
type = None
size = 0
while not type == 'IEND':
if size: f.seek(size+4,1)
size,type = unpack('>L4s',f.read(8))
if type =='IDAT':
self.data_offsets[f.tell()] = size
elif type =='PLTE':
self.Process_palette(f.read(size))
f.seek(4,1)
size = 0
self.size = size
f.close()
return True
def Read_image_data(self,element_size):
if self.interlaced:
self.Read_interlaced_image_data()
return
f = open(self.file,'rb')
data = ''
s = self.data_offsets.keys()
s.sort()
for k in s:
f.seek(k,0)
data += f.read(self.data_offsets[k])
data = zlib.decompress(data)
self.unprocessed = array.array(element_size,data)
f.close()
self.De_filter_rows()
################################################################################
''' Class: XPM_image '''
################################################################################
class XPM_image(Base_image):
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'XPM'
self.Read_header()
self.size_of_plane = self.width * self.height
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
self.Process()
def Process(self):
self.RGBA = RGBA_data(self.width,self.height,fill=chr(255),mode='PIXEL')
from namedrgb import NAMEDCOLOR
self.named_color = NAMEDCOLOR
import binascii
f = open(self.file,'rb')
for x in range(1,self.header['StartLine']):
f.readline()
self.palette = {}
x=0
cl = self.color_length
while x < int(self.header['NumberOfColors']):
data = f.readline()
if not data.startswith('/'):
data = data.split('\"')[1]
cc = data[0:cl]
data = data[cl:].strip()
if data[0] == 'c':
if 'c #' in data:
val = data.split('c #')[1] + 'FF'
else:
data.split(' ')[1]
val = self.Get_named_color(data.split(' ')[1])
elif data[0] == 'm':
if 'm #' in data:
val = data.split('c #')[1] + 'FF'
else:
data.split(' ')[1]
val = self.Get_named_color(data.split(' ')[1])
else:
val = '000000FF'
self.palette[cc] = unpack('L',binascii.unhexlify(val))[0]
x+=1
pos=0
y=0
for line in f:
if y > self.height-1: break
if not line.startswith('/'):
data = line.split('\"')[1]
if data == ',\n': break
x=0
l=len(data)
while x < l:
self.RGBA.data[pos] = self.palette[data[x:x+cl]]
x+=cl
pos+=1
y+=1
f.close()
del binascii
del self.named_color
del NAMEDCOLOR
def Get_named_color(self,name):
if name == 'None':
return '00000000'
self.RGBA.has_alpha = True
else:
return self.named_color[name.upper().replace(' ','')] + 'FF'
def Read_header(self):
f = open(self.file,'rb')
f.seek(self.addr)
x=0
while 1:
x+=1
line = f.readline()
if '\"' in line: break
line = line.replace('\"','')
line = line.replace(',\n','')
line += ' '
self.header = {}
self.header['StartLine'] = x + 1
self.header['Width'],\
self.header['Height'],\
self.header['NumberOfColors'],\
self.header['ColorLength'],\
nothing = line.split(' ',4)
self.width = int(self.header['Width'])
self.height = int(self.header['Height'])
self.color_length = int(self.header['ColorLength'])
self.sourceBpp = 3
f.close()
################################################################################
''' Class: XBM_image '''
################################################################################
class XBM_image(Base_image,Indexed_image):
def __init__(self,addr=0,size=None,file=None,process=True):
self.init()
if not size:
size = ospath_getsize(file)
self.file_size = size
self.file = file
self.addr = addr
self.size = size
self.type = 'XBM'
self.Read_header()
self.size_of_plane = self.width * self.height
self.Bps = self.width * self.sourceBpp
self.Bpp = 4
self.final_size = self.size_of_plane * self.Bpp
self.RGBA = None
if not process: return
self.Process()
self.RGBA.mono = True
def Process(self):
self.RGBA = RGBA_data(self.width,self.height,fill=chr(255),mode='PIXEL')
import binascii
f = open(self.file,'rb')
for x in range(1,self.header['StartLine']):
f.readline()
self.unprocessed = ''
for line in f:
line = line.replace(';','').replace('}','').replace('\n','').replace(' ','').replace('0x','')
vals = line.split(',')
for v in vals:
v = v[2:4] + v[0:2]
if v: self.unprocessed += binascii.unhexlify(v)
f.close()
del binascii
self.unprocessed = array.array('B',self.unprocessed)
self.RGBA = RGBA_data(self.width,self.height,fill=chr(255),mode='PIXEL')
pos=0
y=0
while y < self.height:
x=0
while x < self.width:
byte = self.unprocessed[pos]
k = 1
while k < 256:
if x >= self.width: break
if (byte & k): self.RGBA.data[y*self.width+x] = 4278190080
k<<=1
x+=1
pos+=1
y+=1
def Read_header(self):
f = open(self.file,'rb')
f.seek(self.addr)
self.header = {}
x=0
while 1:
x+=1
line = f.readline()
if 'width' in line:
self.header['Width'] = line.split('width')[-1].split(' ')[-1].replace('\n','')
elif 'height' in line:
self.header['Height'] = line.split('height')[-1].split(' ')[-1].replace('\n','')
elif '{' in line:
break
if '0x' in line:
self.header['StartLine'] = x
else:
self.header['StartLine'] = x+1
self.width = int(self.header['Width'])
self.height = int(self.header['Height'])
self.sourceBpp = 0.125
f.close()
################################################################################
''' Class: SaveImage_base '''
################################################################################
class SaveImage_base:
def RGBA_to_BGR_string(self,pad=0):
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
temp = array.array('B',self.RGBA.data.tostring())
out = array.array('B',chr(0)*((self.width+pad)*self.height*3))
x=0
y=self.height-1
pos=0
Bpp = self.RGBA.Bpp
row_l = self.width * Bpp
while y > -1:
x=0
while x < row_l:
loc = y * row_l + x
out[pos] = temp[loc+2]
out[pos+1] = temp[loc+1]
out[pos+2] = temp[loc]
pos+=3
x+=Bpp
pos+=pad
y-=1
return out.tostring()
def Create_palette_quick(self):
pal = array.array('B',chr(255)*1012)
x = 0
for r in range(5,256,50):
for g in range(3,256,42):
for b in range(5,256,50):
pal[x] = r
pal[x+1] = g
pal[x+2] = b
x+=4
pal.append(0)
pal.append(0)
pal.append(0)
pal.append(0)
return pal
def Create_palette(self):
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
self.RGBA.Pixel_mode()
pixels = {}
l = len(self.RGBA.data)
x=0
diff = 0.0
div=1
if l > 2047:
div = int(l/1024)
div = div + (div%4)
while x < l:
pix = self.RGBA.data[x]
if not pixels.has_key(pix):
pixels[pix] = 1
x+=div
return array.array('B',array.array('L',pixels.keys()[0:256]).tostring())
def Create_indexed_image(self,pad=0,flip=False):
palette = self.Create_palette()
if flip: Manipulator(image=self.RGBA).Flip() #Do something smarter here please :) -----------------FIX
temp = array.array('B',self.RGBA.data.tostring())
if flip: Manipulator(image=self.RGBA).Flip()
image = array.array('B',chr(0)*((self.width+pad)*self.height))
o=0
i=0
w=0
l=len(image)
lp=len(palette)
while i < l:
if w >= self.width:
w=0
i+=pad
r = temp[o]
g = temp[o+1]
b = temp[o+2]
p=0
lastdiff=65536
pal=0
pn=0
while p < lp:
rdif = r - palette[p]
gdif = g - palette[p+1]
bdif = b - palette[p+2]
if rdif < 0: rdif *= -1
if gdif < 0: gdif *= -1
if bdif < 0: bdif *= -1
diff = rdif+gdif+bdif
if diff < lastdiff:
lastdiff = diff
pal = pn
pn+=1
p+=4
image[i]=pal
i+=1
o+=4
w+=1
x=0
l = len(palette)
if self.order == 'BGR':
while x < lp:
t=palette[x]
palette[x] = palette[x+2]
palette[x+2] = t
x+=4
return palette[0:lp].tostring(),image.tostring()
################################################################################
''' Class: BGR_to_BMP '''
################################################################################
class BGR_to_BMP(SaveImage_base):
headerSize=40
planes=1
headerFormat = '<2siI4i2h6i'
order = 'BGR'
def __init__(self,image,filename,type):
self.RGBA = image
self.height = image.height
self.width = image.width
self.file = filename
self.dataOffset = 54
self.compress=0
self.clrUsed=0
self.clrImportant=0
if type == '16':
ps = (4-((self.width*2)%4))%4
self.data = self.RGBA_to_BGR_string(pad=ps)
self.Write_16bit()
elif type == '24':
ps = (4-((self.width*3)%4))%4
self.data = self.RGBA_to_BGR_string(pad=ps)
self.Write_24bit()
elif type == '32':
self.data = self.RGBA_to_BGR_string()
self.Write_32bit()
elif type == '8':
ps = (4-((self.width)%4))%4
self.data = self.Create_indexed_image(pad=ps,flip=True)
self.Write_8bit()
else:
ps = (4-((self.width*3)%4))%4
self.data = self.RGBA_to_BGR_string(pad=ps)
self.Write_24bit()
def Write_8bit(self):
palette,self.data = self.data
self.bitcount = 8
self.dataOffset = 54 + len(palette)
self.clrUsed=len(palette)/4
self.clrImportant=len(palette)/4
f = open(self.file,'wb')
f.write(self.Create_header())
f.write(palette)
f.write(self.data)
f.close()
def Write_16bit(self):
temp = array.array('B',self.data)
out = array.array('H',chr(0)*((len(temp)/3)*2))
x=0
pos=0
l=len(temp)
while x < l:
out[pos] = ((temp[x+2] & 240) << 7) |\
((temp[x+1] & 248) << 2) |\
(temp[x] >> 3)
pos +=1
x+=3
self.data = out.tostring()
self.bitcount = 16
f = open(self.file,'wb')
f.write(self.Create_header())
f.write(self.data)
f.close()
def Write_24bit(self):
self.bitcount = 24
f = open(self.file,'wb')
f.write(self.Create_header())
f.write(self.data)
f.close()
def Write_32bit(self):
temp = array.array('B',self.data)
out = array.array('B',chr(0)*((len(temp)/3)*4))
x=0
pos=0
l=len(temp)
while x < l:
out[pos] = temp[x]
out[pos+1] = temp[x+1]
out[pos+2] = temp[x+2]
out[pos+3] = 0
pos+=4
x+=3
self.data = out.tostring()
self.bitcount = 32
f = open(self.file,'wb')
f.write(self.Create_header())
f.write(self.data)
f.close()
def Create_header(self):
XPPM=2834
YPPM=2834
fSize=self.dataOffset + len(self.data)
imgSize=len(self.data)
header = pack(self.headerFormat,'BM',
fSize,
0,
self.dataOffset,
self.headerSize,
self.width,
self.height,
self.planes,
self.bitcount,
self.compress,
imgSize,
XPPM,
YPPM,
self.clrUsed,
self.clrImportant)
return header
################################################################################
''' Class: RGBA_to_PNG '''
################################################################################
class RGBA_to_PNG(SaveImage_base):
order = 'RGB'
def __init__(self,rgba_data,file,type='RGBA8',filter=0,compression=6):
self.RGBA = rgba_data
try:
height = self.height = self.RGBA.height
width = self.width = self.RGBA.width
except:
print 'Error With Height and/or Width'
return
rgba_data = self.RGBA.data.tostring()
palette = False
filtered = ''
if type == 'RGBA8':
self.Bpp = 4
self.bitdepth = 8
self.type = 6
elif type == 'RGB8':
self.Bpp = 3
self.bitdepth = 8
self.type = 2
data = rgba_data
rgba_data = ''
x=0
while x < len(data):
rgba_data += data[x]
rgba_data += data[x+1]
rgba_data += data[x+2]
x+=4
elif type == 'GREY8':
self.Bpp = 1
self.bitdepth = 8
self.type = 0
data = rgba_data
rgba_data = ''
x=0
while x < len(data):
rgba_data += chr(int((ord(data[x]) + ord(data[x+1]) + ord(data[x+2]))/3))
x+=4
elif type == 'GREYA8':
self.Bpp = 2
self.bitdepth = 8
self.type = 4
data = rgba_data
rgba_data = ''
x=0
while x < len(data):
rgba_data += chr(int((ord(data[x]) + ord(data[x+1]) + ord(data[x+2]))/3)) + data[x+3]
x+=4
elif type == 'INDEX8':
self.Bpp = 1
self.bitdepth = 8
self.type = 3
filter = 0
pal, rgba_data = self.Create_indexed_image()
x=0
palette = ''
while x < len(pal):
palette += pal[x:x+3]
x+=4
del pal
row_l = width * self.Bpp
# Separate these so non-filtering is as fast as possible
if filter:
self.over = array.array('B',chr(0) * row_l)
self.filterBpp = self.Bpp
rgba_data = array.array('B',rgba_data)
if filter == 6:
for x in range(0,height): filtered += self.Filter_adaptive(rgba_data[x*row_l:x*row_l+row_l],x)
elif filter == 5:
for x in range(0,height): filtered += self.Filter_smart(rgba_data[x*row_l:x*row_l+row_l])
elif filter == 4:
for x in range(0,height): filtered += self.Filter_4(rgba_data[x*row_l:x*row_l+row_l])
elif filter == 3:
for x in range(0,height): filtered += self.Filter_3(rgba_data[x*row_l:x*row_l+row_l])
elif filter == 2:
for x in range(0,height): filtered += self.Filter_2(rgba_data[x*row_l:x*row_l+row_l])
else:
for x in range(0,height): filtered += self.Filter_1(rgba_data[x*row_l:x*row_l+row_l])
else:
zero = chr(0)
for x in range(0,height): filtered += zero + rgba_data[x*row_l:x*row_l+row_l]
del rgba_data
signature = chr(0x89) + 'PNG' + chr(0x0d) + chr(0x0a) + chr(0x1a) + chr(0x0a)
header = pack('>LL5B',width,height,self.bitdepth,self.type,0,0,0)
header_chunk = self.Create_chunk('IHDR',header)
data_chunk = self.Create_chunk('IDAT',zlib.compress(filtered,compression))
end_chunk = self.Create_chunk('IEND','')
f=open(file,'wb')
f.write(signature)
f.write(header_chunk)
if palette: f.write(self.Create_chunk('PLTE',palette))
f.write(data_chunk)
f.write(end_chunk)
f.close()
def Filter_0(self,data): #None
self.over = data
return data
def Filter_1(self,data): #Left
raw = data[:]
l=len(data);x=0
while x < l:
left = x - self.filterBpp
if left < 0:
left = 0
else:
left = raw[left]
data[x] = (raw[x] - left) % 256
x+=1
self.over = raw
data.insert(0,1)
return data.tostring()
def Filter_2(self,data): #Up
raw = data[:]
row_l = len(data)
x=0
while x < row_l:
data[x] = (raw[x] - self.over[x]) % 256
x+=1
self.over = raw
data.insert(0,2)
return data.tostring()
def Filter_3(self,data): #Average
raw = data[:]
row_l = len(data)
x=0
while x < row_l:
left = x - self.filterBpp
if left < 0:
left = 0
else:
left = raw[left]
above = self.over[x]
data[x] = (raw[x] - ((left + above)/2)) % 256
x+=1
self.over = raw
data.insert(0,3)
return data.tostring()
def Filter_4(self,data): #Paeth
row_l = len(data)
raw = data[:]
x=0
while x < row_l:
left = x - self.filterBpp
if left < 0:
left = 0
above_left = 0
else:
left = raw[left]
above_left = self.over[x - self.filterBpp]
above = self.over[x]
data[x] = (raw[x] - self.PaethPredictor(left,above,above_left)) % 256
x+=1
self.over = raw
data.insert(0,4)
return data.tostring()
def PaethPredictor(self,l,a,ul):
p = l + a - ul # initial estimate
pa = abs(p - l) # distances to a, b, c
pb = abs(p - a)
pc = abs(p - ul)
# return nearest of a,b,c,
# breaking ties in order a,b,c.
if pa <= pb and pa <= pc:
return l
elif pb <= pc:
return a
else:
return ul
def Filter_test(self,data,type):
row_l = len(data)
x=0
val = 0
test = {}
while x < row_l:
left = x - self.filterBpp
if left < 0:
left = 0
above_left = 0
else:
left = data[left]
above_left = self.over[x - self.filterBpp]
above = self.over[x]
mod = 0
if type == 0:
mod = data[x]
elif type == 1:
mod = (data[x] - left)%256
elif type == 2:
mod = (data[x] - above)%256
elif type == 3:
mod = (data[x] - ((left + above)/2))%256
elif type == 4:
mod = (data[x] - self.PaethPredictor(left,above,above_left))%256
if mod > 127: mod = 256 - mod
val += mod
test[mod] = 1
x+=1
self.temp = test
test.update(self.last)
return len(test.keys()) * val
def Filter_adaptive(self,row_data,pos):
row_l = len(row_data)
type = 0
last = None
self.last = {}
for x in (0,1,2,3,4):
y = 1
val = self.Filter_test(row_data,x)
if val <= last or last == None:
lt = self.temp
last = val
type = x
self.last = lt
if type == 0:
return chr(0) + row_data.tostring()
elif type == 1:
return self.Filter_1(row_data)
elif type == 2:
return self.Filter_2(row_data)
elif type == 3:
return self.Filter_3(row_data)
elif type == 4:
return self.Filter_4(row_data)
def Filter_smart(self,row_data):
return self.Filter_4(row_data)
def Create_chunk(self,type,data):
format = '>L4s' + str(len(data)) + 'sL'
return pack(format,len(data),type,data,self.CRC(type + data))
def CRC(self,buf):
return zlib.crc32(buf)
################################################################################
''' Class: RGBA_to_TGA '''
################################################################################
class RGBA_to_TGA(SaveImage_base):
order = 'BGR'
def __init__(self,rgba,file,type='BGR24',flip=False):
self.RGBA = rgba
self.file = file
self.flip = flip
self.height = self.RGBA.height
self.width = self.RGBA.width
self.ColorMapDepth = 0
self.ColorMapLength = 0
self.ColorMapOrigin = 0
self.ColorMapType = 0
self.ImageDescriptor = 0
if self.flip:
self.ImageDescriptor = 32
if type == 'BGR32':
self.BitsPerPixel = 32
self.DataTypeCode = 2
self.ImageDescriptor |= 8
self.Write_32bit()
elif type == 'BGR24':
self.BitsPerPixel = 24
self.DataTypeCode = 2
self.Write_24bit()
elif type == 'BGR16':
self.BitsPerPixel = 16
self.DataTypeCode = 2
if self.RGBA.has_alpha: self.ImageDescriptor |= 1
self.Write_16bit()
elif type == 'BGR32RLE':
self.BitsPerPixel = 32
self.DataTypeCode = 10
self.ImageDescriptor |= 8
self.Write_32bit(rle=True)
elif type == 'BGR24RLE':
self.BitsPerPixel = 24
self.DataTypeCode = 10
self.Write_24bit(rle=True)
elif type == 'BGR16RLE':
self.BitsPerPixel = 16
self.DataTypeCode = 10
if self.RGBA.has_alpha: self.ImageDescriptor |= 1
self.Write_16bit(rle=True)
elif type == 'GREY16':
self.BitsPerPixel = 16
self.DataTypeCode = 3
self.ImageDescriptor |= 8
self.Write_grey(Bpp=2)
elif type == 'GREY8':
self.BitsPerPixel = 8
self.DataTypeCode = 3
self.Write_grey()
elif type == 'GREY16RLE':
self.BitsPerPixel = 16
self.DataTypeCode = 11
self.ImageDescriptor |= 8
self.Write_grey(Bpp=2,rle=True)
elif type == 'GREY8RLE':
self.BitsPerPixel = 8
self.DataTypeCode = 11
self.Write_grey(rle=True)
elif type == 'INDEX32':
self.BitsPerPixel = 8
self.DataTypeCode = 1
self.ImageDescriptor |= 8
self.Write_indexed(Bpp=4)
elif type == 'INDEX24':
self.BitsPerPixel = 8
self.DataTypeCode = 1
self.Write_indexed(Bpp=3)
elif type == 'INDEX16':
self.BitsPerPixel = 8
self.DataTypeCode = 1
self.Write_indexed(Bpp=2)
elif type == 'INDEX32RLE':
self.BitsPerPixel = 8
self.DataTypeCode = 9
self.ImageDescriptor |= 8
self.Write_indexed(Bpp=4,rle=True)
elif type == 'INDEX24RLE':
self.BitsPerPixel = 8
self.DataTypeCode = 9
self.Write_indexed(Bpp=3,rle=True)
elif type == 'INDEX16RLE':
self.BitsPerPixel = 8
self.DataTypeCode = 9
self.Write_indexed(Bpp=2,rle=True)
def Write_indexed(self,Bpp=3,rle=False):
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
p,out = self.Create_indexed_image(flip=not self.flip)
palette = ''
l = len(p)
x = 0
self.ColorMapDepth = Bpp * 8
self.ColorMapLength = len(p) / 4
if Bpp == 4:
palette = p
elif Bpp == 3:
while x < l:
palette += p[x:x+3]
x+=4
elif Bpp == 2:
palette = array.array('H',chr(0)*(len(p)/2))
pos=0
while x < l:
palette[pos] = (((ord(p[x+2]) >> 3) << 10) |\
((ord(p[x+1]) >> 3) << 5 ) |\
((ord(p[x]) >> 3) )) | 1
pos+=1
x+=4
self.ColorMapDepth = 16
self.ColorMapLength = len(palette)
self.ColorMapType = 1
self.Create_headers()
if rle: out = self.RLE(array.array('B',out),bpp=1).tostring()
f = open(self.file,'wb')
f.write(self.header)
f.write(palette)
f.write(out)
f.write(self.footer)
f.close()
def Write_32bit(self,rle=False):
self.Create_headers()
self.RGBA.Channel_mode()
l=self.RGBA.Data_length()
out = array.array('B',chr(0)* l)
pos=0
x=0
row_l = self.width * 4
if self.flip:
y = 0
compare = self.height * row_l
it = row_l
else:
y = (self.height-1) * row_l
it = 0 - row_l
compare = it
while y != compare:
x=0
while x < row_l:
p = y + x
out[pos] = self.RGBA.data[p+2]
out[pos+1] = self.RGBA.data[p+1]
out[pos+2] = self.RGBA.data[p]
out[pos+3] = self.RGBA.data[p+3]
x+=4
pos+=4
y+=it
if rle: out = self.RLE(out)
f = open(self.file,'wb')
f.write(self.header)
f.write(out.tostring())
f.write(self.footer)
f.close()
def Write_24bit(self,rle=False):
self.Create_headers()
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
if self.flip: Manipulator(image=self.RGBA).Flip() #FIX BGR conversion code to handle flipping ------------------------------------------------------FIX
if rle:
out = self.RLE(array.array('B',self.RGBA_to_BGR_string()),bpp=3).tostring()
else:
out = self.RGBA_to_BGR_string()
if self.flip: Manipulator(image=self.RGBA).Flip() #FIX BGR conversion code to handle flipping ------------------------------------------------------FIX
f = open(self.file,'wb')
f.write(self.header)
f.write(out)
f.write(self.footer)
f.close()
def Write_16bit(self,rle=False):
self.Create_headers()
self.RGBA.Channel_mode()
out = array.array('H',chr(0)*((len(self.RGBA.data)/3)*2))
pos=0
x=0
row_l = self.width * 4
if self.flip:
y = 0
compare = self.height * row_l
it = row_l
else:
y = (self.height-1) * row_l
it = 0 - row_l
compare = it
while y != compare:
x=0
while x < row_l:
p = y + x
alpha = 0
if self.RGBA.data[p+3]: alpha = 1
out[pos] = (((self.RGBA.data[p] >> 3) << 10) |\
((self.RGBA.data[p+1] >> 3) << 5 ) |\
((self.RGBA.data[p+2] >> 3) )) | alpha
pos +=1
x+=4
y+=it
if rle: out = self.RLE(array.array('B',out.tostring()),bpp=2)
f = open(self.file,'wb')
f.write(self.header)
f.write(out.tostring())
f.write(self.footer)
f.close()
def Write_grey(self,Bpp=1,rle=False):
self.Create_headers()
if Bpp == 1:
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
out = array.array('B')
self.RGBA.Channel_mode()
x=0
l = len(self.RGBA.data)
if not self.RGBA.grey:
while x < l:
out.append((self.RGBA.data[x] + self.RGBA.data[x+1] + self.RGBA.data[x+2])/3)
if Bpp == 2: out.append(self.RGBA.data[x+3])
x+=4
else:
while x < l:
out.append(self.RGBA.data[x])
if Bpp == 2: out.append(self.RGBA.data[x+3])
x+=4
if rle: out = self.RLE(out,bpp=Bpp)
f = open(self.file,'wb')
f.write(self.header)
f.write(out.tostring())
f.write(self.footer)
f.close()
def RLE(self,out,bpp=4):
temp = out[:]
out = array.array('B')
x=0
l = len(temp)
r_len = 128 * bpp
last = (99999,) * bpp
rep = 0
run = 0
while x < l:
y=0
while y < r_len:
if x + y+(bpp-1) > l: break
val = temp[x+y:x+y+bpp]
if val == last:
if run: break
rep += 1
else:
if rep: break
run += 1
last = val[:]
y+=bpp
p=0
if rep:
out.append(128 | rep-1)
z=0
while z < bpp:
out.append(temp[x+z])
z+=1
else:
out.append(run-1)
while p < run*bpp:
out.append(temp[x+p])
p+=1
run = 0
rep = 0
x+=y
return out
def Create_headers(self):
format = '<3B2HB4H2B'
self.header = pack(format,0,
self.ColorMapType,
self.DataTypeCode,
self.ColorMapOrigin,
self.ColorMapLength,
self.ColorMapDepth,
0, # xOrigin
0, # yOrigin
self.width,
self.height,
self.BitsPerPixel,
self.ImageDescriptor)
format = '<2L16scB'
self.footer = pack(format,0,
0,
'TRUEVISION-XFILE',
'.',
0)
################################################################################
''' Class: RGBA_to_XPM '''
################################################################################
class RGBA_to_XPM(SaveImage_base):
order = 'RGB'
def __init__(self,rgba,file):
self.RGBA = rgba
self.file = file
self.height = self.RGBA.height
self.width = self.RGBA.width
chrs = """.!"#$%&'*+,-/:;<=>@^_`~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()[]{}|"""
cl = len(chrs)
self.RGBA.Pixel_mode()
self.RGBA.data.byteswap()
l = len(self.RGBA.data)
x=0
pixels = {}
while x < l:
if self.RGBA.data[x] & 255:
pix = (self.RGBA.data[x] >> 8)
if not pixels.has_key(pix): pixels[pix] = 1
x+=1
colors = pixels.keys()
num = len(colors)
test = num
color_width = 1
while test > cl:
test = test/cl
color_width += 1
pos=0
done = []
list = []
space = ' ' * color_width
f = open(self.file,'w')
f.write('/* XPM */\nstatic char * Image_xpm[] = {\n')
f.write('"'+ str(self.width) +' '+ str(self.height) +' '+ str(num+1) +' '+ str(color_width) +'",\n')
f.write('"' + (' ' * color_width) + '\tc None",\n')
palette = {'c None':' '*color_width}
while pos < num:
for c in chrs:
if done:
for d in done:
if pos >= num: break
cc = d + c
list.append(cc)
char = (cc+space)[0:color_width]
val = 'c #' + Hex6(colors[pos])
f.write('"' + char + '\t' + val + '",\n')
palette[val] = char
pos+=1
else:
if pos >= num: break
list.append(c)
cc=c
char = (cc+space)[0:color_width]
val = 'c #' + Hex6(colors[pos])
f.write('"' + char + '\t' + val + '",\n')
palette[val] = char
pos+=1
done = list
list = []
y=0
line = ''
while y < self.height:
if line: line += '",\n'
f.write(line)
line = '"'
x=0
while x < self.width:
pix = self.RGBA.data[y*self.width+x]
if not pix & 255:
line += palette['c None']
else:
line += palette['c #' + Hex6(pix >> 8)]
x+=1
y+=1
f.write(line + '"}\n')
f.close()
self.RGBA.data.byteswap()
################################################################################
''' Class: RGBA_to_XBM '''
################################################################################
class RGBA_to_XBM(SaveImage_base):
order = 'RGB'
def __init__(self,rgba,file):
self.RGBA = rgba
if self.RGBA.has_alpha: Manipulator(image=self.RGBA).Alpha_to_color()
self.RGBA.Channel_mode()
self.file = file
self.height = self.RGBA.height
self.width = self.RGBA.width
l = len(self.RGBA.data)
out = ''
if self.RGBA.mono or self.RGBA.grey:
y=0
x=0
row_l = self.width * 4
while y < self.height:
w=0
row = ''
while w < self.width:
row += chr((self.RGBA.data[x]+self.RGBA.data[x+1]+self.RGBA.data[x+2])/3)
w+=1
x+=4
if self.RGBA.mono:
out += imageop.grey2mono(row,self.width,1,127)
else:
out += imageop.dither2mono(row,self.width,1)
y+=1
else:
y=0
x=0
row_l = self.width * 4
while y < self.height:
w=0
row = ''
while w < self.width:
row += chr((self.RGBA.data[x]+self.RGBA.data[x+1]+self.RGBA.data[x+2])/3)
w+=1
x+=4
out += imageop.dither2mono(row,self.width,1)
y+=1
f = open(self.file,'w')
f.write('#define iu_width ' + str(self.width) + '\n' + '#define iu_height ' + str(self.height) + '\n' + 'static char iu_bits[] = {\n')
out = array.array('B',out)
x=0
l = len(out)
line = ''
while x < l:
if line: f.write(' ' + line + ',\n')
line = ''
y=0
while y < 15:
if x >= l: break
if line: line += ','
b = out[x]
bb = 0
k = 128
c=7
d=0
while k:
bb |= (((b & k) >> c)<<d)
k>>=1
c-=1
d+=1
val = hex(~bb)
if len(val) < 4: val = val.replace('0x','0x0')
line+=val
x+=1
y+=1
f.write(' ' + line + '};\n')
f.close()
def Hex4(val):
return ('000' + hex(val).split('x')[1].replace('L',''))[-4:]
def Hex6(val):
return ('00000' + hex(val).split('x')[1].replace('L',''))[-6:]
def Hex8(val):
return ('0000000' + hex(val).split('x')[1].replace('L',''))[-8:]
################################################################################
### Function: Get_image
################################################################################
def Get_image(mipmap=0,addr=0,size=None,file=None,process=True,options=None):
if not file: return None
f = open(file,'rb')
f.seek(addr)
type = unpack('4s',f.read(4))[0]
f.close()
print type
try:
if type == 'XPR0':
return XPR0_image(mipmap=mipmap,addr=addr,size=size,file=file,process=process)
elif type == 'DDS ':
return DDS_image(mipmap=mipmap,addr=addr,size=size,file=file,process=process)
elif type[:2] == 'BM':
#return BMP_image(addr=addr,size=size,file=file,process=process)
#is_image_bmp
return Fake_BMP_image(addr=addr,size=size,file=file,process=process)
elif type == chr(255) + chr(216) + chr(255) + chr(224):
return JPEG_image(addr=addr,size=size,file=file,process=process)
elif type == chr(137) + 'PNG':
return PNG_image(addr=addr,size=size,file=file,process=process)
elif type == '/* X':
return XPM_image(addr=addr,size=size,file=file,process=process)
else:
ext = ospath_splitext(file)[1].upper()
if ext == '.TGA':
return TGA_image(addr=addr,size=size,file=file,process=process)
elif ext == '.ICO':
return ICO_image(addr=addr,size=size,file=file,process=process,options=options)
elif ext == '.XBM':
return XBM_image(addr=addr,size=size,file=file,process=process)
elif ext == '.XPM':
return XPM_image(addr=addr,size=size,file=file,process=process) #Just in case the first check doesn't work
return None
except:
print file
raise #Image_Error([type[0:3],file,sys.exc_info()[1]])