123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- import io
- import logging
- from PIL import Image, ImageEnhance, ExifTags
-
- try:
- from config import APP_NAME as ROOT_LOGGER_NAME
- except ImportError:
- ROOT_LOGGER_NAME = 'root'
- logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)
-
-
- ORIENTATION_NORMAL = 1
- ORIENTATION_VERTICAL_MIRRORED = 2
- ORIENTATION_HALF_ROTATED = 3
- ORIENTATION_HORIZONTAL_MIRRORED = 4
- ORIENTATION_LEFT_ROTATED = 6
- ORIENTATION_RIGHT_ROTATED = 8
-
- JOIN_TOP_LEFT = 1
- JOIN_TOP_RIGHT = 2
- JOIN_BOT_LEFT = 3
- JOIN_BOT_RIGHT = 4
- JOIN_CENTER = 5
-
-
- class image(object):
- def __init__(self, media_instance=None):
- if media_instance is not None:
- self.load_from_file(media_instance)
- else:
- self._im = None
-
- def load_from_file(self, media_instance):
- from media.convert import get_pil_image
- #
- self._im = get_pil_image(media_instance)
- if self._im is None:
- return False
- try:
- self._exif = dict(self._im._getexif().items())
- except AttributeError:
- self._exif = {}
- if type(self._im) is not Image.Image:
- self._im = self._im.copy()
- logger.debug('loading image from %s', repr(media_instance))
- return True
-
- def save(self, full_path):
- if self._im is None:
- logger.warning('No image available to be saved (%s)', repr(full_path))
- return False
- else:
- logger.debug('Saving image to %s', repr(full_path))
- with open(full_path, 'w') as fh:
- im = self._im.convert('RGB')
- im.save(fh, 'JPEG')
- return True
-
- def image_data(self):
- im = self._im.copy().convert('RGB')
- output = io.BytesIO()
- im.save(output, format='JPEG')
- return output.getvalue()
-
- def resize(self, max_size):
- if self._im is None:
- logger.warning('No image available to be resized')
- return False
- else:
- logger.debug('Resizing picture to max %d pixel in whatever direction', max_size)
- x, y = self._im.size
- xy_max = max(x, y)
- self._im = self._im.resize((int(x * float(max_size) / xy_max), int(y * float(max_size) / xy_max)), Image.NEAREST).rotate(0)
- return True
-
- def rotate_by_orientation(self, orientation=None):
- if self._im is None:
- logger.warning('No image available, rotation not possible')
- return False
-
- if orientation is None:
- exif_tags = dict((v, k) for k, v in ExifTags.TAGS.items())
- try:
- orientation = self._exif[exif_tags['Orientation']]
- logger.debug("No orientation given, orientation %s extract from exif data", repr(orientation))
- except KeyError:
- return False
-
- if orientation == ORIENTATION_HALF_ROTATED:
- angle = 180
- elif orientation == ORIENTATION_LEFT_ROTATED:
- angle = 270
- elif orientation == ORIENTATION_RIGHT_ROTATED:
- angle = 90
- else:
- if type(orientation) == int and orientation > 8:
- logger.warning('Orientation %s unknown for rotation', repr(orientation))
- return False
- logger.debug('Rotating picture by %d (deg)', angle)
- self._im = self._im.rotate(angle, expand=True)
- return True
-
- def join(self, join_image, join_pos=JOIN_TOP_RIGHT, opacity=0.7):
- from media.convert import get_pil_image
-
- def rgba_copy(im):
- if im.mode != 'RGBA':
- return im.convert('RGBA')
- else:
- return im.copy()
-
- if self._im is None:
- logger.warning('No image available, joining not possible')
- return False
-
- # ensure type of join_image is PIL.Image
- join_image = get_pil_image(join_image)
- if join_image is None:
- logger.warning('Image to be joined is not supported %s', repr(join_image))
- return False
-
- im2 = rgba_copy(join_image)
- # change opacity of im2
- alpha = im2.split()[3]
- alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
- im2.putalpha(alpha)
-
- self._im = rgba_copy(self._im)
-
- # create a transparent layer
- layer = Image.new('RGBA', self._im.size, (0, 0, 0, 0))
- # draw im2 in layer
- if join_pos == JOIN_TOP_LEFT:
- layer.paste(im2, (0, 0))
- elif join_pos == JOIN_TOP_RIGHT:
- layer.paste(im2, ((self._im.size[0] - im2.size[0]), 0))
- elif join_pos == JOIN_BOT_LEFT:
- layer.paste(im2, (0, (self._im.size[1] - im2.size[1])))
- elif join_pos == JOIN_BOT_RIGHT:
- layer.paste(im2, ((self._im.size[0] - im2.size[0]), (self._im.size[1] - im2.size[1])))
- elif join_pos == JOIN_CENTER:
- layer.paste(im2, (int((self._im.size[0] - im2.size[0]) / 2), int((self._im.size[1] - im2.size[1]) / 2)))
- else:
- logger.warning("Join position value %s is not supported", join_pos)
- return False
-
- logger.debug('Joining two images')
- self._im = Image.composite(layer, self._im, layer)
-
- return True
|