''' Loads a text file defining color names for rgb values, then goes through a photo and lists the colors it finds. (The first version will just list the colors, a later version may be more abstract about what it lists makeNaivePDF("colors.txt", "production1.pdf", imageFilename = "city.jpeg") ''' from PIL import Image from fpdf import FPDF import urllib.request import math def loadColorFile(filename): colors = [] f = open(filename, "r") for line in f.readlines(): line = line.replace("rgb(", "(") words = line.strip().split() if len(words) >= 3: # then it's probably a color definition # name, #code (r, g, b) if (words[-1][0] == "("): # then it's a color definition name = "" for word in words: if word[0] == "#": break if word[0] == "/": break # used to define alternate spellings/names, # we're ignoring those name += " " + word name = name.strip() rgb = words[-1][1:-1].split(",") # cut off the parens and split colors += [((int(rgb[0]), int(rgb[1]), int(rgb[2])), name)] # now just use vectors #colors += [(rgbToSingleNumber(*(int(x) for x in rgb)), name)] return list(colors) # this was a terrible idea, just compare distances of the vectors instead #def rgbToSingleNumber(r, g, b): # # multiply by powers of 10 to get a single number representing the color # return r*100000 + g*1000 + b def compareVectors(v1, v2): squared = 0 for i in range(len(v1)): sqr = v1[i]-v2[i] squared += sqr*sqr return math.sqrt(squared) def loadImage(filename): img = Image.open(filename) data = img.getdata() width = img.width height = img.height #img.show() img.close() return (data, width, height) def closestColor(color, colors): # returns the name of the closest color to the pixel and the difference ## c = rgbToSingleNumber(*color) ## i = 0 ## while colors[i][0] < c and i +1 < len(colors): ## i += 1 ## if i == 0: ## return colors[i][1], abs(colors[i][0] - c)# the name of that color ## # return the closer color ## if abs(colors[i][0] - c) < abs(colors[i-1][0]): ## return colors[i][1], abs(colors[i][0] - c) ## return colors[i-1], abs(colors[i-1][0] - c) closestIndex = 0 closestDistance = compareVectors(color, colors[0][0]) for i in range(len(colors)): newDistance = compareVectors(color, colors[i][0]) if newDistance < closestDistance: closestDistance = newDistance closestIndex = i return colors[closestIndex], closestDistance def naiveConvert(filename, colors): # return a list of colors/color name tuples corresponding to the closest # to each pixel data, width, height = loadImage(filename) out = [] for i in range(len(data)): out += [closestColor(data[i], colors)] #if i % 1000 == 0: # print(i) return out #[closestColor(x, colors) for x in data] def downloadRandomImage(width = 250, height = 200): url = "http://lorempixel.com/"+str(width)+"/"+str(height)+"/" filename, response = urllib.request.urlretrieve(url) return filename def makeNaivePDF(colorfilename, filename, imageWidth = 250, imageHeight = 200, imageFilename = None): if (imageFilename == None): imageFilename = downloadRandomImage(imageWidth, imageHeight) # load the image and get its width and height and such img = Image.open(imageFilename) imageWidth = img.width imageHeight = img.height img.close() colors = loadColorFile(colorfilename) colorNames = naiveConvert(imageFilename, colors) colorString = ", ".join([str(x[0][1]) for x in colorNames]) colorString = colorString.capitalize() + "." title = "A Picture is Worth " + str(len(colorString.split())) + " Words" pdf = FPDF(format = (8.5, 11), unit = "in") pdf.set_title(title) pdf.set_author("Jordan Faas-Bush?") pdf.add_page() # make the title page pdf.set_font('Times', 'BU', 24) #pdf.cell(0, 10, title) pdf.set_y(4) pdf.cell(0, 0, title, 0, 1, 'C', False) pdf.add_page() # the rest of it pdf.set_font('Times', '', 12) # Output justified text pdf.multi_cell(0, .25, colorString) # now the image pdf.add_page() img = Image.open(imageFilename) img.save(imageFilename + "pngversion.png", "png") # the image by default is 72 dpi, and by default the unit is mm # in order to center it, we do what: x = 4.25 - imageWidth/72/2 y = 11/2 - imageHeight/72/2 pdf.image(imageFilename+"pngversion.png", x, y) pdf.set_y(y+(imageHeight/72)+.25) pdf.cell(0, 0, "Original Image", 0, 1, 'C', False) namedColors = Image.new("RGB", (imageWidth, imageHeight)) colorDifference = Image.new("RGB", (imageWidth, imageHeight)) colorDifferencex10 = Image.new("RGB", (imageWidth, imageHeight)) colorColorDifference = Image.new("RGB", (imageWidth, imageHeight)) for i in range(len(colorNames)): loc = (i%imageWidth, math.floor(i/imageWidth)) namedColors.putpixel(loc, colorNames[i][0][0]) #colorColorDifference.putpixel(loc, (colorNames[i][0][1] # do one with the actual differences not just redscaled colorDifference.putpixel(loc, (min(255, int(colorNames[i][1]/441.6729559300637*255)), 0, 0)) colorDifferencex10.putpixel(loc, (min(255, 10*int(colorNames[i][1]/441.6729559300637*255)), 0, 0)) scaleHeight = 8 redScale = Image.new("RGB", (255, scaleHeight)) for i in range(255): for j in range(scaleHeight): redScale.putpixel((i, j), (i, 0, 0)) scaleX = 4.25 - 255/72/2 namedColors.save(filename+"_namedColors.png", "png") colorDifference.save(filename+"_colorDifference.png", "png") colorDifferencex10.save(filename+"_colorDifferencex10.png", "png") redScale.save("scale.png", "png") pdf.add_page() pdf.image(filename+"_namedColors.png", x, y) pdf.set_y(y+(imageHeight/72)+.25) pdf.cell(0, 0, "Named Colors", 0, 1, 'C', False) pdf.add_page() pdf.image(filename+"_colorDifference.png", x, y) pdf.image("scale.png", scaleX, y+imageHeight/72 + .05) pdf.set_y(y+(imageHeight/72)+.3) pdf.cell(0,0, "Color Difference", 0, 1, 'C', False) pdf.add_page() pdf.image(filename+"_colorDifferencex10.png", x, y) pdf.image("scale.png", scaleX, y+imageHeight/72 + .05) pdf.set_y(y+(imageHeight/72)+.3) pdf.cell(0, 0, "Color Difference Scaled by 10x", 0, 1, 'C', False) pdf.output(filename+".pdf", "F")