Search code examples
javagame-engine

Drawing BufferedImage to JFrame causes NullPointerException Even when the image and graphics are initialized


So I'm writing a 2d game engine, and right now, I'm trying to get a simple Chunk to render, but when I do, I get a blank window, and the following comes up on my console:

javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at sfortress.graphics.image.TileIcon.<init>(TileIcon.java:31)
at sfortress.game.tile.Tiles.init(Tiles.java:15)
at sfortress.SFortress.init(SFortress.java:28)
at sfortress.SFortress.main(SFortress.java:31)
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at sfortress.graphics.image.TileIcon.<init>(TileIcon.java:31)
at sfortress.game.tile.Tiles.init(Tiles.java:21)
at sfortress.SFortress.init(SFortress.java:28)
at sfortress.SFortress.main(SFortress.java:31)
TILES: 2
Initializing 16x16 Chunk...     [ DONE ]
Generating Chunk...      [ OKAY ]
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at sfortress.graphics.image.TileIcon.<init>(TileIcon.java:31)
at sfortress.SFortress.run0(SFortress.java:39)
at sfortress.game.tile.Tiles.init(Tiles.java:28)
at sfortress.SFortress.init(SFortress.java:28)
at sfortress.SFortress.main(SFortress.java:31)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at japi.window.panel.ImagePanel.paintComponent(ImagePanel.java:55)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at japi.window.panel.ImagePanel.paintComponent(ImagePanel.java:55)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at japi.window.panel.ImagePanel.paintComponent(ImagePanel.java:55)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

I've re-written my code 8 or 9 (I lost count) times in the last week and a half, but I've only been able to render anything by calling ImageIO.read(File file) directly in the draw method (which would be very inefficient once I actually get the engine working) If anyone knows how to solve this, I would REALLY appreciate it. All involved code below:

SFortress.java

package sfortress;

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.ImageIO;
import java.io.File;

import util.OS;

import japi.window.panel.ImagePanel;

import sfortress.*;
import sfortress.game.*;
import sfortress.game.character.*;
import sfortress.game.data.positioning.*;
import sfortress.game.tile.*;
import sfortress.graphics.image.TileIcon;
import sfortress.world.chunk.*;

public class SFortress {
  public static String sPath;

  public static void init() {
    sPath = System.getProperty("user.dir");
    OS.init();
    Game.init();
    Tiles.init();
  }
  public static void main(String[] args) {
    init();
  }
  public static void run0() {
    JFrame frame = new JFrame();
    ImagePanel panel = new ImagePanel();
    Chunk chunk = new Chunk(16,new Position("chunk",0,0,0)).generate();
    BufferedImage image = null;
    image = chunk.draw();
    panel.setImage(image);

    frame.add(panel);
    frame.setSize(512,512);
    frame.setResizable(false);
    frame.setLocationRelativeTo(null);
    frame.setTitle("Chunk Rendering Test v5");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }

  public static String path(String input) {
    return ("." + sPath + "." + input).replace("..",".").replace('.',OS.dirChar);
  }
}

Chunk.java

package sfortress.world.chunk;

import java.awt.*;
import java.awt.image.BufferedImage;

import sfortress.game.Game;
import sfortress.game.data.positioning.*;
import sfortress.world.chunk.TileSlot;

import static sfortress.game.Game.world;

public class Chunk {
  public TileSlot[][][] slots;
  public int scale;
  public Position loc;

  public Chunk(int scale,Position loc) {
    System.out.print("Initializing " + scale + 'x' + scale + " Chunk...");
    this.scale = scale;
    this.loc = loc;
    this.slots = new TileSlot[scale][scale][scale];
    for (int x = 0; x < scale; x++) {
      for (int y = 0; y < scale; y++) {
        for (int z = 0; z < scale; z++) {
          slots[x][y][z] = new TileSlot();
        }
      }
    }
    System.out.println("     [ DONE ]");
  }

  /*public void load() {
    new ChunkFile(Game.world.getPath(".chunks.c-x"+loc.x+"_y"+loc.y+"_z"+loc.z+".chunk"),this).load();
  }
  public void unLoad() {
    new ChunkFile(Game.world.getPath(".chunks.c-x"+loc.x+"_y"+loc.y+"_z"+loc.z+".chunk"),this).save();
  }*/

  private Position pgd(int x, int y, int z, Side side) {
    Position pk = null;
    if (side == Side.TOP) {
      pk = new Position("tile",y,x,z);
    } else if (side == Side.BOTTOM) {
      pk = new Position("tile",-y,x,z);
    } else if (side == Side.LEFT) {
      pk = new Position("tile",z,-y,-x);
    } else if (side == Side.RIGHT) {
      pk = new Position("tile",z,y,x);
    } else if (side == Side.FRONT) {
      pk = new Position("tile",z,x,-y);
    } else if (side == Side.BACK) {
      pk = new Position("tile",z,-x,y);
    }
    return pk;
  }
  public BufferedImage draw() {
    Side side = Game.viewerSide;
    Position pos = Game.viewerPosition;
    Position kloc = loc.convert("pixel");
    int px = Game.spriteScale * scale;
    BufferedImage image = new BufferedImage(px,px,BufferedImage.TYPE_INT_ARGB);
    Graphics g = image.createGraphics();
    for (int x = 0; x < scale; x++) {
      for (int y = 0; y < scale; y++) {
        for (int z = 0; z < scale; z++) {
          Position p = pgd(x,y,z,side);
          g.drawImage(slots[p.x][p.y][p.z].getTile().draw(side)[0],0,0,null);
        }
      }
    }
    g.dispose();
    return image;
  }

  public Chunk generate() {
    System.out.print("Generating Chunk...");
    for (int x = 0; x < scale; x++) {
      for (int y = 0; y < scale; y++) {
        for (int z = 0; z < scale; z++) {
          slots[x][y][z].setTile(sfortress.game.tile.Tiles.rand());
        }
      }
    }
    System.out.println("      [ OKAY ]");
    return this;
  }
}

Game.java

package sfortress.game;

import sfortress.game.data.positioning.*;
import sfortress.world.World;

public final class Game {
  public static World world;
  public static int spriteScale;
  public static Position viewerPosition;
  public static Side viewerSide;

  public static void init() {
    spriteScale = 16;
    viewerPosition = new Position("pixel",127,127,255);
    viewerSide = Side.TOP;
    world = new World("Unnamed",12,16);
  }
}

TileIcon.java

package sfortress.graphics.image;

import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

import sfortress.SFortress;
import sfortress.game.data.positioning.*;
import sfortress.graphics.image.GImage;

public class TileIcon extends GImage {
  private BufferedImage top;
  private BufferedImage bottom;
  private BufferedImage right;
  private BufferedImage left;
  private BufferedImage front;
  private BufferedImage back;

  public float glow;

  public TileIcon() {}
  public TileIcon(String name) {
    String p = SFortress.path(".data.sprites.name.");
    File fTop = new File(p + "top.png");
    File fBot = new File(p + "bottom.png");
    File fRig = new File(p + "right.png");
    File fLef = new File(p + "left.png");
    File fFro = new File(p + "front.png");
    File fBac = new File(p + "back.png");
    try {
      front = ImageIO.read(fFro);
      back = ImageIO.read(fBac);
      left = ImageIO.read(fLef);
      right = ImageIO.read(fRig);
      top = ImageIO.read(fTop);
      bottom = ImageIO.read(fBot);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void tick() {}
  public BufferedImage[] draw(Side side) {
    BufferedImage image = null;
    switch (side.toString().toLowerCase()) {
      case "bottom":
        image = bottom;
        break;
      case "right":
        image = right;
        break;
      case "left":
        image = left;
        break;
      case "front":
        image = front;
        break;
      case "back":
        image = back;
        break;
      default:
        image = top;
        break;
    }
    return new BufferedImage[] {image,sfortress.graphics.Renderer.makeGlowLayer(image)};
  }
}

Tiles.java

package sfortress.game.tile;

import java.util.*;

import sfortress.game.tile.*;
import sfortress.graphics.image.TileIcon;

public class Tiles {
  public static ArrayList<Tile> tiles = new ArrayList<Tile>();

  public static void init() {
    SolidTile stone = new SolidTile();
    stone.name = "Stone";
    stone.id = "tiles.stone";
    stone.icon = new TileIcon("tiles.stone");
    stone.meltingPoint = 3000f;
    stone.fluidForm = null;
    SolidTile sandstone = new SolidTile();
    sandstone.name = "Sandstone";
    sandstone.id = "tiles.sandstone";
    sandstone.icon = new TileIcon("tiles.sandstone");
    sandstone.meltingPoint = 3000f;
    sandstone.fluidForm = null;
    tiles.add(stone);
    tiles.add(sandstone);
    System.out.println("TILES: " + tiles.size());

    sfortress.SFortress.run0();
  }

  public static Tile rand() {
    Random random = new Random();
    int index = random.nextInt(tiles.size()-1);
    return tiles.get(index);
  }
}

VoidIcon.java

package sfortress.graphics.image;

import java.awt.image.BufferedImage;

import sfortress.game.Game;

public class VoidIcon extends TileIcon {
  public void tick() {
    return;
  }
  public BufferedImage[] draw() {
    return new BufferedImage[] {new BufferedImage(Game.spriteScale,Game.spriteScale,BufferedImage.TYPE_INT_ARGB),null};
  }
}

GImage.java

package sfortress.graphics.image;

import java.awt.image.BufferedImage;
import sfortress.game.data.positioning.*;

public abstract class GImage {
  public float glow;

  public abstract void tick();
  public abstract BufferedImage[] draw(Side side);
}

Tile.java

package sfortress.game.tile;

import java.awt.image.BufferedImage;

import sfortress.game.data.positioning.*;
import sfortress.graphics.image.TileIcon;
import sfortress.world.chunk.TileSlot;

public abstract class Tile {
  public String name;
  public String id;
  public TileIcon icon;
  public float density;

  protected TileSlot slot;

  public abstract Tile fabricate();

  public void tick() {
    icon.tick();
  }
  public void destroy() {
    return;
  }
  public BufferedImage[] draw(Side side) {
    return icon.draw(side);
  }
  public void set(TileSlot slot) {
    this.slot = slot;
  }
}

ImagePanel.java

package japi.window.panel;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.*;

import java.io.File;
import java.io.IOException;

import javax.swing.*;
import javax.imageio.ImageIO;

public class ImagePanel extends JPanel {
  private BufferedImage image;

  public ImagePanel() {
  }
  public ImagePanel(String path) {
    try {
      setImage(ImageIO.read(new File(path)));
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
  public ImagePanel(BufferedImage image) {
    setImage(image);
  }

  public void setImage(String image) {
    try {
      this.image = ImageIO.read(new File(image));
    } catch (Exception e) {
      e.printStackTrace();
    }
    repaint();
  }
  public void setImage(BufferedImage image) {
    this.image = image;
    repaint();
  }

  @Override
  public int getWidth() {
    return 512;
  }

  @Override
  public int getHeight() {
    return 512;
  }

  @Override
  protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.drawImage(image.getScaledInstance(this.getWidth(),this.getHeight(),Image.SCALE_SMOOTH), 0, 0, null);
  }
}

Also, please tell me If I'm missing a file that you think might help to solve this (I have 36 files in total).


Solution

  • You problems are caused by stuff like this:

    try {
      image = chunk.draw();
    } catch (Exception e) {
      e.printStackTrace();
    }
    

    You are catching exceptions and then ... basically ... ignoring them. It is called exception squashing and it is a bad idea.

    In this particular case, when the exception is squashed, you won't assign anything to image. If image was null to start with, it will remain null. If your code then tries to use it (without checking for null) then an NPE is the most likely outcome.


    If anyone knows how to solve this, I would REALLY appreciate it.

    Solution:

    1. Get rid of all cases of exception squashing in your code. If you can't handle the checked exceptions, let them propagate ... and crash the application.

    2. Once your application is crashing due to the unexpected exceptions, find what causes them, and fix that.


    In this case, it looks like you have a problem with image loading. A comment suggests that it might be that you are using an image format that Java does not understand.

    You commented:

    alright, considering that all the images loaded in Windows Photo Viewer, I'd say they're not corrupted

    That's beside the point. The suggestion was that the images are in the wrong format, not that they are corrupted.


    After a bit more digging, here is the library code that throws the initial exception with that message:

    public static BufferedImage  read(File input) throws IOException {
        if (input == null) {
            throw new IllegalArgumentException("input == null!");
        }
        if (!input.canRead()) {
            throw new IIOException("Can't read input file!");
        }
        ....
    }
    

    This means that the problem is that either the pathname that your application is using for the image file is wrong (i.e. it cannot be resolved), or there is a file or directory permission problem. Note that at this point the image reader has not attempted to read the file. It is just applying some tests prior to attempting to open it.

    (And based on your final comments, this was the problem.)