Advertisement
Doesnt

sprite conversion script (a-series -> decomp)

Jul 25th, 2019
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.18 KB | None | 0 0
  1. from PIL import Image
  2. import os
  3.  
  4. def subfinder(mylist, pattern):
  5. for i in range(len(mylist)):
  6. if mylist[i] == pattern[0] and mylist[i:i+len(pattern)] == pattern:
  7. return i
  8. return -1
  9.  
  10. def LZ77Compress(data) :
  11. compressed = [0x10]
  12. data_length = len(data)
  13. compressed.append(data_length % 256)
  14. compressed.append((data_length >> 8) % 256)
  15. compressed.append((data_length >> 16) % 256)
  16.  
  17. index = 0
  18. w = 4095
  19. window = None
  20. lookahead = None
  21. while True :
  22. bits = []
  23. check = None
  24. currCompSet = []
  25. for n in range(8) :
  26. if index < w : window = data[:index]
  27. else: window = data[index-w:index]
  28. lookahead = data[index:]
  29. if lookahead == [] :
  30. if bits != [] :
  31. while len(bits) != 8 :
  32. bits.append(0)
  33. currCompSet.append(0)
  34. bitfield = bits[7] + 2*bits[6] + 4*bits[5] + 8*bits[4] \
  35. + 16*bits[3] + 32*bits[2] + 64*bits[1] + 128*bits[0]
  36. compressed.append(bitfield)
  37. compressed += currCompSet
  38. break
  39. check = subfinder(window, lookahead[0:3]) # Need to find at least a 3 byte match
  40. if check == -1 :
  41. index += 1
  42. bits.append(0)
  43. currCompSet += [lookahead[0]]
  44. else :
  45. bits.append(1) # Compressed data
  46. length = 2
  47. while check != -1 and length < 18 :
  48. store_length = length
  49. length += 1
  50. store_check = check
  51. check = subfinder(window, lookahead[0:length])
  52. index += store_length
  53. store_length -= 3
  54. position = len(window)-store_check-1
  55. store_length = store_length << 12
  56. pos_and_len = store_length | position
  57. currCompSet.append(pos_and_len >> 8)
  58. currCompSet.append(pos_and_len % 256)
  59. if lookahead == [] :
  60. if bits != [] :
  61. while len(bits) != 8 :
  62. bits.append(0)
  63. currCompSet.append(0)
  64. bitfield = bits[7] + 2*bits[6] + 4*bits[5] + 8*bits[4] \
  65. + 16*bits[3] + 32*bits[2] + 64*bits[1] + 128*bits[0]
  66. compressed.append(bitfield)
  67. compressed += currCompSet
  68. break
  69. bitfield = bits[7] + 2*bits[6] + 4*bits[5] + 8*bits[4] \
  70. + 16*bits[3] + 32*bits[2] + 64*bits[1] + 128*bits[0]
  71. compressed.append(bitfield)
  72. compressed += currCompSet
  73. return compressed
  74.  
  75.  
  76. def ConvertImageToGBA(image, size=(64,64)) :
  77. data = list(image.getdata())
  78. palette = image.getpalette()
  79. height = size[1]
  80. width = size[0]
  81. blocks = []
  82. block_num = int(width/8)
  83. for w in range(int(height/8)) :
  84. for x in range(8) :
  85. block_num -= int(width/8)
  86. for y in range(int(width/8)) :
  87. for z in range(8) :
  88. value = data[0]
  89. try: blocks[block_num]
  90. except: blocks.append([])
  91. blocks[block_num].append(value)
  92. data = data[1:]
  93. block_num += 1
  94. block_num += int(width/8)
  95.  
  96. bgslot = blocks[0][0]
  97.  
  98. for i in range(len(blocks)) :
  99. for j in range(len(blocks[i])) :
  100. if blocks[i][j] == bgslot :
  101. blocks[i][j] = 0
  102. elif blocks[i][j] == 0 :
  103. blocks[i][j] = bgslot
  104. tmp = palette[0]
  105. tmp2 = palette[1]
  106. tmp3 = palette[2]
  107. palette[0] = palette[3*bgslot]
  108. palette[1] = palette[3*bgslot + 1]
  109. palette[2] = palette[3*bgslot + 2]
  110. palette[bgslot*3] = tmp
  111. palette[bgslot*3 + 1] = tmp2
  112. palette[bgslot*3 + 2] = tmp3
  113. gbapal = []
  114. for i in range(16) :
  115. r = palette[0] >> 3
  116. g = palette[1] >> 3
  117. b = palette[2] >> 3
  118. gbacolor = r + (g << 5) + (b << 10)
  119. palette = palette[3:]
  120. gbapal.append(gbacolor % 256)
  121. gbapal.append(gbacolor >> 8)
  122. values = []
  123. for b in blocks :
  124. values += b
  125. i = 0
  126. gbaimg = []
  127. while i < len(values) :
  128. gbaimg.append((values[i+1] << 4) + values[i])
  129. i += 2
  130. return (gbaimg, gbapal)
  131.  
  132. def ConvertGBAToImage(gbaimg, gbapal) :
  133. img = []
  134. blocks = []
  135. block = []
  136. for i in gbaimg :
  137. block.append(i % 16)
  138. block.append(i >> 4)
  139. if len(block) == 64 :
  140. blocks.append(block)
  141. block = []
  142.  
  143. for y in range(64) :
  144. for x in range(64) :
  145. block = blocks[(x >> 3) + 8 * (y >> 3)]
  146. val = block[(8*(y % 8)) + (x % 8)]
  147. img.append(val)
  148.  
  149. pal = []
  150. prevbyte = -1
  151. for i in gbapal:
  152. if prevbyte == -1 :
  153. prevbyte = i
  154. else :
  155. word = prevbyte + (i * 256)
  156. r = (word & 0x001f)
  157. g = (word & 0x03e0) >> 5
  158. b = (word & 0x7c00) >> 10
  159. pal.append(r * 8)
  160. pal.append(g * 8)
  161. pal.append(b * 8)
  162. prevbyte = -1
  163. return [img, pal]
  164.  
  165. def SavePalette(filename, pal) :
  166. with open(filename, "w") as file :
  167. file.write("JASC-PAL\n")
  168. file.write("0100\n")
  169. file.write("16\n")
  170. lines = 0
  171. colors = 0
  172. for i in pal :
  173. file.write(str(i))
  174. colors = colors + 1
  175. if colors == 3 :
  176. file.write("\n")
  177. lines = lines + 1
  178. colors = 0
  179. else :
  180. file.write(" ")
  181. while lines < 16 :
  182. file.write("0 0 0\n")
  183. lines = lines + 1
  184.  
  185.  
  186. def LoadSheetSprite(name):
  187. filename = name + ".png"
  188. raw = Image.open(filename)
  189. name = name.replace("input/", "")
  190. if raw.size != (256,64):
  191. print("it's fucked")
  192. return
  193. else:
  194. front = raw.copy().crop((0, 0, 64, 64))
  195. shiny = raw.copy().crop((64, 0, 128, 64))
  196. back = raw.copy().crop((128, 0, 192, 64))
  197. shinyback = raw.copy().crop((192, 0, 256, 64))
  198. frontback = Image.new("RGB", (64,128))
  199. frontback.paste(front, (0,0))
  200. frontback.paste(back, (0,64))
  201. shinyfb = Image.new("RGB", (64, 128))
  202. shinyfb.paste(shiny, (0,0))
  203. shinyfb.paste(shinyback, (0,64))
  204. if frontback.mode != "P":
  205. frontback = frontback.convert("RGB")
  206. frontback = frontback.convert("P", palette=Image.ADAPTIVE, colors=16)
  207. else:
  208. if len(frontback.getcolors()) > 16:
  209. tmp = frontback.convert("RGB")
  210. frontback = tmp.convert("P", palette=Image.ADAPTIVE, colors=16)
  211. if shinyfb.mode != "P":
  212. shinyfb = shinyfb.convert("RGB")
  213. shinyfb = shinyfb.convert("P", palette=Image.ADAPTIVE, colors=16)
  214. else:
  215. if len(shinyfb.getcolors()) > 16:
  216. tmp = shinyfb.convert("RGB")
  217. shinyfb = tmp.convert("P", palette=Image.ADAPTIVE, colors=16)
  218.  
  219. fbimg, npal = ConvertImageToGBA(frontback, (64, 128))
  220. fimg = fbimg[0:2048]
  221. bimg = fbimg[2048:]
  222. simg, spal = ConvertImageToGBA(shinyfb)
  223.  
  224. # Resolve the shiny palette. This is kind of a pain...
  225. fbdata = list(frontback.getdata())
  226. shdata = list(shinyfb.getdata())
  227. shinypal = shinyfb.getpalette()
  228. newshinypal = shinypal.copy()
  229. for i in range(len(fbdata)) :
  230. normalval = fbdata[i]
  231. shinyval = shdata[i]
  232. if normalval != shinyval :
  233. newshinypal[normalval*3 ] = shinypal[shinyval*3]
  234. newshinypal[normalval*3+1] = shinypal[shinyval*3+1]
  235. newshinypal[normalval*3+2] = shinypal[shinyval*3+2]
  236.  
  237. # Convert shiny palette to GBA format
  238. gbashinypal = []
  239. for i in range(16) :
  240. r = newshinypal[0] >> 3
  241. g = newshinypal[1] >> 3
  242. b = newshinypal[2] >> 3
  243. gbacolor = r + (g << 5) + (b << 10)
  244. newshinypal = newshinypal[3:]
  245. gbashinypal.append(gbacolor % 256)
  246. gbashinypal.append(gbacolor >> 8)
  247.  
  248. # Ensure the background color is in slot 0
  249. bgindex = fbdata[0]
  250. tmp = gbashinypal[bgindex*2]
  251. tmp2 = gbashinypal[bgindex*2 + 1]
  252. gbashinypal[bgindex*2] = gbashinypal[0]
  253. gbashinypal[bgindex*2+1] = gbashinypal[1]
  254. gbashinypal[0] = tmp
  255. gbashinypal[1] = tmp2
  256.  
  257.  
  258. # Convert from GBA format to something normal
  259. fimgout, npout = ConvertGBAToImage(fimg, npal)
  260. trash, spout = ConvertGBAToImage(fimg, spal)
  261. bimgout, trash = ConvertGBAToImage(bimg, npal)
  262. os.mkdir("output/" + name)
  263. frontout = Image.new("P", [64, 64])
  264. frontout.putdata(fimgout)
  265. frontout.putpalette(npout)
  266. frontout.save("output/" + name + "/front.png")
  267. backout = Image.new("P", [64, 64])
  268. backout.putdata(bimgout)
  269. backout.putpalette(npout)
  270. backout.save("output/" + name + "/back.png")
  271. SavePalette("output/" + name + "/normal.pal", npout)
  272. SavePalette("output/" + name + "/shiny.pal", spout)
  273.  
  274. for root, dirs, files in os.walk("input/") :
  275. for file in files :
  276. if file.endswith(".png") :
  277. print(file)
  278. LoadSheetSprite("input/" + file.replace(".png", ""))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement