Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 419|回复: 0

[Swing学习]扩展JLabel实现图像裁剪

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-8 23:56:48 | 显示全部楼层 |阅读模式
    这个组件的功能:       1. 对图片进行裁剪       2. 为每副图像维持一个裁剪操作栈       3. 裁剪的撤销,重做       4. 裁剪时可以遮掩图像,以突出显示裁剪矩形边框       5. 设置遮掩的颜色,裁剪边框的颜色       原理:JLabel持有一个剪裁矩形框,和一个遮掩矩形框。
    并为JLabel添加MouseListener监听器实现开始裁剪和结束裁剪,MouseMotion事件监听器实现设置裁剪矩形边框的大小。 直接上代码:
      
       
       
         
       

         
       
      
    1. import java.awt.Color;  
    2. import java.awt.Graphics;  
    3. import java.awt.Graphics2D;  
    4. import java.awt.Image;  
    5. import java.awt.geom.Point2D;  
    6. import java.awt.geom.Rectangle2D;  
    7. import java.awt.image.BufferedImage;  
    8. import java.util.HashMap;  
    9. import java.util.Vector;  
    10. import javax.swing.Icon;  
    11. import javax.swing.ImageIcon;  
    12. import javax.swing.JLabel;  
    13. import javax.swing.JOptionPane;  
    14. import java.awt.event.MouseAdapter;  
    15. import java.awt.event.MouseEvent;  
    16. import java.awt.event.MouseMotionListener;  
    17. /**
    18.   * 进行图片裁剪
    19.   * @author chosen0ne
    20.   */  
    21. public class ImageCutComponent extends JLabel {  
    22.      private Rectangle2D rect = new Rectangle2D.Double();//剪裁区域  
    23.      private BufferedImage image;//当前显示的图像  
    24.      private Point2D source=new Point2D.Double();//被选择区域的顶点  
    25.      private ImageStack current=new ImageStack();//当前组件显示的图像对应的操作栈  

    26.      //每个图像对应的裁剪操作栈
    27.      private HashMap< String,ImageStack> imageStacks=new HashMap< String, ImageStack>();

    28.      //剪裁时,用于遮挡图像的矩形,这样可以区分剪裁框
    29.      private Rectangle2D rectCover=new Rectangle2D.Double();
    30.      private boolean doCover=false;//指示是否进行遮掩  
    31.      private MouseHandler mouseHandler=new MouseHandler(this);  
    32.      private MouseMotionListener motionListener=new MouseMotionHandler(this);  
    33.      private Color colorCover=new Color(0.7f, 0.7f, 0.7f, 0.3f);//遮掩的颜色  
    34.      private Color colorBorder=Color.yellow;//裁剪矩形的边框的颜色  
    35.      public ImageCutComponent(){  
    36.          this.addMouseListener(this.mouseHandler);  
    37.          this.addMouseMotionListener(motionListener);  
    38.          this.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);//设置水平左对齐  
    39.          this.setVerticalAlignment(javax.swing.SwingConstants.TOP);//设置垂直上对齐  
    40.      }  
    41.      /**
    42.       * 删除裁剪功能
    43.       */  
    44.      public void removeCutAbility(){  
    45.          this.removeMouseListener(mouseHandler);  
    46.          this.removeMouseMotionListener(motionListener);  
    47.      }  
    48.      /**
    49.       * 添加裁剪功能
    50.       */  
    51.      public void addCutAbility(){  
    52.          this.addMouseListener(mouseHandler);  
    53.          this.addMouseMotionListener(motionListener);  
    54.      }  
    55.      @Override  
    56.      public void paintComponent(Graphics g) {  
    57.          super.paintComponent(g);  
    58.          Graphics2D g2 = (Graphics2D) g;  
    59.          if(doCover){//如果进行裁剪,将图像遮掩  
    60.              g2.setColor(colorCover);  
    61.              g2.fill(rectCover);  
    62.          }  
    63.          g2.setColor(Color.YELLOW);  
    64.          g2.draw(rect);  
    65.      }  
    66.      /**
    67.       * 设置是否进行颜色覆盖
    68.       * @param f
    69.       */  
    70.      public void setDoCover(boolean cover){  
    71.          this.doCover=cover;  
    72.      }  
    73.      /**
    74.       * 返回是否进行颜色覆盖
    75.       * @return
    76.       */  
    77.      public boolean getDoCover(){  
    78.          return this.doCover;  
    79.      }  
    80.      /**
    81.       * 返回显示的图像
    82.       * @return
    83.       */  
    84.      public Image getImage(){  
    85.          return this.image;  
    86.      }  
    87.      /**
    88.       * 设置显示的图像
    89.       * @param image
    90.       */  
    91.      public void setImage(BufferedImage image){  
    92.          this.image=image;  
    93.      }  
    94.      /**
    95.       * 删除所有在裁剪过程中,生成的图像
    96.       */  
    97.      public void removeAllImages(){  
    98.          this.imageStacks.clear();  
    99.      }  
    100.      /**
    101.       * 设置剪裁区域
    102.       * @param r
    103.       */  
    104.      public void setSelectRegion(Rectangle2D r) {  
    105.          this.rect.setFrame(r);  
    106.      }  
    107.      /**
    108.       * 清除剪裁区域
    109.       */  
    110.      public void clearSelectRegion() {  
    111.          this.rect.setFrame(0, 0, 0, 0);  
    112.      }  
    113.      /**
    114.       * 得到剪裁区域
    115.       * @return
    116.       */  
    117.      public Rectangle2D getSelectRegion(){  
    118.          return this.rect;  
    119.      }  
    120.      /**
    121.       * 对JLabel的方法进行覆盖,调用此方法时同时设置显示的图像指向该图片
    122.       * 并设置覆盖矩形的大小
    123.       * @param icon
    124.       */  
    125.      @Override  
    126.      public void setIcon(Icon icon) {  
    127.          super.setIcon(icon);  
    128.          ImageIcon imageIcon = (ImageIcon) icon;  
    129.          if (imageIcon != null) {  
    130.              this.image = this.convertImageToBuffer(imageIcon.getImage());  
    131.              rectCover=new Rectangle2D.Double(0,0,image.getWidth(null),image.getHeight(null));  
    132.          }  
    133.      }  
    134.      /**
    135.       * 取得裁剪矩形的左上角顶点
    136.       * @return
    137.       */  
    138.      public Point2D getSource() {  
    139.          return this.source;  
    140.      }  
    141.      /**
    142.       * 设置裁剪矩形的左上角的顶点
    143.       * @param p
    144.       */  
    145.      public void setSource(Point2D p) {  
    146.          this.source = p;  
    147.      }  
    148.      /**
    149.       * 进行裁剪
    150.       */  
    151.      public void doCut() {  
    152.          int result=JOptionPane.showConfirmDialog(this, "进行裁剪", "提示",
    153.                       JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE);  
    154.          if(result==JOptionPane.NO_OPTION){  
    155.              this.clearSelectRegion();  
    156.              this.repaint();  
    157.              return;  
    158.          }  
    159.          Image bImage=this.doResize(image, rect);  
    160.          current.add(bImage);  
    161.          this.setIcon(new ImageIcon(bImage));  
    162.          this.clearSelectRegion();  
    163.          this.repaint();  
    164.      }  
    165.      /**
    166.       * 返回点p在图像上对应的点,不能超过图像的长、宽
    167.       * @param p
    168.       * @return
    169.       */  
    170.      public Point2D getPoint(Point2D p){  
    171.          if(image==null)  
    172.              return new Point2D.Double();  
    173.          int imageWidth = image.getWidth(this);  
    174.          int x=(int) (p.getX() > imageWidth ? imageWidth : p.getX());  
    175.          int imageHeight=image.getHeight(this);  
    176.          int y=(int) (p.getY() > imageHeight ? imageHeight : p.getY());  
    177.          return new Point2D.Double(x, y);  
    178.      }  
    179.      /**
    180.       * 判断某点是否在图像内
    181.       * @param p
    182.       * @return
    183.       */  
    184.      public boolean inImage(Point2D p){  
    185.          if(image==null)  
    186.              return false;  
    187.          int imageWidth = image.getWidth(this);  
    188.          int imageHeight=image.getHeight(this);  
    189.          if(p.getX()< imageWidth&&p.getY()< imageHeight)  
    190.              return true;  
    191.          return false;  
    192.      }  
    193.      /**
    194.       * 操作栈中是否有前一个图像
    195.       * @return
    196.       */  
    197.      public boolean hasPrevious(){  
    198.          return current.hasPrevious();  
    199.      }  
    200.      /**
    201.       * 操作栈中是否有后一个图像
    202.       * @return
    203.       */  
    204.      public boolean hasNext(){  
    205.          return current.hasNext();  
    206.      }  
    207.      /**
    208.       * 设置遮掩颜色
    209.       * @param color
    210.       */  
    211.      public void setColorCover(Color color){  
    212.          this.colorCover=color;  
    213.      }  
    214.      /**
    215.       * 返回遮掩颜色
    216.       * @return
    217.       */  
    218.      public Color getColorCover(){  
    219.          return this.colorCover;  
    220.      }  
    221.      /**
    222.       * 设置裁剪矩形的边框颜色
    223.       * @param color
    224.       */  
    225.      public void setColorBorder(Color color){  
    226.          this.colorBorder=color;  
    227.      }  
    228.       
    229.      /**
    230.       * 返回裁剪矩形边框的颜色
    231.       * @return
    232.       */  
    233.      public Color getColorBorder(){  
    234.          return this.colorBorder;  
    235.      }  
    236.      /**
    237.       * 返回操作栈中前一个图像
    238.       */  
    239.      public Image previous(){  
    240.          Image img=current.previous();  
    241.          this.setIcon(new ImageIcon(img));  
    242.          return img;  
    243.      }  
    244.      /**
    245.       * 返回操作栈中后一个图像
    246.       */  
    247.      public Image next(){  
    248.          Image img=current.next();  
    249.          this.setIcon(new ImageIcon(img));  
    250.          return img;  
    251.      }  
    252.      /**
    253.       * 为每个文件添加原始图像
    254.       * @param image
    255.       */  
    256.      public void addOrdinary(Image image){  
    257.          this.current.add(image);  
    258.      }  
    259.      /**
    260.       * 设置当前操作栈current指向文件fileName对应的操作栈
    261.       * @param fileName
    262.       */  
    263.      public void setCurrent(String fileName){  
    264.          if(!imageStacks.containsKey(fileName))  
    265.              imageStacks.put(fileName, new ImageStack());  
    266.          current=imageStacks.get(fileName);  
    267.      }  
    268.      /**
    269.       * 返回图像file在操作栈对应的当前图像
    270.       * @param file
    271.       * @return
    272.       */  
    273.      public Image getCurrentImage(String file){  
    274.          return imageStacks.get(file).getCurrent();  
    275.      }  
    276.      private BufferedImage convertImageToBuffer(Image pic){   
    277.          BufferedImage bufferedImage = new BufferedImage(pic.getWidth(null),
    278.                     pic.getHeight(null), BufferedImage.TYPE_INT_RGB);   
    279.          Graphics g = bufferedImage.createGraphics();   
    280.          g.drawImage(pic, 0, 0, null);   
    281.          g.dispose();   
    282.          return bufferedImage;   
    283.      }  
    284.      /**
    285.       * 对图像进行裁剪
    286.       * @param image
    287.       * @param rect 裁剪的区域
    288.       * @return
    289.       */  
    290.      public Image doResize(BufferedImage image,Rectangle2D rect){  
    291.          return image.getSubimage((int)rect.getX(), (int)rect.getY(),
    292.                    (int)rect.getWidth(), (int)rect.getHeight());  
    293.      }  
    294.      /**
    295.       * 图像操作栈
    296.       * @author chosen0ne
    297.       */  
    298.      private class ImageStack {  
    299.          private Vector< Image> vec=new Vector< Image>();  
    300.          private int index=-1;  
    301.          public boolean hasNext(){  
    302.              return index< vec.size()-1;  
    303.          }  
    304.          public boolean hasPrevious(){  
    305.              return index>0;  
    306.          }  
    307.          public Image next(){  
    308.              return vec.get(++index);  
    309.          }  
    310.          public Image previous(){  
    311.              return vec.get(--index);  
    312.          }  
    313.          public void add(Image i){  
    314.              vec.add(i);  
    315.              index++;  
    316.          }  
    317.          public Image getCurrent(){  
    318.              return vec.get(index);  
    319.          }  
    320.      }  
    321.      /**
    322.       *
    323.       * @author chosen0ne
    324.       */  
    325.      public class MouseHandler extends MouseAdapter {  
    326.          private ImageCutComponent component;  
    327.          public MouseHandler(ImageCutComponent l) {  
    328.              this.component = l;  
    329.          }  
    330.          /**
    331.           * 当鼠标按下,设置裁剪的起点和并设置进行遮掩
    332.           * @param e
    333.           */  
    334.          @Override  
    335.          public void mousePressed(MouseEvent e) {  
    336.              this.component.setSource(component.getPoint(e.getPoint()));  
    337.              this.component.setDoCover(true);  
    338.          }  
    339.          /**
    340.           * 当释放鼠标,进行图像的裁剪并设置不进行遮掩
    341.           * @param e
    342.           */  
    343.          @Override  
    344.          public void mouseReleased(MouseEvent e){  
    345.              if(component.inImage(e.getPoint())&&component.getSelectRegion().getWidth()!=0  
    346.                      &&component.getSelectRegion().getHeight()!=0){  
    347.                  this.component.doCut();  
    348.                  this.component.setDoCover(false);  
    349.              }  
    350.          }  
    351.      }  
    352.      /**
    353.       *
    354.       * @author chosen0ne
    355.       */  
    356.      class MouseMotionHandler implements MouseMotionListener {  
    357.          private ImageCutComponent component;  
    358.          public MouseMotionHandler(ImageCutComponent l) {  
    359.              this.component = l;  
    360.          }  
    361.          /**
    362.           * 拖拽时,设置裁剪矩形的大小
    363.           * @param e
    364.           */  
    365.          @Override  
    366.          public void mouseDragged(MouseEvent e) {  
    367.              Rectangle2D rect = getRectangle(component.getSource(), component.getPoint(e.getPoint()));  
    368.              this.component.setSelectRegion(rect);  
    369.              this.component.repaint();  
    370.          }  
    371.          public void mouseMoved(MouseEvent e) {  
    372.          }  
    373.          private Rectangle2D getRectangle(Point2D p1, Point2D p2) {  
    374.              int x = (int) Math.min(p1.getX(), p2.getX());  
    375.              int y = (int) Math.min(p1.getY(), p2.getY());  
    376.              double h = Math.abs(p1.getY() - p2.getY());  
    377.              double w = Math.abs(p1.getX() - p2.getX());  
    378.              return new Rectangle2D.Double(x, y, w, h);  
    379.          }  
    380.      }  
    381. }  
    复制代码
    效果图:       
           此组件必须保证图像的左上角定点位于父组件的左上角,可以将这个组件包含于JScrollPanel中,效果很好



      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/8/235648015.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 10:46 , Processed in 0.314468 second(s), 34 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表