Ich erlaube mir mal folgende Anmassung (und zwar ungetestet, aber das werde ich noch ;)):
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
public class AntixImage extends BufferedImage {
private double numPixels;
public AntixImage(int width, int height, Color a, Color b) {
this(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB), a, b);
}
private AntixImage(BufferedImage img, Color a, Color b) {
super(img.getColorModel(), patchRaster(img.getRaster(), a.getRGB(), b.getRGB()), img.isAlphaPremultiplied(), null);
numPixels = img.getWidth() * img.getHeight();
}
private static AntixRaster patchRaster(WritableRaster wr, int rgb1, int rgb2) {
return new AntixRaster(wr, rgb1, rgb2);
}
private static SampleModel patchSampleModel(SampleModel source, int color1, int color2) {
return new AntixSampleModel(source, color1, color2);
}
public double getColorAPercent() {
AntixSampleModel m = (AntixSampleModel) getSampleModel();
double rc = m.getCount1() / numPixels;
return rc;
}
public double getColorBPercent() {
AntixSampleModel m = (AntixSampleModel) getSampleModel();
double rc = m.getCount2() / numPixels;
return rc;
}
private static class AntixRaster extends WritableRaster {
private AntixRaster(WritableRaster source, int color1, int color2) {
super(patchSampleModel(source.getSampleModel(), color1, color2), new Point(source.getSampleModelTranslateX(), source.getSampleModelTranslateY()));
}
}
private static class AntixSampleModel extends SampleModel {
private int color1, color2, count1, count2;
private SampleModel source;
private AntixSampleModel(SampleModel source, int color1, int color2) {
super(source.getDataType(), source.getWidth(), source.getHeight(), source.getNumBands());
this.source = source;
this.color1 = color1;
this.color2 = color2;
}
@Override
public int getNumDataElements() {
return source.getNumDataElements();
}
@Override
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
return source.getDataElements(x, y, obj, data);
}
@Override
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
source.setDataElements(x, y, obj, data);
if(obj instanceof int[]) {
int c = ((int[]) obj)[0];
if(c == color1) {
count1++;
} else if(c == color2) {
count2++;
}
}
}
@Override
public int getSample(int x, int y, int b, DataBuffer data) {
return source.getSample(x, y, b, data);
}
@Override
public void setSample(int x, int y, int b, int s, DataBuffer data) {
source.setSample(x, y, b, s, data);
if(s == color1) {
count1++;
} else if(s == color2) {
count2++;
}
}
@Override
public SampleModel createCompatibleSampleModel(int w, int h) {
return new AntixSampleModel(source.createCompatibleSampleModel(w, h), color1, color2);
}
@Override
public SampleModel createSubsetSampleModel(int[] bands) {
return new AntixSampleModel(source.createSubsetSampleModel(bands), color1, color2);
}
@Override
public DataBuffer createDataBuffer() {
return source.createDataBuffer();
}
@Override
public int[] getSampleSize() {
return source.getSampleSize();
}
@Override
public int getSampleSize(int band) {
return source.getSampleSize(band);
}
public int getCount1() {
return count1;
}
public int getCount2() {
return count2;
}
}
}```
Folgendes: Ein Java-Graphics-Objekt "pinselt" statt über setRGB usw. fröhlich über das SampleModel eines Rasters (WritableRaster) in einen BildPuffer. Folglich ist es ratsam, wenn man genau dort die entsprechenden Farben genau dann heraufzählt, sobald sie gesetzt werden. Was hier so umständlich aussieht, ist für ausgeprochen gute Performance leiner nötig, aber glücklicherweise noch recht überschaubar. Wenn ich nicht gerade meine Datatype-Images verwende, verwende ich ähnliche Konstrukte auch für Kollisionsabfragen, dann sind allerdings mehr die "get...()"-Methoden gefragt). An Performance ist das nicht zu über(unter?)bieten, maw: Es gibt nichts schnelleres, ausser meine DT_Images vllt ;).
edit: Okay... Ich hab vergessen, dass das ColorModel auch noch gepached werden muss, damits kompatibel wird...
*** Edit ***
Ich habe noch etwas mehr vergessen, nämlich den Umstand, dass seit Java7 statt nur dem SunWritableRaster nun auch jedes andere eigene "beschleunigt" werden kann, weil "stolen" nun nicht mehr Sache des Rasters sondern Sache des Buffers ist. Kurzum: Man kann sich dieses ganze gepatche der Models und Raster sparen und eigene implementieren...
Hier mal ein Demo... diesmal getestet ;)
```import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AntixMain extends JPanel {
private static final long serialVersionUID = 8299363071288831840L;
private AntixImage img;
private boolean running;
private AntixMain(final int width, final int height) {
img = new AntixImage(width, height, Color.RED, Color.BLUE);
setPreferredSize(new Dimension(width, height));
setFont(new Font(Font.MONOSPACED, Font.BOLD, 12));
final double hWidth = width / 2.0;
final Graphics2D g2d = img.createGraphics();
g2d.setColor(getBackground());
g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
Thread anim = new Thread("AnixAnim") {
@Override
public void run() {
int x, y, w, h;
while(running) {
double percentA = img.getColorAPercent();
double percentB = img.getColorBPercent();
if(percentA + percentB > .8) {
g2d.setColor(getBackground());
g2d.fillRect(0, 0, width, height);
}
x = (int) (Math.random() * width);
y = (int) (Math.random() * height);
w = (int) (Math.random() * (hWidth - (x % hWidth)));
h = (int) (Math.random() * (height - y));
g2d.setColor((x >= hWidth)? Color.RED : Color.BLUE);
g2d.fillRect(x, y, w, h);
repaint();
try {
Thread.sleep(40);
} catch(InterruptedException e) {
running = false;
}
}
}
};
running = true;
anim.start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
g.drawString(String.format("RED : %2.2f%%", img.getColorAPercent() * 100.0), 10, 15);
g.drawString(String.format("BLUE: %2.2f%%", img.getColorBPercent() * 100.0), 10, 30);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame();
JPanel p = new AntixMain(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(p);
f.pack();
f.setVisible(true);
}
});
}
}
class AntixImage extends BufferedImage {
private double numPixels;
public AntixImage(int width, int height, Color a, Color b) {
this(new AntixColorModel(a.getRGB(), b.getRGB()), width, height);
}
private AntixImage(AntixColorModel model, int width, int height) {
super(model, model.createCompatibleWritableRaster(width, height), false, null);
numPixels = width * height;
}
public double getColorAPercent() {
AntixSampleModel m = (AntixSampleModel) getSampleModel();
double rc = m.getCount1() / numPixels;
return rc;
}
public double getColorBPercent() {
AntixSampleModel m = (AntixSampleModel) getSampleModel();
double rc = m.getCount2() / numPixels;
return rc;
}
private static class AntixRaster extends WritableRaster {
private AntixRaster(int width, int height, int color1, int color2) {
super(new AntixSampleModel(width, height, color1, color2), new Point(0, 0));
}
}
private static class AntixColorModel extends ColorModel {
private int color1, color2;
private AntixColorModel(int color1, int color2) {
super(32);
this.color1 = color1;
this.color2 = color2;
}
@Override
public int getRed(int pixel) {
return (pixel >> 16) & 0xFF;
}
@Override
public int getGreen(int pixel) {
return (pixel >> 8) & 0xFF;
}
@Override
public int getBlue(int pixel) {
return pixel & 0xFF;
}
@Override
public int getAlpha(int pixel) {
return (pixel >> 24) & 0xFF;
}
@Override
public boolean isCompatibleRaster(Raster raster) {
return (raster instanceof AntixRaster);
}
@Override
public SampleModel createCompatibleSampleModel(int w, int h) {
return new AntixSampleModel(w, h, color1, color2);
}
@Override
public WritableRaster createCompatibleWritableRaster(int w, int h) {
return new AntixRaster(w, h, color1, color2);
}
@Override
public Object getDataElements(int rgb, Object pixel) {
if(pixel == null) {
pixel = new int[1];
}
((int[]) pixel)[0] = rgb;
return pixel;
}
}
private static class AntixSampleModel extends SampleModel {
private int color1, color2, count1, count2;
private AntixSampleModel(int width, int height, int color1, int color2) {
super(DataBuffer.TYPE_INT, width, height, 1);
this.color1 = color1;
this.color2 = color2;
}
@Override
public int getNumDataElements() {
return 1;
}
@Override
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
if(obj == null) {
obj = new int[1];
}
((int[]) obj)[0] = getSample(x, y, 0, data);
return obj;
}
@Override
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
int c = ((int[]) obj)[0];
setSample(x, y, 0, c, data);
}
@Override
public int getSample(int x, int y, int b, DataBuffer data) {
return data.getElem(0, y * width + x);
}
@Override
public void setSample(int x, int y, int b, int s, DataBuffer data) {
int c = getSample(x, y, b, data);
data.setElem(y * width + x, s);
if(c == color1) {
count1--;
} else if(c == color2) {
count2--;
}
if(s == color1) {
count1++;
} else if(s == color2) {
count2++;
}
}
@Override
public SampleModel createCompatibleSampleModel(int w, int h) {
return new AntixSampleModel(w, h, color1, color2);
}
@Override
public SampleModel createSubsetSampleModel(int[] bands) {
throw new UnsupportedOperationException("model doesn't have any subsets");
}
@Override
public DataBuffer createDataBuffer() {
return new DataBufferInt(width * height);
}
@Override
public int[] getSampleSize() {
return new int[] {32};
}
@Override
public int getSampleSize(int band) {
if(band != 0) {
return 0;
}
return 32;
}
public int getCount1() {
return count1;
}
public int getCount2() {
return count2;
}
}
}```