I am trying to write a method that can help me declare variables more easily using the method's arguments. I'm very new to java and I'm trying to make a game that would have a decent amount of images and I want to know if there is an easier way to create these BufferedImage Variables.
currently my code looks like this
public class Painter extends JPanel {
BufferedImage sprite = new
BufferedImage(60,60,BufferedImage.TYPE_INT_ARGB);
public void createBufImg() {
try {
sprite = ImageIO.read(new File("Images/SpriteSheet.png"));
System.out.println("File read");
} catch (IOException e) {
System.out.println("Could not read image");
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
createBufImg();
g.drawImage(sprite,20,20,this);
}
}
and I'm looking to see if there is a way to declare the variables so it could be called more like this
sprite = new createBufImg(Images/SpriteSheet.png);
Sure. Make the method take a String (filePath) as a parameter. Set the return type to BufferedImage. Then use that string in the constructor of file.
public BufferedImage createBufImg(String filePath) {
try {
return ImageIO.read(new File(filePath));
} catch (IOException e) {
System.out.println("Could not read image");
}
return null;
}
You can then call the method like this:
sprite = createBufImg("Images/SpriteSheet.png");
Just leave out the new in the createBufImg call, and make it return a BufferedImage that will be created in the method:
public BufferedImage createBufImg(File imagePath) {
try {
return ImageIO.read(imagePath);
} catch (IOException e) {
// handle exception, and either throw an exception or return something appropriate
}
}
...
BufferedImage myImage1 = createBufImage(path1);
BufferedImage myImage2 = createBufImage(path2);
Related
I'm looking for a way to pass a code block to a method, which will then perform actions on other arguments passed to method, take the results of those actions, and pass those results to the code block passed to the method. For clarity:
private static void method1(String filename, int sheetNum) {
runOnSheet(filename, () -> {
doStuffWithStream(FileInputStream fileStream); // Does something with a file stream
doOtherStuffWithStream(FileInputStream fileStream); // Does something else with a file stream
});
}
// Elsewhere
private static void runOnFile(String fileName, Runnable block1) {
try {
fileStream = new FileInputStream(fileName);
} catch (IOException e) {
e.printStackTrace();
}
block1.run(); // I'd like to pass fileStream to this code block. Ideally i could do block1.run(fileStream );
fileStream.close();
}
I want to be able to reuse runOnFile anywhere I need to open a file, run some code on the stream, and close the stream.
What I actually want to do is more complicated, and uses other libraries in addition to FileInputStream, but the structure of what I wish to accomplish is the same.
Thanks for any help!
Java 8+ has a Class called Consumer that can be used for your usecase:
https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html
private static void method1(String filename, int sheetNum) {
runOnFile(filename, (fileStream) -> {
doStuffWithStream(fileStream);
doOtherStuffWithStream(fileStream);
});
}
// Elsewhere
private static void runOnFile(String fileName, Consumer<FileInputStream> block1) {
try {
fileStream = new FileInputStream(fileName);
} catch (IOException e) {
e.printStackTrace();
}
block1.accept(fileStrean);
fileStream.close();
}
EDIT: As suggested by Dimitri using the try-with-resource syntax:
// Elsewhere
private static void runOnFile(String fileName, Consumer<FileInputStream> block1) {
try (FileInputStream fis = new FileInputStream(fileName)) {
block1.accept(fis);
} catch (IOException e) {
e.printStackTrace();
}
}
Try something like this:
private static void method1(String filename, int sheetNum)
{
try ( final FileInputStream fileStream = new FileInputStream(filename))
{
runOnSheet(filename, () ->
{
doStuffWithStream(fileStream); // Does something with a file stream
doOtherStuffWithStream(fileStream); // Does something else with a file stream
});
}
}
What I'm trying to do is create in input box for a game I'm making that displays on-screen with a message such as
"Name: (input would appear here)"
What I did was pass in the message, which object I want my input to go to, and what function will use the variable(such as a function that sets the input to the player's name). Now, I could just access the input variable from the InputBox object, but, in the long run, this will be more efficient. I'm using Method.invoke to pass the function into the object I want with the input string as an argument. Here is my code:
public class InputBox extends Textbox {
public String input = "";
private String out;
private Object obj;
private int lastLastKey = 0;
/**
*
* #param message
* #param cl The object/class where the output variable is.
* #param out The method to run. Only takes the input variable, so use this format: void toRun(String input)
*/
public InputBox(String message, Object obj, String out) {
super(message);
this.out = out;
this.obj = obj;
}
public void tick(Game game){
if (game.input.lastKey != 0 && !game.input.keys[KeyEvent.VK_ENTER]
&& !game.input.keys[KeyEvent.VK_SPACE] && !game.input.keys[KeyEvent.VK_SHIFT] && !game.input.keys[KeyEvent.VK_BACK_SLASH]){
if(game.input.lastKey != lastLastKey) input+=Character.toUpperCase((char) game.input.lastKey);
}else if(game.input.keys[KeyEvent.VK_ENTER] && !input.isEmpty() && !cleared){
Method method = null;
try {
method = obj.getClass().getMethod(out, new Class[]{ String.class, Object.class });
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
try {
method.invoke(obj, new Object[]{ input, obj });
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
cleared = true;
}
lastLastKey = game.input.lastKey;
}
public void render(Graphics g){
if(!cleared){
g.setColor(Color.white);
g.fillRect(10, Display.height-110, Display.width-20, 100);
g.setColor(Color.black);
g.drawRect(10, Display.height-110, Display.width-20, 100);
g.setFont(Game.smallFont);
FontMetrics fm = g.getFontMetrics();
g.drawString(message+" "+input, Display.width/2-fm.stringWidth(message+" "+input)/2, Display.height-50);
}
}
}
Your description for the constructor says that the expected method has a signature of
void toRun(String input) {}
But your reflection code looks for a method with the signature
void toRun(String input, Object o) {}
If you are using Java 8 you can make use of a Consumer and remove all the reflection code:
public class InputBox extends Textbox {
private Consumer<String> out;
public InputBox(String message, Consumer<String> out) {
this.out = out;
...
}
public void tick(Game game){
...
out.apply(input);
...
}
}
Assuming that your Player class has a method setName(String) like this:
public class Player {
public void setName(String name) {
}
}
you can create an InputBox with a method reference
public InputBox createNameInputBox(Player p) {
return new InputBox("Name: ", p::setName);
}
or with a lambda expression
public InputBox createAlternateNameInputBox(Player p) {
return new InputBox("Name: ", name -> p.setName(name));
}
To read more about lambda expressions and method references see the Java Tutorial series (https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html). For a discussion of whether you should use method references or lambda expressions see https://stackoverflow.com/a/24493905/5646962
I am trying to make an application to scan documents from a scanner and i have found an application based on the mmscomputing free library that i found in github https://github.com/ashishkataria/browserWebScanning
It shows a panel from where you can choose a scanner from a list of available ones and scan the document.
public void getScan()
{
try
{
scanner.acquire();
}
catch (ScannerIOException e1)
{
IJ.showMessage("Access denied! \nTwain dialog maybe already opened!");
e1.printStackTrace();
}
}
public Image getImage()
{
Image image = imp.getImage();
return image;
}
public void update(ScannerIOMetadata.Type type, ScannerIOMetadata metadata) {
if (type.equals(ScannerIOMetadata.ACQUIRED))
{
if(imp!=null)
{
jContentPane.remove(ipanel);
jContentPane.remove(cpanel);
jContentPane.remove(crpdpanel);
}
imp = new ImagePlus("Scan", metadata.getImage());
im = imp.getImage();
imagePanel = new ImagePanel(im);
imagePanel.updateUI();
imagePanel.repaint();
imagePanel.revalidate();
ClipMover mover = new ClipMover(imagePanel);
imagePanel.addMouseListener(mover);
imagePanel.addMouseMotionListener(mover);
ipanel = imagePanel.getPanel();
ipanel.setBorder(new LineBorder(Color.blue,1));
ipanel.setBorder(BorderFactory.createTitledBorder("Scanned Image"));
ipanel.setBounds(0, 30,600, 600);
ipanel.repaint();
ipanel.revalidate();
ipanel.updateUI();
jContentPane.add(ipanel);
jContentPane.getRootPane().revalidate();
jContentPane.updateUI();
cpanel = imagePanel.getUIPanel();
cpanel.setBounds(700, 30,300, 150);
cpanel.repaint();
cpanel.setBorder(new LineBorder(Color.blue,1));
cpanel.setBorder(BorderFactory.createTitledBorder("Cropping Image"));
cpanel.setBackground(Color.white);
jContentPane.add(cpanel);
jContentPane.repaint();
jContentPane.revalidate();
metadata.setImage(null);
try {
new uk.co.mmscomputing.concurrent.Semaphore(0, true).tryAcquire(2000, null);
} catch (InterruptedException e) {
IJ.error(e.getMessage());
}
}
else if (type.equals(ScannerIOMetadata.NEGOTIATE)) {
ScannerDevice device = metadata.getDevice();
try {
device.setResolution(100);
} catch (ScannerIOException e) {
IJ.error(e.getMessage());
}
try{
device.setShowUserInterface(true);
device.setResolution(100); }catch(Exception e){
e.printStackTrace(); }
}
else if (type.equals(ScannerIOMetadata.STATECHANGE)) {
System.out.println("Scanner State "+metadata.getStateStr());
System.out.println("Scanner State "+metadata.getState());
if ((metadata.getLastState() == 3) && (metadata.getState() == 4)){}
} else if (type.equals(ScannerIOMetadata.EXCEPTION)) {
IJ.error(metadata.getException().toString());
}
}
I am trying to make it handle multiple documents and save in a pdf file, this library handles only 1 document right now.
i want to know how can i save the images in a buffer or something else and rescan until the user is done .
and is there a function that can save those images in a pdf file ?
I created an application that basically uses robot to get and image in the client and sends to the server every few seconds, so I can watch what's going on on another PC. The problem seems to be that it keeps saving the image in an array or something, because after a few seconds, it crashs. I just recieve the image and write it on the screen when I do. Yet, after a while, it gives me an OutOfMemory. Does anyone have a hint about what may be causing it?
Here are the code snippets that were requested:
server:
private class Conexao extends Thread {
public static final int PORTA = 12000;
public ObjectOutputStream out;
public ObjectInputStream in;
public Image image;
private boolean fim;
public Conexao(String ip) throws IOException {
try {
Socket socket = new Socket(ip, Conexao.PORTA);
this.out = new ObjectOutputStream(socket.getOutputStream());
this.in = new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
throw e;
}
}
public void encerrar() {
this.fim = true;
}
#Override
public void run() {
this.fim = false;
while (!this.fim) {
Mensagem mensagem = null;
try {
mensagem = ((Mensagem) in.readObject());
} catch (IOException | ClassNotFoundException e) {
}
if (mensagem != null) {
this.image = mensagem.getImage();
Cliente.this.painel.repaint();
}
}
}
}
client:
private static class Conexao extends Thread {
private static Image CURSOR;
static {
try {
CURSOR = ImageIO.read(new File("images\\mouse.png"));
} catch (IOException e) {
CURSOR = null;
}
}
private ObjectOutputStream out;
private ObjectInputStream in;
public Conexao() throws IOException {
try {
ServerSocket serverSocket = new ServerSocket(Servidor.PORTA, 1);
Socket socket = serverSocket.accept();
this.out = new ObjectOutputStream(socket.getOutputStream());
this.in = new ObjectInputStream(socket.getInputStream());
} catch (IOException e) {
throw e;
}
}
#Override
public void run() {
try {
Robot robot = new Robot();
for (;;)
try {
Thread.sleep(10);
Point p = MouseInfo.getPointerInfo().getLocation();
BufferedImage img = robot.createScreenCapture(new Rectangle(0, 0, Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height));
if (Conexao.CURSOR != null) {
img.getGraphics().drawImage(CURSOR, p.x, p.y, null);
} else {
Graphics2D g = (Graphics2D) img.getGraphics();
g.setColor(Color.WHITE);
g.fillOval(p.x - 5, p.y - 5, 10, 10);
g.setStroke(new BasicStroke(2));
g.setColor(Color.BLACK);
g.drawOval(p.x - 5, p.y - 5, 10, 10);
g.dispose();
}
this.out.writeObject(new Mensagem(img, p));
this.out.flush();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
} catch (AWTException e) {
}
}
}
The only concrete hint I can offer without seeing your code is to use a memory profiler, such as VisualVM or YourKit.
Something somewhere is keeping references to objects that it probably shouldn't.
Try calling this.out.reset(); after this.out.flush();.
This seems to be an issue with ObjectOutputStream, which (according to the Serialization FAQ and this site) keeps a cache of all objects written to it so that repeated objects can be optimized into cache references. This can also cause problems when a value in the object changes before the object is resent, but the cached object retains the old value. In both cases, calling reset() will fix the issue. Unfortunately, none of this is explained in the class documentation.
The OutOfMemory is caused by insufficient heap space.
Some actions you can try:
Make sure you have a good size of heap space available when you run the application. (-Xmx128M on the java command line where 128 is replaced by the number of megabytes you want to asign)
Release all references (by letting the variables go out of scope or by explicitly setting object variables to null) to objects you no longer need after sending a picture.
If that doesn't help try to reuse objects rather than creating new ones.
Without seeing any code, you are most likely populating a byte[] or ByteArrayOutputStream that is class or instance scoped. You should be writing the content received to a file and then accessing it as necessary. This would mean removing the reference to the content (by having it go out of scope) whenever you switch to the new image.
If you could provide more detail as to how your application works, others should be able to pinpoint the issue.
I'm creating a basic game, and I can load images fine. Now, I'm trying to load sounds but I keep getting NullPointerExceptions. I'm 100% sure the path is correct, I've tried loading more then one sounds and I always get this error. I've only been able to use it once.
Here is my sound bank:
public class SoundBank {
public static Audio oggEffect;
public SoundBank () {
try {
oggEffect = AudioLoader.getAudio("OGG", ResourceLoader.getResourceAsStream("Res/ping_pong_8bit_plop.ogg"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
And my execution code:
else if (Keyboard.isKeyDown(Keyboard.KEY_8)) {
SoundBank.oggEffect.playAsSoundEffect(1.0f, 1.0f, true);
}
I'm pretty sure it should be
/res/ping_pong...ogg
not
res/ping_pong...ogg
never initialize a static variable through constructor.
Method 1 (this prevent you from having to call new SoundBank(); to init):
public class SoundBank {
public static Audio oggEffect;
static {
try {
oggEffect = AudioLoader.getAudio("OGG", ResourceLoader.getResourceAsStream("Res/ping_pong_8bit_plop.ogg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Method 2 (I have it working like this):
public class SoundUtils {
public static void playSound(String res) {
try {
Audio a = AudioLoader.getAudio("OGG", ResourceLoader.getResourceAsStream("res/sfx/" + res + ".ogg"));
a.playAsSoundEffect(1, 1, false);
} catch (IOException e) {
e.printStackTrace();
//You don't need this.
LoggerSys.get().getCurrentLogger().log("wtf i haz dun err0rz (" + e.toString() + ")");
}
}
}
EDIT: Oh, and make sure the path is correct (Res/... instead of res/... etc.)