          self.thread_stdout()
          self.thread_stderr()
          logger.debug("Executed Faceswap")
  
      def read_stdout(self):
          """ Read stdout from the subprocess. If training, pass the loss
          values to Queue """
          logger.debug("Opening stdout reader")
          while True:
              try:
                  output = self.process.stdout.readline()
              except ValueError as err:
 
</s> remove     from .preview_cv import PreviewCV as Preview  # noqa
 </s> add     from .preview_cv import PreviewCV as Preview </s> remove     from .preview_tk import PreviewTk as Preview  # noqa
 </s> add     from .preview_tk import PreviewTk as Preview </s> remove         size = get_config().user_config_dict.get("icon_size", 16)
        size = int(round(size * get_config().scaling_factor))
        icons: Dict[str, ImageTk.PhotoImage] = {}
        pathicons = os.path.join(PATHCACHE, "icons")
        for fname in os.listdir(pathicons):
            name, ext = os.path.splitext(fname)
            if ext != ".png":
                continue
            img = Image.open(os.path.join(pathicons, fname))
            img = ImageTk.PhotoImage(img.resize((size, size), resample=Image.HAMMING))
            icons[name] = img
        logger.debug(icons)
        return icons
 </s> add         logger.debug("Saving preview to %s", filename)
        assert self._preview_image is not None
        self._preview_image.save(filename) </s> remove     def previewoutput(self) -> Tuple[Image.Image, ImageTk.PhotoImage]:
        """ Tuple: First item in the tuple is the extract or convert preview image
        (:class:`PIL.Image`), the second item is the image in a format that tkinter can display
        (:class:`PIL.ImageTK.PhotoImage`).
 </s> add     def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
    def _process_progress_stdout(self, output: str) -> bool:
        """ Process stdout for any faceswap processes that update the status/progress bar(s)

        Parameters
        ----------
        output: str
            The output line read from stdout

        Returns
        -------
        bool
            ``True`` if all actions have been completed on the output line otherwise ``False``
        """
        if self.command == "train" and self.capture_loss(output):
            return True

        if self.command == "effmpeg" and self.capture_ffmpeg(output):
            return True

        if self.command not in ("train", "effmpeg") and self.capture_tqdm(output):
            return True

        return False

    def _process_training_stdout(self, output: str) -> None:
        """ Process any triggers that are required to update the GUI when Faceswap is running a
        training session.

        Parameters
        ----------
        output: str
            The output line read from stdout
        """
        if self.command != "train" or not self.wrapper.tk_vars.is_training.get():
            return

        if "[saved models]" not in output.strip().lower():
            return

        logger.debug("Trigger GUI Training update")
        logger.trace("tk_vars: %s", {itm: var.get()  # type:ignore
                                     for itm, var in self.wrapper.tk_vars.__dict__.items()})
        if not Session.is_training:
            # Don't initialize session until after the first save as state file must exist first
            logger.debug("Initializing curret training session")
            Session.initialize_session(self._session_info["model_folder"],
                                       self._session_info["model_name"],
                                       is_training=True)
        self.wrapper.tk_vars.refresh_graph.set(True)

    def read_stdout(self) -> None:
        """ Read stdout from the subprocess. """
          self.thread_stdout()
          self.thread_stderr()
          logger.debug("Executed Faceswap")
  
    def _process_progress_stdout(self, output: str) -> bool:
        """ Process stdout for any faceswap processes that update the status/progress bar(s)

        Parameters
        ----------
        output: str
            The output line read from stdout

        Returns
        -------
        bool
            ``True`` if all actions have been completed on the output line otherwise ``False``
        """
        if self.command == "train" and self.capture_loss(output):
            return True

        if self.command == "effmpeg" and self.capture_ffmpeg(output):
            return True

        if self.command not in ("train", "effmpeg") and self.capture_tqdm(output):
            return True

        return False

    def _process_training_stdout(self, output: str) -> None:
        """ Process any triggers that are required to update the GUI when Faceswap is running a
        training session.

        Parameters
        ----------
        output: str
            The output line read from stdout
        """
        if self.command != "train" or not self.wrapper.tk_vars.is_training.get():
            return

        if "[saved models]" not in output.strip().lower():
            return

        logger.debug("Trigger GUI Training update")
        logger.trace("tk_vars: %s", {itm: var.get()  # type:ignore
                                     for itm, var in self.wrapper.tk_vars.__dict__.items()})
        if not Session.is_training:
            # Don't initialize session until after the first save as state file must exist first
            logger.debug("Initializing curret training session")
            Session.initialize_session(self._session_info["model_folder"],
                                       self._session_info["model_name"],
                                       is_training=True)
        self.wrapper.tk_vars.refresh_graph.set(True)

    def read_stdout(self) -> None:
        """ Read stdout from the subprocess. """
    def _process_progress_stdout(self, output: str) -> bool:
        """ Process stdout for any faceswap processes that update the status/progress bar(s)

        Parameters
        ----------
        output: str
            The output line read from stdout

        Returns
        -------
        bool
            ``True`` if all actions have been completed on the output line otherwise ``False``
        """
        if self.command == "train" and self.capture_loss(output):
            return True

        if self.command == "effmpeg" and self.capture_ffmpeg(output):
            return True

        if self.command not in ("train", "effmpeg") and self.capture_tqdm(output):
            return True

        return False

    def _process_training_stdout(self, output: str) -> None:
        """ Process any triggers that are required to update the GUI when Faceswap is running a
        training session.

        Parameters
        ----------
        output: str
            The output line read from stdout
        """
        if self.command != "train" or not self.wrapper.tk_vars.is_training.get():
            return

        if "[saved models]" not in output.strip().lower():
            return

        logger.debug("Trigger GUI Training update")
        logger.trace("tk_vars: %s", {itm: var.get()  # type:ignore
                                     for itm, var in self.wrapper.tk_vars.__dict__.items()})
        if not Session.is_training:
            # Don't initialize session until after the first save as state file must exist first
            logger.debug("Initializing curret training session")
            Session.initialize_session(self._session_info["model_folder"],
                                       self._session_info["model_name"],
                                       is_training=True)
        self.wrapper.tk_vars.refresh_graph.set(True)

    def read_stdout(self) -> None:
        """ Read stdout from the subprocess. """
    def _process_progress_stdout(self, output: str) -> bool:
        """ Process stdout for any faceswap processes that update the status/progress bar(s)

        Parameters
        ----------
        output: str
            The output line read from stdout

        Returns
        -------
        bool
            ``True`` if all actions have been completed on the output line otherwise ``False``
        """
        if self.command == "train" and self.capture_loss(output):
            return True

        if self.command == "effmpeg" and self.capture_ffmpeg(output):
            return True

        if self.command not in ("train", "effmpeg") and self.capture_tqdm(output):
            return True

        return False

    def _process_training_stdout(self, output: str) -> None:
        """ Process any triggers that are required to update the GUI when Faceswap is running a
        training session.

        Parameters
        ----------
        output: str
            The output line read from stdout
        """
        if self.command != "train" or not self.wrapper.tk_vars.is_training.get():
            return

        if "[saved models]" not in output.strip().lower():
            return

        logger.debug("Trigger GUI Training update")
        logger.trace("tk_vars: %s", {itm: var.get()  # type:ignore
                                     for itm, var in self.wrapper.tk_vars.__dict__.items()})
        if not Session.is_training:
            # Don't initialize session until after the first save as state file must exist first
            logger.debug("Initializing curret training session")
            Session.initialize_session(self._session_info["model_folder"],
                                       self._session_info["model_name"],
                                       is_training=True)
        self.wrapper.tk_vars.refresh_graph.set(True)

    def read_stdout(self) -> None:
        """ Read stdout from the subprocess. """
          logger.debug("Opening stdout reader")
          while True:
              try:
                  output = self.process.stdout.readline()
              except ValueError as err:
keep keep keep keep replace replace replace keep keep keep keep keep
 GUI - Preview updates
  - Training preview. Embed preview pop-out window
  - Bugfix - convert/extract previews 
lib/gui/wrapper.py