convert.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import Image
  2. import array
  3. import random
  4. from gameduino2.registers import *
  5. from gameduino2.imbytes import imbytes
  6. def convert(im, dither = False, fmt = ARGB1555):
  7. """ Convert PIL image to GD2 format, optionally dithering"""
  8. im = im.convert({
  9. ARGB1555 : "RGBA",
  10. L1 : "L",
  11. L4 : "L",
  12. L8 : "L",
  13. RGB332 : "RGB",
  14. ARGB2 : "RGBA",
  15. ARGB4 : "RGBA",
  16. RGB565 : "RGB",
  17. PALETTED : "RGB"}[fmt])
  18. imdata = []
  19. colorfmts = {
  20. ARGB1555 : (1, 5, 5, 5),
  21. RGB332 : (0, 3, 3, 2),
  22. ARGB2 : (2, 2, 2, 2),
  23. ARGB4 : (4, 4, 4, 4),
  24. RGB565 : (0, 5, 6, 5)}
  25. if dither:
  26. rnd = random.Random()
  27. rnd.seed(0)
  28. if fmt in colorfmts:
  29. im = im.convert("RGBA")
  30. (asz,rsz,gsz,bsz) = colorfmts[fmt]
  31. totalsz = sum((asz,rsz,gsz,bsz))
  32. assert totalsz in (8,16)
  33. for y in range(im.size[1]):
  34. for x in range(im.size[0]):
  35. (r,g,b,a) = im.getpixel((x,y))
  36. if dither:
  37. a = min(255, a + rnd.randrange(256>>asz))
  38. r = min(255, r + rnd.randrange(256>>rsz))
  39. g = min(255, g + rnd.randrange(256>>gsz))
  40. b = min(255, b + rnd.randrange(256>>bsz))
  41. binary = ((a >> (8-asz)) << (bsz+gsz+rsz)) | ((r >> (8-rsz)) << (gsz+bsz)) | ((g >> (8-gsz)) << (bsz)) | (b >> (8-bsz))
  42. imdata.append(binary)
  43. fmtchr = {8:'B',16:'H'}[totalsz]
  44. data = array.array('B', array.array(fmtchr, imdata).tostring())
  45. elif fmt == PALETTED:
  46. im = im.convert("P", palette = Image.ADAPTIVE)
  47. lut = im.resize((256, 1))
  48. lut.putdata(range(256))
  49. palstr = lut.convert("RGBA").tobytes()
  50. rgba = zip(*(array.array('B', palstr[i::4]) for i in range(4)))
  51. data = imbytes(im)
  52. totalsz = 8
  53. elif fmt == L8:
  54. data = imbytes(im)
  55. totalsz = 8
  56. elif fmt == L4:
  57. b0 = imbytes(im)[::2]
  58. b1 = imbytes(im)[1::2]
  59. def to15(c):
  60. if dither:
  61. dc = min(255, c + rnd.randrange(16))
  62. else:
  63. dc = c
  64. return int((15. * dc / 255))
  65. data = array.array('B', [(16 * to15(l) + to15(r)) for (l,r) in zip(b0, b1)])
  66. totalsz = 4
  67. elif fmt == L1:
  68. if dither:
  69. im = im.convert("1", dither=Image.FLOYDSTEINBERG)
  70. else:
  71. im = im.convert("1", dither=Image.NONE)
  72. data = imbytes(im)
  73. totalsz = 1
  74. return (im.size, data)