java project cutout function
The project needs a function of uploading text signatures and removing the background image. When I first heard this requirement, my jaw almost dropped. I never thought that this function could be realized in java. But since the customer needs it, let's do it.
After the realization of this function, I have also strengthened my idea. No matter how weird the demand is, I must first find a way. Don't refuse decisively. Believe, can there be Java天下第一
anything that can't be solved by No. 1 in the world? (Actually, I am already python
eager to learn in my heart, hehe~~~)
1. Rendering
After some searching and modification, I made the following effect with my front-end friends. (The whole is the same as PS, and it immediately feels taller)
The function is relatively simple, upload pictures to the backend, and the backend returns the path of the cutout picture.
The original picture is as follows:
After uploading this picture, first frame select the range and rotate the direction. Note that frame selection and rotate the picture are both front-end operations, and these front-end operations have methods, as shown in the figure below: After setting,
click 抠图
to See the effect of the picture below, it has become transparent. In this step, the cutout calls the cutout interface provided by java.
2. Button interface
The following is the image cutout interface. In this interface, the front end transmits the cropped picture to the back end. In this interface, the back end will pass the picture passed by the front end to the PictureUtils.transApla(restore,169)
method. In this method, the cutout will be performed. And save it again. After saving, return the processed image path to the front end, and the front end can display it directly. The detailed steps are as follows:
- The front-end uploads pictures to the panel. At this time, the back-end interface is not called, and it is only loaded by the front-end.
- Because the size and direction of the pictures uploaded by users are not fixed, some rotation and cropping functions should also be considered. Therefore, we also added these common functions here, and after rotation and cropping, the range was determined. Note that this is all done by the front end itself.
- After processing, call the tailoring interface, which is written in the code below, the focus is only on
PictureUtils.transApla(restore,169)
the method.
The following is the clipping interface:
/**
* 签名图扣掉背景色
* @param request
* @return
*/
@RequestMapping(value = "/signHandle",method = RequestMethod.POST)
public Object getPsPictureSign(HttpServletRequest request){
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
String fileName = null;
String msg = null;
String result = "";
try {
//获取文件
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
if(fileMap == null || fileMap.isEmpty()){
return addResultMapMsg(false,"未上传签名图片");
}
MultipartFile multipartFile = null;//获取文件名
for (Map.Entry<String, MultipartFile> set : fileMap.entrySet()) {
multipartFile = set.getValue();// 文件名
String uploadfileName = multipartFile.getOriginalFilename();
String suffix = uploadfileName.substring(uploadfileName.lastIndexOf(".")+1).toLowerCase();
if(!uploadSuffix.contains(suffix)){
return addResultMapMsg(false,"只能上传 png、jpg 图片格式");
}
}
//先将文件保存到服务器中,然后操作文件
String fileOriginalName = multipartFile.getOriginalFilename();
String resultStr = File.separator + "pictureTmp" + File.separator + File.separator + fileOriginalName.substring(0,fileOriginalName.lastIndexOf(".")+1) +".png";
fileName = realPath + resultStr;
File restore = new File(fileName);
if(!restore.getParentFile().exists()){
restore.getParentFile().mkdirs();
}
//System.out.println(3+"=="+fileName);
multipartFile.transferTo(restore);
// 抠图工具类
PictureUtils.transApla(restore,169); // 169为灰色的rcb色值
result = resultStr;
} catch (Exception e) {
e.printStackTrace();
msg = "处理失败";
}
if(!StringUtils.isEmpty(msg)){
//说明上传有错
return addResultMapMsg(false,msg);
}else {
return addResultMapMsg(true,result.replace("\\","/"));
}
}
The following are packaged tool classes, which can be used directly. In addition, because the method used is directly available in java, there is no need to reference additional jar packages.
The following is the tool class method:
package znxd.lxynzl.controller.photoshop;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.regex.Pattern;
/**
* Created by lingsf on 2020/6/16.
*/
public class PictureUtils {
public static int color_range = 210;
public static Pattern pattern = Pattern.compile("[0-9]*");
public static boolean isNo(String str) {
return pattern.matcher(str).matches();
}
/**
*
* @param file 保存后要处理的png文件
* @param rcb 要扣掉的rcb色值
*/
public static void transApla(File file,int rcb){
InputStream is=null;
try {
is = new FileInputStream(file);
// 如果是MultipartFile类型,那么自身也有转换成流的方法:is = file.getInputStream();
BufferedImage bi = ImageIO.read(is);
Image image = (Image) bi;
ImageIcon imageIcon = new ImageIcon(image);
BufferedImage bufferedImage = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2D = (Graphics2D) bufferedImage.getGraphics();
g2D.drawImage(imageIcon.getImage(), 0, 0, imageIcon.getImageObserver());
int alpha = 0;
color_range = 255 - rcb; // 0
for (int j1 = bufferedImage.getMinY(); j1 < bufferedImage
.getHeight(); j1++) {
for (int j2 = bufferedImage.getMinX(); j2 < bufferedImage
.getWidth(); j2++) {
int rgb = bufferedImage.getRGB(j2, j1);
if (colorInRange(rgb)) {
alpha = 0;
} else {
alpha = 255;
}
rgb = (alpha << 24) | (rgb & 0x00ffffff);
bufferedImage.setRGB(j2, j1, rgb);
}
}
g2D.drawImage(bufferedImage, 0, 0, imageIcon.getImageObserver());
ImageIO.write(bufferedImage, "png", file);// 直接输出文件
} catch (Exception e) {
e.printStackTrace();
} finally {
if(is!=null){
try{
is.close();
}catch (Exception e){
}
}
}
}
public static boolean colorInRange(int color) {
int red = (color & 0xff0000) >> 16;
int green = (color & 0x00ff00) >> 8;
int blue = (color & 0x0000ff);
if (red >= color_range && green >= color_range && blue >= color_range) {
return true;
}
return false;
}
}
3. Summary
The overall function is relatively simple. The backend only provides an interface. The main solution swing
is to replace the pigment used. 固定的色值替换为透明色素
Therefore, the function diagram prompts the user 白底黑字
to upload with the signature as much as possible.
Of course, you have also seen that the signature picture I wrote above was not taken out 白底黑字
, and the picture can still be cut out successfully.
Front-end vue download address: Baidu network disk Extraction code:nvt2