In [11]:
import png
import math
import glob
import os
import numpy as np;
from IPython.display import Image

In [12]:
#returns the width and height (respectively) of the given img
def getPngDimensions(filename):
    img = png.Reader(filename).asDirect()
    
    vals = []
    vals.append(img[0])
    vals.append(img[1])
    return vals

In [17]:
def getPixels(filename):
    pic1 = png.Reader(filename).asRGBA()
    rows = pic1[2]
    pixels = []
    pixelcount = 0
    for row in rows:
        count = 0
        pixel = []
        for entry in row:
            pixel.append(entry)
            count = count + 1
            if (count == 4):
                pixels.append(pixel)
                pixel = []
                pixelcount = pixelcount + 1
                count = 0;
    
    return pixels


def reencodeImageWithGivenBpp(pixels, inRbpp, inGbpp, inBbpp, outRbpp, outGbpp, outBbpp):
    outpixels = []
    for pixel in pixels:
        outpixel = []
        channelCount = 0
        for channel in pixel:
            numIn = -1
            numOut = -1
            colorchar = "?"
            if channelCount == 0:
                numIn = inRbpp
                numOut = outRbpp
                colorchar = "R"
            elif channelCount == 1:
                numIn = inGbpp
                numOut = outGbpp
                colorchar = "G"
            elif channelCount == 2:
                numIn = inBbpp
                numOut = outBbpp
                colorchar = "B"
            elif channelCount == 3:
                outpixel.append(channel)
                break
            
            channelCount = channelCount + 1
            
            #find if we're upscaling or downscaling
            #for downscaling, we need to divide our value by 2^(difference in powers)
            #for upscaling, we need to multiply by the same value. We don't apply any dithering.
            outval = 0;
            if (numIn > numOut):
                dif = numIn - numOut
                outval = channel >> dif
            else:
                dif = numOut - numIn
                outval = channel << dif
            
            outpixel.append(outval)
            
            #print(colorchar + ": " + str(channel) + " --> " + str(outval))
        
        outpixels.append(outpixel)
        
    return outpixels

In [18]:
def ConvertPixelsToPngWriteable(pixels, width):
    resultArray1 = []
    resultArray2 = []
    count = 0;
    for pixel in pixels:
        count = count + 1
        
        resultArray2.append(pixel[0])
        resultArray2.append(pixel[1])
        resultArray2.append(pixel[2])
        
        
        if (count == width):
            count = 0
            resultArray1.append(resultArray2)
            resultArray2 = []
    
    return resultArray1

In [74]:
def MakeDir(path):
    #ignore exception saying it already exists
    try: 
        os.makedirs(path)
    except OSError:
        if not os.path.isdir(path):
            raise

def ProcessFolder(outputImages=False):
    curDir = os.getcwd()
    sizeTotal = 0
    with open(curDir + "\\output.txt", 'w') as outFile:
        outFile.write("#ifndef SPRITE_DEFINITIONS_H\r\n#define SPRITE_DEFINITIONS_H\r\n\r\n")
        
        sizeTotal = ProcessFolderRec(os.getcwd(), outFile, sizeTotal, outputImages)
        
        outFile.write("//" + str(sizeTotal) + " bytes used (estimated)\r\n")
        outFile.write("#endif")
    outFile.close()
    print (str(sizeTotal) + " bytes used (estimate)")


def ProcessFolderRec(folderPath, outFile, sizeTotal, outputImages=False):
    print("Processing folder: " + folderPath)
    os.chdir(folderPath)
    for directory in (d for d in glob.glob('*/') if d != '/out'):
        sizeTotal = sizeTotal + ProcessFolderRec(folderPath + '/' + directory, outFile, outputImages)
    
    #make sure we're in the right working dir
    os.chdir(folderPath)
    for filename in glob.glob('*.png'):
        print("Processing file: " + filename)
        imgdimensions = getPngDimensions(filename)
        imgwidth = imgdimensions[0]
        imgheight = imgdimensions[1]        
        
        inpixels = getPixels(filename)
        outpixels = reencodeImageWithGivenBpp(inpixels, 8,8,8, 5,6,5)
        if(outputImages):
            altPixels = reencodeImageWithGivenBpp(outpixels, 5,6,5, 8,8,8)
            altPixels = ConvertPixelsToPngWriteable(altPixels, imgwidth)

            #try making the output directory
            MakeDir("out/")
                    
            alteredOutFile = open("out/" + filename[:-4] + "_out.png", 'wb')
            writer = png.Writer(size = imgdimensions)
            writer.write(alteredOutFile, altPixels)
            alteredOutFile.close()
        
        ##########################################
        #write the entry
        #get rid of the extension, uppercase everything, and replace spaces with underscores
        spriteName = filename[:-4].upper().replace(" ", "_") 
        
        #start defining the array
        outFile.write("const PROGMEM uint16_t ")
        outFile.write(spriteName) 
        outFile.write("[] = {")
        
        #define the width
        outFile.write(str(imgwidth))
        outFile.write(", ")
        
        #define the height
        outFile.write(str(imgheight))
        outFile.write(", ")
        
        totNumPixels = imgheight * imgwidth
        curpixel = 0
        
        #go through each pixel and calculate the integer representation
        for pixel in outpixels:
            outValue = 0;
            channelCount = 0
            curpixel = curpixel + 1
            
            for channel in pixel:
                if channelCount == 3:
                    #check for transparency. If we're transparent then
                    #ignore what we recorded for the other pixels and 
                    #save magenta in our outvalue
                    if channel == 0:
                        outValue = 0xF81F
                    break
                
                outValue = outValue | channel
                #red has 5 bits, green has 6, and blue has 5
                if channelCount == 0:
                    outValue = outValue << 6
                elif channelCount == 1:
                    outValue = outValue << 5
                    
                #don't shift for the last 5 bits

                channelCount = channelCount + 1        
                
            #write this vlue to our list of pixels
            outFile.write(str(outValue))
            
            #don't put a comma after the last value
            if(curpixel != totNumPixels):
                outFile.write(",")
                
                    
        outFile.write("};\r\n\r\n")
        
        sizeTotal = sizeTotal + (imgwidth * imgheight * 2) + 4
        print("Finished processing entry: " + filename)    
        print ("Current size: " + str(sizeTotal))
    return sizeTotal

In [75]:
ProcessFolder()


Processing folder: C:\Users\Dibbs\Documents\Arduino\ArduinoRoguelike\trunk\Scripts\forest dungeon
Processing file: bush.png
Finished processing entry: bush.png
Current size: 290
Processing file: floor tile variant.png
Finished processing entry: floor tile variant.png
Current size: 580
Processing file: floor tile.png
Finished processing entry: floor tile.png
Current size: 870
Processing file: grass0.png
Finished processing entry: grass0.png
Current size: 1160
Processing file: grass0b.png
Finished processing entry: grass0b.png
Current size: 1450
Processing file: nwall-door.png
Finished processing entry: nwall-door.png
Current size: 1740
Processing file: nwall1.png
Finished processing entry: nwall1.png
Current size: 2030
Processing file: nwall2.png
Finished processing entry: nwall2.png
Current size: 2320
Processing file: nwall3.png
Finished processing entry: nwall3.png
Current size: 2610
Processing file: nwall4.png
Finished processing entry: nwall4.png
Current size: 2900
Processing file: pond.png
Finished processing entry: pond.png
Current size: 4054
Processing file: tree1.png
Finished processing entry: tree1.png
Current size: 4344
Processing file: tree2.png
Finished processing entry: tree2.png
Current size: 4634
Processing file: tree3.png
Finished processing entry: tree3.png
Current size: 4924
Processing file: tree4.png
Finished processing entry: tree4.png
Current size: 5214
Processing file: wall-corner.png
Finished processing entry: wall-corner.png
Current size: 5504
Processing file: wwall1.png
Finished processing entry: wwall1.png
Current size: 5794
Processing file: wwall2.png
Finished processing entry: wwall2.png
Current size: 6084
Processing file: wwall3.png
Finished processing entry: wwall3.png
Current size: 6374
Processing file: wwall4.png
Finished processing entry: wwall4.png
Current size: 6664
6664 bytes used (estimate)

In [ ]:


In [ ]: