|
@@ -25,12 +25,16 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
+import javax.imageio.ImageIO;
|
|
|
+import java.awt.image.BufferedImage;
|
|
|
+import java.io.*;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalTime;
|
|
|
import java.time.ZoneOffset;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
/**
|
|
|
* <p>
|
|
@@ -43,7 +47,7 @@ import java.util.*;
|
|
|
@Service
|
|
|
@Transactional
|
|
|
public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screenshot> implements ScreenshotService {
|
|
|
-
|
|
|
+ public static List<String> nKeyWordsList = new ArrayList<String>();
|
|
|
public static Logger log = Logger.getLogger(ScreenshotServiceImpl.class);
|
|
|
|
|
|
//检测时间间隔秒数
|
|
@@ -51,7 +55,8 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
|
|
|
|
|
|
@Value(value = "${upload.path}")
|
|
|
private String path;
|
|
|
-
|
|
|
+ @Value("classpath:novel_words.data")
|
|
|
+ private org.springframework.core.io.Resource novelWords;
|
|
|
@Autowired
|
|
|
private RedisUtil redisUtil;
|
|
|
|
|
@@ -136,33 +141,39 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
|
|
|
//由于存入数据库的对象被序列化成了json字符串,所以从redis里拿方便
|
|
|
members = redisUtil.members(Constant.COMMON_SOFTWARE_KEYWORDS);
|
|
|
}
|
|
|
- List<String> exeprocessList = ProcessUtil.getExeprocessListfromProcessStr(screenshotvo.getProcessList());
|
|
|
- System.out.println("進程" + exeprocessList);
|
|
|
- boolean derail = false;//判断是否匹配的开关
|
|
|
- Integer lastType = null;
|
|
|
- for (String textContent : textContents) {
|
|
|
- for (Object member : members) {
|
|
|
- //由于redis里存储的member是一个PicContentKeywords类型的json字符串,所以取出关键字内容比较
|
|
|
- JSONObject jsonMember = JSON.parseObject((String) member);
|
|
|
- if (textContent.toLowerCase().contains(jsonMember.getString("content").toLowerCase())) {
|
|
|
- log.info("图片文字中包含了关键词--->" + jsonMember.getString("content"));
|
|
|
- log.info("图片文字识别出的类型--->" + jsonMember.getInteger("type"));
|
|
|
- //找到对应关键字,确定图片是哪个类型的图片
|
|
|
- //结合进程判断
|
|
|
- if (exeprocessList.contains(jsonMember.getString("processName").toLowerCase())) {
|
|
|
- if (!derail) {
|
|
|
- //判断是否是第一次匹配
|
|
|
- log.info("图片中关键字对应的进程名--->" + jsonMember.getString("processName"));
|
|
|
- screenshot.setPicType(jsonMember.getInteger("type"));
|
|
|
- lastType = jsonMember.getInteger("type");
|
|
|
- derail = true;
|
|
|
- } else {
|
|
|
- if (0 == lastType) {
|
|
|
- //软件开发为主
|
|
|
- break;
|
|
|
- } else {
|
|
|
+
|
|
|
+ if (isNovel(textContents)) {
|
|
|
+ screenshot.setPicType(6);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ List<String> exeprocessList = ProcessUtil.getExeprocessListfromProcessStr(screenshotvo.getProcessList());
|
|
|
+ System.out.println("進程" + exeprocessList);
|
|
|
+ boolean derail = false;//判断是否匹配的开关
|
|
|
+ Integer lastType = null;
|
|
|
+ for (String textContent : textContents) {
|
|
|
+ for (Object member : members) {
|
|
|
+ //由于redis里存储的member是一个PicContentKeywords类型的json字符串,所以取出关键字内容比较
|
|
|
+ JSONObject jsonMember = JSON.parseObject((String) member);
|
|
|
+ if (textContent.toLowerCase().contains(jsonMember.getString("content").toLowerCase())) {
|
|
|
+ log.info("图片文字中包含了关键词--->" + jsonMember.getString("content"));
|
|
|
+ log.info("图片文字识别出的类型--->" + jsonMember.getInteger("type"));
|
|
|
+ //找到对应关键字,确定图片是哪个类型的图片
|
|
|
+ //结合进程判断
|
|
|
+ if (exeprocessList.contains(jsonMember.getString("processName").toLowerCase())) {
|
|
|
+ if (!derail) {
|
|
|
+ //判断是否是第一次匹配
|
|
|
+ log.info("图片中关键字对应的进程名--->" + jsonMember.getString("processName"));
|
|
|
screenshot.setPicType(jsonMember.getInteger("type"));
|
|
|
lastType = jsonMember.getInteger("type");
|
|
|
+ derail = true;
|
|
|
+ } else {
|
|
|
+ if (0 == lastType) {
|
|
|
+ //软件开发为主
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ screenshot.setPicType(jsonMember.getInteger("type"));
|
|
|
+ lastType = jsonMember.getInteger("type");
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -170,10 +181,183 @@ public class ScreenshotServiceImpl extends ServiceImpl<ScreenshotMapper, Screens
|
|
|
}
|
|
|
}
|
|
|
screenshot.setIsHandle(1);
|
|
|
+ if (screenshot.getPicType() == null) {
|
|
|
+ //判断是否是游戏
|
|
|
+ if (isGame(new File(filePath))) {
|
|
|
+ screenshot.setPicType(7);
|
|
|
+ }
|
|
|
+ }
|
|
|
screenshotMapper.insert(screenshot);
|
|
|
return new HttpRespMsg();
|
|
|
}
|
|
|
|
|
|
+ //判断文字内容是否是小说
|
|
|
+ private boolean isNovel(List<String> textContents) {
|
|
|
+ /**先粗糙地比较一下, 小说常规包含的词库,匹配频率高,则认为是小说。
|
|
|
+ * 第一步, 90%应该都是中文
|
|
|
+ */
|
|
|
+ int total = 0;
|
|
|
+ int chWNum = 0;
|
|
|
+ for (String w : textContents) {
|
|
|
+ char[] ch = w.toCharArray();
|
|
|
+ for (char c : ch) {
|
|
|
+ total++;
|
|
|
+ if (c >= 0x4E00 && c <= 0x9FBF) {
|
|
|
+ chWNum++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //小说一页中文字至少200个
|
|
|
+ if (chWNum < 200) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ int percent = chWNum*100/total;
|
|
|
+ log.info("中文比例:"+percent);
|
|
|
+ if (percent < 60) {
|
|
|
+ //英文太多,不是小说; 不考虑英文小说。
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //第二步,匹配小说常见词汇,超过5次,认为是小说
|
|
|
+ try {
|
|
|
+ //填充小说关键字到内存,减少重复读取
|
|
|
+ if (nKeyWordsList.size() == 0) {
|
|
|
+ InputStream ins = novelWords.getInputStream();
|
|
|
+ BufferedReader br = new BufferedReader(new InputStreamReader(ins));
|
|
|
+ String line = br.readLine();
|
|
|
+ while (line != null) {
|
|
|
+ nKeyWordsList.add(line);
|
|
|
+ line = br.readLine();
|
|
|
+ System.out.println(line);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int totalKNum = 0;
|
|
|
+ for (String k: textContents) {
|
|
|
+ int kNum = 0;
|
|
|
+ for (String nk : nKeyWordsList) {
|
|
|
+ if (k.contains(nk)) {
|
|
|
+ kNum++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ totalKNum += kNum;
|
|
|
+ //存在第几章这样的关键字, +1分
|
|
|
+ if (matchCategory(k)) {
|
|
|
+ totalKNum += 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ log.info("文章小说匹配得分为=="+totalKNum);
|
|
|
+ if (totalKNum >= 5) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean matchCategory(String str) {
|
|
|
+ String pattern = "^第(.*)章(.*)";
|
|
|
+ // 创建 Pattern 对象
|
|
|
+ return Pattern.matches(pattern, str.trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+// boolean find = matchCategory("第22 重生");
|
|
|
+// System.out.println(find);
|
|
|
+ String str = "中文";
|
|
|
+ System.out.println(str.toCharArray().length);
|
|
|
+ isGame(new File("C://Users/seya/Desktop/1.jpg"));
|
|
|
+ }
|
|
|
+
|
|
|
+ public static boolean isGame(File pic) {
|
|
|
+ try {
|
|
|
+ int[] rgb = new int[3];
|
|
|
+ BufferedImage img = ImageIO.read(pic);
|
|
|
+ int width = img.getWidth();
|
|
|
+ int height = img.getHeight();
|
|
|
+ int minx = img.getMinX();
|
|
|
+ int miny = img.getMinY();
|
|
|
+ System.out.println("width=" + width + ",height=" + height + ".");
|
|
|
+ System.out.println("minx=" + minx + ",miniy=" + miny + ".");
|
|
|
+ //统计出现最多的一个色值,计算所占比重
|
|
|
+ int totalPixl = 0;
|
|
|
+ HashMap<Integer, Integer> colorCntMap = new HashMap<Integer, Integer>();
|
|
|
+ for (int i = minx; i < width; i++) {
|
|
|
+ for (int j = miny; j < height; j++) {
|
|
|
+ totalPixl++;
|
|
|
+// int w=20;
|
|
|
+// int h=20;
|
|
|
+// BufferedImage rect = img.getSubimage(i, j, w, h);
|
|
|
+
|
|
|
+ int pixel = img.getRGB(i, j); // 下面三行代码将一个数字转换为RGB数字
|
|
|
+ if (colorCntMap.get(pixel) == null) {
|
|
|
+ colorCntMap.put(pixel, 1);
|
|
|
+ } else {
|
|
|
+ colorCntMap.put(pixel, colorCntMap.get(pixel) + 1);
|
|
|
+ }
|
|
|
+// rgb[0] = (pixel & 0xff0000) >> 16;
|
|
|
+// rgb[1] = (pixel & 0xff00) >> 8;
|
|
|
+// rgb[2] = (pixel & 0xff);
|
|
|
+// if (rgb[0] != 255 || rgb[1] != 255 || rgb[2] != 255) {
|
|
|
+// //红色判断
|
|
|
+// if (rgb[0]>=200 && rgb[1] <=50 && rgb[2] <= 50) {
|
|
|
+// System.out.println("红色i=" + i + ",j=" + j + ":(" + rgb[0] + ","
|
|
|
+// + rgb[1] + "," + rgb[2] + ")");
|
|
|
+// } else if (rgb[0] <= 50 && rgb[1] >= 200 && rgb[2] <= 50) {
|
|
|
+// System.out.println("绿色i=" + i + ",j=" + j + ":(" + rgb[0] + ","
|
|
|
+// + rgb[1] + "," + rgb[2] + ")");
|
|
|
+// } else if (rgb[0] <= 50 && rgb[1] <= 50 && rgb[2] >= 200) {
|
|
|
+// System.out.println("蓝色i=" + i + ",j=" + j + ":(" + rgb[0] + ","
|
|
|
+// + rgb[1] + "," + rgb[2] + ")");
|
|
|
+// }
|
|
|
+// }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int maxCnt = 0;
|
|
|
+ int key = 0;
|
|
|
+ Set<Map.Entry<Integer, Integer>> entry2 = colorCntMap.entrySet();
|
|
|
+ for(Map.Entry<Integer, Integer> temp : entry2){
|
|
|
+ System.out.println("sortedMap:"+temp.getKey()+" 值"+temp.getValue());
|
|
|
+ if (temp.getValue() > maxCnt) {
|
|
|
+ maxCnt = temp.getValue();
|
|
|
+ key = temp.getKey();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ System.out.println("最.." + maxCnt + ", key=" + key);
|
|
|
+ rgb[0] = (key & 0xff0000) >> 16;
|
|
|
+ rgb[1] = (key & 0xff00) >> 8;
|
|
|
+ rgb[2] = (key & 0xff);
|
|
|
+ System.out.println("色值为: " + rgb[0] + ", " + rgb[1]+", "+rgb[2]);
|
|
|
+ //计算比例, 应该不低于50%
|
|
|
+ int colorPercent = maxCnt * 100 / totalPixl;
|
|
|
+ System.out.println("底色比例=="+colorPercent);
|
|
|
+ } catch (IOException e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 是否全是汉字<br>
|
|
|
+ * 根据汉字编码范围进行判断<br>
|
|
|
+ * CJK统一汉字(不包含中文的,。《》()“‘'”、!¥等符号)<br>
|
|
|
+ *
|
|
|
+ * @param str
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static boolean isChineseByReg(String str) {
|
|
|
+ if (str == null) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Pattern pattern = Pattern.compile("[\\u4E00-\\u9FBF]+");
|
|
|
+ return pattern.matcher(str).matches();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
//每次获取到截屏后计算并处理
|
|
|
private void calculateTime(Screenshot screenshot) {
|
|
|
try {
|