<commit_before># encoding: utf-8

"""
ImagePart and related objects.
"""

import hashlib
import os
import posixpath

try:
    from PIL import Image as PIL_Image
except ImportError:
    import Image as PIL_Image

from StringIO import StringIO

from pptx.opc.package import Part
from pptx.opc.packuri import PackURI
from pptx.opc.spec import image_content_types
from pptx.parts.part import PartCollection
from pptx.util import lazyproperty, Px


class ImagePart(Part):
    """
    An image part, generally having a partname matching the regex
    ``ppt/media/image[1-9][0-9]*.*``.
    """
    def __init__(self, partname, content_type, blob, ext, filepath=None):
        super(ImagePart, self).__init__(partname, content_type, blob)
        self._ext = ext
        self._filepath = filepath

    @classmethod
    def new(cls, partname, image_file):
        """
        Return a new |ImagePart| instance loaded from *img_file*, which may
        be a path to a file (a string), or a file-like object. *partname* is
        assigned to the new image part.
        """
        filepath, ext, content_type, blob = cls._load_from_file(image_file)
        return cls(partname, content_type, blob, ext, filepath)

    @property
    def ext(self):
        """
        Return file extension for this image e.g. ``'png'``.
        """
        return self._ext

    @classmethod
    def load(cls, partname, content_type, blob, package):
        ext = posixpath.splitext(partname)[1]
        return cls(partname, content_type, blob, ext)

    def scale(self, width, height):
        """
        Return scaled image dimensions based on supplied parameters. If
        *width* and *height* are both |None|, the native image size is
        returned. If neither *width* nor *height* is |None|, their values are
        returned unchanged. If a value is provided for either *width* or
        *height* and the other is |None|, the dimensions are scaled,
        preserving the image's aspect ratio.
        """
        native_width_px, native_height_px = self._size
        native_width = Px(native_width_px)
        native_height = Px(native_height_px)

        if width is None and height is None:
            width = native_width
            height = native_height
        elif width is None:
            scaling_factor = float(height) / float(native_height)
            width = int(round(native_width * scaling_factor))
        elif height is None:
            scaling_factor = float(width) / float(native_width)
            height = int(round(native_height * scaling_factor))
        return width, height

    @lazyproperty
    def sha1(self):
        """
        The SHA1 hash digest for the image binary of this image part, like:
        ``'1be010ea47803b00e140b852765cdf84f491da47'``.
        """
        return hashlib.sha1(self._blob).hexdigest()

    @property
    def _desc(self):
        """
        Return filename associated with this image, either the filename of
        the original image file the image was created with or a synthetic
        name of the form ``image.ext`` where ``ext`` is appropriate to the
        image file format, e.g. ``'jpg'``.
        """
        if self._filepath is not None:
            return os.path.split(self._filepath)[1]
        # return generic filename if original filename is unknown
        return 'image.%s' % self.ext

    @staticmethod
    def _ext_from_image_stream(stream):
        """
        Return the filename extension appropriate to the image file contained
        in *stream*.
        """
        ext_map = {
            'BMP': 'bmp', 'GIF': 'gif', 'JPEG': 'jpg', 'PNG': 'png',
            'TIFF': 'tiff', 'WMF': 'wmf'
        }
        stream.seek(0)
        format = PIL_Image.open(stream).format
        if format not in ext_map:
            tmpl = "unsupported image format, expected one of: %s, got '%s'"
            raise ValueError(tmpl % (ext_map.keys(), format))
        return ext_map[format]

    @staticmethod
    def _image_ext_content_type(ext):
        """
        Return the content type corresponding to filename extension *ext*
        """
        key = ext.lower()
        if key not in image_content_types:
            tmpl = "unsupported image file extension '%s'"
            raise ValueError(tmpl % (ext))
        content_type = image_content_types[key]
        return content_type

    @classmethod
    def _load_from_file(cls, image_file):
        """
        Return a (path, ext, content_type, blob) 4-tuple for the image
        located in *image_file*, which may be either a path to an image file
        or a file-like object.
        """
        if isinstance(image_file, basestring):  # image_file is a path
            filepath = image_file
            ext = os.path.splitext(filepath)[1][1:]
            content_type = cls._image_ext_content_type(ext)
            with open(filepath, 'rb') as f:
                blob = f.read()
        else:  # assume image_file is a file-like object
            filepath = None
            ext = cls._ext_from_image_stream(image_file)
            content_type = cls._image_ext_content_type(ext)
            image_file.seek(0)
            blob = image_file.read()
        return filepath, ext, content_type, blob

    @property
    def _size(self):
        """
        Return *width*, *height* tuple representing native dimensions of
        image in pixels.
        """
        image_stream = StringIO(self._blob)
        width_px, height_px = PIL_Image.open(image_stream).size
        image_stream.close()
        return width_px, height_px


class ImageCollection(PartCollection):
    """
    Immutable sequence of images, typically belonging to an instance of
    |Package|. An image part containing a particular image blob appears only
    once in an instance, regardless of how many times it is referenced by a<commit_msg>img: trim file path state var down to filename<commit_after># encoding: utf-8

"""
ImagePart and related objects.
"""

import hashlib
import os
import posixpath

try:
    from PIL import Image as PIL_Image
except ImportError:
    import Image as PIL_Image

from StringIO import StringIO

from pptx.opc.package import Part
from pptx.opc.packuri import PackURI
from pptx.opc.spec import image_content_types
from pptx.parts.part import PartCollection
from pptx.util import lazyproperty, Px


class ImagePart(Part):
    """
    An image part, generally having a partname matching the regex
    ``ppt/media/image[1-9][0-9]*.*``.
    """
    def __init__(self, partname, content_type, blob, ext, filename=None):
        super(ImagePart, self).__init__(partname, content_type, blob)
        self._ext = ext
        self._filename = filename

    @classmethod
    def new(cls, partname, image_file):
        """
        Return a new |ImagePart| instance loaded from *img_file*, which may
        be a path to a file (a string), or a file-like object. *partname* is
        assigned to the new image part.
        """
        filename, ext, content_type, blob = cls._load_from_file(image_file)
        return cls(partname, content_type, blob, ext, filename)

    @property
    def ext(self):
        """
        Return file extension for this image e.g. ``'png'``.
        """
        return self._ext

    @classmethod
    def load(cls, partname, content_type, blob, package):
        ext = posixpath.splitext(partname)[1]
        return cls(partname, content_type, blob, ext)

    def scale(self, width, height):
        """
        Return scaled image dimensions based on supplied parameters. If
        *width* and *height* are both |None|, the native image size is
        returned. If neither *width* nor *height* is |None|, their values are
        returned unchanged. If a value is provided for either *width* or
        *height* and the other is |None|, the dimensions are scaled,
        preserving the image's aspect ratio.
        """
        native_width_px, native_height_px = self._size
        native_width = Px(native_width_px)
        native_height = Px(native_height_px)

        if width is None and height is None:
            width = native_width
            height = native_height
        elif width is None:
            scaling_factor = float(height) / float(native_height)
            width = int(round(native_width * scaling_factor))
        elif height is None:
            scaling_factor = float(width) / float(native_width)
            height = int(round(native_height * scaling_factor))
        return width, height

    @lazyproperty
    def sha1(self):
        """
        The SHA1 hash digest for the image binary of this image part, like:
        ``'1be010ea47803b00e140b852765cdf84f491da47'``.
        """
        return hashlib.sha1(self._blob).hexdigest()

    @property
    def _desc(self):
        """
        Return filename associated with this image, either the filename of
        the original image file the image was created with or a synthetic
        name of the form ``image.ext`` where ``ext`` is appropriate to the
        image file format, e.g. ``'jpg'``.
        """
        # return generic filename if original filename is unknown
        if self._filename is None:
            return 'image.%s' % self.ext
        return self._filename

    @staticmethod
    def _ext_from_image_stream(stream):
        """
        Return the filename extension appropriate to the image file contained
        in *stream*.
        """
        ext_map = {
            'BMP': 'bmp', 'GIF': 'gif', 'JPEG': 'jpg', 'PNG': 'png',
            'TIFF': 'tiff', 'WMF': 'wmf'
        }
        stream.seek(0)
        format = PIL_Image.open(stream).format
        if format not in ext_map:
            tmpl = "unsupported image format, expected one of: %s, got '%s'"
            raise ValueError(tmpl % (ext_map.keys(), format))
        return ext_map[format]

    @staticmethod
    def _image_ext_content_type(ext):
        """
        Return the content type corresponding to filename extension *ext*
        """
        key = ext.lower()
        if key not in image_content_types:
            tmpl = "unsupported image file extension '%s'"
            raise ValueError(tmpl % (ext))
        content_type = image_content_types[key]
        return content_type

    @classmethod
    def _load_from_file(cls, image_file):
        """
        Return a (path, ext, content_type, blob) 4-tuple for the image
        located in *image_file*, which may be either a path to an image file
        or a file-like object.
        """
        if isinstance(image_file, basestring):  # image_file is a path
            path = image_file
            filename = os.path.split(path)[1]
            ext = os.path.splitext(path)[1][1:]
            content_type = cls._image_ext_content_type(ext)
            with open(path, 'rb') as f:
                blob = f.read()
        else:  # assume image_file is a file-like object
            filename = None
            ext = cls._ext_from_image_stream(image_file)
            content_type = cls._image_ext_content_type(ext)
            image_file.seek(0)
            blob = image_file.read()
        return filename, ext, content_type, blob

    @property
    def _size(self):
        """
        Return *width*, *height* tuple representing native dimensions of
        image in pixels.
        """
        image_stream = StringIO(self._blob)
        width_px, height_px = PIL_Image.open(image_stream).size
        image_stream.close()
        return width_px, height_px


class ImageCollection(PartCollection):
    """
    Immutable sequence of images, typically belonging to an instance of
    |Package|. An image part containing a particular image blob appears only
    once in an instance, regardless of how many times it is referenced by a
{'fraction_non_alphanumeric': 0.08960054509837322, 'fraction_numerical': 0.007154416148539307, 'mean_word_length': 2.367364496702036, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4184268', 'n_tokens_mistral': 3374, 'n_tokens_neox': 3317, 'n_words': 1106}