package ctbrec.ui.action; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; import java.util.UUID; import java.util.function.Consumer; import javax.imageio.ImageIO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.Model; import ctbrec.StringUtil; import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.FileSelectionBox; import javafx.geometry.Insets; import javafx.scene.Cursor; import javafx.scene.Node; import javafx.scene.control.Label; import javafx.scene.layout.GridPane; public class SetPortraitAction { private static final Logger LOG = LoggerFactory.getLogger(SetPortraitAction.class); public static final String FORMAT = "jpg"; private Node source; private Model model; private Consumer callback; public SetPortraitAction(Node source, Model selectedModel, Consumer callback) { this.source = source; this.model = selectedModel; this.callback = callback; } public void execute() { source.setCursor(Cursor.WAIT); String portraitId = Config.getInstance().getSettings().modelPortraits.getOrDefault(model.getUrl(), UUID.nameUUIDFromBytes(model.getUrl().getBytes(StandardCharsets.UTF_8)).toString()); GridPane pane = new GridPane(); Label l = new Label("Select a portrait image. Leave empty to remove a portrait again."); pane.add(l, 0, 0); FileSelectionBox portraitSelectionBox = new FileSelectionBox(); pane.add(portraitSelectionBox, 0, 1); GridPane.setMargin(l, new Insets(5)); GridPane.setMargin(portraitSelectionBox, new Insets(5)); boolean accepted = Dialogs.showCustomInput(source.getScene(), "Select a portrait image", pane); if (!accepted) { source.setCursor(Cursor.DEFAULT); return; } String selectedFile = portraitSelectionBox.fileProperty().getValue(); if (StringUtil.isBlank(selectedFile)) { removePortrait(portraitId); } else { LOG.debug("User selected {}", selectedFile); boolean success = processImageFile(portraitId, selectedFile); if (success) { Config.getInstance().getSettings().modelPortraits.put(model.getUrl(), portraitId); try { Config.getInstance().save(); runCallback(); } catch (IOException e) { Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e); } } } source.setCursor(Cursor.DEFAULT); } private void removePortrait(String portraitId) { File portraitFile = getPortraitFile(portraitId); try { if (portraitFile.exists()) { Files.delete(portraitFile.toPath()); } Config.getInstance().getSettings().modelPortraits.remove(model.getUrl()); Config.getInstance().save(); runCallback(); } catch (IOException e) { Dialogs.showError("Remove Portrait", "Couldn't remove portrait image: ", e); } } private void runCallback() { if (callback != null) { try { callback.accept(model); } catch (Exception e) { LOG.error("Error while executing callback", e); } } } private boolean processImageFile(String portraitId, String selectedFile) { try { BufferedImage portrait = convertToScaledJpg(selectedFile); boolean success = copyToCacheAsJpg(portraitId, portrait); if (!success) { LOG.debug("Available formats: {}", Arrays.toString(ImageIO.getWriterFormatNames())); throw new IOException("No suitable writer found for image format " + FORMAT); } return success; } catch (IOException e) { LOG.error("Error while changing portrait image", e); Dialogs.showError("Set Portrait", "Couldn't change portrait image: ", e); return false; } } private BufferedImage convertToScaledJpg(String file) throws IOException { BufferedImage portrait = ImageIO.read(new File(file)); Image scaledPortrait = portrait.getScaledInstance(-1, 256, Image.SCALE_SMOOTH); BufferedImage bimage = new BufferedImage(scaledPortrait.getWidth(null), scaledPortrait.getHeight(null), BufferedImage.TYPE_INT_RGB); Graphics2D bGr = bimage.createGraphics(); bGr.drawImage(scaledPortrait, 0, 0, null); bGr.dispose(); return bimage; } private boolean copyToCacheAsJpg(String portraitId, BufferedImage portrait) throws IOException { File output = getPortraitFile(portraitId); Files.createDirectories(output.getParentFile().toPath()); LOG.debug("Writing scaled portrait to {}", output); return ImageIO.write(portrait, FORMAT, output); } private File getPortraitFile(String portraitId) { File configDir = Config.getInstance().getConfigDir(); File portraitDir = new File(configDir, "portraits"); File output = new File(portraitDir, portraitId + '.' + FORMAT); return output; } }