You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by da...@apache.org on 2012/09/26 07:39:31 UTC
svn commit: r1390281 - in
/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging:
formats/bmp/ formats/gif/ formats/ico/ formats/pcx/ formats/xpm/ palette/
Author: damjan
Date: Wed Sep 26 05:39:31 2012
New Revision: 1390281
URL: http://svn.apache.org/viewvc?rev=1390281&view=rev
Log:
Palette cleanup. Finish the fancy exact palette algorithm, document
everything, and use clearer names.
Modified:
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/xpm/XpmImageParser.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/MedianCutQuantizer.java
commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/PaletteFactory.java
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/bmp/BmpImageParser.java Wed Sep 26 05:39:31 2012
@@ -772,7 +772,7 @@ public class BmpImageParser extends Imag
throw new ImageWriteException("Unknown parameter: " + firstKey);
}
- final SimplePalette palette = new PaletteFactory().makePaletteSimple(
+ final SimplePalette palette = new PaletteFactory().makeSimpleRgbPalette(
src, 256);
BmpWriter writer = null;
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/gif/GifImageParser.java Wed Sep 26 05:39:31 2012
@@ -812,13 +812,13 @@ public class GifImageParser extends Imag
int max_colors = hasAlpha ? 255 : 256;
- Palette palette2 = new PaletteFactory().makePaletteSimple(src,
+ Palette palette2 = new PaletteFactory().makeSimpleRgbPalette(src,
max_colors);
// int palette[] = new PaletteFactory().makePaletteSimple(src, 256);
// Map palette_map = paletteToMap(palette);
if (palette2 == null) {
- palette2 = new PaletteFactory().makePaletteQuantized(src,
+ palette2 = new PaletteFactory().makeQuantizedRgbPalette(src,
max_colors);
if (verbose)
System.out.println("quantizing");
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/ico/IcoImageParser.java Wed Sep 26 05:39:31 2012
@@ -730,7 +730,7 @@ public class IcoImageParser extends Imag
final PaletteFactory paletteFactory = new PaletteFactory();
final SimplePalette palette = paletteFactory
- .makePaletteSimple(src, 256);
+ .makeSimpleRgbPalette(src, 256);
final int bitCount;
final boolean hasTransparency = paletteFactory.hasTransparency(src);
if (palette == null) {
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/pcx/PcxWriter.java Wed Sep 26 05:39:31 2012
@@ -130,7 +130,7 @@ public class PcxWriter implements PcxCon
throws ImageWriteException, IOException {
final PaletteFactory paletteFactory = new PaletteFactory();
final SimplePalette palette = paletteFactory
- .makePaletteSimple(src, 256);
+ .makeSimpleRgbPalette(src, 256);
BinaryOutputStream bos = new BinaryOutputStream(os,
BinaryOutputStream.BYTE_ORDER_INTEL);
if (palette == null || bitDepth == 24 || bitDepth == 32) {
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/xpm/XpmImageParser.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/xpm/XpmImageParser.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/xpm/XpmImageParser.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/formats/xpm/XpmImageParser.java Wed Sep 26 05:39:31 2012
@@ -661,7 +661,7 @@ public class XpmImageParser extends Imag
int maxColors = writePalette.length;
int charsPerPixel = 1;
for (; palette == null;) {
- palette = paletteFactory.makePaletteSimple(src,
+ palette = paletteFactory.makeSimpleRgbPalette(src,
hasTransparency ? maxColors - 1 : maxColors);
if (palette == null) {
maxColors *= writePalette.length;
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/MedianCutQuantizer.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/MedianCutQuantizer.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/MedianCutQuantizer.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/MedianCutQuantizer.java Wed Sep 26 05:39:31 2012
@@ -256,69 +256,65 @@ public class MedianCutQuantizer {
List<ColorGroup> color_groups = new ArrayList<ColorGroup>();
ColorGroup root = new ColorGroup(new ArrayList<ColorCount>(
color_map.values()));
- {
- color_groups.add(root);
+ color_groups.add(root);
- final Comparator<ColorGroup> comparator = new Comparator<ColorGroup>() {
- public int compare(ColorGroup cg1, ColorGroup cg2) {
- if (cg1.max_diff == cg2.max_diff)
- return cg2.diff_total - cg1.diff_total;
- return cg2.max_diff - cg1.max_diff;
- }
- };
+ final Comparator<ColorGroup> comparator = new Comparator<ColorGroup>() {
+ public int compare(ColorGroup cg1, ColorGroup cg2) {
+ if (cg1.max_diff == cg2.max_diff)
+ return cg2.diff_total - cg1.diff_total;
+ return cg2.max_diff - cg1.max_diff;
+ }
+ };
- while (color_groups.size() < max_colors) {
- Collections.sort(color_groups, comparator);
+ while (color_groups.size() < max_colors) {
+ Collections.sort(color_groups, comparator);
- ColorGroup color_group = color_groups.get(0);
+ ColorGroup color_group = color_groups.get(0);
- if (color_group.max_diff == 0)
- break;
- if (!ignoreAlpha
- && color_group.alpha_diff > color_group.red_diff
- && color_group.alpha_diff > color_group.green_diff
- && color_group.alpha_diff > color_group.blue_diff) {
- doCut(color_group, ALPHA, color_groups);
- } else if (color_group.red_diff > color_group.green_diff
- && color_group.red_diff > color_group.blue_diff) {
- doCut(color_group, RED, color_groups);
- } else if (color_group.green_diff > color_group.blue_diff) {
- doCut(color_group, GREEN, color_groups);
- } else {
- doCut(color_group, BLUE, color_groups);
- }
+ if (color_group.max_diff == 0)
+ break;
+ if (!ignoreAlpha
+ && color_group.alpha_diff > color_group.red_diff
+ && color_group.alpha_diff > color_group.green_diff
+ && color_group.alpha_diff > color_group.blue_diff) {
+ doCut(color_group, ALPHA, color_groups);
+ } else if (color_group.red_diff > color_group.green_diff
+ && color_group.red_diff > color_group.blue_diff) {
+ doCut(color_group, RED, color_groups);
+ } else if (color_group.green_diff > color_group.blue_diff) {
+ doCut(color_group, GREEN, color_groups);
+ } else {
+ doCut(color_group, BLUE, color_groups);
}
}
- {
- int palette_size = color_groups.size();
- if (verbose)
- Debug.debug("palette size: " + palette_size);
+ int palette_size = color_groups.size();
+ if (verbose)
+ Debug.debug("palette size: " + palette_size);
- int palette[] = new int[palette_size];
+ int palette[] = new int[palette_size];
- for (int i = 0; i < color_groups.size(); i++) {
- ColorGroup color_group = color_groups.get(i);
+ for (int i = 0; i < color_groups.size(); i++) {
+ ColorGroup color_group = color_groups.get(i);
- palette[i] = color_group.getMedianValue();
+ palette[i] = color_group.getMedianValue();
- color_group.palette_index = i;
+ color_group.palette_index = i;
- if (color_group.color_counts.size() < 1)
- throw new ImageWriteException("empty color_group: "
- + color_group);
+ if (color_group.color_counts.size() < 1)
+ throw new ImageWriteException("empty color_group: "
+ + color_group);
- // if(color_group.)
- // Debug.debug("color_group", color_group);
- // Debug.debug("palette[" + i + "]", palette[i] + " ("
- // + Integer.toHexString(palette[i]) + ")");
- }
+ // if(color_group.)
+ // Debug.debug("color_group", color_group);
+ // Debug.debug("palette[" + i + "]", palette[i] + " ("
+ // + Integer.toHexString(palette[i]) + ")");
+ }
- if (palette_size > discrete_colors)
- throw new ImageWriteException("palette_size>discrete_colors");
+ if (palette_size > discrete_colors)
+ throw new ImageWriteException("palette_size>discrete_colors");
- return new MedianCutPalette(root, palette);
- }
+ return new MedianCutPalette(root, palette);
}
private static final int ALPHA = 0;
@@ -377,45 +373,42 @@ public class MedianCutQuantizer {
}
color_groups.remove(color_group);
+ List<ColorCount> color_counts1 = new ArrayList<ColorCount>(
+ color_group.color_counts.subList(0, median_index + 1));
+ List<ColorCount> color_counts2 = new ArrayList<ColorCount>(
+ color_group.color_counts.subList(median_index + 1,
+ color_group.color_counts.size()));
+
+ ColorGroup less, more;
{
- List<ColorCount> color_counts1 = new ArrayList<ColorCount>(
- color_group.color_counts.subList(0, median_index + 1));
- List<ColorCount> color_counts2 = new ArrayList<ColorCount>(
- color_group.color_counts.subList(median_index + 1,
- color_group.color_counts.size()));
-
- ColorGroup less, more;
- {
- less = new ColorGroup(new ArrayList<ColorCount>(color_counts1));
- color_groups.add(less);
- }
- {
- more = new ColorGroup(new ArrayList<ColorCount>(color_counts2));
- color_groups.add(more);
- }
-
- ColorCount median_value = color_group.color_counts
- .get(median_index);
- int limit;
- switch (mode) {
- case ALPHA:
- limit = median_value.alpha;
- break;
- case RED:
- limit = median_value.red;
- break;
- case GREEN:
- limit = median_value.green;
- break;
- case BLUE:
- limit = median_value.blue;
- break;
- default:
- throw new Error("Bad mode.");
- }
- color_group.cut = new ColorGroupCut(less, more, mode, limit);
+ less = new ColorGroup(new ArrayList<ColorCount>(color_counts1));
+ color_groups.add(less);
+ }
+ {
+ more = new ColorGroup(new ArrayList<ColorCount>(color_counts2));
+ color_groups.add(more);
+ }
+ ColorCount median_value = color_group.color_counts
+ .get(median_index);
+ int limit;
+ switch (mode) {
+ case ALPHA:
+ limit = median_value.alpha;
+ break;
+ case RED:
+ limit = median_value.red;
+ break;
+ case GREEN:
+ limit = median_value.green;
+ break;
+ case BLUE:
+ limit = median_value.blue;
+ break;
+ default:
+ throw new Error("Bad mode.");
}
+ color_group.cut = new ColorGroupCut(less, more, mode, limit);
}
private static class ColorGroupCut {
Modified: commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/PaletteFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/PaletteFactory.java?rev=1390281&r1=1390280&r2=1390281&view=diff
==============================================================================
--- commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/PaletteFactory.java (original)
+++ commons/proper/imaging/trunk/src/main/java/org/apache/commons/imaging/palette/PaletteFactory.java Wed Sep 26 05:39:31 2012
@@ -26,10 +26,19 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import org.apache.commons.imaging.ImageWriteException;
+
public class PaletteFactory {
private static final boolean debug = false;
- public void makePaletteFancy(BufferedImage src) {
+ /**
+ * Builds an exact complete opaque palette containing all the colors in {@code src},
+ * using an algorithm that is faster than {@linkplain #makePaletteSimple} for large images
+ * but uses 2 mebibytes of working memory. Treats all the colors as opaque.
+ * @param src the image whose palette to build
+ * @return the palette
+ */
+ public Palette makeExactRgbPaletteFancy(BufferedImage src) {
// map what rgb values have been used
byte rgbmap[] = new byte[256 * 256 * 32];
@@ -37,7 +46,7 @@ public class PaletteFactory {
int width = src.getWidth();
int height = src.getHeight();
- for (int y = 0; y < height; y++)
+ for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int argb = src.getRGB(x, y);
int rggbb = 0x1fffff & argb;
@@ -45,19 +54,12 @@ public class PaletteFactory {
int mask = 1 << highred;
rgbmap[rggbb] |= mask;
}
+ }
int count = 0;
for (int i = 0; i < rgbmap.length; i++) {
int eight = 0xff & rgbmap[i];
- if ((i < 3) || ((i - rgbmap.length) > -3)) {
- }
- for (int j = 0; j < 8; j++) {
- int mask = 1 << (7 - j);
- int bit = eight & mask;
- if (bit > 0)
- count++;
-
- }
+ count += Integer.bitCount(eight);
}
if (debug)
@@ -67,29 +69,21 @@ public class PaletteFactory {
int mapsize = 0;
for (int i = 0; i < rgbmap.length; i++) {
int eight = 0xff & rgbmap[i];
-
+ int mask = 0x80;
for (int j = 0; j < 8; j++) {
- int mask = 1 << (7 - j);
int bit = eight & mask;
+ mask >>>= 1;
if (bit > 0) {
int rgb = i | ((7 - j) << 21);
- if (mapsize < colormap.length)
- colormap[mapsize] = rgb;
- mapsize++;
+ colormap[mapsize++] = rgb;
}
}
}
- if (debug)
- System.out.println("mapsize: " + mapsize);
-
- // for (int i = 0; i < colormap.length; i++)
- // {
- // int rgb = colormap[i];
- // }
-
+ Arrays.sort(colormap);
+ return new SimplePalette(colormap);
}
private int pixelToQuantizationTableIndex(int argb, int precision) {
@@ -323,13 +317,13 @@ public class PaletteFactory {
}
/**
- * Builds an inexact palette of at most {@code max} colors in {@code src}
+ * Builds an inexact opaque palette of at most {@code max} colors in {@code src}
* using the Median Cut algorithm.
* @param src the image whose palette to build
* @param max the maximum number of colors the palette can contain
* @return the palette of at most {@code max} colors
*/
- public Palette makePaletteQuantized(BufferedImage src, int max) {
+ public Palette makeQuantizedRgbPalette(BufferedImage src, int max) {
int precision = 6; // in bits
int table_scale = precision * components;
@@ -385,15 +379,27 @@ public class PaletteFactory {
return new QuantizedPalette(subsets, precision);
}
+
+ /**
+ * Builds an inexact possibly translucent palette of at most {@code max} colors in {@code src}
+ * using the Median Cut algorithm.
+ * @param src the image whose palette to build
+ * @param transparent whether to consider the alpha values
+ * @param max the maximum number of colors the palette can contain
+ * @return the palette of at most {@code max} colors
+ */
+ public Palette makeQuantizedRgbaPalette(BufferedImage src, boolean transparent, int max) throws ImageWriteException {
+ return new MedianCutQuantizer(!transparent).process(src, max, false);
+ }
/**
- * Builds an exact and complete palette containing all the colors in {@code src},
+ * Builds an exact complete opaque palette containing all the colors in {@code src},
* and fails by returning {@code null} if there are more than {@code max} colors necessary to do this.
* @param src the image whose palette to build
* @param max the maximum number of colors the palette can contain
* @return the complete palette of {@code max} or less colors, or {@code null} if more than {@code max} colors are necessary
*/
- public SimplePalette makePaletteSimple(BufferedImage src, int max) {
+ public SimplePalette makeSimpleRgbPalette(BufferedImage src, int max) {
// This is not efficient for large values of max, say, max > 256;
Set<Integer> rgbs = new HashSet<Integer>();