0

changed most PIL paste() calls into composite.alpha_over() calls

The ones I have not changed are those where paste() is really
preferred, and I've noted why in comments.

Calls to "dest.paste(src, rect, mask)" were converted to calls to
"composite.alpha_over(dest, src, rect, mask)".
This commit is contained in:
Aaron Griffith
2010-10-23 13:36:55 -04:00
parent 8120bcd455
commit 395e26ef9c
3 changed files with 61 additions and 49 deletions

View File

@@ -22,6 +22,7 @@ import logging
import nbt import nbt
import textures import textures
import world import world
import composite
""" """
This module has routines related to rendering one particular chunk into an This module has routines related to rendering one particular chunk into an
@@ -36,7 +37,11 @@ image
# of the dest image will have its alpha channel modified. To prevent this: # of the dest image will have its alpha channel modified. To prevent this:
# first use im.split() and take the third item which is the alpha channel and # first use im.split() and take the third item which is the alpha channel and
# use that as the mask. Then take the image and use im.convert("RGB") to strip # use that as the mask. Then take the image and use im.convert("RGB") to strip
# the image from its alpha channel, and use that as the source to paste() # the image from its alpha channel, and use that as the source to alpha_over()
# (note that this workaround is NOT technically needed when using the
# alpha_over extension, BUT this extension may fall back to PIL's
# paste(), which DOES need the workaround.)
def get_lvldata(filename): def get_lvldata(filename):
"""Takes a filename and returns the Level struct, which contains all the """Takes a filename and returns the Level struct, which contains all the
@@ -556,36 +561,36 @@ class ChunkRenderer(object):
# tint the block with a color proportional to its depth # tint the block with a color proportional to its depth
if cave: if cave:
# no lighting for cave -- depth is probably more useful # no lighting for cave -- depth is probably more useful
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1]) composite.alpha_over(img, Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else: else:
if not self.world.lighting: if not self.world.lighting:
# no lighting at all # no lighting at all
img.paste(t[0], (imgx, imgy), t[1]) composite.alpha_over(img, t[0], (imgx, imgy), t[1])
elif blockid in transparent_blocks: elif blockid in transparent_blocks:
# transparent means draw the whole # transparent means draw the whole
# block shaded with the current # block shaded with the current
# block's light # block's light
black_coeff, _ = self.get_lighting_coefficient(x, y, z) black_coeff, _ = self.get_lighting_coefficient(x, y, z)
img.paste(Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1]) composite.alpha_over(img, Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
else: else:
# draw each face lit appropriately, # draw each face lit appropriately,
# but first just draw the block # but first just draw the block
img.paste(t[0], (imgx, imgy), t[1]) composite.alpha_over(img, t[0], (imgx, imgy), t[1])
# top face # top face
black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1) black_coeff, face_occlude = self.get_lighting_coefficient(x, y, z + 1)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
# left face # left face
black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z) black_coeff, face_occlude = self.get_lighting_coefficient(x - 1, y, z)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# right face # right face
black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z) black_coeff, face_occlude = self.get_lighting_coefficient(x, y + 1, z)
if not face_occlude: if not face_occlude:
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) composite.alpha_over(img, black_color, (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
# Draw edge lines # Draw edge lines
if blockid in (44,): # step block if blockid in (44,): # step block
@@ -616,6 +621,8 @@ def generate_facemasks():
toppart = textures.transform_image(white) toppart = textures.transform_image(white)
leftpart = textures.transform_image_side(white) leftpart = textures.transform_image_side(white)
# using the real PIL paste here (not alpha_over) because there is
# no alpha channel (and it's mode "L")
top.paste(toppart, (0,0)) top.paste(toppart, (0,0))
left.paste(leftpart, (0,6)) left.paste(leftpart, (0,6))
right = left.transpose(Image.FLIP_LEFT_RIGHT) right = left.transpose(Image.FLIP_LEFT_RIGHT)

View File

@@ -29,6 +29,7 @@ import util
from PIL import Image from PIL import Image
from optimizeimages import optimize_image from optimizeimages import optimize_image
import composite
""" """
@@ -450,6 +451,9 @@ def render_innertile(dest, name, imgformat, optimizeimg):
# Create the actual image now # Create the actual image now
img = Image.new("RGBA", (384, 384), (38,92,255,0)) img = Image.new("RGBA", (384, 384), (38,92,255,0))
# we'll use paste (NOT alpha_over) for quadtree generation because
# this is just straight image stitching, not alpha blending
if q0path: if q0path:
try: try:
quad0 = Image.open(q0path).resize((192,192), Image.ANTIALIAS) quad0 = Image.open(q0path).resize((192,192), Image.ANTIALIAS)
@@ -613,7 +617,7 @@ def render_worldtile(chunks, colstart, colend, rowstart, rowend, path, imgformat
xpos = -192 + (col-colstart)*192 xpos = -192 + (col-colstart)*192
ypos = -96 + (row-rowstart)*96 ypos = -96 + (row-rowstart)*96
tileimg.paste(chunkimg.convert("RGB"), (xpos, ypos), chunkimg) composite.alpha_over(tileimg, chunkimg.convert("RGB"), (xpos, ypos), chunkimg)
# Save them # Save them
tileimg.save(imgpath) tileimg.save(imgpath)

View File

@@ -24,6 +24,7 @@ import numpy
from PIL import Image, ImageEnhance from PIL import Image, ImageEnhance
import util import util
import composite
def _find_file(filename, mode="rb"): def _find_file(filename, mode="rb"):
"""Searches for the given file and returns an open handle to it. """Searches for the given file and returns an open handle to it.
@@ -157,13 +158,13 @@ def transform_image_side(img, blockID=None):
# img to be unchanged # img to be unchanged
mask = img.crop((0,8,16,16)) mask = img.crop((0,8,16,16))
n = Image.new(img.mode, img.size, (38,92,255,0)) n = Image.new(img.mode, img.size, (38,92,255,0))
n.paste(mask,(0,0,16,8), mask) composite.alpha_over(n, mask,(0,0,16,8), mask)
img = n img = n
if blockID in (78,): # snow if blockID in (78,): # snow
# make the top three quarters transparent # make the top three quarters transparent
mask = img.crop((0,12,16,16)) mask = img.crop((0,12,16,16))
n = Image.new(img.mode, img.size, (38,92,255,0)) n = Image.new(img.mode, img.size, (38,92,255,0))
n.paste(mask,(0,12,16,16), mask) composite.alpha_over(n, mask,(0,12,16,16), mask)
img = n img = n
# Size of the cube side before shear # Size of the cube side before shear
@@ -189,7 +190,7 @@ def _build_block(top, side, blockID=None):
top = transform_image(top, blockID) top = transform_image(top, blockID)
if not side: if not side:
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return img return img
side = transform_image_side(side, blockID) side = transform_image_side(side, blockID)
@@ -212,29 +213,29 @@ def _build_block(top, side, blockID=None):
if blockID in (37,38,6,39,40,50,83): ## flowers, sapling, mushrooms, regular torch, reeds if blockID in (37,38,6,39,40,50,83): ## flowers, sapling, mushrooms, regular torch, reeds
# instead of pasting these blocks at the cube edges, place them in the middle: # instead of pasting these blocks at the cube edges, place them in the middle:
# and omit the top # and omit the top
img.paste(side, (6,3), side) composite.alpha_over(img, side, (6,3), side)
img.paste(otherside, (6,3), otherside) composite.alpha_over(img, otherside, (6,3), otherside)
return img return img
if blockID in (81,): # cacti! if blockID in (81,): # cacti!
img.paste(side, (2,6), side) composite.alpha_over(img, side, (2,6), side)
img.paste(otherside, (10,6), otherside) composite.alpha_over(img, otherside, (10,6), otherside)
img.paste(top, (0,2), top) composite.alpha_over(img, top, (0,2), top)
elif blockID in (44,): # half step elif blockID in (44,): # half step
# shift each texture down 6 pixels # shift each texture down 6 pixels
img.paste(side, (0,12), side) composite.alpha_over(img, side, (0,12), side)
img.paste(otherside, (12,12), otherside) composite.alpha_over(img, otherside, (12,12), otherside)
img.paste(top, (0,6), top) composite.alpha_over(img, top, (0,6), top)
elif blockID in (78,): # snow elif blockID in (78,): # snow
# shift each texture down 9 pixels # shift each texture down 9 pixels
img.paste(side, (0,6), side) composite.alpha_over(img, side, (0,6), side)
img.paste(otherside, (12,6), otherside) composite.alpha_over(img, otherside, (12,6), otherside)
img.paste(top, (0,9), top) composite.alpha_over(img, top, (0,9), top)
else: else:
img.paste(side, (0,6), side) composite.alpha_over(img, side, (0,6), side)
img.paste(otherside, (12,6), otherside) composite.alpha_over(img, otherside, (12,6), otherside)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
# Manually touch up 6 pixels that leave a gap because of how the # Manually touch up 6 pixels that leave a gap because of how the
# shearing works out. This makes the blocks perfectly tessellate-able # shearing works out. This makes the blocks perfectly tessellate-able
@@ -366,7 +367,7 @@ def generate_special_texture(blockID, data):
track = transform_image(raw_straight, blockID) track = transform_image(raw_straight, blockID)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(track, (0,12), track) composite.alpha_over(img, track, (0,12), track)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 59: # crops if blockID == 59: # crops
@@ -376,9 +377,9 @@ def generate_special_texture(blockID, data):
crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(crop1, (0,12), crop1) composite.alpha_over(img, crop1, (0,12), crop1)
img.paste(crop2, (6,3), crop2) composite.alpha_over(img, crop2, (6,3), crop2)
img.paste(crop3, (6,3), crop3) composite.alpha_over(img, crop3, (6,3), crop3)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 61: #furnace if blockID == 61: #furnace
@@ -388,9 +389,9 @@ def generate_special_texture(blockID, data):
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(side1, (0,6), side1) composite.alpha_over(img, side1, (0,6), side1)
img.paste(side2, (12,6), side2) composite.alpha_over(img, side2, (12,6), side2)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 62: # lit furnace if blockID == 62: # lit furnace
@@ -400,9 +401,9 @@ def generate_special_texture(blockID, data):
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(side1, (0,6), side1) composite.alpha_over(img, side1, (0,6), side1)
img.paste(side2, (12,6), side2) composite.alpha_over(img, side2, (12,6), side2)
img.paste(top, (0,0), top) composite.alpha_over(img, top, (0,0), top)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID == 65: # ladder if blockID == 65: # ladder
@@ -414,22 +415,22 @@ def generate_special_texture(blockID, data):
# have to render this thing anyway. same for data == 2 # have to render this thing anyway. same for data == 2
tex = transform_image_side(raw_texture) tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 2: if data == 2:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 3: if data == 3:
tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_texture).transpose(Image.FLIP_LEFT_RIGHT)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if data == 4: if data == 4:
tex = transform_image_side(raw_texture) tex = transform_image_side(raw_texture)
img = Image.new("RGBA", (24,24), (38,92,255,0)) img = Image.new("RGBA", (24,24), (38,92,255,0))
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])
if blockID in (64,71): #wooden door, or iron door if blockID in (64,71): #wooden door, or iron door
@@ -450,36 +451,36 @@ def generate_special_texture(blockID, data):
if (data & 0x03) == 0: if (data & 0x03) == 0:
if not swung: if not swung:
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
else: else:
# flip first to set the doornob on the correct side # flip first to set the doornob on the correct side
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
tex = tex.transpose(Image.FLIP_LEFT_RIGHT) tex = tex.transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
if (data & 0x03) == 1: if (data & 0x03) == 1:
if not swung: if not swung:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (0,0), tex) composite.alpha_over(img, tex, (0,0), tex)
else: else:
tex = transform_image_side(raw_door) tex = transform_image_side(raw_door)
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
if (data & 0x03) == 2: if (data & 0x03) == 2:
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
img.paste(tex, (12,0), tex) composite.alpha_over(img, tex, (12,0), tex)
else: else:
tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
if (data & 0x03) == 3: if (data & 0x03) == 3:
if not swung: if not swung:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)).transpose(Image.FLIP_LEFT_RIGHT)
img.paste(tex, (12,6), tex) composite.alpha_over(img, tex, (12,6), tex)
else: else:
tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT)) tex = transform_image_side(raw_door.transpose(Image.FLIP_LEFT_RIGHT))
img.paste(tex, (0,6), tex) composite.alpha_over(img, tex, (0,6), tex)
return (img.convert("RGB"), img.split()[3]) return (img.convert("RGB"), img.split()[3])