0

I'm working with a 16bit grayscale image:

BufferedImage bufferedImage = new BufferedImage(320, 240, BufferedImage.TYPE_USHORT_GRAY);

I'm able to edit that image by grabbing a reference to its underlying storage. The data is stored in a linear array, in row major order:

short[] data = ((DataBufferUShort)bufferedImage.getRaster().getDataBuffer()).getData();

However, if bufferedImage has been rendered to any screen, editing data no longer has any effect.; I can edit the data before its displayed on the screen, but after displaying it I can no longer change it.

I've of course tried repainting the AWT control -- it didn't update with the new pixel data. I've even tried getDataElements & setDataElements. Nothing seems to work, after the image has been displayed.

Mr. Smith
  • 4,288
  • 7
  • 40
  • 82

1 Answers1

1

I suspect there's something wrong with the way you're painting your image to the screen.

Here's some minimal code that demonstrates what you're doing should work:

public class Test {
    public static void main(String[] args) throws InterruptedException, InvocationTargetException {
        JFrame frame = new JFrame("Image Test");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_USHORT_GRAY);
        ImageComponent component = new ImageComponent(image);
        frame.add(component);
        frame.pack();
        frame.setVisible(true);

        short gray = 0;
        short[] data = ((DataBufferUShort) image.getRaster().getDataBuffer()).getData();
        while (true) {
            for (int i = 0; i < data.length; i++) {
                data[i] = gray;
            }
            Thread.sleep(20);
            gray += 1000;
            component.repaint();
        }
    }

    static class ImageComponent extends JComponent {
        private BufferedImage image;

        public ImageComponent(BufferedImage image) {
            this.image = image;
            this.setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
        }

        @Override
        protected void paintComponent(Graphics g) {
            g.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
        }
    }
}
teppic
  • 7,051
  • 1
  • 29
  • 35
  • 1. You really should be calling `super.paintComponent`, as the component might be larger then it's preferred size; 2. You should override `getPreferredSize` over `setPreferredSize` as it prevents the possibility of other elements changing it; 3. The `ImageObserver` for `Graphics#drawImage` should be `this`; 4. While only an example, modifying the `BufferedImage` which is shared between two threads is a bad idea and worth noting – MadProgrammer Oct 08 '17 at 21:30
  • @MadProgrammer: according to the [graphics tutorial](https://docs.oracle.com/javase/tutorial/2d/images/drawimage.html) the image observer isn't needed when rendering a `BufferedImage`. – teppic Oct 09 '17 at 00:54
  • This is true - but it's a good habit to use - because you won't always know that ;) – MadProgrammer Oct 09 '17 at 00:57