/
githubmirror
/
faceswap
Обзор
Документация
Войти
/
githubmirror
/
faceswap
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
plugins/convert/writer/pillow.py
144 строки
5 KB
torzdf
Extraction Overhaul (#1533)
21 мар 2026, 02:52
Не верифицирован
21 мар 2026, 02:52
d217812
Код
Авторство
О чём код?
#!/usr/bin/env python3 """ Image output writer for faceswap.py converter """ from io import BytesIO from PIL import Image import numpy as np from lib.utils import get_module_objects from ._base import Output, logger from . import pillow_defaults as cfg class Writer(Output): """ Images output writer using Pillow Parameters ---------- output_folder: str The full path to the output folder where the converted media should be saved config_file: str, optional The full path to a custom configuration ini file. If ``None`` is passed then the file is loaded from the default location. Default: ``None``. """ def __init__(self, output_folder: str, **kwargs) -> None: super().__init__(output_folder, **kwargs) self._check_transparency_format() # Correct format namings for writing to byte stream self._format_dict = {"jpg": "JPEG", "jp2": "JPEG 2000", "tif": "TIFF"} self._separate_mask = self.output_alpha and cfg.separate_mask() self._kwargs = self._get_save_kwargs() @property def output_alpha(self) -> bool: """ bool : Pillow can output alpha channel. Returns ``True`` """ return cfg.draw_transparent() def _check_transparency_format(self) -> None: """ Make sure that the output format is correct if draw_transparent is selected """ # pylint:disable=duplicate-code if not self.output_alpha or (self.output_alpha and cfg.format() in ("png", "tif")): return logger.warning("Draw Transparent selected, but the requested format does not support " "transparency. Changing output format to 'png'") cfg.format.set("png") def _get_save_kwargs(self) -> dict[str, bool | int | str]: """ Return the save parameters for the file format Returns ------- dict The specific keyword arguments for the selected file format """ filetype = cfg.format() kwargs: dict[str, bool | int | str] = {} if filetype in ("gif", "jpg", "png"): kwargs["optimize"] = cfg.optimize() if filetype == "gif": kwargs["interlace"] = cfg.gif_interlace() if filetype == "png": kwargs["compress_level"] = cfg.png_compress_level() if filetype == "tif": kwargs["compression"] = cfg.tif_compression() logger.debug(kwargs) return kwargs def write(self, filename: str, image: list[BytesIO]) -> None: """ Write out the pre-encoded image to disk. If separate mask has been selected, write out the encoded mask to a sub-folder in the output directory. Parameters ---------- filename: str The full path to write out the image to. image: list List of :class:`BytesIO` objects of length 1 (containing just the image to write out) or length 2 (containing the image and mask to write out) """ logger.trace("Outputting: (filename: '%s'", filename) # type:ignore filenames = self.get_output_filename(filename, cfg.format(), self._separate_mask) try: for fname, img in zip(filenames, image): with open(fname, "wb") as outfile: outfile.write(img.read()) except Exception as err: # pylint:disable=broad-except logger.error("Failed to save image '%s'. Original Error: %s", filename, err) def pre_encode(self, image: np.ndarray, **kwargs) -> list[BytesIO]: """ Pre_encode the image in lib/convert.py threads as it is a LOT quicker Parameters ---------- image: :class:`numpy.ndarray` A 3 or 4 channel BGR swapped frame Returns ------- list List of :class:`BytesIO` objects ready for writing. The list will be of length 1 with image bytes object as the only member unless separate mask has been requested, in which case it will be length 2 with the image in position 0 and mask in position 1 """ logger.trace("Pre-encoding image") # type:ignore if self._separate_mask: encoded_mask = self._encode_image(image[..., -1]) image = image[..., :3] rgb = [2, 1, 0, 3] if image.shape[2] == 4 else [2, 1, 0] encoded_image = self._encode_image(image[..., rgb]) retval = [encoded_image] if self._separate_mask: retval.append(encoded_mask) return retval def _encode_image(self, image: np.ndarray) -> BytesIO: """ Encode an image in the correct format as a bytes object for saving Parameters ---------- image: :class:`np.ndarray` The single channel mask to encode for saving Returns ------- :class:`BytesIO` The image as a bytes object ready for writing to disk """ fmt = self._format_dict.get(cfg.format(), cfg.format().upper()) encoded = BytesIO() out_image = Image.fromarray(image) out_image.save(encoded, fmt, **self._kwargs) encoded.seek(0) return encoded def close(self) -> None: """ Does nothing as Pillow writer does not need a close method """ return __all__ = get_module_objects(__name__)