<commit_before>"""
PSD Image module.
"""
from __future__ import absolute_import, unicode_literals
import logging

from psd_tools.constants import (
    Clipping, Compression, ColorMode, SectionDivider, Resource, Tag
)
from psd_tools.psd import PSD, FileHeader, ImageData, ImageResources
from psd_tools.api.layers import (
    Artboard, Group, PixelLayer, ShapeLayer, SmartObjectLayer, TypeLayer,
    GroupMixin
)
from psd_tools.api import adjustments
from psd_tools.api import pil_io
from psd_tools.api import deprecated

logger = logging.getLogger(__name__)


class PSDImage(GroupMixin):
    """
    Photoshop PSD/PSB file object.

    The low-level data structure is accessible at :py:attr:`PSDImage._record`.

    Example::

        from psd_tools import PSDImage

        psd = PSDImage.open('example.psd')
        image = psd.compose()

        for layer in psd:
            layer_image = layer.compose()
    """

    def __init__(self, data):
        assert isinstance(data, PSD)
        self._record = None
        self._record = data
        self._layers = []
        self._tagged_blocks = None
        self._init()

    @classmethod
    def new(cls, mode, size, color=0, depth=8, **kwargs):
        """
        Create a new PSD document.

        :param mode: The color mode to use for the new image.
        :param size: A tuple containing (width, height) in pixels.
        :param color: What color to use for the image. Default is black.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        header = cls._make_header(mode, size, depth)
        image_data = ImageData.new(header, color=color, **kwargs)
        # TODO: Add default metadata.
        return cls(
            PSD(
                header=header,
                image_data=image_data,
                image_resources=ImageResources.new(),
            )
        )

    @classmethod
    def frompil(cls, image, compression=Compression.PACK_BITS):
        """
        Create a new PSD document from PIL Image.

        :param image: PIL Image object.
        :param compression: ImageData compression option. See
            :py:class:`~psd_tools.constants.Compression`.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        header = cls._make_header(image.mode, image.size)
        # TODO: Add default metadata.
        # TODO: Perhaps make this smart object.
        image_data = ImageData(compression=compression)
        image_data.set_data([channel.tobytes() for channel in image.split()],
                            header)
        return cls(
            PSD(
                header=header,
                image_data=image_data,
                image_resources=ImageResources.new(),
            )
        )

    @classmethod
    def open(cls, fp):
        """
        Open a PSD document.

        :param fp: filename or file-like object.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        if hasattr(fp, 'read'):
            self = cls(PSD.read(fp))
        else:
            with open(fp, 'rb') as f:
                self = cls(PSD.read(f))
        return self

    def save(self, fp, mode='wb'):
        """
        Save the PSD file.

        :param fp: filename or file-like object.
        :param mode: file open mode, default 'wb'.
        """
        if hasattr(fp, 'write'):
            self._record.write(fp)
        else:
            with open(fp, mode) as f:
                self._record.write(f)

    def topil(self, channel=None, **kwargs):
        """<commit_msg>add kwargs to open and save methods<commit_after>"""
PSD Image module.
"""
from __future__ import absolute_import, unicode_literals
import logging

from psd_tools.constants import (
    Clipping, Compression, ColorMode, SectionDivider, Resource, Tag
)
from psd_tools.psd import PSD, FileHeader, ImageData, ImageResources
from psd_tools.api.layers import (
    Artboard, Group, PixelLayer, ShapeLayer, SmartObjectLayer, TypeLayer,
    GroupMixin
)
from psd_tools.api import adjustments
from psd_tools.api import pil_io
from psd_tools.api import deprecated

logger = logging.getLogger(__name__)


class PSDImage(GroupMixin):
    """
    Photoshop PSD/PSB file object.

    The low-level data structure is accessible at :py:attr:`PSDImage._record`.

    Example::

        from psd_tools import PSDImage

        psd = PSDImage.open('example.psd')
        image = psd.compose()

        for layer in psd:
            layer_image = layer.compose()
    """

    def __init__(self, data):
        assert isinstance(data, PSD)
        self._record = None
        self._record = data
        self._layers = []
        self._tagged_blocks = None
        self._init()

    @classmethod
    def new(cls, mode, size, color=0, depth=8, **kwargs):
        """
        Create a new PSD document.

        :param mode: The color mode to use for the new image.
        :param size: A tuple containing (width, height) in pixels.
        :param color: What color to use for the image. Default is black.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        header = cls._make_header(mode, size, depth)
        image_data = ImageData.new(header, color=color, **kwargs)
        # TODO: Add default metadata.
        return cls(
            PSD(
                header=header,
                image_data=image_data,
                image_resources=ImageResources.new(),
            )
        )

    @classmethod
    def frompil(cls, image, compression=Compression.PACK_BITS):
        """
        Create a new PSD document from PIL Image.

        :param image: PIL Image object.
        :param compression: ImageData compression option. See
            :py:class:`~psd_tools.constants.Compression`.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        header = cls._make_header(image.mode, image.size)
        # TODO: Add default metadata.
        # TODO: Perhaps make this smart object.
        image_data = ImageData(compression=compression)
        image_data.set_data([channel.tobytes() for channel in image.split()],
                            header)
        return cls(
            PSD(
                header=header,
                image_data=image_data,
                image_resources=ImageResources.new(),
            )
        )

    @classmethod
    def open(cls, fp, **kwargs):
        """
        Open a PSD document.

        :param fp: filename or file-like object.
        :param encoding: charset encoding of the pascal string within the file,
            default 'macroman'. Some psd files need explicit encoding option.
        :return: A :py:class:`~psd_tools.api.psd_image.PSDImage` object.
        """
        if hasattr(fp, 'read'):
            self = cls(PSD.read(fp, **kwargs))
        else:
            with open(fp, 'rb') as f:
                self = cls(PSD.read(f, **kwargs))
        return self

    def save(self, fp, mode='wb', **kwargs):
        """
        Save the PSD file.

        :param fp: filename or file-like object.
        :param encoding: charset encoding of the pascal string within the file,
            default 'macroman'.
        :param mode: file open mode, default 'wb'.
        """
        if hasattr(fp, 'write'):
            self._record.write(fp, **kwargs)
        else:
            with open(fp, mode) as f:
                self._record.write(f, **kwargs)

    def topil(self, channel=None, **kwargs):
        """
{'fraction_non_alphanumeric': 0.10133155792276964, 'fraction_numerical': 0.0005326231691078562, 'mean_word_length': 2.099876186545605, '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': '4203718', 'n_tokens_mistral': 2214, 'n_tokens_neox': 2148, 'n_words': 617}