from PIL import Image def getErr(r, g, b, stdCol): r -= stdCol[0] g -= stdCol[1] b -= stdCol[2] return r * r + g * g + b * b def getNear(r, g, b, curPal): ind = 0 err = getErr(r, g, b, curPal[0]) for i in range(1, len(curPal)): cur = getErr(r, g, b, curPal[i]) if cur < err: err = cur ind = i return ind def addVal(c, r, g, b, k): return [c[0] + (r * k) / 32, c[1] + (g * k) / 32, c[2] + (b * k) / 32] def procImg(img, dW, dH, dX, dY, palInd, isLvl, isRed, palArr): if isRed and ((palInd & 1) == 0): raise ValueError("This white-black display") if not isRed: palInd = palInd & 0xFE curPal = palArr[palInd] sW = img.width sH = img.height pDst = Image.new("RGB", (dW, dH)) pixels = pDst.load() if isLvl: # Level-based processing for j in range(dH): y = dY + j for i in range(dW): x = dX + i if 0 <= x < sW and 0 <= y < sH: r, g, b = img.getpixel((x, y)) color_index = getNear(r, g, b, curPal) pixels[i, j] = tuple(curPal[color_index]) else: pixels[i, j] = tuple( curPal[(i + j) % 2] ) # checkerboard for out of bounds else: # Dithering errArr = [[[0, 0, 0] for _ in range(dW)] for _ in range(2)] aInd = 0 bInd = 1 for j in range(dH): y = dY + j aInd, bInd = bInd, aInd # swap buffers for i in range(dW): errArr[bInd][i] = [0, 0, 0] for i in range(dW): x = dX + i if 0 <= x < sW and 0 <= y < sH: old = errArr[aInd][i] r_orig, g_orig, b_orig = img.getpixel((x, y)) r = r_orig + old[0] g = g_orig + old[1] b = b_orig + old[2] color_index = getNear(r, g, b, curPal) colVal = curPal[color_index] pixels[i, j] = tuple(colVal) r_err = r - colVal[0] g_err = g - colVal[1] b_err = b - colVal[2] # Propagate error (Floyd-Steinberg-like) if i == 0: errArr[bInd][i] = addVal( errArr[bInd][i], r_err, g_err, b_err, 7.0 ) if dW > 1: errArr[bInd][i + 1] = addVal( errArr[bInd][i + 1], r_err, g_err, b_err, 2.0 ) errArr[aInd][i + 1] = addVal( errArr[aInd][i + 1], r_err, g_err, b_err, 7.0 ) elif i == dW - 1: errArr[bInd][i - 1] = addVal( errArr[bInd][i - 1], r_err, g_err, b_err, 7.0 ) errArr[bInd][i] = addVal( errArr[bInd][i], r_err, g_err, b_err, 9.0 ) else: errArr[bInd][i - 1] = addVal( errArr[bInd][i - 1], r_err, g_err, b_err, 3.0 ) errArr[bInd][i] = addVal( errArr[bInd][i], r_err, g_err, b_err, 5.0 ) errArr[bInd][i + 1] = addVal( errArr[bInd][i + 1], r_err, g_err, b_err, 1.0 ) errArr[aInd][i + 1] = addVal( errArr[aInd][i + 1], r_err, g_err, b_err, 7.0 ) else: pixels[i, j] = tuple(curPal[(i + j) % 2]) # checkerboard return pDst