Added logging, improved image conversion wizard UX

This commit is contained in:
badvision 2017-07-05 20:19:59 -05:00
parent db83c0aa86
commit 64a0a56d9e
5 changed files with 162 additions and 69 deletions

View File

@ -77,7 +77,7 @@ public abstract class Palette {
}
public static double distance(int c1[], int c2[]) {
double rmean = ( c1[0] + c2[1] ) / 2.0;
double rmean = ( c1[0] + c2[0] ) / 2.0;
double r = c1[0] - c2[0];
double g = c1[1] - c2[1];
double b = c1[2] - c2[2];

View File

@ -10,18 +10,25 @@
package org.badvision.outlaweditor.data;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@ -36,15 +43,108 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.badvision.outlaweditor.api.ApplicationState;
import org.badvision.outlaweditor.data.xml.Block;
import org.badvision.outlaweditor.data.xml.Field;
import org.badvision.outlaweditor.data.xml.GameData;
import org.badvision.outlaweditor.data.xml.Global;
import org.badvision.outlaweditor.data.xml.Image;
import org.badvision.outlaweditor.data.xml.Map;
import org.badvision.outlaweditor.data.xml.NamedEntity;
import org.badvision.outlaweditor.data.xml.Scope;
import org.badvision.outlaweditor.data.xml.Script;
import org.badvision.outlaweditor.data.xml.Scripts;
import org.badvision.outlaweditor.data.xml.Statement;
import org.badvision.outlaweditor.data.xml.Tile;
import org.badvision.outlaweditor.data.xml.Value;
import org.badvision.outlaweditor.ui.UIAction;
public class DataUtilities {
public static void logDataStructure(GameData gameData) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
PrintWriter logger = new PrintWriter(os);
if (gameData != null) {
logger.println("Game data detected");
logMapStructure(gameData.getMap(), logger);
logGlobalStrcture(gameData.getGlobal(), logger);
logImageStructure(gameData.getImage(), logger);
logTileStructure(gameData.getTile(), logger);
} else {
logger.println("Game data was not detected");
}
logger.flush();
System.out.print(os.toString());
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] md5sum = digest.digest(os.toByteArray());
System.out.println();
System.out.print("checksum: ");
for (int i = 0; i < md5sum.length; i++) {
System.out.printf("%02X", md5sum[i]);
}
System.out.println();
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(DataUtilities.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void logGlobalStrcture(Global global, PrintWriter logger) {
if (global != null) {
logScripts(global.getScripts(), logger);
} else {
logger.println("No global data was detected");
}
}
private static void logScripts(Scripts scripts, PrintWriter logger) {
if (scripts != null && scripts.getScript() != null || !scripts.getScript().isEmpty()) {
scripts.getScript().forEach((script) -> {
Queue<Block> evaluateStack = new ArrayDeque<>();
evaluateStack.add(script.getBlock());
int blockCount = 0;
while (!evaluateStack.isEmpty()) {
Block current = evaluateStack.poll();
blockCount++;
if (current.getNext() != null && current.getNext().getBlock() != null) {
evaluateStack.add(current.getNext().getBlock());
}
extract(current, Value.class).map(Value::getBlock).filter(Objects::nonNull).forEach(evaluateStack::addAll);
extract(current, Statement.class).map(Statement::getBlock).filter(Objects::nonNull).forEach(evaluateStack::addAll);
}
logger.println("Script " + script.getName() + "; " + blockCount + " blocks");
});
} else {
logger.println("No scripts were detected");
}
}
private static void logImageStructure(List<Image> images, PrintWriter logger) {
if (images != null && images.size() > 0) {
logger.println(images.size() + " images were detected");
} else {
logger.println("No images were detected");
}
}
private static void logMapStructure(List<Map> maps, PrintWriter logger) {
if (maps != null && maps.size() > 0) {
for (Map m : maps) {
logger.println(">> Map "+m.getName());
logScripts(m.getScripts(), logger);
}
} else {
logger.println("No maps were detected");
}
}
private static void logTileStructure(List<Tile> tiles, PrintWriter logger) {
if (tiles != null && tiles.size() > 0) {
logger.println(tiles.size() + " tiles were detected");
} else {
logger.println("No tiles were detected");
}
}
private DataUtilities() {
}
@ -160,8 +260,8 @@ public class DataUtilities {
public static List<List<String>> readFromFile(File file) {
try {
if (file.getName().toLowerCase().endsWith("txt") ||
file.getName().toLowerCase().endsWith("tsv")) {
if (file.getName().toLowerCase().endsWith("txt")
|| file.getName().toLowerCase().endsWith("tsv")) {
return readTextFile(file);
} else if (file.getName().toLowerCase().endsWith("xls")) {
return readLegacyExcel(file);
@ -171,7 +271,7 @@ public class DataUtilities {
} catch (IOException | InvalidFormatException ex) {
Logger.getLogger(DataUtilities.class.getName()).log(Level.SEVERE, null, ex);
}
UIAction.alert("Couldn't figure out how to import file "+file.getName());
UIAction.alert("Couldn't figure out how to import file " + file.getName());
return Collections.EMPTY_LIST;
}
@ -181,7 +281,7 @@ public class DataUtilities {
}
public static List<List<String>> readLegacyExcel(File file) throws FileNotFoundException, IOException {
return readSheet(new HSSFWorkbook(new FileInputStream(file)));
return readSheet(new HSSFWorkbook(new FileInputStream(file)));
}
public static List<List<String>> readExcel(File file) throws FileNotFoundException, IOException, InvalidFormatException {
@ -215,11 +315,11 @@ public class DataUtilities {
default:
return "???";
}
}
}
public static String hexDump(byte[] data) {
StringBuilder dump = new StringBuilder();
for (int i=0; i < data.length; i++) {
for (int i = 0; i < data.length; i++) {
if (i > 0) {
dump.append(",");
}
@ -231,7 +331,7 @@ public class DataUtilities {
public static String getHexValueFromByte(byte val) {
return getHexValue(val & 0x0ff);
}
public static String getHexValue(int val) {
if (val < 16) {
return "0" + Integer.toHexString(val);
@ -239,7 +339,7 @@ public class DataUtilities {
return Integer.toHexString(val);
}
}
//------------------------------ String comparators
/**
* Rank two strings similarity in terms of distance The lower the number,

View File

@ -122,6 +122,7 @@ public class UIAction {
DataUtilities.ensureGlobalExists();
DataUtilities.cleanupAllScriptNames();
ApplicationUIController.getController().updateSelectors();
DataUtilities.logDataStructure(newData);
break;
case Quit:
quit();

View File

@ -18,11 +18,14 @@ import java.util.ResourceBundle;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Rectangle2D;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.effect.ColorAdjust;
@ -30,6 +33,7 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import org.badvision.outlaweditor.apple.ImageDitherEngine;
import org.badvision.outlaweditor.ui.ImageConversionPostAction;
@ -124,6 +128,15 @@ public class ImageConversionWizardController implements Initializable {
hueValue.textProperty().bindBidirectional(hueSlider.valueProperty(), NumberFormat.getNumberInstance());
saturationValue.textProperty().bindBidirectional(saturationSlider.valueProperty(), NumberFormat.getNumberInstance());
HBox panel = (HBox) convertedImageView.getParent().getParent();
DoubleBinding height = panel.heightProperty().subtract(30);
DoubleBinding width = panel.widthProperty().divide(2.0).subtract(10);
sourceImageView.setPreserveRatio(false);
sourceImageView.fitHeightProperty().bind(height);
sourceImageView.fitWidthProperty().bind(width);
convertedImageView.fitHeightProperty().bind(height);
convertedImageView.fitWidthProperty().bind(width);
brightnessValue.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue)
-> javafx.application.Platform.runLater(this::updateImageAdjustments));
contrastValue.textProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue)
@ -197,8 +210,6 @@ public class ImageConversionWizardController implements Initializable {
private void updateSourceView(Image image) {
sourceImageView.setImage(image);
sourceImageView.setFitWidth(0);
sourceImageView.setFitHeight(0);
int width = (int) image.getWidth();
int height = (int) image.getHeight();
defaultTextFieldValues.put(cropRightValue, String.valueOf(width));
@ -224,6 +235,8 @@ public class ImageConversionWizardController implements Initializable {
private void prepareForConversion() {
ditherEngine.setCoefficients(getCoefficients());
ditherEngine.setDivisor(getDivisor());
// SnapshotParameters params = new SnapshotParameters();
// params.setViewport(new Rectangle2D(0, 0, sourceImage.getWidth(), sourceImage.getHeight()));
ditherEngine.setSourceImage(sourceImageView.snapshot(null, null));
}
@ -316,8 +329,7 @@ public class ImageConversionWizardController implements Initializable {
0, 3, 5, 1, 0,
0, 0, 0, 0, 0
);
// setDivisor(16);
setDivisor(18);
setDivisor(17);
}
@FXML
@ -338,8 +350,7 @@ public class ImageConversionWizardController implements Initializable {
3, 5, 7, 5, 3,
1, 3, 5, 3, 1
);
// setDivisor(48);
setDivisor(57);
setDivisor(50);
}
@FXML
@ -349,8 +360,7 @@ public class ImageConversionWizardController implements Initializable {
2, 4, 8, 4, 2,
1, 2, 4, 2, 1
);
// setDivisor(42);
setDivisor(52);
setDivisor(44);
}
@FXML
@ -360,7 +370,7 @@ public class ImageConversionWizardController implements Initializable {
0, 1, 1, 1, 0,
0, 0, 1, 0, 0
);
setDivisor(8);
setDivisor(7);
}
@FXML
@ -370,7 +380,7 @@ public class ImageConversionWizardController implements Initializable {
2, 4, 8, 4, 2,
0, 0, 0, 0, 0
);
setDivisor(37);
setDivisor(34);
// setDivisor(32);
}
@ -381,8 +391,7 @@ public class ImageConversionWizardController implements Initializable {
2, 4, 5, 4, 2,
0, 2, 3, 2, 0
);
// setDivisor(32);
setDivisor(41);
setDivisor(34);
}
@FXML
@ -392,7 +401,6 @@ public class ImageConversionWizardController implements Initializable {
1, 2, 3, 2, 1,
0, 0, 0, 0, 0
);
// setDivisor(16);
setDivisor(18);
}
@ -403,8 +411,6 @@ public class ImageConversionWizardController implements Initializable {
0, 1, 1, 0, 0,
0, 0, 0, 0, 0
);
// setDivisor(4);
setDivisor(5);
}
}
}

View File

@ -1,59 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.shape.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import java.net.URL?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.Slider?>
<?import javafx.scene.control.SplitMenuButton?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorPane" maxHeight="482.0" maxWidth="600.0" prefHeight="482.0" prefWidth="600.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.ImageConversionWizardController">
<AnchorPane id="AnchorPane" maxHeight="482.0" maxWidth="600.0" prefHeight="482.0" prefWidth="600.0" styleClass="mainFxmlClass" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.badvision.outlaweditor.ui.impl.ImageConversionWizardController">
<stylesheets>
<URL value="@/styles/imageconversionwizard.css" />
</stylesheets>
<children>
<HBox layoutX="14.0" layoutY="14.0" styleClass="imageViews" AnchorPane.bottomAnchor="276.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="14.0">
<children>
<StackPane HBox.hgrow="ALWAYS">
<VBox prefHeight="200.0" prefWidth="100.0" HBox.hgrow="ALWAYS">
<children>
<ScrollPane fitToWidth="true" minHeight="192.0" pannable="true" styleClass="imageViewScroll">
<content>
<AnchorPane minHeight="188.0" styleClass="imageView">
<children>
<ImageView fx:id="sourceImageView" fitHeight="185.0" fitWidth="271.0" pickOnBounds="true" preserveRatio="true" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<Label alignment="BOTTOM_CENTER" text="Source Image" textAlignment="CENTER" StackPane.alignment="BOTTOM_CENTER">
<StackPane.margin>
<Insets bottom="-20.0" />
</StackPane.margin>
</Label>
<ImageView fx:id="sourceImageView" fitHeight="185.0" fitWidth="271.0" pickOnBounds="true" preserveRatio="true"/>
<Label alignment="BOTTOM_CENTER" text="Source Image" textAlignment="CENTER" />
</children>
</StackPane>
<Region prefHeight="1" prefWidth="14.0" />
<StackPane HBox.hgrow="ALWAYS">
</VBox>
<VBox prefHeight="200.0" prefWidth="100.0" HBox.hgrow="ALWAYS">
<children>
<ScrollPane fitToWidth="true" minHeight="192.0" pannable="true" styleClass="imageViewScroll">
<content>
<AnchorPane minHeight="188.0" styleClass="imageView">
<children>
<ImageView fx:id="convertedImageView" fitHeight="185.0" fitWidth="271.0" pickOnBounds="true" preserveRatio="true" />
</children>
</AnchorPane>
</content>
</ScrollPane>
<Label alignment="BOTTOM_CENTER" text="Converted" textAlignment="CENTER" StackPane.alignment="BOTTOM_CENTER">
<StackPane.margin>
<Insets bottom="-20.0" />
</StackPane.margin>
</Label>
<ImageView fx:id="convertedImageView" fitHeight="185.0" fitWidth="100.0" pickOnBounds="true" preserveRatio="true" />
<Label alignment="BOTTOM_CENTER" text="Converted" textAlignment="CENTER" />
</children>
</StackPane>
</VBox>
</children>
</HBox>
<Separator layoutX="14.0" layoutY="227.0" prefHeight="9.0" prefWidth="442.0" AnchorPane.bottomAnchor="246.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" />