convert_image.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. # Python tool to convert an image to C array for SAF.
  2. #
  3. # usage: python convert_image.py [-b|-c] image_file
  4. #
  5. # -b 1bit image (otherwise color image)
  6. # -c compress image
  7. #
  8. # by drummyfish
  9. # released under CC0 1.0.
  10. import sys
  11. from PIL import Image
  12. def rgbTo332(rgb):
  13. return ((rgb[0] >> 5) << 5) | ((rgb[1] >> 5) << 2) | ((rgb[2] >> 6))
  14. def hexByte(b):
  15. return "0x" + hex(b)[2:].zfill(2)
  16. def findClosestColor(color332,palette):
  17. bestD = 10000
  18. bestI = 0
  19. for i in range(len(palette)):
  20. c = palette[i]
  21. dr = abs((color332 >> 5) - (c >> 5))
  22. dg = abs(((color332 >> 2) & 0x07) - ((c >> 2) & 0x07))
  23. db = abs((color332 & 0x03) - (c & 0x03))
  24. d = dr + dg + db
  25. if d < bestD:
  26. bestD = d
  27. bestI = i
  28. return bestI
  29. MODE_NORMAL = 0
  30. MODE_COMPRESSED = 1
  31. MODE_BINARY = 2
  32. filename = ""
  33. mode = MODE_NORMAL
  34. result = []
  35. for s in sys.argv:
  36. if s [:2] == "-b":
  37. mode = MODE_BINARY
  38. if s [:2] == "-c":
  39. mode = MODE_COMPRESSED
  40. else:
  41. filename = s
  42. imageArray = []
  43. image = Image.open(filename).convert("RGB")
  44. pixels = image.load()
  45. result.append(image.size[0] % 256) # width
  46. result.append(image.size[1] % 256) # height
  47. byte = 0
  48. bitPosition = 0
  49. colorHistogram = [0 for i in range(256)]
  50. palette = [-1 for i in range(16)]
  51. if mode == MODE_COMPRESSED: # create 16 color palette
  52. for y in range(image.size[1]):
  53. for x in range(image.size[0]):
  54. colorHistogram[rgbTo332(pixels[(x,y)])] += 1
  55. for i in range(256):
  56. count = colorHistogram[i]
  57. for pos in range(16):
  58. if palette[pos] == -1 or count > colorHistogram[palette[pos]]:
  59. palette = (palette[:pos] + [i] + palette[pos:])[:-1]
  60. break
  61. for i in range(16):
  62. result.append(palette[i])
  63. rlePrevious = -1
  64. rleCount = 16
  65. for y in range(image.size[1]):
  66. for x in range(image.size[0]):
  67. pixel = pixels[(x,y)]
  68. last = x == image.size[0] - 1 and y == image.size[1] - 1
  69. if mode == MODE_NORMAL:
  70. result.append(rgbTo332(pixel))
  71. elif mode == MODE_BINARY:
  72. byte = (byte << 1) | (1 if pixel[0] > 127 else 0)
  73. bitPosition += 1
  74. if bitPosition >= 8 or last:
  75. result.append(byte << (8 - bitPosition))
  76. bitPosition = 0
  77. byte = 0
  78. else: # MODE_COMPRESSED
  79. index = findClosestColor(rgbTo332(pixel),palette)
  80. if index != rlePrevious or rleCount >= 15 or last:
  81. if rlePrevious != -1:
  82. result.append(rlePrevious | (rleCount << 4))
  83. rlePrevious = index
  84. rleCount = 0
  85. else:
  86. rleCount += 1
  87. print("uint8_t image[" + str(len(result)) + "] = {")
  88. lineCount = 0
  89. string = ""
  90. for i in range(len(result)):
  91. string += hexByte(result[i])
  92. if i != len(result) - 1:
  93. string += ","
  94. lineCount += 1
  95. if lineCount >= 16:
  96. lineCount = 0
  97. string += "\n"
  98. print(string + "};")