Merge pull request #1526 from CounterPillow/webp-support
Add WebP image format support
This commit is contained in:
@@ -694,16 +694,29 @@ Image options
|
|||||||
|
|
||||||
``imgformat``
|
``imgformat``
|
||||||
This is which image format to render the tiles into. Its value should be a
|
This is which image format to render the tiles into. Its value should be a
|
||||||
string containing "png", "jpg", or "jpeg".
|
string containing "png", "jpg", "jpeg" or "webp".
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
For WebP, your PIL/Pillow needs to be built with WebP support. Do
|
||||||
|
keep in mind that not all browsers support WebP images.
|
||||||
|
|
||||||
**Default:** ``"png"``
|
**Default:** ``"png"``
|
||||||
|
|
||||||
``imgquality``
|
``imgquality``
|
||||||
This is the image quality used when saving the tiles into the JPEG image
|
This is the image quality used when saving the tiles into the JPEG or WebP
|
||||||
format. Its value should be an integer between 0 and 100.
|
image format. Its value should be an integer between 0 and 100.
|
||||||
|
|
||||||
|
For WebP images in lossless mode, it determines how much effort is spent
|
||||||
|
on compressing the image.
|
||||||
|
|
||||||
**Default:** ``95``
|
**Default:** ``95``
|
||||||
|
|
||||||
|
``imglossless``
|
||||||
|
Determines whether a WebP image is saved in lossless or lossy mode. Has
|
||||||
|
no effect on other image formats.
|
||||||
|
|
||||||
|
**Default:** ``True``
|
||||||
|
|
||||||
``optimizeimg``
|
``optimizeimg``
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
|
|||||||
@@ -533,7 +533,11 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
|
|
||||||
# only pass to the TileSet the options it really cares about
|
# only pass to the TileSet the options it really cares about
|
||||||
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
|
render['name'] = render_name # perhaps a hack. This is stored here for the asset manager
|
||||||
tileSetOpts = util.dict_subset(render, ["name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "defaultzoom", "imgquality", "optimizeimg", "rendermode", "worldname_orig", "title", "dimension", "changelist", "showspawn", "overlay", "base", "poititle", "maxzoom", "showlocationmarker", "minzoom"])
|
tileSetOpts = util.dict_subset(render, [
|
||||||
|
"name", "imgformat", "renderchecks", "rerenderprob", "bgcolor", "defaultzoom",
|
||||||
|
"imgquality", "imglossless", "optimizeimg", "rendermode", "worldname_orig", "title",
|
||||||
|
"dimension", "changelist", "showspawn", "overlay", "base", "poititle", "maxzoom",
|
||||||
|
"showlocationmarker", "minzoom"])
|
||||||
tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this
|
tileSetOpts.update({"spawn": w.find_true_spawn()}) # TODO find a better way to do this
|
||||||
for rset in rsets:
|
for rset in rsets:
|
||||||
tset = tileset.TileSet(w, rset, assetMrg, tex, tileSetOpts, tileset_dir)
|
tset = tileset.TileSet(w, rset, assetMrg, tex, tileSetOpts, tileset_dir)
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ renders = Setting(required=True, default=util.OrderedDict(),
|
|||||||
"forcerender": Setting(required=False, validator=validateBool, default=None),
|
"forcerender": Setting(required=False, validator=validateBool, default=None),
|
||||||
"imgformat": Setting(required=True, validator=validateImgFormat, default="png"),
|
"imgformat": Setting(required=True, validator=validateImgFormat, default="png"),
|
||||||
"imgquality": Setting(required=False, validator=validateImgQuality, default=95),
|
"imgquality": Setting(required=False, validator=validateImgQuality, default=95),
|
||||||
|
"imglossless": Setting(required=False, validator=validateBool,
|
||||||
|
default=True),
|
||||||
"bgcolor": Setting(required=True, validator=validateBGColor, default="1a1a1a"),
|
"bgcolor": Setting(required=True, validator=validateBGColor, default="1a1a1a"),
|
||||||
"defaultzoom": Setting(required=True, validator=validateDefaultZoom, default=1),
|
"defaultzoom": Setting(required=True, validator=validateDefaultZoom, default=1),
|
||||||
"optimizeimg": Setting(required=True, validator=validateOptImg, default=[]),
|
"optimizeimg": Setting(required=True, validator=validateOptImg, default=[]),
|
||||||
|
|||||||
@@ -115,9 +115,14 @@ def validateRerenderprob(s):
|
|||||||
return val
|
return val
|
||||||
|
|
||||||
def validateImgFormat(fmt):
|
def validateImgFormat(fmt):
|
||||||
if fmt not in ("png", "jpg", "jpeg"):
|
if fmt not in ("png", "jpg", "jpeg", "webp"):
|
||||||
raise ValidationException("%r is not a valid image format" % fmt)
|
raise ValidationException("%r is not a valid image format" % fmt)
|
||||||
if fmt == "jpeg": fmt = "jpg"
|
if fmt == "jpeg": fmt = "jpg"
|
||||||
|
if fmt == "webp":
|
||||||
|
try:
|
||||||
|
from PIL import _webp
|
||||||
|
except ImportError:
|
||||||
|
raise ValidationException("WebP is not supported by your PIL/Pillow installation")
|
||||||
return fmt
|
return fmt
|
||||||
|
|
||||||
def validateImgQuality(qual):
|
def validateImgQuality(qual):
|
||||||
|
|||||||
@@ -261,12 +261,15 @@ class TileSet(object):
|
|||||||
rest of this discussion.
|
rest of this discussion.
|
||||||
|
|
||||||
imgformat
|
imgformat
|
||||||
A string indicating the output format. Must be one of 'png' or
|
A string indicating the output format. Must be one of 'png',
|
||||||
'jpeg'
|
'jpeg' or 'webp'
|
||||||
|
|
||||||
imgquality
|
imgquality
|
||||||
An integer 1-100 indicating the quality of the jpeg output. Only
|
An integer 1-100 indicating the quality of the jpeg output. Only
|
||||||
relevant in jpeg mode.
|
relevant in jpeg and webp mode.
|
||||||
|
|
||||||
|
imglossless
|
||||||
|
A boolean indicating whether to save a webp image in lossless mode.
|
||||||
|
|
||||||
optimizeimg
|
optimizeimg
|
||||||
A list of optimizer instances to use.
|
A list of optimizer instances to use.
|
||||||
@@ -387,8 +390,10 @@ class TileSet(object):
|
|||||||
self.imgextension = 'png'
|
self.imgextension = 'png'
|
||||||
elif self.options['imgformat'] in ('jpeg', 'jpg'):
|
elif self.options['imgformat'] in ('jpeg', 'jpg'):
|
||||||
self.imgextension = 'jpg'
|
self.imgextension = 'jpg'
|
||||||
|
elif self.options['imgformat'] == 'webp':
|
||||||
|
self.imgextension = 'webp'
|
||||||
else:
|
else:
|
||||||
raise ValueError("imgformat must be one of: 'png' or 'jpg'")
|
raise ValueError("imgformat must be one of: 'png', 'jpg' or 'webp'")
|
||||||
|
|
||||||
# This sets self.treedepth, self.xradius, and self.yradius
|
# This sets self.treedepth, self.xradius, and self.yradius
|
||||||
self._set_map_size()
|
self._set_map_size()
|
||||||
@@ -1000,8 +1005,11 @@ class TileSet(object):
|
|||||||
if imgformat == 'jpg':
|
if imgformat == 'jpg':
|
||||||
img.convert('RGB').save(tmppath, "jpeg", quality=self.options['imgquality'],
|
img.convert('RGB').save(tmppath, "jpeg", quality=self.options['imgquality'],
|
||||||
subsampling=0)
|
subsampling=0)
|
||||||
else: # PNG
|
elif imgformat == 'png': # PNG
|
||||||
img.save(tmppath, "png")
|
img.save(tmppath, "png")
|
||||||
|
elif imgformat == 'webp':
|
||||||
|
img.save(tmppath, "webp", quality=self.options['imgquality'],
|
||||||
|
lossless=self.options['imglossless'])
|
||||||
|
|
||||||
if self.options['optimizeimg']:
|
if self.options['optimizeimg']:
|
||||||
optimize_image(tmppath, imgformat, self.options['optimizeimg'])
|
optimize_image(tmppath, imgformat, self.options['optimizeimg'])
|
||||||
@@ -1101,8 +1109,11 @@ class TileSet(object):
|
|||||||
if self.imgextension == 'jpg':
|
if self.imgextension == 'jpg':
|
||||||
tileimg.convert('RGB').save(tmppath, "jpeg", quality=self.options['imgquality'],
|
tileimg.convert('RGB').save(tmppath, "jpeg", quality=self.options['imgquality'],
|
||||||
subsampling=0)
|
subsampling=0)
|
||||||
else: # PNG
|
elif self.imgextension == 'png': # PNG
|
||||||
tileimg.save(tmppath, "png")
|
tileimg.save(tmppath, "png")
|
||||||
|
elif self.imgextension == 'webp':
|
||||||
|
tileimg.save(tmppath, "webp", quality=self.options['imgquality'],
|
||||||
|
lossless=self.options['imglossless'])
|
||||||
if self.options['optimizeimg']:
|
if self.options['optimizeimg']:
|
||||||
optimize_image(tmppath, self.imgextension, self.options['optimizeimg'])
|
optimize_image(tmppath, self.imgextension, self.options['optimizeimg'])
|
||||||
os.utime(tmppath, (max_chunk_mtime, max_chunk_mtime))
|
os.utime(tmppath, (max_chunk_mtime, max_chunk_mtime))
|
||||||
|
|||||||
Reference in New Issue
Block a user