123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- # Python tool to convert an image to C array for small3dlib.
- #
- # by drummyfish
- # released under CC0 1.0.
- import sys
- from PIL import Image
- def printHelp():
- print("Convert image to C array for small3dlib.")
- print("usage:\n")
- print(" python img2array.py [-xW -yH -h -nS -pT -5] file\n")
- print(" -xW set width of the output to W pixels")
- print(" -yH set height of the output to H pixels")
- print(" -h include header guards (for texture per file)")
- print(" -nS use the name S for the texture (defaut: \"texture\")")
- print(" -pT use palette from file T and indexed colors (otherwise direct colors)")
- print(" -5 use 565 format instead of RGB8")
- print(" -c compress (4 bpp, 16 color palette), only with -pT")
- print(" -t transpose (store by columns)")
- print("");
- print("by Miloslav \"drummyfish\" Ciz")
- print("released under CC0 1.0")
- def rgbTo565(rgb):
- return ((rgb[0] >> 3) << 11) | ((rgb[1] >> 2) << 5) | ((rgb[2] >> 3))
- if len(sys.argv) < 2:
- printHelp()
- quit()
- FILENAME = ""
- PALETTE = ""
- USE_PALETTE = False
- NAME = "texture"
- GUARDS = False
- OUT_WIDTH = 64
- OUT_HEIGHT = 64
- USE_565 = False
- TRANSPOSE = False
- COMPRESS = False
- for s in sys.argv:
- if s [:2] == "-x":
- OUT_WIDTH = int(s[2:])
- elif s [:2] == "-y":
- OUT_HEIGHT = int(s[2:])
- elif s == "-h":
- GUARDS = True
- elif s[:2] == "-n":
- NAME = s[2:]
- elif s[:2] == "-5":
- USE_565 = True
- elif s[:2] == "-p":
- PALETTE = s[2:]
- USE_PALETTE = True
- elif s[:2] == "-t":
- TRANSPOSE = True
- elif s[:2] == "-c":
- COMPRESS = True
- else:
- FILENAME = s
- if not USE_PALETTE:
- COMPRESS = False
- imageArray = []
- paletteColors = []
- paletteArray = []
- image = Image.open(FILENAME).convert("RGB")
- pixels = image.load()
- if USE_PALETTE > 0:
- palette = Image.open(PALETTE).convert("RGB")
- pixelsPal = palette.load()
- for y in range(palette.size[1]):
- for x in range(palette.size[0]):
- c = pixelsPal[x,y]
- paletteColors.append(c)
- if USE_565:
- paletteArray.append(rgbTo565(c))
- else:
- paletteArray.append(c[0])
- paletteArray.append(c[1])
- paletteArray.append(c[2])
- image2 = Image.new("RGB",(OUT_WIDTH,OUT_HEIGHT),color="white")
- pixels2 = image2.load()
- def findClosestColor(pixel,paletteColors):
- closestIndex = 0
- closestDiff = 1024
- # find the index of the closest color:
- for i in range(len(paletteColors)):
- c = paletteColors[i]
- diff = abs(pixel[0] - c[0]) + abs(pixel[1] - c[1]) + abs(pixel[2] - c[2])
- if diff < closestDiff:
- closestIndex = i
- closestDiff = diff
- return closestIndex
- for y in range(OUT_HEIGHT):
- for x in range(OUT_WIDTH):
- x2 = y if TRANSPOSE else x
- y2 = x if TRANSPOSE else y
- coord = (
- int(x2 / float(OUT_WIDTH) * image.size[0]),
- int(y2 / float(OUT_HEIGHT) * image.size[1]))
- pixel = pixels[coord]
- if USE_PALETTE:
- closestIndex = findClosestColor(pixel,paletteColors)
- imageArray.append(closestIndex)
- pixels2[x,y] = paletteColors[closestIndex]
- else:
- if USE_565:
- imageArray.append(rgbTo565(pixel))
- else:
- imageArray.append(pixel[0])
- imageArray.append(pixel[1])
- imageArray.append(pixel[2])
- pixels2[x,y] = pixel
- #-----------------------
- def compressImageArray(a):
- result = []
- reducedPalette = []
- histogram = [0 for i in range(256)]
- for c in a:
- histogram[c] += 1
- for i in range(16):
- maxValue = 0
- maxIndex = 0
- for j in range(256):
- if histogram[j] > maxValue:
- maxValue = histogram[j]
- maxIndex = j
- reducedPalette.append(maxIndex)
- histogram[maxIndex] = 0
- paletteMap = [findClosestColor(paletteColors[i],[paletteColors[j] for j in reducedPalette]) for i in range(256)]
- oneByte = 0
- byteCount = 0
- for c in a:
- if byteCount % 2 == 0:
- oneByte = paletteMap[c]
- else:
- oneByte = (oneByte << 4) | paletteMap[c]
- result.append(oneByte)
- byteCount += 1
- result = reducedPalette + result
- return result
- def printArray(array, name, sizeString, dataType="const uint8_t"):
- print(dataType + " " + name + "[" + sizeString + "] = {")
- arrayString = ""
- lineLen = 0
- for v in array:
- item = str(v) + ","
- lineLen += len(item)
- if lineLen > 80:
- arrayString += "\n"
- lineLen = len(item)
- arrayString += item
- print(arrayString[:-1])
- print("}; // " + name)
- if GUARDS:
- print("#ifndef " + NAME.upper() + "_TEXTURE_H")
- print("#define " + NAME.upper() + "_TEXTURE_H\n")
- if USE_PALETTE:
- printArray(paletteArray,NAME + "Palette",str(len(paletteArray)),"const uint16_t" if USE_565 else "const uint8_t")
- print("")
- print("#define " + NAME.upper() + "_TEXTURE_WIDTH " + str(OUT_WIDTH))
- print("#define " + NAME.upper() + "_TEXTURE_HEIGHT " + str(OUT_HEIGHT))
- print("")
-
- if COMPRESS:
- imageArray = compressImageArray(imageArray)
- printArray(imageArray,NAME + "Texture",str(len(imageArray)))
- if GUARDS:
- print("\n#endif // guard")
- image2.save(NAME + "_preview.png")
|