简体   繁体   English

image.setRGB()无法正常工作

[英]image.setRGB() not working as intended

I'm trying to make my own, very inefficient "image copier". 我正在尝试制作自己的效率很低的“图像复印机”。 I'm doing it by reading the pixels from the original image on to an array and then resetting those same pixels in my default BufferedImage . 我这样做是通过将原始图像中的像素读取到数组上,然后在default BufferedImage重置相同的像素来default BufferedImage And then repaint the frame. 然后重新粉刷框架。 Row by row. 一行一行。

I'm trying to repaint the frame every after each row of pixels has been stored in the array. 我试图在每行像素存储在数组中后重新绘制框架。 But the frame only gets updated once; 但是框架只更新一次; when it finishes storing the pixels. 完成存储像素后。

My code is all over the place, and I'm probably doing a lot of stuff wrong. 我的代码到处都是,我可能做错了很多东西。 This is for an assignment and I've been going at it for a while now and would really appreciate some help. 这是一项任务,我已经花了一段时间了,非常感谢您的帮助。

Here is my code: 这是我的代码:

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);
   }
}

Here is the picture I'm reading the pixels from: 这是我从中读取像素的图片:

这是原始图片

and this is how it's coming out: 它是这样出来的:

在此处输入图片说明

The program doesn't give any errors or anything. 该程序没有给出任何错误或任何信息。

The basic answer to your question is, you're blocking the Event Dispatching Thread. 您问题的基本答案是,您正在阻止事件调度线程。

Swing is both single threaded and NOT thread safe. 秋千既是单线程的,也不是线程安全的。 This means you can't run long running or blocking operations from within the EDT AND you should't not update the UI or some state the UI depends on from outside the EDT. 这意味着您不能在EDT内部运行长时间运行或阻止的操作,也不应更新UI或UI依赖于EDT外部的某些状态。

I recommend that you start by having a look at Concurrency in Swing . 我建议您先看看Swing中的并发

This leaves with three basic options: 剩下三个基本选项:

  1. Use another Thread . 使用另一个Thread This is problematic as you need to ensure that any state that the UI relies on is only updated from within the context of the EDT 这是有问题的,因为您需要确保仅从EDT上下文中更新UI依赖的任何状态
  2. Use a SwingWorker . 使用SwingWorker This is basically the previous option, but with built in management which allows you to publish updates which are process 'ed on the EDT 这基本上是以前的选项,但是具有内置的管理功能,该功能使您可以publish在EDT上process的更新。
  3. Use a Swing Timer . 使用Swing Timer In your case, this is probably not the best solution, but it is the simplest. 在您的情况下,这可能不是最佳解决方案,但这是最简单的解决方案。

For example 例如

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);
        }

    }
}

The Thread.sleep in the SwingWorker is intended to do two things: SwingWorkerThread.sleep旨在做两件事:

  1. Give time for the EDT to process the results from the process call and 留出时间让EDT处理process调用中的结果,然后
  2. Slow down the worker so that the results can be updated on the UI. 降低工作程序的速度,以便可以在UI上更新结果。

In my testing without it, the image was pretty much updated instantly. 在没有它的测试中,图像几乎立即被更新。

I also recommend you take the time to better understand the paint process in Swing, start by having a look at: 我还建议您花些时间更好地了解Swing中的绘制过程,首先看一下:

The scaling mechanism you were using (and the one I've implemented) aren't the best solutions. 您使用的缩放机制(以及我已经实现的缩放机制)不是最佳解决方案。 I recommend having look at: 我建议看一下:

for some better ideas. 一些更好的想法。

You made a couple of mistakes, the first one is using 0 as scansize which should be the width of the image, also in the same line you should use the width and height instead of i and j . 您犯了两个错误,第一个错误是使用0作为scansize ,它应该是图像的宽度,并且在同一行中,您应该使用width和height而不是ij

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

There is one other mistake which I will let you find on your own, it should be obvious after you see the image with the above fixed line. 我会让您自己发现另一个错误,当您看到带有上述固定线的图像后,这应该很明显。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM