121 lines
3.9 KiB
Python
121 lines
3.9 KiB
Python
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
|