实例1:图片读取、写入、两张图片的拼接与剪裁
package basic;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class ImageTest {
public static void main(String[] args) throws Exception {
readAndWrite();
readComparison();
cropImage("c:/temp/ecnu.jpg", "c:/temp/shida.jpg", 750, 250, 700, 300, "jpg", "jpg");
combineImagesHorizontally("c:/temp/ecnu.jpg","c:/temp/ecnu.jpg","jpg", "c:/temp/ecnu2.jpg");
combineImagesVertically("c:/temp/ecnu.jpg","c:/temp/ecnu.jpg","jpg", "c:/temp/ecnu3.jpg");
}
public static void readAndWrite() throws Exception {
//使用ImageIO的read方法读取一个文件获得image对象
BufferedImage image = ImageIO.read(new File("c:/temp/ecnu.jpg"));
System.out.println("Height: " + image.getHeight()); // 高度像素
System.out.println("Width: " + image.getWidth()); // 宽度像素
ImageIO.write(image, "png", new File("c:/temp/ecnu.png"));
}
public static void readComparison() throws Exception {
System.out.println("===========加载速度测试==============");
// ImageIO需要测试图片的类型,加载合适的ImageReader来读取图片,耗时更长
long startTime = System.nanoTime();
BufferedImage image = ImageIO.read(new File("c:/temp/ecnu.jpg"));
System.out.println("Height: " + image.getHeight()); // 高度像素
System.out.println("Width: " + image.getWidth()); // 宽度像素
long endTime = System.nanoTime();
System.out.println((endTime - startTime) / 1000000.0 + "毫秒");
// 指定用jpg Reader来加载,速度会加快
startTime = System.nanoTime();
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("jpg");
ImageReader reader = (ImageReader) readers.next();
System.out.println(reader.getClass().getName());
ImageInputStream iis = ImageIO.createImageInputStream(new File("c:/temp/ecnu.jpg"));
reader.setInput(iis, true);
System.out.println("Height:" + reader.getHeight(0));
System.out.println("Width:" + reader.getWidth(0));
endTime = System.nanoTime();
System.out.println((endTime - startTime) / 1000000.0 + "毫秒");
}
/**
* cropImage 将原始图片文件切割一个矩形,并输出到目标图片文件
* @param fromPath 原始图片
* @param toPath 目标图片
* @param x 坐标起点x
* @param y 坐标起点y
* @param width 矩形宽度
* @param height 矩形高度
* @param readImageFormat 原始文件格式
* @param writeImageFormat 目标文件格式
* @throws Exception
*/
public static void cropImage(String fromPath, String toPath, int x, int y, int width, int height,
String readImageFormat,String writeImageFormat) throws Exception {
FileInputStream fis = null;
ImageInputStream iis = null;
try {
// 读取原始图片文件
fis = new FileInputStream(fromPath);
//创建一个Iterator<ImageReader>迭代器,用于接受确定了格式的ImageReader对象
Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(readImageFormat);
//获取下一个ImageReader对象
ImageReader reader = it.next();
//使用文件输入流创建一个图像输入流(ImageInputStream)对象
iis = ImageIO.createImageInputStream(fis);
//使用ImageReader对象的setInput方法接受图像输入流来读取图片
reader.setInput(iis, true);
// 定义一个矩形 并放入切割参数中
ImageReadParam param = reader.getDefaultReadParam();
Rectangle rect = new Rectangle(x, y, width, height);
param.setSourceRegion(rect);
//从源文件读取一个矩形大小的图像
BufferedImage bi = reader.read(0, param);
//写入到目标文件
//第1参数是BufferedImage对象,第2参数是图片格式
//第3参数是新文件的输出路径
ImageIO.write(bi, writeImageFormat, new File(toPath));
} finally {
fis.close();
iis.close();
}
}
/**
* 横向拼接两张图片,并写入到目标文件
* 拼接的本质,就是申请一个大的新空间,然后将原始的图片像素点拷贝到新空间,最后保存
* @param firstPath 第一张图片的路径
* @param secondPath 第二张图片的路径
* @param imageFormat 拼接生成图片的格式
* @param toPath 目标图片的路径
*/
public static void combineImagesHorizontally(String firstPath, String secondPath,String imageFormat, String toPath){
try {
//读取第一张图片
File first = new File(firstPath);
BufferedImage imageOne = ImageIO.read(first);
int width1 = imageOne.getWidth();//图片宽度
int height1 = imageOne.getHeight();//图片高度
//从第一张图片中读取RGB
int[] firstRGB = new int[width1*height1];
firstRGB = imageOne.getRGB(0,0,width1,height1,firstRGB,0,width1);
//对第二张图片做同样的处理
File second = new File(secondPath);
BufferedImage imageTwo = ImageIO.read(second);
int width2 = imageTwo.getWidth();
int height2 = imageTwo.getHeight();
int[] secondRGB = new int[width2*height2];
secondRGB = imageTwo.getRGB(0,0,width2,height2,secondRGB,0,width2);
//生成新图片
int height3 = (height1>height2)?height1:height2; //挑选高度大的,作为目标文件的高度
int width3 = width1 + width2; //宽度,两张图片相加
BufferedImage imageNew = new BufferedImage(width3,height3,BufferedImage.TYPE_INT_RGB);
//设置左半部分的RGB 从(0,0) 开始
imageNew.setRGB(0,0,width1,height1,firstRGB,0,width1);
//设置右半部分的RGB 从(width1, 0) 开始
imageNew.setRGB(width1,0,width2,height2,secondRGB,0,width2);
//保存图片
ImageIO.write(imageNew, imageFormat, new File(toPath));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 纵向拼接图片(两张)
* 拼接的本质,就是申请一个大的新空间,然后将原始的图片像素点拷贝到新空间,最后保存
* @param firstPath 读取的第一张图片
* @param secondPath 读取的第二张图片
* @param imageFormat 图片写入格式
* @param toPath 图片写入路径
*/
public static void combineImagesVertically(String firstPath, String secondPath,String imageFormat, String toPath){
try {
//读取第一张图片
File first = new File(firstPath);
BufferedImage imageOne = ImageIO.read(first);
int width1 = imageOne.getWidth();//图片宽度
int height1 = imageOne.getHeight();//图片高度
//从图片中读取RGB
int[] firstRGB = new int[width1*height1];
firstRGB = imageOne.getRGB(0,0,width1,height1,firstRGB,0,width1);
//对第二张图片做相同的处理
File second = new File(secondPath);
BufferedImage imageTwo = ImageIO.read(second);
int width2 = imageTwo.getWidth();
int height2 = imageTwo.getHeight();
int[] secondRGB = new int[width2*height2];
secondRGB = imageTwo.getRGB(0,0,width2,height2,secondRGB,0,width2);
//生成新图片
int width3 = (width1>width2)?width1:width2; //挑选宽度大的,作为目标文件的宽度
int height3 = height1+height2; //高度,两张图片相加
BufferedImage imageNew = new BufferedImage(width3,height3,BufferedImage.TYPE_INT_RGB);
//设置上半部分的RGB 从(0,0) 开始
imageNew.setRGB(0,0,width1,height1,firstRGB,0,width1);
//设置下半部分的RGB 从(0, height1) 开始
imageNew.setRGB(0,height1,width2,height2,secondRGB,0,width2);
//保存图片
ImageIO.write(imageNew, imageFormat, new File(toPath));
} catch (Exception e) {
e.printStackTrace();
}
}
}
实例2:图表制作(饼图、柱状图、折线图)
package charts;
import java.awt.Font;
import java.io.File;
import java.io.IOException;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
public class JFreeChartTest {
public static void main(String[] args) {
writeBar("c:/temp/bar.jpg"); // 柱状图
writePie("c:/temp/pie.jpg"); // 饼图
writeLine("c:/temp/line.jpg");// 折线图
}
public static StandardChartTheme getChineseTheme()
{
StandardChartTheme chineseTheme = new StandardChartTheme("CN");
chineseTheme.setExtraLargeFont(new Font("隶书", Font.BOLD, 20));
chineseTheme.setRegularFont(new Font("宋书", Font.PLAIN, 15));
chineseTheme.setLargeFont(new Font("宋书", Font.PLAIN, 15));
return chineseTheme;
}
public static void writeBar(String fileName) {
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(11, "", "第一季度");
dataset.addValue(41, "", "第二季度");
dataset.addValue(51, "", "第三季度");
dataset.addValue(4, "", "第四季度");
// PlotOrientation.HORIZONTAL横向 PlotOrientation.VERTICAL 竖向
// 引入中文主题样式
ChartFactory.setChartTheme(getChineseTheme());
JFreeChart chart = ChartFactory.createBarChart3D("柱状图", "2018年", "产品总量", dataset, PlotOrientation.VERTICAL,
false, false, false);
try {
ChartUtilities.saveChartAsJPEG(new File(fileName), chart, 600, 300);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void writePie(String fileName) {
DefaultPieDataset pds = new DefaultPieDataset();
pds.setValue("C人数", 100);
pds.setValue("C++人数", 200);
pds.setValue("Java人数", 300);
try {
ChartFactory.setChartTheme(getChineseTheme());
JFreeChart chart = ChartFactory.createPieChart("饼图", pds);
ChartUtilities.saveChartAsJPEG(new File(fileName), chart, 600, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void writeLine(String fileName) {
DefaultCategoryDataset lines = new DefaultCategoryDataset();
//第一条线
lines.addValue(100, "Java", "1月");
lines.addValue(200, "Java", "2月");
lines.addValue(400, "Java", "3月");
lines.addValue(500, "Java", "4月");
//第二条线
lines.addValue(100, "C++", "1月");
lines.addValue(400, "C++", "2月");
lines.addValue(900, "C++", "3月");
try {
ChartFactory.setChartTheme(getChineseTheme());
JFreeChart chart = ChartFactory.createLineChart("折线图", "时间", "人数", lines);
ChartUtilities.saveChartAsJPEG(new File(fileName), chart, 600, 300);
} catch (Exception e) {
e.printStackTrace();
}
}
}
实例3:验证码图片制作
package code;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
public class ValidateCodeTest {
//没有1 I L 0 o
static char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
static int charNum = codeSequence.length;
public static void main(String[] a) throws IOException
{
generateCode("c:/temp/code.jpg");
}
public static void generateCode(String filePath) throws IOException {
// 首先定义验证码图片框
int width = 1000; // 验证码图片的宽度
int height = 300; // 验证码图片的高度
BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
//定义图片上的图形和干扰线
Graphics2D gd = buffImg.createGraphics();
gd.setColor(Color.LIGHT_GRAY); // 将图像填充为浅灰色
gd.fillRect(0, 0, width, height);
gd.setColor(Color.BLACK); // 画边框。
gd.drawRect(0, 0, width - 1, height - 1);
// 随机产生16条灰色干扰线,使图像中的认证码不易识别
gd.setColor(Color.gray);
// 创建一个随机数生成器类 用于随机产生干扰线
Random random = new Random();
for (int i = 0; i < 16; i++) {
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
gd.drawLine(x, y, x + xl, y + yl);
}
//计算字的位置坐标
int codeCount = 4; // 字符个数
int fontHeight; // 字体高度
int codeX; // 第一个字符的x坐标,因为后面的字符坐标依次递增,所以它们的x轴值是codeX的倍数
int codeY; // 验证字符的y坐标,因为并排所以值一样
// width-4 除去左右多余的位置,使验证码更加集中显示,减得越多越集中。
// codeCount+1 //等比分配显示的宽度,包括左右两边的空格
codeX = (width - 4) / (codeCount + 1); //第一个字母的起始位置
fontHeight = height - 110; // height - 10 高度中间区域显示验证码
codeY = height - 220;
// 创建字体,字体的大小应该根据图片的高度来定。
Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
gd.setFont(font);
// 随机产生codeCount数字的验证码。
for (int i = 0; i < codeCount; i++) {
// 每次随机拿一个字母,赋予随机的颜色
String strRand = String.valueOf(codeSequence[random.nextInt(charNum)]);
int red = random.nextInt(255);
int green = random.nextInt(255);
int blue = random.nextInt(255);
gd.setColor(new Color(red,green,blue));
//把字放到图片上!!!
gd.drawString(strRand, (i + 1) * codeX, codeY);
}
ImageIO.write(buffImg, "jpg", new File(filePath));
}
}
仅供学习参考!欢迎讨论交流~