我正在寫一個曼德爾布羅分形觀衆騎自行車的形象,我想實現一個聰明的辦法顏色循環。給定一個圖像,我想修改它的IndexColorModel。高效彩色在Java中
據我所知,有沒有辦法來修改一個IndexColorModel,而且也沒有辦法給出一個圖像的新IndexColorModel的。事實上,我認爲無法提取其顏色模型或圖像數據。
看來,唯一的解決方案是堅持用於創建圖像的原始圖像數據和調色板,手動創建一個新的調色板與旋轉的顏色,創建一個新的IndexColorModel,然後創建一個全新的來自數據和新顏色模型的圖像。
這一切都似乎有太多的工作。有更簡單快捷的方法嗎?
這是我能拿出最好的解決方案。此代碼創建一個1000x1000像素的圖像,並顯示以大約每秒30幀循環的顏色動畫。
(舊)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ColorCycler {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame jFrame = new JFrame("Color Cycler");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(new MyPanel());
jFrame.pack();
jFrame.setVisible(true);
}
}
class MyPanel extends JPanel implements ActionListener {
private byte[] reds = new byte[216];
private byte[] greens = new byte[216];
private byte[] blues = new byte[216];
private final byte[] imageData = new byte[1000 * 1000];
private Image image;
public MyPanel() {
generateColors();
generateImageData();
(new Timer(35, this)).start();
}
// The window size is 1000x1000 pixels.
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
// Generate 216 unique colors for the color model.
private void generateColors() {
int index = 0;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
for (int k = 0; k < 6; k++, index++) {
reds[index] = (byte) (i * 51);
greens[index] = (byte) (j * 51);
blues[index] = (byte) (k * 51);
}
}
}
}
// Create the image data for the MemoryImageSource.
// This data is created once and never changed.
private void generateImageData() {
for (int i = 0; i < 1000 * 1000; i++) {
imageData[i] = (byte) (i % 216);
}
}
// Draw the image.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, 1000, 1000, null);
}
// This method is called by the timer every 35 ms.
// It creates the modified image to be drawn.
@Override
public void actionPerformed(ActionEvent e) { // Called by Timer.
reds = cycleColors(reds);
greens = cycleColors(greens);
blues = cycleColors(blues);
IndexColorModel colorModel = new IndexColorModel(8, 216, reds, greens, blues);
image = createImage(new MemoryImageSource(1000, 1000, colorModel, imageData, 0, 1000));
repaint();
}
// Cycle the colors to the right by 1.
private byte[] cycleColors(byte[] colors) {
byte[] newColors = new byte[216];
newColors[0] = colors[215];
System.arraycopy(colors, 0, newColors, 1, 215);
return newColors;
}
}
編輯2:
現在我預先計算IndexColorModels。這意味着在每一幀我只需要用一個新的IndexColorModel更新MemoryImageSource。這似乎是最好的解決方案。 (我也注意到在我的分形瀏覽器中,我可以在每個生成的圖像上重新使用一組預先計算好的IndexColorModels,這意味着140K的一次性成本讓我可以實時對所有的事物進行實時顏色循環。是偉大的)
下面的代碼:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ColorCycler {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame jFrame = new JFrame("Color Cycler");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(new MyPanel());
jFrame.pack();
jFrame.setVisible(true);
}
}
class MyPanel extends JPanel implements ActionListener {
private final IndexColorModel[] colorModels = new IndexColorModel[216];
private final byte[] imageData = new byte[1000 * 1000];
private final MemoryImageSource imageSource;
private final Image image;
private int currentFrame = 0;
public MyPanel() {
generateColorModels();
generateImageData();
imageSource = new MemoryImageSource(1000, 1000, colorModels[0], imageData, 0, 1000);
imageSource.setAnimated(true);
image = createImage(imageSource);
(new Timer(35, this)).start();
}
// The window size is 1000x1000 pixels.
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
// Generate 216 unique colors models, one for each frame.
private void generateColorModels() {
byte[] reds = new byte[216];
byte[] greens = new byte[216];
byte[] blues = new byte[216];
int index = 0;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
for (int k = 0; k < 6; k++, index++) {
reds[index] = (byte) (i * 51);
greens[index] = (byte) (j * 51);
blues[index] = (byte) (k * 51);
}
}
}
for (int i = 0; i < 216; i++) {
colorModels[i] = new IndexColorModel(8, 216, reds, greens, blues);
reds = cycleColors(reds);
greens = cycleColors(greens);
blues = cycleColors(blues);
}
}
// Create the image data for the MemoryImageSource.
// This data is created once and never changed.
private void generateImageData() {
for (int i = 0; i < 1000 * 1000; i++) {
imageData[i] = (byte) (i % 216);
}
}
// Draw the image.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, 1000, 1000, null);
}
// This method is called by the timer every 35 ms.
// It updates the ImageSource of the image to be drawn.
@Override
public void actionPerformed(ActionEvent e) { // Called by Timer.
currentFrame++;
if (currentFrame == 216) {
currentFrame = 0;
}
imageSource.newPixels(imageData, colorModels[currentFrame], 0, 1000);
repaint();
}
// Cycle the colors to the right by 1.
private byte[] cycleColors(byte[] colors) {
byte[] newColors = new byte[216];
newColors[0] = colors[215];
System.arraycopy(colors, 0, newColors, 1, 215);
return newColors;
}
}
編輯:(舊)
Heisenbug建議我使用newPixels MemoryImageSource的()方法。答案已經被刪除,但結果是一個好主意。現在我只創建一個MemoryImageSource和一個Image。在每一幀我創建一個新的IndexColorModel並更新MemoryImageSource。
下面是更新的代碼:(舊)
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
public class ColorCycler {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
JFrame jFrame = new JFrame("Color Cycler");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.add(new MyPanel());
jFrame.pack();
jFrame.setVisible(true);
}
}
class MyPanel extends JPanel implements ActionListener {
private byte[] reds = new byte[216];
private byte[] greens = new byte[216];
private byte[] blues = new byte[216];
private final byte[] imageData = new byte[1000 * 1000];
private final MemoryImageSource imageSource;
private final Image image;
public MyPanel() {
generateColors();
generateImageData();
IndexColorModel colorModel = new IndexColorModel(8, 216, reds, greens, blues);
imageSource = new MemoryImageSource(1000, 1000, colorModel, imageData, 0, 1000);
imageSource.setAnimated(true);
image = createImage(imageSource);
(new Timer(35, this)).start();
}
// The window size is 1000x1000 pixels.
public Dimension getPreferredSize() {
return new Dimension(1000, 1000);
}
// Generate 216 unique colors for the color model.
private void generateColors() {
int index = 0;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
for (int k = 0; k < 6; k++, index++) {
reds[index] = (byte) (i * 51);
greens[index] = (byte) (j * 51);
blues[index] = (byte) (k * 51);
}
}
}
}
// Create the image data for the MemoryImageSource.
// This data is created once and never changed.
private void generateImageData() {
for (int i = 0; i < 1000 * 1000; i++) {
imageData[i] = (byte) (i % 216);
}
}
// Draw the image.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, 1000, 1000, null);
}
// This method is called by the timer every 35 ms.
// It updates the ImageSource of the image to be drawn.
@Override
public void actionPerformed(ActionEvent e) { // Called by Timer.
reds = cycleColors(reds);
greens = cycleColors(greens);
blues = cycleColors(blues);
IndexColorModel colorModel = new IndexColorModel(8, 216, reds, greens, blues);
imageSource.newPixels(imageData, colorModel, 0, 1000);
repaint();
}
// Cycle the colors to the right by 1.
private byte[] cycleColors(byte[] colors) {
byte[] newColors = new byte[216];
newColors[0] = colors[215];
System.arraycopy(colors, 0, newColors, 1, 215);
return newColors;
}
}
關於預計算一個週期,然後動畫圖片會出現什麼? –
@thomas上面的代碼示例顯示216個1000x1000像素的幀。計算幀使用每個像素4個字節。這是864 MB。我已經嘗試過了,現在我特意避開它。 – dln385
不要預先計算所有的幀,只需做三個支架:3 * 216 * 216 =〜140K – trashgod