Move to pilkit.
Replace the custom code in the image module by pilkit generators.
This commit is contained in:
@@ -33,7 +33,7 @@ from multiprocessing import Pool
|
||||
from os.path import join
|
||||
from PIL import Image as PILImage
|
||||
|
||||
from .image import Image
|
||||
from .image import generate_image, generate_thumbnail
|
||||
from .settings import get_thumb
|
||||
from .writer import Writer
|
||||
|
||||
@@ -211,7 +211,6 @@ class Gallery(object):
|
||||
for f in img_iterator:
|
||||
filename = os.path.split(f)[1]
|
||||
outname = join(outpath, filename)
|
||||
self.logger.info(filename)
|
||||
|
||||
if os.path.isfile(outname) and not self.force:
|
||||
self.logger.info("%s exists - skipping", filename)
|
||||
@@ -239,25 +238,27 @@ def process_image(filepath, outpath, settings):
|
||||
|
||||
filename = os.path.split(filepath)[1]
|
||||
outname = join(outpath, filename)
|
||||
ext = os.path.splitext(filename)
|
||||
|
||||
img = Image(filepath)
|
||||
if ext in ['.jpg', '.jpeg', '.JPG', '.JPEG']:
|
||||
options = settings['jpg_options']
|
||||
elif ext == '.png':
|
||||
options = {'optimize': True}
|
||||
else:
|
||||
options = {}
|
||||
|
||||
if settings['keep_orig']:
|
||||
img.save(join(outpath, settings['orig_dir'], filename),
|
||||
options=settings['jpg_options'])
|
||||
# TODO
|
||||
# if settings['keep_orig']:
|
||||
# img.save(join(outpath, settings['orig_dir'], filename),
|
||||
# options=settings['jpg_options'])
|
||||
|
||||
img.resize(settings['img_size'])
|
||||
|
||||
if settings['copyright']:
|
||||
img.add_copyright(settings['copyright'])
|
||||
|
||||
img.save(outname, options=settings['jpg_options'])
|
||||
generate_image(filepath, outname, settings['img_size'], None,
|
||||
options=options, copyright_text=settings['copyright'])
|
||||
|
||||
if settings['make_thumbs']:
|
||||
thumb_name = join(outpath, get_thumb(settings, filename))
|
||||
img.thumbnail(thumb_name, settings['thumb_size'],
|
||||
fit=settings['thumb_fit'],
|
||||
quality=settings['jpg_options']['quality'])
|
||||
generate_thumbnail(outname, thumb_name, settings['thumb_size'], None,
|
||||
fit=settings['thumb_fit'], options=options)
|
||||
|
||||
|
||||
def get_metadata(path):
|
||||
@@ -266,8 +267,8 @@ def get_metadata(path):
|
||||
- title
|
||||
- thumbnail image
|
||||
- description
|
||||
"""
|
||||
|
||||
"""
|
||||
descfile = join(path, DESCRIPTION_FILE)
|
||||
|
||||
if not os.path.isfile(descfile):
|
||||
@@ -279,11 +280,10 @@ def get_metadata(path):
|
||||
'thumbnail': ''
|
||||
}
|
||||
else:
|
||||
md = markdown.Markdown(extensions=['meta'])
|
||||
|
||||
with codecs.open(descfile, "r", "utf-8") as f:
|
||||
text = f.read()
|
||||
|
||||
md = markdown.Markdown(extensions=['meta'])
|
||||
html = md.convert(text)
|
||||
|
||||
meta = {
|
||||
|
||||
108
sigal/image.py
108
sigal/image.py
@@ -20,96 +20,60 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import logging
|
||||
import os
|
||||
from PIL import Image as PILImage
|
||||
from PIL import ImageDraw, ImageOps
|
||||
from pilkit.processors import ProcessorPipeline, Transpose, ResizeToFill
|
||||
from pilkit.utils import save_image
|
||||
|
||||
# EXIF specs Orientation constant
|
||||
EXIF_ORIENTATION_TAG = 274
|
||||
|
||||
def generate_image(source, outname, size, format, options=None,
|
||||
autoconvert=True, copyright_text=''):
|
||||
"""Image processor, rotate and resize the image.
|
||||
|
||||
class Image(object):
|
||||
"""Image container
|
||||
|
||||
Prepare images: resize images, and create thumbnails with some options
|
||||
(squared thumbs, ...).
|
||||
|
||||
:param filename: path to an image
|
||||
:param source: path to an image
|
||||
:param options: dict with PIL options (quality, optimize, progressive)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.imgname = os.path.split(filename)[1]
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.img = PILImage.open(filename)
|
||||
logger = logging.getLogger(__name__)
|
||||
img = PILImage.open(source)
|
||||
original_format = img.format
|
||||
|
||||
# Try to read exif metadata. This can fail if:
|
||||
# - the image does not have exif (png files) -> AttributeError
|
||||
# - PIL fail to read exif -> IOError
|
||||
try:
|
||||
exif = self.img._getexif()
|
||||
except (IOError, AttributeError):
|
||||
exif = False
|
||||
# Run the processors
|
||||
processors = [
|
||||
Transpose(), # use exif to rotate the img
|
||||
ResizeToFill(*size)
|
||||
]
|
||||
img = ProcessorPipeline(processors).process(img)
|
||||
|
||||
if exif:
|
||||
# http://www.impulseadventure.com/photo/exif-orientation.html
|
||||
orientation = exif.get(EXIF_ORIENTATION_TAG)
|
||||
rotate_map = {3: 180, 6: -90, 8: 90}
|
||||
rotation = rotate_map.get(orientation)
|
||||
if rotation:
|
||||
self.img = self.img.rotate(rotation)
|
||||
if copyright_text:
|
||||
add_copyright(img, copyright_text)
|
||||
|
||||
def save(self, filename, format='JPEG', options=None, autoconvert=True):
|
||||
"""Save the image.
|
||||
format = format or img.format or original_format or 'JPEG'
|
||||
logger.debug('Save resized image to {0} ({1})'.format(outname, format))
|
||||
save_image(img, outname, format, options=options, autoconvert=autoconvert)
|
||||
|
||||
Pass a dict with PIL options (quality, optimize, progressive).
|
||||
|
||||
"""
|
||||
save_image(self.img, filename, format, options=options,
|
||||
autoconvert=autoconvert)
|
||||
def generate_thumbnail(source, outname, box, format, fit=True, options=None):
|
||||
"Create a thumbnail image"
|
||||
|
||||
def resize(self, size):
|
||||
"""Resize the image.
|
||||
logger = logging.getLogger(__name__)
|
||||
img = PILImage.open(source)
|
||||
original_format = img.format
|
||||
|
||||
- check if the image format is portrait or landscape and adjust `size`.
|
||||
- compute the width and height ratio, and keep the min to resize the
|
||||
image inside the `size` box without distorting it.
|
||||
if fit:
|
||||
img = ImageOps.fit(img, box, PILImage.ANTIALIAS)
|
||||
else:
|
||||
img.thumbnail(box, PILImage.ANTIALIAS)
|
||||
|
||||
:param size: tuple with the (with, height) to resize
|
||||
format = format or img.format or original_format or 'JPEG'
|
||||
logger.debug('Save thumnail image to {0} ({1})'.format(outname, format))
|
||||
save_image(img, outname, format, options=options, autoconvert=True)
|
||||
|
||||
"""
|
||||
|
||||
if self.img.size[0] > self.img.size[1]:
|
||||
newsize = size
|
||||
else:
|
||||
newsize = (size[1], size[0])
|
||||
def add_copyright(img, text):
|
||||
"Add a copyright to the image"
|
||||
|
||||
wratio = newsize[0] / self.img.size[0]
|
||||
hratio = newsize[1] / self.img.size[1]
|
||||
ratio = min(wratio, hratio)
|
||||
newsize = (int(ratio * self.img.size[0]),
|
||||
int(ratio * self.img.size[1]))
|
||||
|
||||
if ratio < 1:
|
||||
self.img = self.img.resize(newsize, PILImage.ANTIALIAS)
|
||||
|
||||
def add_copyright(self, text):
|
||||
"Add a copyright to the image"
|
||||
|
||||
draw = ImageDraw.Draw(self.img)
|
||||
draw.text((5, self.img.size[1] - 15), '\xa9 ' + text)
|
||||
|
||||
def thumbnail(self, filename, box, fit=True, quality=90):
|
||||
"Create a thumbnail image"
|
||||
|
||||
if fit:
|
||||
self.img = ImageOps.fit(self.img, box, PILImage.ANTIALIAS)
|
||||
else:
|
||||
self.img.thumbnail(box, PILImage.ANTIALIAS)
|
||||
|
||||
self.img.save(filename, quality=quality)
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text((5, img.size[1] - 15), '\xa9 ' + text)
|
||||
|
||||
@@ -33,7 +33,7 @@ from distutils.dir_util import copy_tree
|
||||
from jinja2 import Environment, FileSystemLoader, ChoiceLoader, PrefixLoader
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
|
||||
from .image import Image
|
||||
from .image import generate_thumbnail
|
||||
from .settings import get_thumb
|
||||
from .pkgmeta import __url__ as sigal_link
|
||||
|
||||
@@ -147,10 +147,11 @@ class Writer(object):
|
||||
# generate the thumbnail if it is missing (if
|
||||
# settings['make_thumbs'] is False)
|
||||
if not os.path.exists(thumb_path):
|
||||
img = Image(os.path.join(self.output_dir, dpath, alb_thumb))
|
||||
img.thumbnail(thumb_path, self.settings['thumb_size'],
|
||||
fit=self.settings['thumb_fit'],
|
||||
quality=self.settings['jpg_quality'])
|
||||
source = os.path.join(self.output_dir, dpath, alb_thumb)
|
||||
generate_thumbnail(
|
||||
source, thumb_path, self.settings['thumb_size'],
|
||||
fit=self.settings['thumb_fit'],
|
||||
quality=self.settings['jpg_options']['quality'])
|
||||
|
||||
ctx['albums'].append({
|
||||
'url': d + '/' + self.url_ext,
|
||||
|
||||
@@ -1,35 +1,18 @@
|
||||
# -*- coding:utf-8 -*-
|
||||
|
||||
import os
|
||||
from tempfile import mkdtemp
|
||||
from shutil import rmtree
|
||||
|
||||
try:
|
||||
import unittest2 as unittest
|
||||
except ImportError:
|
||||
import unittest # NOQA
|
||||
|
||||
from sigal.image import Image
|
||||
from sigal.image import generate_image, generate_thumbnail
|
||||
|
||||
CURRENT_DIR = os.path.dirname(__file__)
|
||||
TEST_IMAGE = 'exo20101028-b-full.jpg'
|
||||
|
||||
|
||||
class TestImage(unittest.TestCase):
|
||||
def test_image(tmpdir):
|
||||
"Test the Image class."
|
||||
|
||||
def setUp(self):
|
||||
self.temp_path = mkdtemp()
|
||||
self.srcfile = os.path.join(CURRENT_DIR, 'sample', 'dir2', TEST_IMAGE)
|
||||
self.dstfile = os.path.join(self.temp_path, TEST_IMAGE)
|
||||
self.img = Image(self.srcfile)
|
||||
srcfile = os.path.join(CURRENT_DIR, 'sample', 'dir2', TEST_IMAGE)
|
||||
dstfile = str(tmpdir.join(TEST_IMAGE))
|
||||
|
||||
def tearDown(self):
|
||||
rmtree(self.temp_path)
|
||||
|
||||
def test_imgname(self):
|
||||
self.assertEqual(self.img.imgname, TEST_IMAGE)
|
||||
|
||||
def test_save(self):
|
||||
self.img.save(self.dstfile)
|
||||
self.assertTrue(os.path.isfile(self.dstfile))
|
||||
generate_thumbnail(srcfile, dstfile, (200, 150))
|
||||
assert os.path.isfile(dstfile)
|
||||
|
||||
Reference in New Issue
Block a user