`
tju_ZhangJ
  • 浏览: 38553 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

用java2D构造图片遮罩效果

阅读更多
引用
前些天做一个项目需要实现Applet中图片的遮罩效果,于是在网上搜索了一些资料,终于搞出来了。发出来与大家共享一下



import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.Transparency;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.PixelGrabber;
import java.awt.image.RGBImageFilter;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/***
 * 功能介绍: 
 * 两幅图片叠加,一个在上面,一个在下面,上面的图片掏空部分,即可以透明显示下面的图片
 * 
 * 通过鼠标点取实现透过上面的图片控制下面的图片
 * 首先确定鼠标点取的地方是透明区域还是非透明区域
 * 
 * 图片的透明区域中的RGB值存在一个有效范围,
 * 此范围与图片的格式及其他属性有关,一般范围大小不超过40
 * 通过这个有效范围,可以判断鼠标点取处是透明区还是非透明区
 * 但这个范围存在精确度的问题,所以在处理图片的时候需要多次试验得到准确数据。

 * 当遮罩图片通过getInstanceScale()函数将它的长宽改变时,它的RGB值变成自己定义的值了(0,0,0)
 * */
public class ImageCover extends JFrame{

 private BufferedImage top_img;
 private BufferedImage bot_img;
 
 private int frame_width=600;
 private int frame_height=500;
 
 /**指定绘制图片路径
  * 
  * 需要镂空的图片必须是纯正的gif格式图片,最好是表情一类的。
  * 不可以从jpg或其他格式转换而来,只有gif格式的图片才可以很好的设置透明度
  * */
 //图片名 与之对应的rgb值
 private String filetop="app7topimg.gif";
 private int red=0,green=0,blue=0;

 private boolean hascut=false;
 
 //抠出一定范围图片
 //private String filetop="21015.gif";
 //private int red_min=200,red_max=220,green_min=150,green_max=175,blue_min=135,blue_max=160;
 private String filebottom="bottom.jpg";
 
 /**保存图片转换过程中的临时文件*/
 private String path="e:/tempImg.gif";
 
 
 /**临时装载rgb值,alp临时装载像素值*/
 int rgb[]=null,alp=255;
 /**需要指定的透明度0~255,当=0时,为透明,当大于1,都是不透明的*/
 int decAlpha=0;
 
 private int top_x=10,top_y=30;
 private int bottom_x=10,bottom_y=20;
 private int frame_x=400,frame_y=200;
 
 Shape sh_top,sh_bottom;
 Graphics g;
 AlphaComposite alphaComposite=null;
 
 /**
  * 闪屏问题: 调用repaint()函数,它在调用paint()函数前会自动清除屏幕,
  * 所以在一个毫秒内我们会看到一个空白的屏幕,在快速的变换操作中就 出现了闪烁现象。
     *
  * 利用双缓冲技术处理绘图时的闪屏问题
  * 
  * 1.首先我们在update方法中用createImage方法新建一后台图像类变量
    * 2.然后使用getGraphics()方法得到当前图像的图形关联
   * 3.在后台处理所有相关的处理,如清除屏幕,后台绘画等等
     * 其中核心代码见update方法实现。
     * 需要注意两点:
     * 在paint方法中不可有super.paint()
     * 在update方法中已经调用的paint方法,所以其他地方不再需要调用repaint()
  * */
 BufferedImage offScreenImg=null;
 
 //MyFilter myFilter=new MyFilter();
   
 public static void main(String[] args) throws Exception{
  // TODO Auto-generated method stub
           new ImageCover("图片遮罩测试");
 }
 
 public ImageCover(String title) throws Exception{
  
  MouseControl mc=new MouseControl();
  setTitle(title);
  setSize(frame_width,frame_height);
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  setLayout(new BorderLayout());
  setBackground(Color.white);
  setLocation(frame_x,frame_y);
  initImage();
  
  alphaComposite=AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0f);
  
  this.addMouseListener(mc);
  //this.addMouseMotionListener(mc);//取消鼠标拖拽图片
  
  setVisible(true);
  
  //getGraphics()方法只有当图像显示以后才可以返回Graphics对象,否则返回null
  g=this.getGraphics();
  g.setColor(Color.white);
  g.fillRect(0, 0, frame_width, frame_height);
 }
 
 /**初始化图片*/
 private void initImage() throws Exception{
  
  
  URL bottom=ImageCover.class.getResource(filebottom);
  String topfile;
  if(hascut){
   topfile=filetop;
  }else{
      topfile=createTopImg();
  }
  bot_img=ImageIO.read(bottom);
   
  //top_img图像大小缩放到与bot_img大小一样
  top_img=toBufferedImage((new ImageIcon(topfile)).getImage().getScaledInstance(bot_img.getWidth(), bot_img.getHeight(), java.awt.Image.SCALE_SMOOTH));
 }
 
   /**给定一个Image对象,返回一个BufferedImage对象*/
   public BufferedImage toBufferedImage(Image image) {   
         if (image instanceof BufferedImage) {   
             return (BufferedImage)image;   
         }   
        
         // 确保Image中的所有像素都被加载进来 
         image = new ImageIcon(image).getImage();   
        
         /**
          * 判断该Image是否具有透明度
          * */
         boolean hasAlpha = hasAlpha(image);   
        
         BufferedImage bimage = null;   
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();   
         try {   
             /**
              * OPAQUE 表示保证完全不透明的图像数据,意味着所有像素 alpha 值都为 1.0
              * TRANSLUCENT 表示包含或可能包含位于 0.0 和 1.0(含两者)之间的任意 alpha 值的图像数据 
              * BITMASK 表示保证完全不透明的图像数据(alpha 值为 1.0)或完全透明的图像数据(alpha 值为 0.0)
              * */
             int transparency = Transparency.OPAQUE;   
             if (hasAlpha) {   
                 transparency = Transparency.TRANSLUCENT;   
             }   
        
             //创建BufferedImage  
             GraphicsDevice gs = ge.getDefaultScreenDevice();   
             GraphicsConfiguration gc = gs.getDefaultConfiguration(); 
             if(image==null){
              System.out.println("image is null");
             }
             bimage = gc.createCompatibleImage(   
                 image.getWidth(null), image.getHeight(null), transparency);   
         } catch (HeadlessException e) {   
             e.printStackTrace();  
         }   
        
         if (bimage == null) {   
             //使用默认ColorModel创建一个BufferedImage   
             int type = BufferedImage.TYPE_INT_RGB;   
             if (hasAlpha) {
              System.out.println("hasAlpha");
                 type = BufferedImage.TYPE_INT_ARGB;   
             }   
             bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);   
         }   
        
         Graphics g = bimage.createGraphics();   
        
         g.drawImage(image, 0, 0, null);   
         g.dispose();   
        
         return bimage;   
     }  

   /**判断Image是否具有透明度*/
   public boolean hasAlpha(Image image) { 
    
         if (image instanceof BufferedImage) {   
             BufferedImage bimage = (BufferedImage)image;   
             return bimage.getColorModel().hasAlpha();   
         }   
        
          /**构造一个PixelGrabber对象,获取image矩阵上的(0,0)点像素值*/  
         PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, true);   
         try {   
             pg.grabPixels();   
         } catch (InterruptedException e) {   
         }   
        
         ColorModel cm = pg.getColorModel();  
         System.out.println("ColorModel : "+cm+" , alpha:"+cm.hasAlpha());
         
         return cm.hasAlpha();   
     }  

 /**抠出topimg图片,同时返回图片路径*/
 private String createTopImg() throws Exception{
  
  BufferedImage temImg=null;
  URL top=ImageCover.class.getResource(filetop);
  
  temImg=ImageIO.read(top);
  
  ColorModel cm=temImg.getColorModel();
  System.out.println("cm : "+cm);
  
  if(!cm.hasAlpha()){
   setImageAlpha(temImg);
   File newTopFile=new File(path);
   temImg=ImageIO.read(newTopFile);
  }
  ColorModel cm2=temImg.getColorModel();
  System.out.println("cm2 : "+cm2);
  /**
   * 将top图片抠图操作与重绘操作分离开,降低了资源损耗
   * 将top图片镂空以后,保存在指定路径下,然后再读取该路径下的图片
   * 
   * 镂空图片方法,将图片中不需要的部分设置成同一颜色,然后将其抠出
   * */
  for (int x = temImg.getMinX(); x < temImg.getWidth(); x++) {
   for (int y = temImg.getMinY(); y < temImg.getHeight(); y++){
    int pixel = temImg.getRGB(x, y);
    rgb  =   new   int [ 3 ];
    rgb[ 0 ]  =  (pixel  &   0xff0000 )  >>   16 ;
    rgb[ 1 ]  =  (pixel  &   0xff00 )  >>   8 ;
    rgb[ 2 ]  =  (pixel  &   0xff );
    
    //alphaComposite=AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f);
    
    if(rgb[0]==red && rgb[1]==green && rgb[2]==blue){
     alp= decAlpha<< 24 | rgb[ 0 ]  << 16 |  rgb[ 1 ] << 8 |  rgb[ 2 ];
     temImg.setRGB(x,y,alp);
    }else{
     
     
    }
    /*设置抠出图片中一定范围的图像*/
    /*if (rgb[0] > red_min && rgb[0] < red_max && rgb[1] > green_min
      && rgb[1] < green_max && rgb[2] > blue_min
      && rgb[2] < blue_max) {
                    rgb[0]=1;
                    rgb[1]=1;
                    rgb[2]=1;
     alp=0;
     alp= decAlpha<< 24 | rgb[ 0 ]  << 16 |  rgb[ 1 ] << 8 |  rgb[ 2 ];
     temImg.setRGB(x,y,alp);
    }*/
    
   }
  }
  try{
  FileOutputStream out = new FileOutputStream(path);
     JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
     encoder.encode(temImg);
     out.close();
  }catch(Exception e){
   
  }

  return path;
 }
 
 
 /**有些图片没有透明度,所以必须添加透明度
  * */
 private void setImageAlpha(BufferedImage temImg){
  
  
  int setAlpha=0;
  
  for (int x = temImg.getMinX(); x < temImg.getWidth(); x++) {
   for (int y = temImg.getMinY(); y < temImg.getHeight(); y++){
   
    int pixel = temImg.getRGB(x, y);
    rgb  =   new   int [ 3 ];
    rgb[ 0 ]  =  (pixel  &   0xff0000 )  >>   16 ;
    rgb[ 1 ]  =  (pixel  &   0xff00 )  >>   8 ;
    rgb[ 2 ]  =  (pixel  &   0xff );
    
    alp= setAlpha<< 24 | rgb[ 0 ]  << 16 |  rgb[ 1 ] << 8 |  rgb[ 2 ];
    temImg.setRGB(x,y,alp);
    
   }
  }
  
  try{
   FileOutputStream out = new FileOutputStream(path);
      JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
      encoder.encode(temImg);
      out.close();
   }catch(Exception e){
    e.printStackTrace();
   }
 }
 
 public void paint(Graphics g){
  //super.paint(g);
  
  Graphics2D g2d=(Graphics2D)g;
  g2d.drawImage(bot_img,bottom_x, bottom_y, null);
  
  g2d.setComposite(alphaComposite);  
  sh_bottom=new Rectangle.Double(bottom_x,bottom_y,bot_img.getWidth(),bot_img.getHeight());
  g2d.draw(sh_bottom);
 
  alphaComposite=AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
  g2d.setComposite(alphaComposite);
  g2d.drawImage(top_img, top_x, top_y, null);
  alphaComposite=AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0f);
  g2d.setComposite(alphaComposite);
  if(top_img==null){
   System.out.println("null");
  }
  sh_top=new Rectangle.Double(top_x,top_y,top_img.getWidth(),top_img.getHeight());
  g2d.draw(sh_top);
  g2d.dispose();
 }
 
 public void update(Graphics g) {
  if (offScreenImg == null) {
   offScreenImg = (BufferedImage) this.createImage(frame_width,
     frame_height);
  }
  Graphics goffScreen = offScreenImg.getGraphics();
  Color c = goffScreen.getColor();
  goffScreen.setColor(Color.white);
  goffScreen.fillRect(0, 0, frame_width, frame_height);
  goffScreen.setColor(c);
  paint(goffScreen);  
  g.drawImage(offScreenImg, 0, 0, this);
        
 }

 
 /**鼠标控制两张图片移动*/
 class MouseControl extends MouseAdapter implements MouseMotionListener{

      private int x;
         private int y;
            
         private int maxr=0,maxg=0,maxb=0;
         private int minr=255,ming=255,minb=255;
         
         private int mrgb[]=null;
         
         private boolean onTop=false,onBottom=false;
        
         public void mousePressed(MouseEvent e) {
             x = e.getX();
             y = e.getY();
             
             /**通过两个shape对象来获取鼠标点取的图形*/
             if(sh_top.contains(x, y)){
              //点取top图
              onTop=true;
              onBottom=false;
              
              getPixelAlpha(top_img,x-top_x,y-top_y);
              
             }else if(sh_bottom.contains(x, y)){
              //点取bottom
              onBottom=true;
              onTop=false;
              //getPixelAlpha(bot_img,x-bottom_x,y-bottom_y);
             }
            
         }
         
         public void mouseReleased(MouseEvent e){
          onTop=false;
          onBottom=false;
         }

         public void mouseDragged(MouseEvent e) {

             int dx = e.getX()-x;
             int dy = e.getY()-y;
                
             if(onTop){
              
              top_x=top_x+dx;
              top_y=top_y+dy;
              
             }else if(onBottom){
              
              bottom_x=bottom_x+dx;
              bottom_y=bottom_y+dy;
              
             }else{
              System.out.println("doNothing");
             }
             update(g);
             //repaint();
             
             x=x+dx;
             y=y+dy;
         }  
         
         /**给定一个BufferedImage,判断该图像上点Pt的透明度值
          * 
          * ptx:bfImg图像上点x坐标
          * pty:bfImg图像上点y坐标
          * 
          * 当ptx或pty值超过了图像大小则抛出ArrayOutOfBoundsException异常
          * */
         private void getPixelAlpha(BufferedImage bfImg,int ptx, int pty){
          
          int pixel = bfImg.getRGB(ptx, pty);
    mrgb  =   new   int [ 3 ];
    mrgb[ 0 ]  =  (pixel  &   0xff0000 )  >>   16 ;
    mrgb[ 1 ]  =  (pixel  &   0xff00 )  >>   8 ;
    mrgb[ 2 ]  =  (pixel  &   0xff );
          
    
    if(mrgb[0]==0 && mrgb[1]==0 && mrgb[2]==0){
     System.out.println("透明区域");
    }else{
     System.out.println("不透明区域");
    }
    
      // printRGB(mrgb[0],mrgb[1],mrgb[2]);
         }
      
         /**
          * 通过鼠标点取找到透明区域中RGB值的最大值和最小值从而确定一个有效范围
          * 输出最大值和最小值
          * */
         private void   printRGB(int r,int g,int b){
          
          if(r>maxr){
           maxr=r;
          }else if(r<minr){
           minr=r;
          }
          if(r>maxg){
           maxg=g;
          }else if(g<ming){
           ming=g;
          }
                if(r>maxb){
           maxb=b;
          }else if(b<minb){
           minb=b;
          }
          System.out.println(minr+"<R<"+maxr+" , "+ming+"<G<"+maxg+" , "+minb+"<B<"+maxb);
         }
  
  
 }
 
 /**
  * MyFilter类,用于过滤指定像素值,
  * 但频繁的函数调用会使运行效率降低,所以不采用
  * */
 class MyFilter extends RGBImageFilter {
          
  int alpha=0;
  
  /**构造器*/
  public MyFilter() {
   this.canFilterIndexColorModel = true;
  }
  /***********************************************************************
   * i: 图像的x坐标值 j: 图像的y坐标值 k: 图像(i,j)坐标点上的RGB值
   **********************************************************************/
  public int filterRGB(int i, int j, int k) {

   DirectColorModel dcm = (DirectColorModel) ColorModel
     .getRGBdefault();
   // DirectColorModel类用来将ARGB值独立分解出来
   int red = dcm.getRed(k);
   int green =0;
   int blue = 0;
   //int alp = dcm.getAlpha(k);
   
   // 如果像素为指定RGB值,则让它透明
   if (red==0 ) {
    green = dcm.getGreen(k);
    if(green==74){
     blue = dcm.getBlue(k);
     if(blue==74){
      alpha = decAlpha;
      return alpha << 24 | red << 16 | green << 8 | blue;
     }
    } 
   } 
   return alpha << 24 | red << 16 | green << 8 | blue;
  }

 }

}





分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics