调用另一个方法后调用方法的nullpointerexception?

时间:2011-10-17 19:16:00

标签: java image image-processing compiler-errors nullpointerexception

我有一个图像编辑程序。它有几种方法,如灰度,缩放,合并图像等。每种方法都可以完美地完成。但是,在调用mergeImg方法后调用grayScale方法时出现错误。如果我先应用灰度,就不会发生这种情况。

这是错误:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Picture.width(Picture.java:51)
at Picture$4.actionPerformed(Picture.java:222)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.AbstractButton.doClick(AbstractButton.java:376)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:833)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:877)
at java.awt.Component.processMouseEvent(Component.java:6504)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6269)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4860)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4686)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2713)
at java.awt.Component.dispatchEvent(Component.java:4686)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:707)
at java.awt.EventQueue.access$000(EventQueue.java:101)
at java.awt.EventQueue$3.run(EventQueue.java:666)
at java.awt.EventQueue$3.run(EventQueue.java:664)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:680)
at java.awt.EventQueue$4.run(EventQueue.java:678)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:677)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:128)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:117)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

这是我的代码:

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.image.*;
import javax.imageio.ImageIO;
import java.lang.Math;

public class Picture{
    JFileChooser fileChooser = new JFileChooser(); //file chooser
    final JFrame frame = new JFrame("ImageEdit");  //creates JFrame
    Container content; //creates container to place GUI objects in
    static BufferedImage image; //original image
    BufferedImage image2; //image after changes are made
    BufferedImage mergeImage; //used for mergeImg method
    JLabel imageLabel; //used to display image

    //constructor; welcomes user, asks for image input
    public Picture() {
        //pops up prior to JFileChooser, intstructing user on what to do
        Object[] options = {"Browse...", "Exit"};
        ImageIcon welcomeIcon = new ImageIcon("GUI-images/welcome-icon.png");
        int getFile = JOptionPane.showOptionDialog(frame, "Welcome to ImageEdit. To begin, please select an image file to edit.", 
                "Welcome!", JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, welcomeIcon, options, options[0]);

        //if user selects browse option, do this:
        if (getFile == JOptionPane.YES_OPTION) {
            //asks for image file as input
            browse();
        }

        //otherwise, exit program
        else {
            //exit program
            System.exit(0); 
        }
    }

    //method returns width of image
    public int width() {
        int width = image.getWidth();
        return width;
    }

    //method returns height of image
    public int height() {
        int height = image.getHeight();
        return height;
    }

    //method sets updated image as "original" image
    public void setImage() {
        this.image = image2;
    }

    //method writes image in destination
    public void saveImage() {
        //gets file name & destination from user through JFileChooser
        fileChooser.setDialogTitle("Save As...");
        fileChooser.showSaveDialog(frame);

        //writes image to new file with given name & location
        try {
            ImageIO.write(this.image, "JPG", fileChooser.getSelectedFile());
        }
        catch (IOException f) {
            System.out.println("Saving failed! Could not save image.");
        }
    }

    //method browses for new file
    public void browse() {
        //asks for new image file
        fileChooser.setDialogTitle("Choose an image file:");
        fileChooser.showOpenDialog(frame);
        File selectedFile = fileChooser.getSelectedFile();

        //if user has selected image file, continue
        if (fileChooser.getSelectedFile() != null) {
            try {
                //reads selectedFile as image
                image = ImageIO.read(selectedFile);
            } 
            catch (IOException e) {
                System.out.println("Invalid image file: " + selectedFile);
                System.exit(0);
            }
        }

        //else print error message
        else {
            System.out.println("Error! No File Selected.");
        }
    }

    //method creates frame, adds menubar with options, provides parameters for other methods
    public void show() {
        //set frame title, set it visible, etc
        content = frame.getContentPane();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);

        //add the image to the frame
        ImageIcon icon = new ImageIcon(image);
        imageLabel = new JLabel(icon);
        frame.setContentPane(imageLabel);

        //adds a menubar on the frame with program name, File & Edit menus
        JMenuBar menuBar = new JMenuBar();
        frame.setJMenuBar(menuBar);
        JMenu progName = new JMenu("ImageEdit");
        progName.setBackground(Color.RED);
        menuBar.add(progName);
        JMenu fileMenu = new JMenu("File");
        menuBar.add(fileMenu);
        JMenu editMenu = new JMenu("Edit");
        menuBar.add(editMenu);

        //adds options to JMenus
        //option to exit application
        ImageIcon exitIcon = new ImageIcon("GUI-images/app-exit.png");
        JMenuItem exitAction = new JMenuItem("Exit", exitIcon);
        progName.add(exitAction);

        //if exit option is selected, do this:
        exitAction.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //prompts to save file before exiting
                    ImageIcon saveIcon = new ImageIcon("GUI-images/save-icon.png");
                    int askSave = JOptionPane.showConfirmDialog(null,"Save image before exit?", "Save...", 
                            JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, saveIcon);
                    if (askSave == JOptionPane.YES_OPTION) {
                        //opens save image method, then exits
                        saveImage();
                        System.exit(0);
                    }
                    else {
                        //exits without saving
                        System.exit(0);
                    }
                }
            });

        //option to open a new image
        ImageIcon newIcon = new ImageIcon("GUI-images/new-image.png");
        JMenuItem newAction = new JMenuItem("Open Image", newIcon);
        fileMenu.add(newAction);

        //if new option is selected, do this:
        newAction.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //prompts to save image before opening new image
                    ImageIcon saveIcon = new ImageIcon("GUI-images/save-icon.png");
                    int askSave = JOptionPane.showConfirmDialog(null,"Save current image?", "Save...", 
                            JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, saveIcon);
                    //if they do want to save first, do this:
                    if (askSave == JOptionPane.YES_OPTION) {
                        //opens save image method, then asks asks for new image file
                        saveImage();

                        //clears old image
                        imageLabel.setIcon(null);

                        //browses for new image
                        browse();
                        //displays new image
                        imageLabel.setIcon(new ImageIcon(image));

                        //resizes canvas to fit new image
                        frame.setSize(width(), height());
                    }
                    //if they don't want to save, do this:
                    else {
                        //erases old image
                        imageLabel.setIcon(null);

                        //browses for new image
                        browse();

                        //displays new image
                        imageLabel.setIcon(new ImageIcon(image));

                        //resizes canvas to fit new image
                        frame.setSize(width(), height());
                    }
                }
            });

        //option to save current image
        ImageIcon saveIcon = new ImageIcon("GUI-images/save-image.png");
        JMenuItem saveAction = new JMenuItem("Save Image As...", saveIcon);
        fileMenu.add(saveAction);

        //if save option is selected, do this:
        saveAction.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //opens save image method
                    saveImage();
                }
            });

        //option to make current image grayscale
        ImageIcon gsIcon = new ImageIcon("GUI-images/grayscale-image.png");
        JMenuItem grayScale = new JMenuItem("Grayscale", gsIcon);
        editMenu.add(grayScale);

        //if grayscale option is selected, do this:
        grayScale.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //grabs height and width of image,
                    //then calls grayscale method
                    grayscale(width(), height());
                }
            });

        //option to scale current window to new dimensions
        ImageIcon scaleIcon = new ImageIcon("GUI-images/scale-image.png");
        JMenuItem scaleImg = new JMenuItem("Scale Image", scaleIcon);
        editMenu.add(scaleImg);

        //if scale option is selected, do this:
        scaleImg.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //asks for height and width to create new image
                    ImageIcon widthIcon = new ImageIcon("GUI-images/LR-arrows.png");
                    String scaleWidth = (String)JOptionPane.showInputDialog(null,"What should the new width be?", 
                            "Scale Image", JOptionPane.QUESTION_MESSAGE, widthIcon, null, null);
                    ImageIcon heightIcon = new ImageIcon("GUI-images/UD-arrows.png");
                    String scaleHeight = (String)JOptionPane.showInputDialog(null,"What should the new height be?", 
                            "Scale Image", JOptionPane.QUESTION_MESSAGE, widthIcon, null, null);

                    //turns user input strings into doubles
                    double x = Double.parseDouble(scaleWidth);
                    double y = Double.parseDouble(scaleHeight);

                    //casts doubles as ints
                    int newWidth = (int)x;
                    int newHeight = (int)y;

                    //resizes frame to fit new image dimensions
                    frame.setSize(newWidth, newHeight);

                    //calls scale method to resize image using given dimensions
                    scale(newWidth, newHeight);
                }
            });

        //option to merge two images together
        ImageIcon mergeIcon = new ImageIcon("GUI-images/merge-image.png");
        JMenuItem mergeImg = new JMenuItem("Merge Image", mergeIcon);
        editMenu.add(mergeImg);

        //if merge option is selected, do this:
        mergeImg.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    //asks for image file as input
                    fileChooser.setDialogTitle("Choose an image file to merge current image with.");
                    fileChooser.showOpenDialog(frame);
                    File mergeFile = fileChooser.getSelectedFile();

                    //if user has selected image file, continue
                    if (fileChooser.getSelectedFile() != null) {
                        try {
                            //reads selectedFile as image
                            mergeImage = ImageIO.read(mergeFile);
                        } 
                        catch (IOException f) {
                            System.out.println("Invalid image file: " + mergeFile);
                            System.exit(0);
                        }
                    }

                    //else print error message
                    else {
                        System.out.println("Error! No File Selected.");
                    }

                    //if two images are same size, merge them
                    if (width() == mergeImage.getWidth() && height() == mergeImage.getHeight()) {
                        mergeImg(width(), height(), mergeImage);
                    }
                    //else, resize the second image to size of original, then merge
                    else {
                        scale(width(), height());
                        mergeImg(width(), height(), mergeImage);
                    }
                }
            });

        //option to rotate image by x degrees
        ImageIcon rotateIcon = new ImageIcon("GUI-images/rotate-image.png");
        JMenuItem rotateImage = new JMenuItem("Rotate Image", rotateIcon);
        editMenu.add(rotateImage);

        //if rotate option is selected, do this:
        rotateImage.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    String rotateAngle = (String)JOptionPane.showInputDialog(null,"By what angle would you like to rotate?", 
                            "Input Degrees", JOptionPane.QUESTION_MESSAGE, null/*icon goes here*/, null, null);

                    //turns user input strings into doubles
                    double angleDegs = Double.parseDouble(rotateAngle);

                    //converts degrees to rads
                    double angle = Math.toRadians(angleDegs);

                    //applies sine and cosine functions
                    int sin = (int)Math.sin(angle);
                    int cos = (int)Math.cos(angle);

                    //gets new width of rotated image
                    int newWidth = width()*sin + height()*cos;
                    int newHeight = height()*sin + width()*cos;

                    //sets frame to new image size
                    frame.setSize(newWidth, newHeight);

                    //calls rotate method to rotate image
                    rotate(newWidth, newHeight, angle);
                }
            });

        //paint the frame
        frame.pack();
        frame.repaint();
        frame.setVisible(true);
    }

    //method converts image to grayscale; 6 lines of code
    public void grayscale(int width, int height) {
        // create a grayscale image with original dimensions
        image2 = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);

        // convert colored image to grayscale
        ColorConvertOp grayScale = new ColorConvertOp(image.getColorModel().getColorSpace(),
                image2.getColorModel().getColorSpace(),null);
        grayScale.filter(image,image2);
        imageLabel.setIcon(new ImageIcon(image2));

        //sets new image as "original"
        setImage();
    }

    //method scales image to user-input dimensions; 5 lines of code
    public void scale(int width, int height){
        //uses user-input dimensions to create new image
        image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = image2.createGraphics();

        //gets new dimensions and resizes image
        g.drawImage(image, 0, 0, image2.getWidth(), image2.getHeight(), 0, 0, width(), height(), null);  
        imageLabel.setIcon(new ImageIcon(image2));

        //sets new image as "original"
        setImage();
    }

    //method merges two images together; 14 lines of code
    public void mergeImg(int width, int height, BufferedImage mergeImage) {
        //creates new image from two images of same size
        BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                //get color from original image
                Color c = new Color(image.getRGB(i, j));

                //get colors from merge image
                Color c2 = new Color(mergeImage.getRGB(i, j));

                //average the colors
                int r = (c.getRed()+c2.getRed())/2;
                int g = (c.getGreen()+c2.getGreen())/2;
                int b = (c.getBlue()+c2.getBlue())/2;
                Color avgColor = new Color(r, g, b);

                //set colors of new image to average of the two images
                image2.setRGB(i, j, avgColor.getRGB());
                imageLabel.setIcon(new ImageIcon(image2));
            }
        }

        mergeImage = null;
        //sets new image as "original"
        setImage();
    }

    //method rotates image by user-input angle; 18 lines of code
    public void rotate(int width, int height, double angle) {
        //rotates image around center point
        BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        //defines sin and cos functions
        double sin = Math.sin(angle);
        double cos = Math.cos(angle);

        //gets coordinates of image center
        double Xc = width/2;
        double Yc = height/2;

        //rotate
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                //new i,j at center of image
                double iPrime = i - Xc;
                double jPrime = j - Yc;
                //i,j at new points after rotation
                int xPrime = (int) (iPrime * cos - jPrime * sin + Xc);
                int yPrime = (int) (iPrime * sin + jPrime * cos + Yc);

                // plot pixel (i, j) the same color as (xPrime, yPrime) if it's in bounds
                if (xPrime >= 0 && xPrime < width && yPrime >= 0 && yPrime < height) {
                    image2.setRGB(xPrime, yPrime, image.getRGB(i, j));
                    imageLabel.setIcon(new ImageIcon(image2));
                }
            }
        }

        //sets new image as "original"
        setImage();
    }

    //main method; starts program
    public static void main(String[] args) {
        //creates new picture from image file
        Picture p = new Picture();

        //shows picture on JFrame
        p.show();
    }
}

任何想法可能是什么?感谢帮助!

2 个答案:

答案 0 :(得分:5)

从堆栈跟踪和代码判断,看起来像这个方法

//method returns width of image
public int width() {
    int width = image.getWidth();
    return width;
}

抛出NullPointerException。唯一可能导致此问题的是imagenull

我建议您逐步解决有问题的方法,并检查null变量的image的位置和原因。


一个可能的问题是您在方法image2rotate中重新声明mergeImg

BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

这有效地“隐藏”this.image2。稍后再拨打setImage并执行

this.image = image2;

image2未引用您准备的局部变量。

答案 1 :(得分:2)

从堆栈跟踪中,您的实例变量图像似乎为空。

    public int width() {
      int width = image.getWidth();
      return width;
    }

尝试添加:

public int width() {
    int width = 0;
    if (null != image) {
        width = image.getWidth();
    }
    return width;
}
编辑:正如有人已经评论过的那样,你不应该使用这么多的实例varibale。如果没有param的setImage()应该响铃;-)。我会在这个方法中添加一个图像参数,这样你就可以确保用你刚刚使用的东西更新你的图像实例变量了!

喜欢

public void setImage(BufferedImage workingImg)

依赖于许多类方法修改的不同实例变量的状态是获得不可预测结果的最佳方法。

祝你好运