fix:修改图片合成、图片分享、EXIF识别等功能

develop
wangyi 2 weeks ago
parent b0cd0fab39
commit 4a68c1a5f4

@ -16,6 +16,13 @@
</description>
<dependencies>
<dependency>
<groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId>
<version>2.19.0</version>
</dependency>
<!--JAVA使用javacv实现图片合成短视频相关JAR包-->
<dependency>
<groupId>org.bytedeco</groupId>

@ -1,8 +1,15 @@
package com.bs.ct.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import com.bs.common.utils.SecurityUtils;
import com.bs.common.utils.StringUtils;
import com.bs.ct.domain.CtGalleryShareUser;
import com.bs.ct.service.ICtGalleryShareUserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
@ -40,6 +47,8 @@ public class CtGalleryCataShareController extends BaseController {
@Resource
private ICtGalleryCataShareService ctGalleryCataShareService;
@Resource
private ICtGalleryShareUserService ctGalleryShareUserService;
/**
*
*/
@ -50,6 +59,9 @@ public class CtGalleryCataShareController extends BaseController {
LambdaQueryWrapper<CtGalleryCataShare> queryWrapper = new LambdaQueryWrapper();
condition(queryWrapper,ctGalleryCataShare);
List<CtGalleryCataShare> list = ctGalleryCataShareService.list(queryWrapper);
if ("mine".equals(ctGalleryCataShare.getQueryType())) {
list = getShareUser(list);
}
return getDataTable(list);
}
@ -62,9 +74,37 @@ public class CtGalleryCataShareController extends BaseController {
LambdaQueryWrapper<CtGalleryCataShare> queryWrapper = new LambdaQueryWrapper();
condition(queryWrapper,ctGalleryCataShare);
List<CtGalleryCataShare> list = ctGalleryCataShareService.list(queryWrapper);
if ("mine".equals(ctGalleryCataShare.getQueryType())) {
list = getShareUser(list);
}
return success(list);
}
private List<CtGalleryCataShare> getShareUser(List<CtGalleryCataShare> list) {
List<Long> ids = new ArrayList<>();
Map<Long, List<CtGalleryShareUser>> dataMap = new HashMap<>();
if (null != list && list.size() > 0) {
for (CtGalleryCataShare share : list) {
ids.add(share.getId());
}
List<CtGalleryShareUser> lsUser = ctGalleryShareUserService.list(new LambdaQueryWrapper<CtGalleryShareUser>().in(CtGalleryShareUser::getShareId, ids));
if (null != lsUser && lsUser.size() > 0) {
for (CtGalleryShareUser user : lsUser) {
List<CtGalleryShareUser> lsShareUser = dataMap.get(user.getShareId());
if (null == lsShareUser) {
lsShareUser = new ArrayList<>();
}
lsShareUser.add(user);
dataMap.put(user.getShareId(), lsShareUser);
}
}
for (CtGalleryCataShare share : list) {
share.setLsUsers(dataMap.get(share.getId()));
}
}
return list;
}
/**
*
*/
@ -95,6 +135,60 @@ public class CtGalleryCataShareController extends BaseController {
@Log(title = "图库目录共享新增", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody CtGalleryCataShare ctGalleryCataShare) {
if (null != ctGalleryCataShare) {
if (StringUtils.isEmpty(ctGalleryCataShare.getType())) {
return warn("请选择需要共享的类型");
}
if (null == ctGalleryCataShare.getCataIds() || ctGalleryCataShare.getCataIds().size() == 0) {
return warn("请选择需要共享的图片/目录");
}
if (StringUtils.isEmpty(ctGalleryCataShare.getUserType())) {
return warn("请选择需要共享的用户类型");
}
if (null == ctGalleryCataShare.getUserIds() || ctGalleryCataShare.getUserIds().size() == 0) {
return warn("请选择需要共享的部门/人员");
}
for (Long cataId : ctGalleryCataShare.getCataIds()) {
for (Long userId : ctGalleryCataShare.getUserIds()) {
// 判断是否有重复共享
LambdaQueryWrapper<CtGalleryCataShare> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(CtGalleryCataShare::getType, ctGalleryCataShare.getType());
queryWrapper.eq(CtGalleryCataShare::getCataId, cataId);
List<CtGalleryCataShare> lsData = ctGalleryCataShareService.list(queryWrapper);
Long shareId = -1L;
if (null != lsData && lsData.size() > 0) {
shareId = lsData.get(0).getId();
} else {
// 未共享,则生成共享数据
CtGalleryCataShare share = new CtGalleryCataShare();
share.setType(ctGalleryCataShare.getType());
share.setCataId(cataId);
share.setCataName(ctGalleryCataShare.getCataName());
ctGalleryCataShareService.save(share);
shareId = share.getId();
}
if (shareId > 0) {
//queryWrapper.inSql(CtGalleryCataShare::getId, "select share_id from ct_gallery_share_user where type='" + ctGalleryCataShare.getUserType() + "' and user_id =" + userId);
// 如果有数据,则先删除旧数据
LambdaQueryWrapper<CtGalleryShareUser> userWrapper = new LambdaQueryWrapper();
userWrapper.eq(CtGalleryShareUser::getShareId, shareId);
userWrapper.eq(CtGalleryShareUser::getUserId, userId);
userWrapper.eq(CtGalleryShareUser::getUserType, ctGalleryCataShare.getUserType());
ctGalleryShareUserService.remove(userWrapper);
// 插入新数据
CtGalleryShareUser user = new CtGalleryShareUser();
user.setUserType(ctGalleryCataShare.getUserType());
user.setUserId(userId);
user.setShareId(shareId);
user.setBeginDate(ctGalleryCataShare.getBeginDate());
user.setEndDate(ctGalleryCataShare.getEndDate());
ctGalleryShareUserService.save(user);
}
}
}
} else {
return error("请选择需要共享的图片/目录");
}
return toAjax(ctGalleryCataShareService.save(ctGalleryCataShare));
}
@ -115,6 +209,9 @@ public class CtGalleryCataShareController extends BaseController {
@Log(title = "图库目录共享删除", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable List<Long> ids) {
LambdaQueryWrapper<CtGalleryShareUser> userWrapper = new LambdaQueryWrapper();
userWrapper.in(CtGalleryShareUser::getShareId, ids);
ctGalleryShareUserService.remove(userWrapper);
return toAjax(ctGalleryCataShareService.removeBatchByIds(ids));
}
@ -123,6 +220,11 @@ public class CtGalleryCataShareController extends BaseController {
*/
private void condition (LambdaQueryWrapper<CtGalleryCataShare> queryWrapper,CtGalleryCataShare ctGalleryCataShare){
if ("mine".equals(ctGalleryCataShare.getQueryType())) {
queryWrapper.eq(CtGalleryCataShare::getCreateBy, SecurityUtils.getUserId());
} else if ("mine".equals(ctGalleryCataShare.getQueryType())) {
queryWrapper.inSql(CtGalleryCataShare::getId, "select share_id from ct_gallery_share_user where del_flag = 0 and ( (user_type = 'user' and user_id = " + SecurityUtils.getUserId() +") or (user_type = 'dept' and user_id = " + SecurityUtils.getDeptId() + "))");
}
//id
if(Validator.isNotEmpty(ctGalleryCataShare.getId())){
@ -134,6 +236,10 @@ public class CtGalleryCataShareController extends BaseController {
queryWrapper.eq(CtGalleryCataShare::getType,ctGalleryCataShare.getType());
}
if(Validator.isNotEmpty(ctGalleryCataShare.getCataName())) {
queryWrapper.like(CtGalleryCataShare::getCataName, ctGalleryCataShare.getCataName());
}
//目录id
if(Validator.isNotEmpty(ctGalleryCataShare.getCataId())){
queryWrapper.eq(CtGalleryCataShare::getCataId,ctGalleryCataShare.getCataId());

@ -13,14 +13,22 @@ import com.bs.cm.service.ICmAttachService;
import com.bs.common.config.BsConfig;
import com.bs.common.core.domain.entity.SysDept;
import com.bs.common.core.domain.model.LoginUser;
import com.bs.common.utils.StringUtils;
import com.bs.common.utils.file.FileUploadUtils;
import com.bs.common.utils.file.FileUtils;
import com.bs.ct.domain.*;
import com.bs.ct.service.*;
import com.bs.ct.utils.ExifUtils;
import com.bs.ct.utils.OperateImageUtils;
import com.bs.ct.utils.UUIDUtils;
import com.bs.framework.config.ServerConfig;
import com.bs.system.service.ISysDeptService;
import com.drew.imaging.ImageMetadataReader;
import com.drew.imaging.ImageProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
@ -46,6 +54,8 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import static com.bs.common.config.BsConfig.getProfile;
/**
* Controller
*
@ -248,8 +258,9 @@ public class CtGalleryImagesController extends BaseController {
String attachUrl = galleryImages.getImagePath().replace("/profile", "");
String filePath = profile + attachUrl;
try {
imgs[index++] = OperateImageUtils.getBufferedImage(filePath);
imgMap.put(index++, new File(filePath));
imgs[index] = OperateImageUtils.getBufferedImage(filePath);
imgMap.put(index, new File(filePath));
index = index + 1 ;
} catch (IOException e) {
e.printStackTrace();
return AjaxResult.error("读取图片失败: " + filePath);
@ -257,6 +268,7 @@ public class CtGalleryImagesController extends BaseController {
}
BufferedImage destImg = null;
String outputFileName = null;
String mp4SavePath = "";
try {
switch (imageType) {
case "nineGrid":
@ -296,20 +308,23 @@ public class CtGalleryImagesController extends BaseController {
case "video":
int width = imgs[0].getWidth();
int height = imgs[0].getHeight();
String mp4SavePath = profile + UUIDUtils.generatorUUID() + "output.mp4";
OperateImageUtils.createMp4(mp4SavePath, imgMap, width, height);
mp4SavePath = UUIDUtils.generatorUUID() + "output.mp4";
OperateImageUtils.createMp4(profile, mp4SavePath, imgMap, width, height);
break;
default:
return AjaxResult.error("不支持的图片类型: " + imageType);
return AjaxResult.error("不支持的生成类型: " + imageType);
}
} catch (IOException e) {
e.printStackTrace();
}
if (destImg != null) {
OperateImageUtils.saveImage(destImg, profile , outputFileName, "jpg");
return AjaxResult.success("图片生成成功");
return AjaxResult.success("图片生成成功", outputFileName);
}
if (StringUtils.isNotEmpty(mp4SavePath)) {
return AjaxResult.success("视频生成成功", mp4SavePath);
}
return AjaxResult.error("图片生成失败");
return AjaxResult.error("图片/视频生成失败");
}
//
@ -337,6 +352,9 @@ public class CtGalleryImagesController extends BaseController {
String filePath = BsConfig.getUploadPath();
// 上传并返回新文件名称
String fileName = FileUploadUtils.upload(filePath, file);
String realName = fileName.replace("profile", "");
String exifInfo = ExifUtils.getExifInfo(getProfile() + realName).toString();
ctGalleryImages.setExifInfo(exifInfo);
String url = serverConfig.getUrl() + fileName;
String newFileName = FileUtils.getName(fileName);
String originalFilename = file.getOriginalFilename();
@ -650,4 +668,22 @@ public class CtGalleryImagesController extends BaseController {
}
public static void main(String[] args) {
try {
System.out.println(ExifUtils.getExifInfo("d:\\1.jpg").toString());
/*File imageFile = new File("d:\\1.jpg");
Metadata metadata = ImageMetadataReader.readMetadata(imageFile);
for (Directory directory : metadata.getDirectories()) {
for (Tag tag : directory.getTags()) {
System.out.println(tag.getTagName() + " = " + tag.getDescription());
}
}*/
} catch (ImageProcessingException e) {
// 处理异常
} catch (IOException e) {
// 处理IO异常
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

@ -35,7 +35,7 @@ import javax.annotation.Resource;
*/
@Api(tags = "图库目录共享用户")
@RestController
@RequestMapping("/share/user")
@RequestMapping("/gallery/share/user")
public class CtGalleryShareUserController extends BaseController {
@Resource
private ICtGalleryShareUserService ctGalleryShareUserService;

@ -1,6 +1,8 @@
package com.bs.ct.domain;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.bs.common.annotation.Excel;
import com.bs.common.core.domain.BaseEntity;
@ -43,12 +45,26 @@ public class CtGalleryCataShare extends BaseEntity{
@ApiModelProperty(value = "目录id")
private Long cataId;
@Excel(name = "共享名称")
@ApiModelProperty(value = "共享名称")
private String cataName;
@TableField(exist = false)
private List<Long> cataIds;
@TableField(exist = false)
private String userType;
/** 共享用户 */
@Excel(name = "共享用户")
@ApiModelProperty(value = "共享用户")
private Long userId;
@TableField(exist = false)
private List<Long> userIds;
/** 开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@ -69,7 +85,10 @@ public class CtGalleryCataShare extends BaseEntity{
@ApiModelProperty(value = "备注")
private String remarks;
@TableField(exist = false)
private List<CtGalleryShareUser> lsUsers;
@TableField(exist = false)
private String queryType;
}

@ -97,6 +97,10 @@ public class CtGalleryImages extends BaseEntity{
@ApiModelProperty(value = "附件id")
private Long fileId;
@Excel(name = "EXIF信息")
@ApiModelProperty(value = "EXIF信息")
private String exifInfo;
/** 备注 */
@Excel(name = "备注")

@ -2,6 +2,7 @@ package com.bs.ct.domain;
import com.bs.common.annotation.Excel;
import com.bs.common.core.domain.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
@ -11,6 +12,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
/**
* ct_gallery_share_user
*
@ -35,6 +38,10 @@ public class CtGalleryShareUser extends BaseEntity{
@ApiModelProperty(value = "共享id")
private Long shareId;
@Excel(name = "用户类型")
@ApiModelProperty(value = "用户类型")
private String userType;
/** 共享用户 */
@Excel(name = "共享用户")
@ -42,6 +49,18 @@ public class CtGalleryShareUser extends BaseEntity{
private Long userId;
/** 开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "开始时间", width = 30, dateFormat = "yyyy-MM-dd")
@ApiModelProperty(value = "开始时间")
private Date beginDate;
/** 结束时间 */
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "结束时间", width = 30, dateFormat = "yyyy-MM-dd")
@ApiModelProperty(value = "结束时间")
private Date endDate;
}

@ -0,0 +1,74 @@
package com.bs.ct.utils;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifIFD0Directory;
import com.drew.metadata.exif.ExifSubIFDDirectory;
import com.drew.metadata.exif.GpsDirectory;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class ExifUtils {
private static final Map<String, String> CHINESE_TAG_NAMES = new HashMap<>();
static {
// 初始化常用EXIF标签的中文翻译
CHINESE_TAG_NAMES.put("Compression Type", "压缩类型");
CHINESE_TAG_NAMES.put("Image Width", "图像宽度");
CHINESE_TAG_NAMES.put("Image Height", "图像高度");
CHINESE_TAG_NAMES.put("Data Precision", "数据精度");
CHINESE_TAG_NAMES.put("Make", "制造商");
CHINESE_TAG_NAMES.put("Model", "型号");
CHINESE_TAG_NAMES.put("Orientation", "方向");
CHINESE_TAG_NAMES.put("DateTime Original", "拍摄时间");
CHINESE_TAG_NAMES.put("Create Date", "创建日期");
CHINESE_TAG_NAMES.put("Exposure Time", "曝光时间");
CHINESE_TAG_NAMES.put("F-Number", "光圈值");
CHINESE_TAG_NAMES.put("ISO Speed Ratings", "ISO速度");
CHINESE_TAG_NAMES.put("Focal Length", "焦距");
CHINESE_TAG_NAMES.put("Flash", "闪光灯");
CHINESE_TAG_NAMES.put("Metering Mode", "测光模式");
CHINESE_TAG_NAMES.put("White Balance", "白平衡");
CHINESE_TAG_NAMES.put("Exposure Program", "曝光程序");
CHINESE_TAG_NAMES.put("Exposure Bias Value", "曝光补偿");
CHINESE_TAG_NAMES.put("GPS Latitude", "GPS纬度");
CHINESE_TAG_NAMES.put("GPS Longitude", "GPS经度");
CHINESE_TAG_NAMES.put("GPS Altitude", "GPS海拔");
CHINESE_TAG_NAMES.put("GPS Date Stamp", "GPS日期");
CHINESE_TAG_NAMES.put("GPS Time Stamp", "GPS时间");
CHINESE_TAG_NAMES.put("File Name", "文件名");
CHINESE_TAG_NAMES.put("File Size", "文件大小");
CHINESE_TAG_NAMES.put("File Modified Date", "文件修改时间");
}
public static Map<String, String> getExifInfoMap(String imagePath) throws Exception {
Map<String, String> result = new LinkedHashMap<>();
Metadata metadata = ImageMetadataReader.readMetadata(new File(imagePath));
for (Directory directory : metadata.getDirectories()) {
for (Tag tag : directory.getTags()) {
String chineseName = CHINESE_TAG_NAMES.getOrDefault(tag.getTagName(), tag.getTagName());
result.put(chineseName, tag.getDescription());
}
}
return result;
}
public static StringBuffer getExifInfo(String imagePath) throws Exception {
StringBuffer result = new StringBuffer();
Metadata metadata = ImageMetadataReader.readMetadata(new File(imagePath));
for (Directory directory : metadata.getDirectories()) {
for (Tag tag : directory.getTags()) {
String chineseName = CHINESE_TAG_NAMES.getOrDefault(tag.getTagName(), tag.getTagName());
result.append(chineseName + ":" + tag.getDescription() + "\n");
}
}
return result;
}
}

@ -67,7 +67,12 @@ public class OperateImageUtils {
return false;
}
String fileUrl = saveDir + fileName;
String fileUrl = "";
if (saveDir.endsWith("/") || saveDir.endsWith("\\")) {
fileUrl = saveDir + fileName;
} else {
fileUrl = saveDir + "/" + fileName;
}
File file = new File(fileUrl);
try {
flag = ImageIO.write(savedImg, format, file);
@ -213,7 +218,13 @@ public class OperateImageUtils {
return destImage;
}
public static void createMp4(String mp4SavePath, Map<Integer, File> imgMap, int width, int height) throws FrameRecorder.Exception {
public static void createMp4(String saveDir, String fileName, Map<Integer, File> imgMap, int width, int height) throws FrameRecorder.Exception {
String mp4SavePath = "";
if (saveDir.endsWith("/") || saveDir.endsWith("\\")) {
mp4SavePath = saveDir + fileName;
} else {
mp4SavePath = saveDir + "/" + fileName;
}
// 调整宽度和高度为偶数
width = width % 2 == 0 ? width : width + 1;
height = height % 2 == 0 ? height : height + 1;
@ -317,8 +328,8 @@ public class OperateImageUtils {
// 测试图片转视频
int width = imgs[0].getWidth();
int height = imgs[0].getHeight();
String mp4SavePath = "D:\\edge下载\\下载\\1_2019年-2024年数据\\output.mp4";
createMp4(mp4SavePath, imgMap, width, height);
String mp4SavePath = "\\output.mp4";
createMp4("D:\\edge下载\\下载\\1_2019年-2024年数据", mp4SavePath, imgMap, width, height);
System.out.println("MP4视频生成完毕!");
} catch (IOException e) {

Loading…
Cancel
Save