Skip to content

Commit

Permalink
0.5.1
Browse files Browse the repository at this point in the history
  • Loading branch information
asiekierka committed Jan 30, 2021
1 parent 66e28ff commit 168e4b0
Show file tree
Hide file tree
Showing 12 changed files with 276 additions and 35 deletions.
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ plugins {
}

group 'pl.asie.zima'
version '0.5.0'
version '0.5.1'

repositories {
mavenCentral()
}

dependencies {
implementation 'com.google.code.gson:gson:2.8.6'

testImplementation(platform('org.junit:junit-bom:5.7.0'))
testImplementation('org.junit.jupiter:junit-jupiter')
}

license {
Expand Down
13 changes: 13 additions & 0 deletions docs/changelog/0.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Improvements:

* In order to combat the issue of border halfchars forming around images, new aspect ratio preservation modes have been
added as follows:
* Snap to char (new default) - rounds width/height to the nearest character.
* Snap to center - rounds width/height to the nearest character which allows the image to be centered.
* The aspect ratio preservation mode is now saved as part of the profile.
* The window title now displays the program version.

Bugs fixed:

* The window pane showing scroll bars when unnecessary on some platforms has been fixed.
* The correct program version is now displayed (regression in 0.4.2+).
5 changes: 4 additions & 1 deletion docs/changelog/versions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
0.2.0
0.3.0
0.4.0
0.4.1
0.4.1
0.4.2
0.5.0
0.5.1
8 changes: 8 additions & 0 deletions src/main/java/pl/asie/zima/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
public final class Version {
private static final List<String> versions;

public static String getCurrentWindowName(String appName) {
if (appName.isBlank()) {
return "zima " + getCurrent();
} else {
return "zima " + getCurrent() + " :: " + appName;
}
}

public static String getCurrent() {
return versions != null && !versions.isEmpty() ? versions.get(versions.size() - 1) : "[unknown version]";
}
Expand Down
44 changes: 38 additions & 6 deletions src/main/java/pl/asie/zima/image/TrixImageMseCalculator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import pl.asie.libzzt.TextVisualData;

import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -35,6 +37,7 @@ public class TrixImageMseCalculator implements ImageMseCalculator {
private final boolean[][] charLut1x1Precalc;
private final float[] colDistPrecalc;
private final boolean blinkingDisabled;
private final int[][] blendingColorPrecalc;
private final Set<Integer> blendingChars = new HashSet<>();

private static class ImageLutHolder {
Expand Down Expand Up @@ -139,21 +142,39 @@ public TrixImageMseCalculator(TextVisualData visual, boolean blinkingDisabled, f
blendingChars.add(i);
}
}

blendingColorPrecalc = new int[256][];
Map<Integer, int[]> bcpMap = new HashMap<>();
final int bcpMax = (visual.getCharWidth() * visual.getCharHeight());
for (int i = 0; i < 256; i++) {
if (blendingChars.contains(i)) {
int count = 0;
for (int j = 0; j < bcpMax; j++) {
count += charLut1x1Precalc[i][j] ? 1 : 0;
}
blendingColorPrecalc[i] = bcpMap.computeIfAbsent(count, c -> {
float factor = c / (float) bcpMax;
int[] data = new int[256];
for (int k = 0; k < 256; k++) {
data[k] = ColorUtils.mix(visual.getPalette()[k >> 4], visual.getPalette()[k & 15], factor);
}
return data;
});
}
}
}

@Override
public Applier applyMse(BufferedImage image, int px, int py) {
final ImageLutHolder holder = new ImageLutHolder(visual, image, px, py, visual.getCharWidth(), visual.getCharHeight());
float[] mseContrastPrecalc = new float[256];
float[] macroRatioPrecalc = new float[256];
for (int i = 0; i < 256; i++) {
float imgContrast = holder.maxDistance;
float chrContrast = colDistPrecalc[i];
float contrastDiff = (imgContrast - chrContrast);
mseContrastPrecalc[i] = contrastReduction * contrastDiff * contrastDiff;

macroRatioPrecalc[i] = blendingChars.contains(i) ? 1.0f : accurateApproximate;
}
final int[] palette = visual.getPalette();
final int colorMask = blinkingDisabled ? 0xFF : 0x7F;
return (proposed, maxMse) -> {
int chr = proposed.getCharacter();
Expand All @@ -163,10 +184,21 @@ public Applier applyMse(BufferedImage image, int px, int py) {
int[] dataMacro2x2 = holder.dataMacro2x2;

float mseContrastReduction = mseContrastPrecalc[col];
float macroRatio = macroRatioPrecalc[chr];
float macroRatio = accurateApproximate;

mse += dataMacro2x2.length * mseContrastReduction;
if (mse <= maxMse) {
int[] blendingRatio = blendingColorPrecalc[chr];
if (blendingRatio != null) {
for (int i = 0; i < dataMacro2x2.length; i++) {
mse += ColorUtils.distance(blendingRatio[col], dataMacro2x2[i]);
if (mse > maxMse) {
return Float.MAX_VALUE;
}
}
return mse;
}

if (macroRatio < 1.0f) {
float invMacroRatio = ((1 - macroRatio) * 0.25f);
float[][] dataMacro1x1 = holder.dataMacro1x1;
Expand All @@ -178,7 +210,7 @@ public Applier applyMse(BufferedImage image, int px, int py) {
int charColor = charData[dm1p] ? fg : bg;
mse += dataMacro1x1[dm1p][charColor] * invMacroRatio;
if (mse > maxMse) {
return mse;
return Float.MAX_VALUE;
}
}
}
Expand All @@ -192,7 +224,7 @@ public Applier applyMse(BufferedImage image, int px, int py) {
float dist2x2 = ColorUtils.distance(char2x2Lut, dataMacro2x2[i]);
mse += dist2x2 * macroRatio;
if (mse > maxMse) {
return mse;
return Float.MAX_VALUE;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package pl.asie.zima.image.gui;

import lombok.Getter;
import pl.asie.libzzt.Board;
import pl.asie.libzzt.Platform;
import pl.asie.libzzt.TextVisualData;
import pl.asie.libzzt.TextVisualRenderer;
Expand Down Expand Up @@ -54,7 +53,7 @@ public class ZimaConversionProfile {
public static final Property<Float> BRIGHTNESS = Property.create("image.colorFilter.brightness", 0.0f, FILTERED_IMAGE);
public static final Property<Float> CONTRAST = Property.create("image.colorFilter.contrast", 0.0f, FILTERED_IMAGE);
public static final Property<Float> SATURATION = Property.create("image.colorFilter.saturation", 0.0f, FILTERED_IMAGE);
public static final Property<Boolean> PRESERVE_ASPECT_RATIO = Property.create("image.preserveAspectRatio", true, SCALED_IMAGE);
public static final Property<AspectRatioPreservationMode> ASPECT_RATIO_PRESERVATION_MODE = Property.create("image.preserveAspectRatio", AspectRatioPreservationMode.SNAP_CHAR, SCALED_IMAGE);

public static final Property<Integer> CROP_LEFT = Property.create("image.crop.left", 0, SCALED_IMAGE);
public static final Property<Integer> CROP_RIGHT = Property.create("image.crop.right", 0, SCALED_IMAGE);
Expand Down Expand Up @@ -167,7 +166,7 @@ public void updateImage(BufferedImage input) {
int width = properties.get(VISUAL_DATA).getCharWidth() * properties.get(CHARS_WIDTH);
int height = properties.get(VISUAL_DATA).getCharHeight() * properties.get(CHARS_HEIGHT);

this.scaledImage = ImageUtils.scale(img, width, height, properties.get(PRESERVE_ASPECT_RATIO), properties.get(PLATFORM).isDoubleWide(), Color.BLACK);
this.scaledImage = ImageUtils.scale(img, width, height, properties.get(ASPECT_RATIO_PRESERVATION_MODE), properties.get(PLATFORM).isDoubleWide(), Color.BLACK);
localHolder.affect(FILTERED_IMAGE);
}

Expand Down
36 changes: 27 additions & 9 deletions src/main/java/pl/asie/zima/image/gui/ZimaFrontendSwing.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,8 @@
import pl.asie.libzzt.Platform;
import pl.asie.libzzt.TextVisualData;
import pl.asie.libzzt.ZOutputStream;
import pl.asie.zima.util.FileUtils;
import pl.asie.zima.util.MZMWriter;
import pl.asie.zima.util.Pair;
import pl.asie.zima.util.Property;
import pl.asie.zima.util.PropertyHolder;
import pl.asie.zima.Version;
import pl.asie.zima.util.*;
import pl.asie.zima.image.*;
import pl.asie.zima.util.gui.ImageFileChooser;
import pl.asie.zima.util.gui.SimpleCanvas;
Expand Down Expand Up @@ -140,7 +137,7 @@ Platform.MEGAZEUX, new ImageConverterRuleset(List.of())
// "Image" tab
private JLabel imageDataLabel;
private JCheckBox showInputImageEdit;
private JCheckBox preserveAspectRatioEdit;
private JComboBox<AspectRatioPreservationMode> aspectRatioEdit;
private JSlider brightnessEdit;
private JButton brightnessReset;
private JSlider contrastEdit;
Expand Down Expand Up @@ -188,7 +185,7 @@ public ZimaFrontendSwing(byte[] defaultCharset, int[] defaultPalette, String zim
this.profile.getProperties().set(ZimaConversionProfile.PLATFORM, Platform.ZZT);
this.profile.getProperties().set(ZimaConversionProfile.FAST_RULESET, ImageConverterRulesZZT.RULES_BLOCKS);

this.window = new JFrame("zima :: image converter");
this.window = new JFrame(Version.getCurrentWindowName("image converter"));
this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.previewCanvas = new SimpleCanvas();
Expand Down Expand Up @@ -313,8 +310,8 @@ public ZimaFrontendSwing(byte[] defaultCharset, int[] defaultPalette, String zim

appendTabRow(this.optionsImagePanel, gbc, "Image info", this.imageDataLabel = new JLabel(""));

appendTabRow(this.optionsImagePanel, gbc, "Preserve aspect ratio", this.preserveAspectRatioEdit = new JCheckBox());
bindPropertyBoolean(this.profile.getProperties(), ZimaConversionProfile.PRESERVE_ASPECT_RATIO, this.preserveAspectRatioEdit);
appendTabRow(this.optionsImagePanel, gbc, "Aspect ratio", this.aspectRatioEdit = createEnumComboBox(AspectRatioPreservationMode.class));
bindPropertyEnum(this.profile.getProperties(), ZimaConversionProfile.ASPECT_RATIO_PRESERVATION_MODE, this.aspectRatioEdit);

appendTabRow(this.optionsImagePanel, gbc, "Brightness",
this.brightnessEdit = new JSlider(JSlider.HORIZONTAL, -160, 160, 0),
Expand Down Expand Up @@ -476,6 +473,7 @@ public ZimaFrontendSwing(byte[] defaultCharset, int[] defaultPalette, String zim
this.copyItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
this.pasteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK));

this.previewCanvasPane.setBorder(null);
this.previewCanvas.setMinimumSize(new Dimension(480, 350));
this.previewCanvasPane.setMinimumSize(this.previewCanvas.getMinimumSize());
this.previewCanvas.setPreferredSize(this.previewCanvas.getMinimumSize());
Expand Down Expand Up @@ -942,6 +940,8 @@ public ZimaProfileSettings getSettings() {
settings.setContrastReduction(this.profile.getProperties().get(ZimaConversionProfile.TRIX_CONTRAST_REDUCTION));
settings.setAccurateApproximate(this.profile.getProperties().get(ZimaConversionProfile.TRIX_ACCURATE_APPROXIMATE));

settings.setAspectRatioPreservationMode(this.profile.getProperties().get(ZimaConversionProfile.ASPECT_RATIO_PRESERVATION_MODE));

return settings;
}

Expand Down Expand Up @@ -1018,11 +1018,29 @@ public void setSettings(ZimaProfileSettings settings) {
this.profile.getProperties().set(ZimaConversionProfile.TRIX_ACCURATE_APPROXIMATE, settings.getAccurateApproximate());
}

if (settings.getAspectRatioPreservationMode() != null) {
this.profile.getProperties().set(ZimaConversionProfile.ASPECT_RATIO_PRESERVATION_MODE, settings.getAspectRatioPreservationMode());
}

rerender();
}

// Re-render call listeners

public <T extends Enum<?>> JComboBox<T> createEnumComboBox(Class<T> enumClass) {
JComboBox<T> comboBox = new JComboBox<>();
for (T value : enumClass.getEnumConstants()) {
comboBox.addItem(value);
}
return comboBox;
}

public <T extends Enum<?>> void bindPropertyEnum(PropertyHolder holder, Property<T> property, JComboBox<T> comboBox) {
comboBox.setSelectedItem(property.getDefaultValue());
comboBox.addItemListener((e) -> holder.set(property, (T) comboBox.getSelectedItem()));
holder.addChangeListener(property, (k, v) -> comboBox.setSelectedItem(v));
}

public void bindPropertyBoolean(PropertyHolder holder, Property<Boolean> property, JCheckBox checkBox) {
Boolean defValue = property.getDefaultValue();
checkBox.setSelected(Objects.equals(defValue, Boolean.TRUE));
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/pl/asie/zima/image/gui/ZimaProfileSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import lombok.Data;
import pl.asie.zima.image.ElementRule;
import pl.asie.zima.util.AspectRatioPreservationMode;

import java.util.List;

Expand All @@ -37,4 +38,6 @@ public class ZimaProfileSettings {
private Boolean colorsBlink;
private Float contrastReduction;
private Float accurateApproximate;

private AspectRatioPreservationMode aspectRatioPreservationMode;
}
37 changes: 37 additions & 0 deletions src/main/java/pl/asie/zima/util/AspectRatioPreservationMode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) 2020, 2021 Adrian Siekierka
*
* This file is part of zima.
*
* zima is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* zima is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with zima. If not, see <http://www.gnu.org/licenses/>.
*/
package pl.asie.zima.util;

public enum AspectRatioPreservationMode {
PRESERVE("Preserve"),
SNAP_CHAR("Snap to character"),
SNAP_CENTER("Snap to center"),
IGNORE("Stretch");

private final String label;

AspectRatioPreservationMode(String label) {
this.label = label;
}

@Override
public String toString() {
return label;
}
}
Loading

0 comments on commit 168e4b0

Please sign in to comment.