Slick PNGDecoder Error - java.lang.UnsupportedOper

2019-09-20 18:19发布

问题:

I'm making a simple little Galaga clone in Java with the Slick library. Unfortunately, I've run into an issue in which I get this error, followed by the game closing:

Mon May 12 08:54:32 EDT 2014 WARN:class org.newdawn.slick.opengl.PNGImageData failed to
read the data
java.lang.UnsupportedOperationException: Unsupported format for this image
at org.newdawn.slick.opengl.PNGDecoder.decode(PNGDecoder.java:272)
at org.newdawn.slick.opengl.PNGImageData.loadImage(PNGImageData.java:97)
    at org.newdawn.slick.opengl.CompositeImageData.loadImage(CompositeImageData.
    java:62)
    at org.newdawn.slick.opengl.CompositeImageData.loadImage(CompositeImageData.
    java:43)
    at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.
    java:292)
    at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.
    java:254)
at org.newdawn.slick.opengl.InternalTextureLoader.getTexture(InternalTextureLoader.
    java:187)
at org.newdawn.slick.Image.<init>(Image.java:192)
at org.newdawn.slick.Image.<init>(Image.java:166)
at org.newdawn.slick.Image.<init>(Image.java:154)
at org.newdawn.slick.Image.<init>(Image.java:132)
at com.othinolis.danmaku.Play.init(Play.java:21)
at com.othinolis.danmaku.Game.initStatesList(Game.java:20)
at org.newdawn.slick.state.StateBasedGame.init(StateBasedGame.java:164)
at org.newdawn.slick.AppGameContainer.setup(AppGameContainer.java:393)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:317)
at com.othinolis.danmaku.Game.main(Game.java:29)
Mon May 12 08:54:35 EDT 2014 ERROR:null
java.lang.NullPointerException
at com.othinolis.danmaku.Play.render(Play.java:32)
at org.newdawn.slick.state.StateBasedGame.render(StateBasedGame.java:199)
at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:688)
at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:411)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:321)
at com.othinolis.danmaku.Game.main(Game.java:29)
Mon May 12 08:54:35 EDT 2014 ERROR:Game.render() failure - check the game code.
org.newdawn.slick.SlickException: Game.render() failure - check the game code.
at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:691)
at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:411)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:321)
at com.othinolis.danmaku.Game.main(Game.java:29)

This happens after I attempt to move states from the main menu and into the game proper, when PNGs are first loaded. All of my resources are PNGs. Here's my other class files:

Game.java:

package com.othinolis.danmaku;

import org.newdawn.slick.*;
import org.newdawn.slick.state.*;

public class Game extends StateBasedGame{

   public static final String gamename = "Danmaku Courage";
   public static final int menu = 0;
   public static final int play = 1;

   public Game(String gamename){
      super(gamename);
      this.addState(new Menu(menu));
      this.addState(new Play(play));
   }

   public void initStatesList(GameContainer gc) throws SlickException{
      this.getState(menu).init(gc, this);
      this.getState(play).init(gc, this);
      this.enterState(menu);
   }

   public static void main(String[] args) {
      AppGameContainer appgc;
      try{
         appgc = new AppGameContainer(new Game(gamename));
         appgc.setDisplayMode(600, 600, false);
         appgc.start();
      }catch(SlickException e){
         e.printStackTrace();
      }
   }

}

Menu.java (state 0, runs with no issues):

package com.othinolis.danmaku;

import org.lwjgl.input.Mouse;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;

public class Menu extends BasicGameState{

   Image playNow;
   Image exitGame;

   public Menu(int state){
   }

   public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
      playNow = new Image("res/playButton.png");
      exitGame = new Image("res/exitGame.png");
   }

   public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
      g.drawString("Danmaku Courage", 230, 50);
      g.drawString("mousex: " + Mouse.getX() + " mousey: " + Mouse.getY(), 300, 400);
      playNow.draw(200,100);
      exitGame.draw(200,200);
   }

   public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
      int posX = Mouse.getX();
      int posY = Mouse.getY();
      //play now button
      if((posX>237 && posX<364)&&(posY>425 && posY<460)){
         if(Mouse.isButtonDown(0)){
            sbg.enterState(1);
         }
      }

      //exit game
      if((posX>254 && posX<335)&&(posY>338 && posY<361)){
         if(Mouse.isButtonDown(0)){
            System.exit(0);
         }
      }
   }

   public int getID(){
      return 0;
   }
}

and Play.java (moving between Menu and Play is where the issue hits. The numbers for collisions with the side of the screen and what have you may not be exact.):

package com.othinolis.danmaku;

import org.newdawn.slick.*;
import org.newdawn.slick.state.*;

public class Play extends BasicGameState{

   Animation player, movingLeft, movingRight; //2 animations, player will be set to one
   Image worldMap;
   boolean quit = false;
   int[] duration = {200,200}; //length of the frame
   float playerPositionX = 0; //player will start at coordinates 0,0
   float playerPositionY = 0;
   float shiftX = buckyPositionX + 320; //this will shift the screen so bucky appears in middle
   float shiftY = buckyPositionY + 160; //half the length and half the width of the screen

   public Play(int state){
   }

   public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
      worldMap = new Image("res/background.png");
      Image[] walkLeft = {new Image("res/player.png"), new Image("res/player.png")};
      Image[] walkRight = {new Image("res/player.png"), new Image("res/player.png")};

      movingLeft = new Animation(walkLeft, duration, false);
      movingRight = new Animation(walkRight, duration, false);
      player = movingDown; //by default as soon as game loads, player will be facing down
   }

   public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
      worldMap.draw(buckyPositionX,buckyPositionY); //draw the map at 0,0 to start
      player.draw(shiftX,shiftY); //draw player at 320, 160 (center of the screen)
      g.drawString("player's X: "+playerPositionX+"\nplayer's Y: "+playerPositionY, 400, 20); //indicator to see where player is

      //when they press escape
      if(quit==true){
         g.drawString("Resume (R)", 250, 100);
         g.drawString("Main Menu (M)", 250, 150);
         g.drawString("Quit Game (Q)", 250, 200);
         if(quit==false){
            g.clear();
         }
      }
   }

   public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
      Input input = gc.getInput();
      if(input.isKeyDown(Input.KEY_LEFT)){
         player = movingLeft;
         playerPositionX += delta * .1f;
         if(playerPositionX>324){
            playerPositionX -= delta * .1f;
         }
      }
      if(input.isKeyDown(Input.KEY_RIGHT)){
         player = movingRight;
         playerPositionX -= delta * .1f;
         if(playerPositionX<-840){
            playerPositionX += delta * .1f;
         }
      }

      //escape
      if(input.isKeyDown(Input.KEY_ESCAPE)){
         quit = true;
      }      

      //when they hit escape
      if(quit==true){
         if(input.isKeyDown(Input.KEY_R)){
            quit = false;
         }
         if(input.isKeyDown(Input.KEY_M)){
            sbg.enterState(0);
            try{
               Thread.sleep(250);
            }catch(InterruptedException e){
               e.printStackTrace();
            }
         }
         if(input.isKeyDown(Input.KEY_Q)){
            System.exit(0);
         }
      }
   }

   public int getID(){
      return 1;
   }
}

What I know of slick has come from the several Forum posts I've read about issues like this one, (none of them had the exact issue nor the solution, of course) and Bucky's Slick tutorials that are here. If you'd like to download the project so you can import it and see if you can help me, I've thrown it onto Dropbox here.

回答1:

That's way too much code for anyone to read or debug. But regarding the actual problem: AFAIK, the Slick PNG loader only supports very few PNG file types (somehow related to performance when reading them, but that may be a myth...). It should be possible to load the image with something like

// "Image" here refers to a Slick Image, and NOT to java.awt.Image!
private static Image loadImage(String path) throws IOException
{
    BufferedImage bufferedImage = ImageIO.read(new File(path));
    Texture texture = BufferedImageUtil.getTexture("", bufferedImage);
    Image image = new Img(texture.getImageWidth(), texture.getImageHeight());
    image.setTexture(texture); 
    return image;
}


回答2:

I had the same error when loading PNG Image using Slick-util library. The only thing I did was opening PNG file to Paint (Yes, Windows image editor) and saving as new PNG image. The problem was probably connected with type of PNG image (PNG Basics) and Paint saves it as some other type.

My function looked like below (took from Loading Images for LWJGL):

public int loadTexture(String fileName) {
Texture texture = null;
try {                
    texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("res/" + fileName + ".png"));

    GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
    GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER,
                        GL11.GL_LINEAR_MIPMAP_LINEAR);
    GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, 0f);
} catch (Exception e) {
    e.printStackTrace();
    System.err.println("Tried to load texture " + fileName + ".png , didn't work");
    System.exit(-1);
}
    textures.add(texture.getTextureID());
    return texture.getTextureID();
}