<commit_before>"""Data structures to hold collections of images, with optional caching."""

from __future__ import with_statement

import os
from glob import glob
import re
from copy import copy

import numpy as np
import six
from PIL import Image

from skimage.external.tifffile import TiffFile


__all__ = ['MultiImage', 'ImageCollection', 'concatenate_images',
           'imread_collection_wrapper']


def concatenate_images(ic):
    """Concatenate all images in the image collection into an array.

    Parameters
    ----------
    ic: an iterable of images (including ImageCollection and MultiImage)
        The images to be concatenated.

    Returns
    -------
    ar : np.ndarray
        An array having one more dimension than the images in `ic`.

    See Also
    --------
    ImageCollection.concatenate, MultiImage.concatenate

    Raises
    ------
    ValueError
        If images in `ic` don't have identical shapes.
    """
    all_images = [img[np.newaxis, ...] for img in ic]
    try:
        ar = np.concatenate(all_images)
    except ValueError:
        raise ValueError('Image dimensions must agree.')
    return ar


def alphanumeric_key(s):
    """Convert string to list of strings and ints that gives intuitive sorting.

    Parameters
    ----------
    s: string

    Returns
    -------
    k: a list of strings and ints

    Examples
    --------
    >>> alphanumeric_key('z23a')
    ['z', 23, 'a']
    >>> filenames = ['f9.10.png', 'e10.png', 'f9.9.png', 'f10.10.png',
    ...              'f10.9.png']
    >>> sorted(filenames)
    ['e10.png', 'f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png']
    >>> sorted(filenames, key=alphanumeric_key)
    ['e10.png', 'f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png']
    """
    k = [int(c) if c.isdigit() else c for c in re.split('([0-9]+)', s)]
    return k


class MultiImage(object):
    """A class containing a single multi-frame image.

    Parameters
    ----------
    filename : str
        The complete path to the image file.
    conserve_memory : bool, optional
        Whether to conserve memory by only caching a single frame. Default is
        True.

    Notes
    -----
    If ``conserve_memory=True`` the memory footprint can be reduced, however
    the performance can be affected because frames have to be read from file
    more often.

    The last accessed frame is cached, all other frames will have to be read
    from file.

    The current implementation makes use of PIL.

    Examples
    --------
    >>> from skimage import data_dir

    >>> img = MultiImage(data_dir + '/multipage.tif') # doctest: +SKIP
    >>> len(img) # doctest: +SKIP
    2
    >>> for frame in img: # doctest: +SKIP
    ...     print(frame.shape) # doctest: +SKIP
    (15, 10)
    (15, 10)

    """
    def __init__(self, filename, conserve_memory=True, dtype=None):
        """Load a multi-img."""
        self._filename = filename
        self._conserve_memory = conserve_memory
        self._dtype = dtype
        self._cached = None


        if filename.lower().endswith(('.tiff', '.tif')):
            self.tif_img = img = TiffFile(self._filename)

        else:
            img = Image.open(self._filename)
            self.tif_img = None

        if self._conserve_memory:
            self._numframes = self._find_numframes(img)

        else:
            self._frames = self._getallframes(img)
            self._numframes = len(self._frames)

        img.close()

    @property
    def filename(self):
        return self._filename

    @property
    def conserve_memory(self):
        return self._conserve_memory

    def _find_numframes(self, img):
        """Find the number of frames in the multi-img."""
        if self.tif_img:
            return len(img.pages)

        else:
            i = 0
            while True:
                i += 1
                try:
                    img.seek(i)
                except EOFError:
                    break
            return i

    def _getframe(self, framenum):
        """Open the image and extract the frame."""
        if self.tif_img:
            return self.tif_img[framenum].asarray()

        else:
            img = Image.open(self.filename)
            for i in range(framenum + 1):
                img.seek(i)
            ret = np.asarray(img, dtype=self._dtype)
            img.close()
            return ret<commit_msg>Add a comment about reading in order<commit_after>"""Data structures to hold collections of images, with optional caching."""

from __future__ import with_statement

import os
from glob import glob
import re
from copy import copy

import numpy as np
import six
from PIL import Image

from skimage.external.tifffile import TiffFile


__all__ = ['MultiImage', 'ImageCollection', 'concatenate_images',
           'imread_collection_wrapper']


def concatenate_images(ic):
    """Concatenate all images in the image collection into an array.

    Parameters
    ----------
    ic: an iterable of images (including ImageCollection and MultiImage)
        The images to be concatenated.

    Returns
    -------
    ar : np.ndarray
        An array having one more dimension than the images in `ic`.

    See Also
    --------
    ImageCollection.concatenate, MultiImage.concatenate

    Raises
    ------
    ValueError
        If images in `ic` don't have identical shapes.
    """
    all_images = [img[np.newaxis, ...] for img in ic]
    try:
        ar = np.concatenate(all_images)
    except ValueError:
        raise ValueError('Image dimensions must agree.')
    return ar


def alphanumeric_key(s):
    """Convert string to list of strings and ints that gives intuitive sorting.

    Parameters
    ----------
    s: string

    Returns
    -------
    k: a list of strings and ints

    Examples
    --------
    >>> alphanumeric_key('z23a')
    ['z', 23, 'a']
    >>> filenames = ['f9.10.png', 'e10.png', 'f9.9.png', 'f10.10.png',
    ...              'f10.9.png']
    >>> sorted(filenames)
    ['e10.png', 'f10.10.png', 'f10.9.png', 'f9.10.png', 'f9.9.png']
    >>> sorted(filenames, key=alphanumeric_key)
    ['e10.png', 'f9.9.png', 'f9.10.png', 'f10.9.png', 'f10.10.png']
    """
    k = [int(c) if c.isdigit() else c for c in re.split('([0-9]+)', s)]
    return k


class MultiImage(object):
    """A class containing a single multi-frame image.

    Parameters
    ----------
    filename : str
        The complete path to the image file.
    conserve_memory : bool, optional
        Whether to conserve memory by only caching a single frame. Default is
        True.

    Notes
    -----
    If ``conserve_memory=True`` the memory footprint can be reduced, however
    the performance can be affected because frames have to be read from file
    more often.

    The last accessed frame is cached, all other frames will have to be read
    from file.

    The current implementation makes use of PIL.

    Examples
    --------
    >>> from skimage import data_dir

    >>> img = MultiImage(data_dir + '/multipage.tif') # doctest: +SKIP
    >>> len(img) # doctest: +SKIP
    2
    >>> for frame in img: # doctest: +SKIP
    ...     print(frame.shape) # doctest: +SKIP
    (15, 10)
    (15, 10)

    """
    def __init__(self, filename, conserve_memory=True, dtype=None):
        """Load a multi-img."""
        self._filename = filename
        self._conserve_memory = conserve_memory
        self._dtype = dtype
        self._cached = None


        if filename.lower().endswith(('.tiff', '.tif')):
            self.tif_img = img = TiffFile(self._filename)

        else:
            img = Image.open(self._filename)
            self.tif_img = None

        if self._conserve_memory:
            self._numframes = self._find_numframes(img)

        else:
            self._frames = self._getallframes(img)
            self._numframes = len(self._frames)

        img.close()

    @property
    def filename(self):
        return self._filename

    @property
    def conserve_memory(self):
        return self._conserve_memory

    def _find_numframes(self, img):
        """Find the number of frames in the multi-img."""
        if self.tif_img:
            return len(img.pages)

        else:
            i = 0
            while True:
                i += 1
                try:
                    img.seek(i)
                except EOFError:
                    break
            return i

    def _getframe(self, framenum):
        """Open the image and extract the frame."""
        if self.tif_img:
            return self.tif_img[framenum].asarray()

        else:
            img = Image.open(self.filename)
            # GIFs must be read *in order*
            for i in range(framenum + 1):
                img.seek(i)
            ret = np.asarray(img, dtype=self._dtype)
            img.close()
            return ret
{'fraction_non_alphanumeric': 0.11870748299319728, 'fraction_numerical': 0.013605442176870748, 'mean_word_length': 1.9600671140939598, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 51, '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': '629032', 'n_tokens_mistral': 2734, 'n_tokens_neox': 2583, 'n_words': 801}