1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
__all__ = (
'pil2pict',
)
headerLen=512
maxLen = 127 #maximum length for raw/rle
#Opcodes
picVersion=0x11
background=0x1b
headerOp=0x0C00
clipRgn=0x01
PackBitsRect=0x98
EndOfPicture=0xFF
MAXCOLORS=256
def pil2pict(cols, rows, pixels, palette, tc=-1):
from struct import pack as struct_pack
from io import BytesIO
npixels = len(pixels)
colors = len(palette)
__bs__ = BytesIO() #where we write the bytes
def putc(c):
__bs__.write(c)
def putFill(n):
__bs__.write(n*b'\x00')
def putShort(v):
__bs__.write(struct_pack('>H',v))
def putLong(v):
__bs__.write(struct_pack('>l',v))
def putRect(s0, s1, s2, s3):
putShort(s0)
putShort(s1)
putShort(s2)
putShort(s3)
colors //= 3
# write the header
putFill(headerLen)
# write picSize and picFrame
putShort(0) #will be overridden when we know it
putRect(0, 0, rows, cols)
# write version op and version
putShort(picVersion)
putShort(0x02FF)
putShort(headerOp)
putLong(-1)
putRect(72, 0, 72, 0) #h/v resolutions
putRect(cols, 0, rows, 0)
putFill(4)
# seems to be needed by many PICT2 programs
putShort(0x1e) #DefHilite
putShort(clipRgn)
putShort(10)
putRect(0, 0, rows, cols)
if tc!=-1:
putShort(background)
putShort((((tc>>16)&0xFF)*65535)//255)
putShort((((tc>>8)&0xFF)*65535)//255)
putShort(((tc&0xFF)*65535)//255)
putShort(5) #src mode
putShort(36|64)
putShort(8) #src mode
putShort(36|64)
# write picture
putShort(PackBitsRect)
putShort(cols | 0x8000)
putRect(0, 0, rows, cols)
putShort(0) # pmVersion
putShort(0) # packType
putLong(0) # packSize
putRect(72, 0, 72, 0) # hRes/vRes
putShort(0) # pixelType
putShort(8) # pixelSize
putShort(1) # cmpCount
putShort(8) # cmpSize
putLong(0) # planeBytes
putLong(0) # pmTable
putLong(0) # pmReserved
putLong(0) # ctSeed
putShort(0) # ctFlags
putShort(colors-1) # ctSize
#Write out the colormap
for i in range(colors):
putShort(i)
putShort((palette[3*i]*65535)//255)
putShort((palette[3*i+1]*65535)//255)
putShort((palette[3*i+2]*65535)//255)
putRect(0, 0, rows, cols) #srcRect
putRect(0, 0, rows, cols) #dstRect
putShort((36|64) if tc!=-1 else 0) #transfer mode
#write out the pixel data.
oc = 0
d = bytearray()
r = bytearray()
r_append = r.append
r_extend = r.extend
r_reverse = r.reverse
cols1 = cols - 1
if cols>=250:
putRLen = putShort
rli = 2
else:
putRLen = lambda c: putc(bytes([c]))
rli = 1
rtc = lambda c: 257-c #run to char
ctc = lambda c: c-1 #count to char
def endrun():
nonlocal run, count
if run < 3:
while run>0:
r_append(cb)
run -= 1
count += 1
if count==128:
r_append(127)
count -= 128
run = 1
else: #cb!=d[k] and r>=3
if count>0:
r_append(ctc(count))
count = 0
while run>0:
rep = 128 if run > 128 else run
r_append(cb)
r_append(rtc(rep)&0xff)
run -= rep
run = 1
for j in range(rows):
j0 = j*cols #first byte in our pixel data
d[:] = bytearray(pixels[j0:j0+cols])
r[:] = bytearray()
run = count = 0
k = cols1 #our pointer
cb = d[-1] #current byte
i = cols1
while i>=0:
#work backwards through the columns of this row
if cb == d[k]:
run += 1 #just increase the run
else:
endrun()
i -= 1
cb = d[k]
k -= 1
endrun()
if count>0:
r_append(ctc(count))
pc = len(r)
oc += pc+rli
putRLen(pc)
r_reverse()
__bs__.write(bytes(r))
if oc & 1: putc(b'\x00') #pad to even number of bytes
putShort(EndOfPicture)
lb = __bs__.tell()
lp = lb - headerLen
__bs__.seek(headerLen)
putShort(lp & 0xffff) #put picture size at the end of the header
return __bs__.getvalue()
|