第十四章学习笔记

一,教材学习内容(14.图形、图像和音频)

1、图形

Java中绘制基本图形,可以使用Java类库中的Graphics类,此类位于java.awt包中。在我们自己的java程序文件中,要使用Graphics类就需要使用import java.awt.Graphics语句将Graphics类导入进来。

Graphics类提供基本的几何图形绘制方法,主要有:画线段、画矩形、画圆、画带颜色的图形、画椭圆、画圆弧、画多边形等。本项目仅用到画直线的功能,其它图形绘制请自行点击查阅Java API

Graphics类的drawLine()方法:drawLine(int x1,int y1,int x2,int y2)

此方法的功能是:在此图形上下文的坐标系中,使用当前颜色在点 (x1,y1) 和 (x2,y2)之间画一条线。

这里需要理解几个概念:

1)图形上下文:通俗点讲,就是画图环境。每个窗口构件(如主窗口、按钮等),都有一个自己的图形上下文对象,我们就是使用这个对象来实现在构件上画图。这个对象就是Graphics对象。

2)如何获得图形上下文:我们要在哪个构件上绘图,就调用那个构件的getGraphics()方法即可获得该构件的图形上下文对象,然后使用这个对象绘图。

3)Java坐标系:

例如我们绘制一个红格子图

扫描二维码关注公众号,回复: 4422916 查看本文章
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
  

/**
 * 
 * 程序入口
 *
 */
public class TestDrawLine {   
    public static void main(String[] args) {   
        new DrawSee();
    }   
}   

class DrawSee extends JFrame {
    private static final long serialVersionUID = 2L;
    private static final int sx = 50;//小方格宽度
    private static final int sy = 50;//小方格高度
    private static final int w = 40;
    private static final int rw = 400;
    private int px = 0, py = 0;
    
    private Graphics jg;
    private int cc = 0;// 被选中的方格个数
    private int[][] map;// 存放游戏数据的二维数组
    private boolean isEnd = false;
    private Color rectColor = new Color(0xf5f5f5);
    
    /**
     * DrawSee构造方法
     */
    public DrawSee() {
        Container p = getContentPane();
        setBounds(100, 100, 500, 500);
        setVisible(true);
        p.setBackground(rectColor);
        setLayout(null);   
        setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        
        
        try {
            // 创建游戏数据地图
            map = SeeAgain.createMap();
            
            Thread.sleep(500);
        } catch (Exception e) {
            e.printStackTrace();
        }        

        // 获取专门用于在窗口界面上绘图的对象
        jg =  this.getGraphics();
        
        // 绘制游戏区域
        paintComponents(jg);
        
        
        // 添加鼠监听事件,当鼠标点击时触发
        this.addMouseListener(new MouseAdapter() {
            
            // 定义鼠标点击事件响应过程
            @Override
            public void mouseClicked(MouseEvent e) {
                // 如果游戏结束,返回,不执行后面的代码
                if(isEnd) {                    
                    return;
                }                

                //获取鼠标点击的那一点的x,y坐标
                int x = e.getX(), y = e.getY();
                
                /**
                 * 计算当前点击的方格是第几个
                 * cx:当前点击的方格处于水平方向第几个
                 * cy: 当前点击的方格处于竖直方向第几个
                 */
                int cx = (x - sx) / w, cy = (y - sy) / w;                

                /**
                 * 如果点击的方格处于游戏区域之外,
                 * 直接返回,不执行后面的代码
                 */
                if(cx < 1 || cy < 1 || cx > 8 || cy > 8) {
                    return;
                }
                
                // 被选中的方格个数增加一个
                cc ++;
                
                compare(cx,cy);
                
            }
        });
        
    }
    
    /**
     * 判断二维数组map中的所有元素是否均为0,
     * 只要有一个不为0,返回false,表示游戏还没结束;否则返回true表示游戏结束
     * @param map 二维数组,元素为int类型
     * @return
     */
    public boolean isEnd(int[][] map) {
        for(int[] ms : map) {
            for(int m : ms) {
                if(m != 0) {
                    return false;
                }
            }
        }
        return true;
    }    

    
    public void paintComponents(Graphics g) {
        try {
            
            // 设置线条颜色为红色
            g.setColor(Color.RED);
            
            // 绘制外层矩形框
            g.drawRect(sx, sy, rw, rw);
            
            /* 绘制水平10个,垂直10个方格。
             * 即水平方向9条线,垂直方向9条线,
             * 外围四周4条线已经画过了,不需要再画。
             * 同时内部64个方格填写数字。
             */
            for(int i = 1; i < 10; i ++) {
                // 绘制第i条竖直线
                g.drawLine(sx + (i * w), sy, sx + (i * w), sy + rw);
                
                // 绘制第i条水平线
                g.drawLine(sx, sy + (i * w), sx + rw, sy + (i * w));
                
                // 填写第i行从第1个方格到第8个方格里面的数字(方格序号从0开始)
                for(int j = 0; j < 10; j ++) {
                    drawString(g, j, i);                    
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void drawString(Graphics g, int x, int y) {
        // 为0就不显示
        if(map[x][y] != 0) {
            g.setColor(Color.RED);// Graphics对象颜色在之前又被修改过,所以每次需要将颜色重新设置为红色
            g.setFont(new Font("Arial", 0, 40));// 设置Graphics对象字体大小
            g.drawString(map[x][y] + "", sx + (y  * w) + 5, sy + ((x + 1) * w) - 5);// 绘制字符
        }
    }

    /***
     * 讲制定小方格设置为指定背景颜色
     * @param cx 方格的水平方向序号
     * @param cy 方格的垂直方向序号
     * @param color
     */
    private void setGrid(int cx,int cy,Color color){
        // 将绘图对象设置为灰色,后面会将所点击的方格背景设置为此颜色
        jg.setColor(color);
        
        /**
         * 将所点击的方格上绘制一个小一点的矩形,矩形背景颜色为color,
         * 绘制的这个Rect会导致该方格上原有的文字被覆盖
         */
        jg.fillRect(sx + (cx * w) + 1, sy + (cy * w) + 1, w - 2, w - 2);
        
        // 将覆盖的数字重新写出来,这样就又看到红色的文字了。
        drawString(jg, cy, cx);
    }
    
    private void compare(int cx,int cy){
        /**
         *  如果cc是1,表示当前一共选中了一个方格,用px,py来记住这个方格的位置;
         *  否则,表示现在选中的这个方格要与之前选中的方案比较,决定是否要删除
         */
        if(cc == 1) {
            px = cx;
            py = cy;
            
            // 将所点击的方格背景设置为灰色
            setGrid(cx,cy,Color.LIGHT_GRAY);                        
        }                
        else{//此时,cc肯定是大于1的,表示要比较两个方格的值是否相同
            SeeAgain.removed(map, py, px, cy, cx );// 让SeeAgain类的remove方法去判断上一次所选
                                                //的(px,py)处的方格值与本次选择的(cx,cy)处的方格值是否可以消掉
            
            // 处理第一个方格
            setGrid(cx,cy,rectColor);
            
            // 处理第二个方格
            setGrid(px,py,rectColor);

            cc = 0;//将cc的值复位
        }
        
        // 判断是否结束游戏
        isEnd = isEnd(map);        
        if(isEnd) {
            jg.setColor(Color.RED);
            jg.setFont(new Font("Arial", 0, 62));
            jg.drawString("Game Over!", 100, 220);
        }
    }
}

注意,在窗口元素上绘制直线、写文字等操作,使用到的是一个叫做Graphics的对象。在构造函数的第58行语句中,this.getGraphics()语句是获取游戏窗口的绘图对象(一个Graphics对象),这里的this是指程序运行后用户看到的那个窗口,getGraphics()方法就是得到绘图对象。获取到这个对象后,被保存到成员变量jg中,这样,在其他成员方法中就可以直接使用这个jg对象来绘图了。

DrawSee类另外几个成员:

setGrid(int cx,int cy,Color color):设置被选中的cx行,cy列网格的背景

compare(int cx,int cy):比较cx行cy列网格和之前选中的网格是否可以消除

drawString(Graphics g, int x, int y):在x行y列网格上写数字

isEnd(int[][] map) :判断二维数组map是不是全0。

2、图像

具体操作在代码中展示,算是一个小demo吧。

package com.cy.thumb;

import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

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

public class Thumb {
    public static void main(String[] args) throws IOException {
        
        //把图片image.png 长宽等比缩小5倍。
        reduceImage("E:/image.png", "E:/image1.png", 5);
        
        //把图片image.png 长宽各设置为100
        reduceImage("E:/image.png", "E:/image2.png", 100, 100);
        
    }
    
    
    /**
     * 对图片进行剪裁   返回字节数组
     * @param is            图片输入流
     * @param width            裁剪图片的宽
     * @param height        裁剪图片的高
     * @param imageFormat    输出图片的格式 "jpeg jpg等"
     * @return
     */
    public static byte[] clipImage(InputStream is,int width, int height, String imageFormat){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            // 构造Image对象
            BufferedImage src = javax.imageio.ImageIO.read(is);
            // 缩小边长 
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 绘制 缩小  后的图片 
            tag.getGraphics().drawImage(src, 0, 0, width, height, null); 
            ImageIO.write(tag, imageFormat, bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        return bos.toByteArray();
    }
    
    
    
    /**
     * 重置图片大小
     * @param srcImagePath            读取图片路径
     * @param toImagePath            写入图片路径
     * @param width                    重新设置图片的宽
     * @param height                重新设置图片的高
     * @throws IOException
     */
    public static void reduceImage(String srcImagePath,String toImagePath,int width, int height) throws IOException{
        FileOutputStream out = null;
        try{
            //读入文件  
            File file = new File(srcImagePath);
            // 构造Image对象 
            BufferedImage src = javax.imageio.ImageIO.read(file);
            // 缩小边长 
            BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 绘制 缩小  后的图片 
            tag.getGraphics().drawImage(src, 0, 0, width, height, null);  
            out = new FileOutputStream(toImagePath);  
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);  
            encoder.encode(tag);  
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(out != null){
                  out.close();  
            }
        }
    }
    
    /**
     * 按倍率缩小图片
     * @param srcImagePath        读取图片路径
     * @param toImagePath        写入图片路径
     * @param ratio                缩小比率  宽、高一起等比率缩小
     * @throws IOException
     */
    public static void reduceImage(String srcImagePath,String toImagePath,int ratio) throws IOException{
        FileOutputStream out = null;
        try{
            //读入文件  
            File file = new File(srcImagePath);
            // 构造Image对象 
            BufferedImage src = javax.imageio.ImageIO.read(file);
            int width = src.getWidth();  
            int height = src.getHeight();  
            // 缩小边长 
            BufferedImage tag = new BufferedImage(width / ratio, height / ratio, BufferedImage.TYPE_INT_RGB);
            // 绘制 缩小  后的图片 
            tag.getGraphics().drawImage(src, 0, 0, width / ratio, height / ratio, null);  
            out = new FileOutputStream(toImagePath);  
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);  
            encoder.encode(tag);  
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(out != null){
                  out.close();  
            }
        }
    }
    
    
    
    /**
     * 对图片裁剪,并把裁剪新图片保存
     * @param srcPath               读取源图片路径
     * @param toPath             写入图片路径
     * @param x                     剪切起始点x坐标
     * @param y                     剪切起始点y坐标
     * @param width                 剪切宽度
     * @param height             剪切高度
     * @param readImageFormat     读取图片格式
     * @param writeImageFormat   写入图片格式
     */
    public static void cropImage(String srcPath, String toPath, int x,int y,int width,int height, String readImageFormat,String writeImageFormat){
        FileInputStream fis = null ;
        ImageInputStream iis =null ;
        try{ 
            //读取图片文件
            fis = new FileInputStream(srcPath);
            Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(readImageFormat); 
            ImageReader reader = readers.next();
            //获取图片流
            iis = ImageIO.createImageInputStream(fis); 
            reader.setInput(iis, true);
            ImageReadParam param = reader.getDefaultReadParam();
            //定义一个矩形
            Rectangle rect = new Rectangle(x, y, width, height);
            //提供一个 BufferedImage,将其用作解码像素数据的目标。
            param.setSourceRegion(rect);
            BufferedImage bi = reader.read(0, param);
            //保存新图片
            ImageIO.write(bi, writeImageFormat, new File(toPath));
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            try{
                if(fis!=null){
                    fis.close();
                }
                if(iis!=null){
                    iis.close();
                }
            }catch(Exception e){
                e.printStackTrace();
            }
        }
    }
    
    
}

猜你喜欢

转载自blog.csdn.net/Huangxu_MIKU/article/details/84891437