/*这个问题困惑了很久,问我们java老师也能没解决,真诚地希望您能帮我解答一下,thanks for your time and consideration!问题描述:从文件里读取一个图像--->使图像旋转一个角度--->保存旋转后的图像(.jpg)(宽和高也相应的变化。前两步已实现,就是保存旋转后的图像出问题,宽和高是可以实现变换的,但保存的图像始终没有旋转,但可以看到图像在panel里是显现出来已经转了啊?不明白,那些旋转数据缓存到哪里了?为了明白起见,我把每次点击鼠标后图像的变化都有保存,你要找个(* * .jpg)的图像,修改程序中两处文件路径,程序可以运行。
*/
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;public class ScrollPaneDemo extends JFrame implements MouseListener {         private static final long serialVersionUID = -8833161611850547265L;         ImagePanel jp;         JScrollPane jsp;
         public ScrollPaneDemo() {
                 super("JScrollPane Demo 图像旋转");
                 jp = new ImagePanel();
                 jp.setPreferredSize(new Dimension(800, 600));
                 jsp = new JScrollPane(jp);
                 jp.addMouseListener(this);
                 getContentPane().add(jsp);
                 setSize(1000,800);
                 setDefaultCloseOperation(EXIT_ON_CLOSE);
                 setVisible(true);
         }
         public static void main(String[] args) {
                new ScrollPaneDemo();
            }         public void mouseClicked(MouseEvent e) {
                 System.out.println("mouseClicked");
                        //jp.enlarge();
                 jp.RotateRight();
                 jp.setPreferredSize(jp.getPreferredSize());
                 jsp.validate();
         }         public void mousePressed(MouseEvent e) {
                 // System.out.println("mousePressed");
         }         public void mouseReleased(MouseEvent e) {
                // System.out.println("mouseReleased");
         }         public void mouseEntered(MouseEvent e) {
                // System.out.println("mouseEntered");
         }         public void mouseExited(MouseEvent e) {
                // System.out.println("mouseExited");
         }      
}class ImagePanel extends JPanel {         private Image image;        //要旋转的图像
         private double currentAngle;//当前角度         private Dimension theSize = new Dimension(800,600);         double w = theSize.getWidth();         double h = theSize.getHeight();         public ImagePanel() {
                 this.image = Toolkit.getDefaultToolkit().getImage("F:\\vvECC\\Winter.jpg"); //从文件中读取图像
                 MediaTracker mt = new MediaTracker(this);
                 mt.addImage(image, 0);
                 try {
                         mt.waitForID(0);
                 } catch (InterruptedException e) {
                         e.printStackTrace();
                 }
                
         }            public void paintComponent(Graphics g) {
            System.out.println("in paintComponent");
         
         File newImage;
                 super.paintComponent(g);
                 Graphics2D g2d = (Graphics2D) g;
                 AffineTransform origXform = g2d.getTransform();
                 AffineTransform newXform = (AffineTransform) (origXform.clone());
                 int xRot = this.getWidth() / 2;
                 int yRot = this.getHeight() / 2;
                 newXform.rotate(Math.toRadians(currentAngle), xRot, yRot);
                 g2d.setTransform(newXform);
                 int x = (getWidth() - image.getWidth(this)) / 2;
                 int y = (getHeight() - image.getHeight(this)) / 2;
                 g2d.drawImage(image, x, y, this); 
                 /*
                  * g2d.drawImage(image, x, y, this),我理解为把旋转后的出来,此时"image"已被旋转了吗?
                  * 可用下面的几行代码的保存的大小变化正确,但图像本身始终是没有旋转的。不明白.
                  */                 BufferedImage bImage = new BufferedImage(theSize.width, theSize.height, BufferedImage.TYPE_INT_RGB);
                 Graphics gr = bImage.getGraphics();      
                           
         gr.dispose();
        
                 newImage = new File("F:/vvECC/NewImage.jpg");  
         try {
       ImageIO.write(bImage, "jpg", newImage);//把bImage写到newImage.jpg
      } catch (IOException e) {
       e.printStackTrace();
      } 
     
                 g2d.setTransform(origXform);
         }         public void RotateRight() {
                 currentAngle +=30.0;// 顺时针旋转30度
                 // currentAngle -= 30.0;//逆时针旋转30度
                 if (currentAngle >= 360.0) {
                         currentAngle = 0;
                 }                 double cos = Math.abs(Math.cos(Math.toRadians(currentAngle)));
                 double sin = Math.abs(Math.sin(Math.toRadians(currentAngle)));                 theSize.width = (int) (w * cos + h * sin);
                 theSize.height = (int) (w * sin + h * cos);                 setSize(theSize);                 repaint();
         }         public Dimension getPreferredSize() {
                        return this.theSize;
         }
}

解决方案 »

  1.   

    你使用了AffineTransform, 注意, JPanel中的图片显示旋转, 但是实际上图片的数据并没有改变.旋转图片要可以使用PixelGrabber来取得图像的像素数据(存放在int数组中), 然后对这个数组中的数据进行改变, 旋转的话, 实际上是改变数据中像素数据在数据中的位置, 如旋转180度就是第一行与最后一行交换, 第二行与倒数第二行交换,..., 不同的旋转角度, 交换的算法也不一样. 然后用MemoryImageSource使用这个已经修改过后的数据生成图片(好像是BufferedImage), 最后把这个图片写入文件.public class PixelGrabber
    extends Object
    implements ImageConsumerThe PixelGrabber class implements an ImageConsumer which can be attached to an Image or ImageProducer object to retrieve a subset of the pixels in that image. Here is an example: public void handlesinglepixel(int x, int y, int pixel) {
            int alpha = (pixel >> 24) & 0xff;
            int red   = (pixel >> 16) & 0xff;
            int green = (pixel >>  8) & 0xff;
            int blue  = (pixel      ) & 0xff;
            // Deal with the pixel as necessary...
     } public void handlepixels(Image img, int x, int y, int w, int h) {
            int[] pixels = new int[w * h];
            PixelGrabber pg = new PixelGrabber(img, x, y, w, h, pixels, 0, w);
            try {
                pg.grabPixels();
            } catch (InterruptedException e) {
                System.err.println("interrupted waiting for pixels!");
                return;
            }
            if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
                System.err.println("image fetch aborted or errored");
                return;
            }
            for (int j = 0; j < h; j++) {
                for (int i = 0; i < w; i++) {
                    handlesinglepixel(x+i, y+j, pixels[j * w + i]);
                }
            }
     } public class MemoryImageSource
    extends Object
    implements ImageProducerThis class is an implementation of the ImageProducer interface which uses an array to produce pixel values for an Image. Here is an example which calculates a 100x100 image representing a fade from black to blue along the X axis and a fade from black to red along the Y axis: 
            int w = 100;
            int h = 100;
            int pix[] = new int[w * h];
            int index = 0;
            for (int y = 0; y < h; y++) {
                int red = (y * 255) / (h - 1);
                for (int x = 0; x < w; x++) {
                    int blue = (x * 255) / (w - 1);
                    pix[index++] = (255 << 24) | (red << 16) | blue;
                }
            }
            Image img = createImage(new MemoryImageSource(w, h, pix, 0, w));
     
     The MemoryImageSource is also capable of managing a memory image which varies over time to allow animation or custom rendering. Here is an example showing how to set up the animation source and signal changes in the data (adapted from the MemoryAnimationSourceDemo by Garth Dickie):        int pixels[];
            MemoryImageSource source;        public void init() {
                int width = 50;
                int height = 50;
                int size = width * height;
                pixels = new int[size];            int value = getBackground().getRGB();
                for (int i = 0; i < size; i++) {
                    pixels[i] = value;
                }            source = new MemoryImageSource(width, height, pixels, 0, width);
                source.setAnimated(true);
                image = createImage(source);
            }        public void run() {
                Thread me = Thread.currentThread( );
                me.setPriority(Thread.MIN_PRIORITY);            while (true) {
                    try {
                        thread.sleep(10);
                    } catch( InterruptedException e ) {
                        return;
                    }                // Modify the values in the pixels array at (x, y, w, h)                // Send the new data to the interested ImageConsumers
                    source.newPixels(x, y, w, h);
                }
            }
    至于你们老师解决不了这个问题, 并不是说明这个问题难.再指出一点, 把
    try {
           ImageIO.write(bImage, "jpg", newImage);//把bImage写到newImage.jpg
          } catch (IOException e) {
           e.printStackTrace();
          }  
    放在paintComponent中, 实在是一大败笔.
    因为paintComponent这个函数很可能会执行很多次, 难道你每次都想把图片写到同一个文件中?
      

  2.   

    swing设计的灵活性得益于将数据和呈现方式剥离,正如楼上所说,你在panel中看到的是图片的呈现方式,但是图片的数据并没有变化,因此你还需要将数据也改变掉。
      

  3.   

    很多开源项目里有这样功能啊,,比如imagej,