Skip to content

Commit

Permalink
Fix some palette mentions in docs.
Browse files Browse the repository at this point in the history
This also makes the threshold for analyze() consistent at 100.
  • Loading branch information
tommyettinger committed Sep 15, 2022
1 parent 21865c5 commit fa0aba0
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 35 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ version 0.3.5 .

You can create a PaletteReducer object by manually specifying an exact palette (useful for pixel art), attempting to
analyze an existing image or animation (which can work well for large palette sizes, but not small sizes), or using the
default palette (called "HALTONIC", it has 255 colors plus transparent). Of these, using `analyze()` is the trickiest,
and it generally should be permitted all 256 colors to work with. With `analyze()`, you can specify the threshold
between colors for it to consider adding one to the palette, and this is a challenging value to set that depends on the
image being dithered. Typically, between 50 and 600 are used, with higher values for smaller or more diverse palettes
(that is, ones with fewer similar colors to try to keep). Usually you will do just fine with the default "HALTONIC"
palette, or almost any practical 250+ color palette, because with so many colors it's hard to go wrong. Creating a
PaletteReducer without arguments, or calling `setDefaultPalette()` later, will set it to use HALTONIC.
default palette (made by DawnBringer and called "AURORA", it has 255 colors plus transparent). Of these, using
`analyze()` is the trickiest, and it generally should be permitted all 256 colors to work with. With `analyze()`, you
can specify the threshold between colors for it to consider adding one to the palette, and this is a challenging value
to set that depends on the image being dithered. Typically, between 50 and 600 are used, with higher values for smaller
or more diverse palettes (that is, ones with fewer similar colors to try to keep). Usually you will do just fine with
the default "AURORA" palette, or almost any practical 250+ color palette, because with so many colors it's hard to go
wrong. Creating a PaletteReducer without arguments, or calling `setDefaultPalette()` later, will set it to use AURORA.

As of version 0.3.3, GIF supports using a different palette for each frame of an
animation, analyzing colors separately for each frame. This supplements the previous behavior where a palette would
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/github/tommyettinger/anim8/AnimatedGif.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public void write(OutputStream output, Array<Pixmap> frames, int fps) {
if (clearPalette) {
if (fastAnalysis && frames.size > 1) {
palette = new PaletteReducer();
palette.analyzeFast(frames.first(), 150, 256);
palette.analyzeFast(frames.first(), 100, 256);
}
else
palette = new PaletteReducer(frames.first());
Expand Down Expand Up @@ -463,9 +463,9 @@ protected void analyzePixels() {
if(seq > 1 && clearPalette)
{
if(fastAnalysis)
palette.analyzeFast(image, 150, 256);
palette.analyzeFast(image, 100, 256);
else
palette.analyze(image, 150, 256);
palette.analyze(image, 100, 256);
}
final int[] paletteArray = palette.paletteArray;
final byte[] paletteMapping = palette.paletteMapping;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/github/tommyettinger/anim8/PNG8.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ public void write (FileHandle file, Pixmap pixmap) {
* colors in pixmap. When computePalette is true, if there are 256 or less colors and none are transparent, this
* will use 256 colors in its palette exactly with no transparent entry, but if there are more than 256 colors or
* any are transparent, then one color will be used for "fully transparent" and 255 opaque colors will be used. When
* computePalette is false, this uses the last palette this had computed, or the 256-color "Haltonic" palette if no
* computePalette is false, this uses the last palette this had computed, or the 256-color "Aurora" palette if no
* palette had been computed yet.
* @param file a FileHandle that must be writable, and will have the given Pixmap written as a PNG-8 image
* @param pixmap a Pixmap to write to the given file
Expand Down
30 changes: 13 additions & 17 deletions src/main/java/com/github/tommyettinger/anim8/PaletteReducer.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ public class PaletteReducer {
* preset grayscale colors) will produce a similarly-distributed palette. Typically, 64 items from this are enough
* to make pixel art look good enough with dithering, and it continues to improve with more colors. It has exactly 8
* colors that are purely grayscale, all right at the start after transparent.
* <br>
* While you can modify the individual items in this array, this is discouraged, because various constructors and
* methods in this class use HALTONIC with a pre-made distance mapping of its colors. This mapping would become
* incorrect if any colors in this array changed.
*/
public static final int[] HALTONIC = new int[]{
0x00000000, 0x010101FF, 0xFEFEFEFF, 0x7B7B7BFF, 0x555555FF, 0xAAAAAAFF, 0x333333FF, 0xE0E0E0FF,
Expand Down Expand Up @@ -478,9 +474,9 @@ public static byte[] loadPreloadFile(FileHandle file) {
}

/**
* Constructs a default PaletteReducer that uses the "Haltonic" 255-color-plus-transparent palette.
* Constructs a default PaletteReducer that uses the "Aurora" 255-color-plus-transparent palette.
* Note that this uses a more-detailed and higher-quality metric than you would get by just specifying
* {@code new PaletteReducer(PaletteReducer.HALTONIC)}; this metric would be too slow to calculate at
* {@code new PaletteReducer(PaletteReducer.AURORA)}; this metric would be too slow to calculate at
* runtime, but as pre-calculated data it works very well.
*/
public PaletteReducer() {
Expand Down Expand Up @@ -593,7 +589,7 @@ public PaletteReducer(int[] palette, byte[] preload)
* (see {@link #analyze(Pixmap, double)} for more info).
*
* @param pixmap a Pixmap to analyze in detail to produce a palette
* @param threshold the minimum difference between colors required to put them in the palette (default 150)
* @param threshold the minimum difference between colors required to put them in the palette (default 100)
*/
public PaletteReducer(Pixmap pixmap, double threshold) {
analyze(pixmap, threshold);
Expand Down Expand Up @@ -826,10 +822,10 @@ public double differenceHW(int r1, int g1, int b1, int r2, int g2, int b2) {
}

/**
* Resets the palette to the 256-color (including transparent) "Haltonic" palette. PaletteReducer already
* Resets the palette to the 256-color (including transparent) "Aurora" palette. PaletteReducer already
* stores most of the calculated data needed to use this one palette. Note that this uses a more-detailed
* and higher-quality metric than you would get by just specifying
* {@code new PaletteReducer(PaletteReducer.HALTONIC)}; this metric would be too slow to calculate at
* {@code new PaletteReducer(PaletteReducer.AURORA)}; this metric would be too slow to calculate at
* runtime, but as pre-calculated data it works very well.
*/
public void setDefaultPalette(){
Expand All @@ -839,7 +835,7 @@ public void setDefaultPalette(){
* Builds the palette information this PNG8 stores from the RGBA8888 ints in {@code rgbaPalette}, up to 256 colors.
* Alpha is not preserved except for the first item in rgbaPalette, and only if it is {@code 0} (fully transparent
* black); otherwise all items are treated as opaque. If rgbaPalette is null, empty, or only has one color, then
* this defaults to the "Haltonic" palette with 256 well-distributed colors (including transparent).
* this defaults to the "Aurora" palette with 256 well-distributed colors (including transparent).
*
* @param rgbaPalette an array of RGBA8888 ints; all will be used up to 256 items or the length of the array
*/
Expand All @@ -851,7 +847,7 @@ public void exact(int[] rgbaPalette) {
* or {@code limit}, whichever is less.
* Alpha is not preserved except for the first item in rgbaPalette, and only if it is {@code 0} (fully transparent
* black); otherwise all items are treated as opaque. If rgbaPalette is null, empty, or only has one color, or if
* limit is less than 2, then this defaults to the "Haltonic" palette with 256 well-distributed colors (including
* limit is less than 2, then this defaults to the "Aurora" palette with 256 well-distributed colors (including
* transparent).
*
* @param rgbaPalette an array of RGBA8888 ints; all will be used up to 256 items or the length of the array
Expand Down Expand Up @@ -948,7 +944,7 @@ public void exact(int[] palette, byte[] preload)
* 256 colors.
* Alpha is not preserved except for the first item in colorPalette, and only if its r, g, b, and a values are all
* 0f (fully transparent black); otherwise all items are treated as opaque. If rgbaPalette is null, empty, or only
* has one color, then this defaults to the "Haltonic" palette with 256 well-distributed colors (including
* has one color, then this defaults to the "Aurora" palette with 256 well-distributed colors (including
* transparent).
*
* @param colorPalette an array of Color objects; all will be used up to 256 items or the length of the array
Expand All @@ -962,7 +958,7 @@ public void exact(Color[] colorPalette) {
* 256 colors or {@code limit}, whichever is less.
* Alpha is not preserved except for the first item in colorPalette, and only if its r, g, b, and a values are all
* 0f (fully transparent black); otherwise all items are treated as opaque. If rgbaPalette is null, empty, only has
* one color, or limit is less than 2, then this defaults to the "Haltonic" palette with 256 well-distributed
* one color, or limit is less than 2, then this defaults to the "Aurora" palette with 256 well-distributed
* colors (including transparent).
*
* @param colorPalette an array of Color objects; all will be used up to 256 items, limit, or the length of the array
Expand Down Expand Up @@ -1019,15 +1015,15 @@ public void exact(Color[] colorPalette, int limit) {
* aren't exact, and dithering works better when the palette can choose colors that are sufficiently different, this
* uses a threshold value to determine whether it should permit a less-common color into the palette, and if the
* second color is different enough (as measured by {@link #differenceAnalyzing(int, int)}) by a value of at least
* 150, it is
* 100, it is
* allowed in the palette, otherwise it is kept out for being too similar to existing colors. This doesn't return a
* value but instead stores the palette info in this object; a PaletteReducer can be assigned to the
* {@link PNG8#palette} field or can be used directly to {@link #reduce(Pixmap)} a Pixmap.
*
* @param pixmap a Pixmap to analyze, making a palette which can be used by this to {@link #reduce(Pixmap)} or by PNG8
*/
public void analyze(Pixmap pixmap) {
analyze(pixmap, 150);
analyze(pixmap, 100);
}

private static final Comparator<IntIntMap.Entry> entryComparator = new Comparator<IntIntMap.Entry>() {
Expand Down Expand Up @@ -1921,7 +1917,7 @@ public int blend(int rgba1, int rgba2, float preference) {
* sufficiently different, this takes a threshold value to determine whether it should permit a less-common color
* into the palette, and if the second color is different enough (as measured by
* {@link #differenceAnalyzing(int, int, int, int)}) by a
* value of at least 150, it is allowed in the palette, otherwise it is kept out for being too similar to existing
* value of at least 100, it is allowed in the palette, otherwise it is kept out for being too similar to existing
* colors. This doesn't return a value but instead stores the palette info in this object; a PaletteReducer can be
* assigned to the {@link PNG8#palette} or {@link AnimatedGif#palette} fields, or can be used directly to
* {@link #reduce(Pixmap)} a Pixmap.
Expand Down Expand Up @@ -2102,7 +2098,7 @@ public void analyze(Pixmap[] pixmaps, int pixmapCount, double threshold, int lim
* sufficiently different, this takes a threshold value to determine whether it should permit a less-common color
* into the palette, and if the second color is different enough (as measured by
* {@link #differenceHW(int, int, int, int)}) by a
* value of at least 150, it is allowed in the palette, otherwise it is kept out for being too similar to existing
* value of at least 100, it is allowed in the palette, otherwise it is kept out for being too similar to existing
* colors. This doesn't return a value but instead stores the palette info in this object; a PaletteReducer can be
* assigned to the {@link PNG8#palette} or {@link AnimatedGif#palette} fields, or can be used directly to
* {@link #reduce(Pixmap)} a Pixmap.
Expand Down
8 changes: 4 additions & 4 deletions src/test/java/com/github/tommyettinger/ShaderCaptureDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,13 @@ public void create() {
long state = 0x123456789L; name = "flashy"; // flashy, bw, gb
// long state = 0x1234567890L; name = "green"; // green

String[] nms = {"blanket", "bold", "ocean", "flashy", "pastel", "green", "bw", "gb", "haltonic", "db8"};
int[][] pals = {null, null, null, null, null, null, {0x00000000, 0x000000FF, 0xFFFFFFFF}, {0x00000000, 0x081820FF, 0x346856FF, 0x88C070FF, 0xE0F8D0FF}, PaletteReducer.HALTONIC, {0x00000000, 0x000000FF, 0x55415FFF, 0x646964FF, 0xD77355FF, 0x508CD7FF, 0x64B964FF, 0xE6C86EFF, 0xDCF5FFFF}};
String[] nms = {"blanket", "bold", "ocean", "flashy", "pastel", "green", "bw", "gb", "aurora", "db8"};
int[][] pals = {null, null, null, null, null, null, {0x00000000, 0x000000FF, 0xFFFFFFFF}, {0x00000000, 0x081820FF, 0x346856FF, 0x88C070FF, 0xE0F8D0FF}, PaletteReducer.AURORA, {0x00000000, 0x000000FF, 0x55415FFF, 0x646964FF, 0xD77355FF, 0x508CD7FF, 0x64B964FF, 0xE6C86EFF, 0xDCF5FFFF}};
long[] sds = {0x123456789L, -1L, 0x1234567890L, 0x123456789L, -1L, 0x1234567890L, 0x123456789L, 0x123456789L, 0x123456789L, 0x123456789L};
ShaderProgram[] shs = {shader2, shader2, shader2, shader, shader, shader, shader, shader, shader, shader};

// String[] nms = {"pastel", "green", "bw", "gb", "haltonic"};
// int[][] pals = {null, null, {0x00000000, 0x000000FF, 0xFFFFFFFF}, {0x00000000, 0x081820FF, 0x346856FF, 0x88C070FF, 0xE0F8D0FF}, PaletteReducer.HALTONIC};
// String[] nms = {"pastel", "green", "bw", "gb", "aurora"};
// int[][] pals = {null, null, {0x00000000, 0x000000FF, 0xFFFFFFFF}, {0x00000000, 0x081820FF, 0x346856FF, 0x88C070FF, 0xE0F8D0FF}, PaletteReducer.AURORA};
// long[] sds = {-1L, 0x1234567890L, 0x123456789L, 0x123456789L, 0x123456789L};
// ShaderProgram[] shs = {shader, shader, shader, shader, shader};

Expand Down
2 changes: 2 additions & 0 deletions src/test/java/com/github/tommyettinger/StillImageDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ public void create() {
// for(String name : new String[]{"Mona_Lisa.jpg", "Cat.jpg", "Frog.jpg", "Landscape.jpg", "Pixel_Art.png",}) {
for(String name : new String[]{"Mona_Lisa.jpg", "Earring.jpg", "Cat.jpg", "Frog.jpg", "Landscape.jpg", "Pixel_Art.png",}) {
// for(String name : new String[]{"Mona_Lisa.jpg", "Earring.jpg", "Cat.jpg", "Frog.jpg", "Landscape.jpg", "Pixel_Art.png", "Anemone.png",}) {
System.out.println("Rendering PNG8 for " + name);
renderPNG8(name);
System.out.println("Rendering GIF for " + name);
renderGif(name);
// renderPNG(name);
}
Expand Down
12 changes: 9 additions & 3 deletions src/test/java/com/github/tommyettinger/VideoConvertDemo.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
public class VideoConvertDemo extends ApplicationAdapter {
private long startTime;
private static final String name = "market";
private boolean fastAnalysis = true;
private final boolean fastAnalysis = true;
@Override
public void create() {
startTime = TimeUtils.millis();

Gdx.files.local("images").mkdirs();
// renderAPNG(); // comment this out if you aren't using the full-color animated PNGs, because this is slow.
// renderPNG8();
String[] names = new String[]{"-Analyzed", "-Haltonic", "-BW", "-Green", "-DB8"};
String[] names = new String[]{"-Analyzed", "-Aurora", "-BW", "-Green", "-DB8"};
int[][] palettes = new int[][]{
null,
PaletteReducer.HALTONIC,
PaletteReducer.AURORA,
new int[]{0x00000000, 0x000000FF, 0xFFFFFFFF},
new int[]{0x00000000,
0x000000FF, 0x081820FF, 0x132C2DFF, 0x1E403BFF, 0x295447FF, 0x346856FF, 0x497E5BFF, 0x5E9463FF,
Expand Down Expand Up @@ -107,6 +107,7 @@ public void renderPNG8() {
}

public void renderVideoGif(String[] names, int[][] palettes) {
System.out.println("Rendering video GIF");
String name = "market";
Array<Pixmap> pixmaps = new Array<>(true, 90, Pixmap.class);
for (int i = 1; i <= 90; i++) {
Expand Down Expand Up @@ -148,6 +149,7 @@ public void renderVideoGif(String[] names, int[][] palettes) {
}

public void renderPixelGif(String[] names, int[][] palettes) {
System.out.println("Rendering tyrant GIF");
String name = "tyrant";
Array<Pixmap> pixmaps = new Array<>(true, 64, Pixmap.class);
for (int i = 0; i < 64; i++) {
Expand Down Expand Up @@ -185,6 +187,7 @@ public void renderPixelGif(String[] names, int[][] palettes) {
}

public void renderTankGif(String[] names, int[][] palettes) {
System.out.println("Rendering pixel tank GIF");
String name = "tank";
Array<Pixmap> pixmaps = new Array<>(true, 16, Pixmap.class);
for (int i = 0; i < 16; i++) {
Expand Down Expand Up @@ -222,6 +225,7 @@ public void renderTankGif(String[] names, int[][] palettes) {
}

public void renderGlobeGif(String[] names, int[][] palettes) {
System.out.println("Rendering globe GIF");
String name = "globe";
Array<Pixmap> pixmaps = new Array<>(true, 180, Pixmap.class);
for (int i = 0; i < 180; i++) {
Expand Down Expand Up @@ -259,6 +263,7 @@ public void renderGlobeGif(String[] names, int[][] palettes) {
}

public void renderOklabGif(String[] names, int[][] palettes) {
System.out.println("Rendering oklab GIF");
String name = "oklab";
Array<Pixmap> pixmaps = new Array<>(true, 120, Pixmap.class);
for (int i = 0; i < 120; i++) {
Expand Down Expand Up @@ -297,6 +302,7 @@ public void renderOklabGif(String[] names, int[][] palettes) {


public void renderSolidsGif(String[] names, int[][] palettes) {
System.out.println("Rendering solids GIF");
String name = "solids";
Array<Pixmap> pixmaps = new Array<>(true, 256, Pixmap.class);
for (int i = 0; i < 256; i++) {
Expand Down

0 comments on commit fa0aba0

Please sign in to comment.