image.setRGB() 未按预期工作

image.setRGB() not working as intended

我正在尝试自己制作,效率很低"image copier"。我通过将原始图像中的像素读取到数组然后在我的 default BufferedImage 中重置这些相同的像素来做到这一点。然后重新绘制框架。一行一行。

我试图在每行像素存储在数组中后重新绘制帧。但是框架只会更新一次;当它完成存储像素时。

我的代码到处都是,我可能做错了很多事情。这是一项作业,我已经做了一段时间了,非常感谢您的帮助。

这是我的代码:

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class pixelReloc extends JComponent {
   static BufferedImage image,newImg;
   static JFrame frame;
   public void initialize() {
      int width = getSize().width;
      int height = getSize().height;
      int pixels[];
      int index = 0;
      int j=0,i=0;
      File f = new File("/path/to/file/images/shrek4life.jpg");
      try{
          image = ImageIO.read(f);
      }catch(IOException e){}
          System.out.println("checkpoint 1");
      image = createResizedCopy(image,500,500,true);
      newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
      pixels = new int[(image.getWidth()) * (image.getHeight())];
      System.out.println("checkpoint 2");
      for(i= 0; i < newImg.getWidth(); i++){
          for(j = 0; j < newImg.getHeight(); j++){
              //get the rgb color of the old image
              Color c = new Color(image.getRGB(i, j));
              int r = c.getRed();
              int g = c.getGreen();
              int b = c.getBlue();
              pixels[index++] = (r<<16) | (g<<8) | b;
         }
         newImg.setRGB(0, 0, i, j, pixels, 0, 0);
         frame.getContentPane().validate();
         frame.getContentPane().repaint();
      }
      System.out.println("checkpoint 4");
      //image.setRGB(0, 0, width, height, data, 0, width);
   }
   public BufferedImage createResizedCopy(BufferedImage originalImage,
            int scaledWidth, int scaledHeight,
            boolean preserveAlpha)
    {
        System.out.println("resizing...");
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha) {
            g.setComposite(AlphaComposite.Src);
        }
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
        g.dispose();
        return scaledBI;
    }
   public void paint(Graphics g) {
      if (image == null)
      initialize();
      g.drawImage(newImg, 0, 0, this);
   }
   public static void main(String[] args) {
      frame = new JFrame("P I X E L S");
      frame.getContentPane().add(new pixelReloc ());
      frame.setSize(500, 500);
      frame.setLocation(100, 100);
      frame.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
            System.exit(0);
         }
      });
      frame.setVisible(true);
   }
}

这是我正在读取像素的图片:

结果是这样的:

程序没有给出任何错误或任何东西。

你的问题的基本答案是,你阻塞了事件调度线程。

Swing 是单线程的并且不是线程安全的。这意味着你不能 运行 long 运行ning 或从 EDT 中阻塞操作并且你不应该更新 UI 或 UI 依赖于的某些状态在美国东部时间之外。

我建议您先看看 Concurrency in Swing

剩下三个基本选项:

  1. 使用另一个 Thread。这是有问题的,因为您需要确保 UI 依赖的任何状态仅从 EDT
  2. 的上下文中更新
  3. 使用 SwingWorker。这基本上是以前的选项,但内置管理允许您 publish 更新,这些更新在 EDT
  4. process
  5. 使用秋千 Timer。对于您的情况,这可能不是最佳解决方案,但却是最简单的。

例如

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new PixelReloc());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class Pixel {

        private int x, y;
        private int color;

        public Pixel(int x, int y, int color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public int getX() {
            return x;
        }

        public int getY() {
            return y;
        }

        public int getColor() {
            return color;
        }

    }

    public class PixelReloc extends JComponent {

        private BufferedImage image;
        private BufferedImage newImg;

        public PixelReloc() {

            SwingWorker<Integer[], List<Pixel>> worker = new SwingWorker<Integer[], List<Pixel>>() {
                Integer pixels[];

                @Override
                protected Integer[] doInBackground() throws Exception {
                    pixels = new Integer[image.getWidth() * image.getHeight()];
                    int index = 0;
                    List<Pixel> pixies = new ArrayList<>(image.getWidth());
                    for (int y = 0; y < image.getHeight(); y++) {
                        for (int x = 0; x < image.getWidth(); x++) {
                            int color = image.getRGB(x, y);
                            pixels[index++] = color;
                            pixies.add(new Pixel(x, y, color));
                        }
                        publish(new ArrayList<Pixel>(pixies));
                        pixies = new ArrayList<>(image.getWidth());
                        Thread.sleep(100);
                    }
                    return pixels;
                }

                @Override
                protected void process(List<List<Pixel>> chunks) {
                    for (List<Pixel> pixels : chunks) {
                        for (Pixel pixel : pixels) {
                            newImg.setRGB(pixel.getX(), pixel.getY(), pixel.getColor());
                        }
                    }
                    repaint();
                }

            };

            File f = new File("/Volumes/Big Fat Extension/Dropbox/MegaTokyo/chaotic_megatokyo_by_fredrin-d9k84so.jpg");
            try {
                image = ImageIO.read(f);
            } catch (IOException e) {
            }
            System.out.println("checkpoint 1");
            image = createResizedCopy(image, 200, 200, true);
            newImg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
            worker.execute();
            //          pixels = new int[(image.getWidth()) * (image.getHeight())];
            //          System.out.println("checkpoint 2");
            //          for (i = 0; i < newImg.getWidth(); i++) {
            //              for (j = 0; j < newImg.getHeight(); j++) {
            //                  //get the rgb color of the old image
            //                  Color c = new Color(image.getRGB(i, j));
            //                  int r = c.getRed();
            //                  int g = c.getGreen();
            //                  int b = c.getBlue();
            //                  pixels[index++] = (r << 16) | (g << 8) | b;
            //              }
            //          }
            //          System.out.println("checkpoint 4");
            //image.setRGB(0, 0, width, height, data, 0, width);
        }

        @Override
        public Dimension getPreferredSize() {
            return image == null ? new Dimension(200, 200) : new Dimension(image.getWidth(), image.getHeight());
        }

        public BufferedImage createResizedCopy(BufferedImage originalImage,
                        int scaledWidth, int scaledHeight,
                        boolean preserveAlpha) {
            System.out.println("resizing...");
            Image scaled = originalImage.getScaledInstance(scaledWidth, -1, Image.SCALE_SMOOTH);
            BufferedImage scaledBI = new BufferedImage(scaled.getWidth(null), scaled.getHeight(null), BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = scaledBI.createGraphics();
            g.drawImage(scaled, 0, 0, null);
            g.dispose();
            return scaledBI;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(newImg, 0, 0, this);
        }

    }
}

SwingWorker中的Thread.sleep是为了做两件事:

  1. 给 EDT 时间来处理 process 调用的结果,并且
  2. 降低 worker 的速度,以便可以在 UI.
  3. 上更新结果

在我没有使用它的测试中,图像几乎是即时更新的。

我还建议您花时间更好地了解 Swing 中的绘制过程,首先看看:

您使用的缩放机制(以及我已经实施的缩放机制)不是最佳解决方案。我建议看看:

  • Java: maintaining aspect ratio of JPanel background image
  • Quality of Image after resize very low -- Java

一些更好的想法。

你犯了几个错误,第一个是使用 0 作为 scansize 这应该是图像的宽度,同样在同一行你应该使用宽度和高度而不是 ij

newImg.setRGB(0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth());

还有一个错误让你自己找,看到上面固定线的图片应该就很明显了。