逻辑梳理:
1、根据图片切割出来小图片,原图片小图片部分加阴影。
2、阴影图片和切割后图片传给前台
3、前段确定用户图片拖动长度
4、这里产生分歧,长度验证是传回后端验证,还是直接在前段处理。
无论如何,业务逻辑不谈,核心是要存在工具切割图片达到效果,这里展示下我的工具。
一、ImageUtils cut方法即为切割逻辑
package com.cloudwise.util;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import sun.misc.BASE64Encoder;
public class ImageUtils {
/**
* jpg图片格式
*/
private static final String IMAGE_FORM_OF_JPG = "jpg";
/**
* png图片格式
*/
private static final String IMAGE_FORM_OF_PNG = "png";
/**
* 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
* 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
*
* @param postFix
* 文件的后缀名
* @return
*/
public static Iterator<ImageReader> getImageReadersByFormatName(String postFix) {
switch (postFix) {
case IMAGE_FORM_OF_JPG:
return ImageIO.getImageReadersByFormatName(IMAGE_FORM_OF_JPG);
case IMAGE_FORM_OF_PNG:
return ImageIO.getImageReadersByFormatName(IMAGE_FORM_OF_PNG);
default:
return ImageIO.getImageReadersByFormatName(IMAGE_FORM_OF_JPG);
}
}
/**
* 对图片裁剪,并把裁剪完de新图片保存 。
* @param srcpath 源图片路径
* @param subpath 剪切图片存放路径
* @throws IOException
*/
public static Map<String,String> cut(ImageCutParam param1) throws IOException {
FileInputStream is = null;
ImageInputStream iis = null;
try {
// 读取图片文件
is = new FileInputStream(param1.getResourcePath());
// 获取文件的后缀名
String postFix = getPostfix(param1.getResourcePath());
System.out.println("图片格式为:" + postFix);
/*
* 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
* 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
*/
Iterator<ImageReader> it = getImageReadersByFormatName(postFix);
ImageReader reader = it.next();
// 获取图片流
iis = ImageIO.createImageInputStream(is);
/*
* <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
* 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
*/
reader.setInput(iis, true);
/*
* <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O
* 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的
* getDefaultReadParam 方法中返回 ImageReadParam 的实例。
*/
ImageReadParam param = reader.getDefaultReadParam();
/*
* 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域,通过 Rectangle 对象
* 的左上顶点的坐标(x,y)、宽度和高度可以定义这个区域。
*/
Rectangle rect = new Rectangle(param1.getX(), param1.getY(), param1.getW(), param1.getH());
// 提供一个 BufferedImage,将其用作解码像素数据的目标。
param.setSourceRegion(rect);
/*
* 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象,并将 它作为一个完整的
* BufferedImage 返回。
*/
BufferedImage bi = reader.read(0, param);
ByteArrayOutputStream CatBaos = new ByteArrayOutputStream();//io流
ImageIO.write(bi, postFix, CatBaos);//写入流中
byte[] CutBytes = CatBaos.toByteArray();//转换成字节
BASE64Encoder encoder = new BASE64Encoder();
String CutPng_base64 = encoder.encodeBuffer(CutBytes).trim();//转换成base64串
CutPng_base64 = CutPng_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
// String path = subpath + "_" + new Date().getTime() + "." + postFix;
//
File file = new File(param1.getTargetPath()+"\\"+new Date().getTime()+"."+postFix);
File fileParent = file.getParentFile();
if(!fileParent.exists()){
System.out.println("自动创建文件");
fileParent.mkdirs();
}
file.createNewFile();
// 保存新图片
ImageIO.write(bi, postFix, file);
/*********************************************************************************/
/*************************生成数组*************************/
BufferedImage sourceImg = ImageIO.read(new FileInputStream(param1.getResourcePath()));
int[][] data = new int[sourceImg.getWidth()][sourceImg.getHeight()];
for (int i=0;i<sourceImg.getWidth();i++){//1280
for(int j=0;j<sourceImg.getHeight();j++){//720
if(i< param1.getX() +200 && i >= param1.getX() && j < param1.getY() + 120 && j > param1.getY()){
data[i][j]=1;
}else {
data[i][j]=0;
}
}
}
/*********************************************************/
/************************图片局部变黑************************/
for (int i = 0; i < sourceImg.getWidth(); i++) {
for (int j = 0; j < sourceImg.getHeight(); j++) {
int rgb = data[i][j];
// 原图中对应位置变色处理
int rgb_ori = sourceImg.getRGB(i, j);
if (rgb == 1) {
//颜色处理
int r = (0XFF000000 & rgb_ori);
int g = (0XFF000000 & (rgb_ori >> 8));
int b = (0XFF000000 & (rgb_ori >> 16));
int Gray = (r*2 + g*5 + b*1) >> 3;
//原图对应位置颜色变化
sourceImg.setRGB(i, j, Gray);
}
}
}
/**********************************************************/
/************************阴影图片转base64************************/
//BASE64Encoder encoder = new BASE64Encoder();
ByteArrayOutputStream YYbaos = new ByteArrayOutputStream();//io流
ImageIO.write(sourceImg, postFix, YYbaos);//写入流中
byte[] bytes = YYbaos.toByteArray();//转换成字节
String YYPng_base64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
YYPng_base64 = YYPng_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
FileOutputStream fos = new FileOutputStream(
new File(param1.getTargetPath()+"\\"+new Date().getTime()+"." +postFix));
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(bytes);
Map<String, String> map = new HashMap<String,String>();
map.put("x", param1.getX()+""); //裁剪开始X坐标
map.put("y", param1.getY()+""); //裁剪开始Y坐标
map.put("backGroud", YYPng_base64); //阴影图片base
map.put("cutImg", CutPng_base64);//裁剪图片base
return map;
} finally {
if (is != null)
is.close();
if (iis != null)
iis.close();
}
}
/**
* 获取inputFilePath的后缀名,如:"e:/test.pptx"的后缀名为:"pptx"<br>
*
* @param inputFilePath
* @return
*/
public static String getPostfix(String inputFilePath) {
return inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1);
}
}
2、上面需要的参数类ImageCutParam
package com.cloudwise.util;
import java.util.Random;
public class ImageCutParam {
/**
* 代表背景图片的长和宽
*/
private final static int Image_Width = 700;
private final static int Image_Height = 480;
/**
* 在被裁剪的图上的裁剪位置的x
*/
private int x;
/**
*在被裁剪的图上的裁剪位置的y
*/
private int y;
/**
* 要裁剪出来的图片的长
*/
private int w = 200;
/**
* 要裁剪出来的图片的宽
*/
private int h = 120;
private String resourcePath;
private String targetPath = "D:\\aimg";
public ImageCutParam() {}
public ImageCutParam(String resourcePath) {
super();
Random rand = new Random();
int ImgIndex = rand.nextInt(5) +1; //生成0-6以内的随机数
int x = rand.nextInt(ImageCutParam.Image_Width); //生成0-700以内的随机数
int y = rand.nextInt(ImageCutParam.Image_Height); //生成0-480以内的随机数
if(x < this.getW()){
x = x + 200;
}
if(x > ImageCutParam.Image_Width-this.getW()){
x = x-this.getW();
}
if(y > ImageCutParam.Image_Height - this.getH()){
y = y -this.getH();
}
this.x = x;
this.y = y;
this.resourcePath = resourcePath;
}
public ImageCutParam(int x, int y, int w, int h, String resourcePath, String targetPath) {
super();
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.resourcePath = resourcePath;
this.targetPath = targetPath;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getW() {
return w;
}
public void setW(int w) {
this.w = w;
}
public int getH() {
return h;
}
public void setH(int h) {
this.h = h;
}
public String getResourcePath() {
return resourcePath;
}
public void setResourcePath(String resourcePath) {
this.resourcePath = resourcePath;
}
public String getTargetPath() {
return targetPath;
}
public void setTargetPath(String targetPath) {
this.targetPath = targetPath;
}
}
三、使用例子
package com.cloudwise.latch;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
import com.cloudwise.util.ImageCutParam;
import com.cloudwise.util.ImageUtils;
public class Test {
public static void main(String[] args) throws IOException {
Map<Object,Object> map = new HashMap<Object,Object>();
ImageCutParam param = new ImageCutParam("D:\\aimg\\timg.jpg");
Map<String,String> map1 = ImageUtils.cut(param);
map1.forEach((k,v) -> {
System.out.println("key : "+ k +" , value : " + v);
});
}
}
最后只展示下切割后的图片: