水印
This commit is contained in:
parent
7e8eebdef5
commit
180ba67de8
@ -70,4 +70,8 @@ public class ScenicConfigEntity {
|
|||||||
private String storeConfigJson;
|
private String storeConfigJson;
|
||||||
private BigDecimal brokerDirectRate;
|
private BigDecimal brokerDirectRate;
|
||||||
private Integer faceDetectHelperThreshold;
|
private Integer faceDetectHelperThreshold;
|
||||||
|
|
||||||
|
private String watermarkType;
|
||||||
|
private String watermarkScenicText;
|
||||||
|
private String watermarkDtFormat;
|
||||||
}
|
}
|
||||||
|
168
src/main/java/com/ycwl/basic/task/ImageWatermarkTask.java
Normal file
168
src/main/java/com/ycwl/basic/task/ImageWatermarkTask.java
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package com.ycwl.basic.task;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.ycwl.basic.image.watermark.ImageWatermarkFactory;
|
||||||
|
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
|
||||||
|
import com.ycwl.basic.image.watermark.exception.ImageWatermarkException;
|
||||||
|
import com.ycwl.basic.image.watermark.operator.IOperator;
|
||||||
|
import com.ycwl.basic.mapper.SourceMapper;
|
||||||
|
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
|
||||||
|
import com.ycwl.basic.model.pc.mp.MpConfigEntity;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
|
||||||
|
import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
|
||||||
|
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
|
||||||
|
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
|
||||||
|
import com.ycwl.basic.notify.entity.WxMpSrvConfig;
|
||||||
|
import com.ycwl.basic.repository.FaceRepository;
|
||||||
|
import com.ycwl.basic.repository.ScenicRepository;
|
||||||
|
import com.ycwl.basic.storage.StorageFactory;
|
||||||
|
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||||
|
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||||
|
import com.ycwl.basic.utils.WxMpUtil;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@EnableScheduling
|
||||||
|
@Slf4j
|
||||||
|
public class ImageWatermarkTask {
|
||||||
|
@Autowired
|
||||||
|
private FaceRepository faceRepository;
|
||||||
|
@Autowired
|
||||||
|
private ScenicRepository scenicRepository;
|
||||||
|
@Autowired
|
||||||
|
private SourceMapper sourceMapper;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class Task {
|
||||||
|
public Long memberId;
|
||||||
|
public Long faceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConcurrentLinkedQueue<Task> queue = new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
|
public static void addTask(Long memberId, Long faceId) {
|
||||||
|
queue.add(new Task(memberId, faceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(fixedRate = 200L)
|
||||||
|
public void doTask() {
|
||||||
|
Task task = queue.poll();
|
||||||
|
if (task == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log.info("poll task: {}/{}", task, queue.size());
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
runTask(task);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("run task error", e);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runTask(Task task) {
|
||||||
|
// 生成二维码
|
||||||
|
FaceEntity face = faceRepository.getFace(task.faceId);
|
||||||
|
if (face == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ScenicEntity scenic = scenicRepository.getScenic(face.getScenicId());
|
||||||
|
if (scenic == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(face.getScenicId());
|
||||||
|
MpConfigEntity scenicMpConfig = scenicRepository.getScenicMpConfig(face.getScenicId());
|
||||||
|
if (scenicMpConfig == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<SourceEntity> sourceEntities = sourceMapper.listImageByFaceRelation(task.memberId, task.faceId);
|
||||||
|
if (sourceEntities == null || sourceEntities.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File qrcode = new File("qrcode_"+face.getMemberId()+".jpg");
|
||||||
|
try {
|
||||||
|
String urlLink = WxMpUtil.generateUrlLink(scenicMpConfig.getAppId(), scenicMpConfig.getAppSecret(), "pages/videoSynthesis/index", "scenicId=" + face.getScenicId() + "&faceId=" + face.getId());
|
||||||
|
QrCodeUtil.generate(urlLink + "?cq=", 300, 300, qrcode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("generateWXQRCode error", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IStorageAdapter adapter = StorageFactory.get(scenicConfig.getStoreType());
|
||||||
|
adapter.loadConfig(JSONObject.parseObject(scenicConfig.getStoreConfigJson(), Map.class));
|
||||||
|
// TODO
|
||||||
|
WatermarkInfo info = new WatermarkInfo();
|
||||||
|
info.setQrcodeFile(qrcode);
|
||||||
|
final ThreadPoolExecutor executor = new ThreadPoolExecutor(16, 128, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(128));
|
||||||
|
for (SourceEntity sourceEntity : sourceEntities) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
String url;
|
||||||
|
try {
|
||||||
|
IOperator operator = ImageWatermarkFactory.get(scenicConfig.getWatermarkType());
|
||||||
|
File dstFile = new File(sourceEntity.getId() + ".jpg");
|
||||||
|
File watermarkedFile = new File(sourceEntity.getId() + "_w.png");
|
||||||
|
try {
|
||||||
|
HttpUtil.downloadFile(sourceEntity.getUrl(), dstFile);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("downloadFile error", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info.setOriginalFile(dstFile);
|
||||||
|
info.setScenicLine(scenicConfig.getWatermarkScenicText());
|
||||||
|
info.setDatetime(sourceEntity.getCreateTime());
|
||||||
|
info.setDtFormat(scenicConfig.getWatermarkDtFormat());
|
||||||
|
info.setWatermarkedFile(watermarkedFile);
|
||||||
|
try {
|
||||||
|
operator.process(info);
|
||||||
|
} catch (ImageWatermarkException e) {
|
||||||
|
log.error("process error", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
url = adapter.uploadFile(watermarkedFile, "photo_w", watermarkedFile.getName());
|
||||||
|
adapter.setAcl(StorageAcl.PUBLIC_READ, "photo_w", watermarkedFile.getName());
|
||||||
|
} catch (ImageWatermarkException e) {
|
||||||
|
// 不支持
|
||||||
|
url = sourceEntity.getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemberSourceEntity memberSource = new MemberSourceEntity();
|
||||||
|
memberSource.setMemberId(task.memberId);
|
||||||
|
memberSource.setScenicId(face.getScenicId());
|
||||||
|
memberSource.setFaceId(task.faceId);
|
||||||
|
memberSource.setType(sourceEntity.getType());
|
||||||
|
memberSource.setSourceId(sourceEntity.getId());
|
||||||
|
memberSource.setWaterUrl(url);
|
||||||
|
sourceMapper.updateWaterUrl(memberSource);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000L);
|
||||||
|
log.info("executor等待被结束![A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
|
||||||
|
executor.shutdown();
|
||||||
|
executor.awaitTermination(30, TimeUnit.SECONDS);
|
||||||
|
log.info("executor已结束![A:{}/T:{}/F:{}]", executor.getActiveCount(), executor.getTaskCount(), executor.getCompletedTaskCount());
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -14,7 +14,8 @@ import java.io.FileOutputStream;
|
|||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public class WxMpUtil {
|
public class WxMpUtil {
|
||||||
private static final String GET_WXA_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode?access_token=%s";
|
private static final String GET_WXA_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s";
|
||||||
|
private static final String GET_URL_LICK_URL = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=%s";
|
||||||
|
|
||||||
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
|
private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
|
||||||
private static String ACCESS_TOKEN = "";
|
private static String ACCESS_TOKEN = "";
|
||||||
@ -61,6 +62,33 @@ public class WxMpUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String generateUrlLink(String appId, String appSecret, String path, String query) throws Exception {
|
||||||
|
String url = String.format(GET_URL_LICK_URL, getAccessToken(appId, appSecret));
|
||||||
|
CloseableHttpClient httpClient = HttpClients.createDefault();
|
||||||
|
HttpPost httpPost = new HttpPost(url);
|
||||||
|
JSONObject json = new JSONObject();
|
||||||
|
json.put("path", path);
|
||||||
|
json.put("query", query);
|
||||||
|
StringEntity entity = new StringEntity(json.toJSONString(), "utf-8");
|
||||||
|
httpPost.setEntity(entity);
|
||||||
|
httpPost.setHeader("Content-Type", "application/json");
|
||||||
|
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||||
|
if (response.getStatusLine().getStatusCode() != 200) {
|
||||||
|
expireTime = new Date();
|
||||||
|
throw new Exception("获取小程序码失败");
|
||||||
|
}
|
||||||
|
HttpEntity responseEntity = response.getEntity();
|
||||||
|
if (responseEntity != null) {
|
||||||
|
String responseStr = EntityUtils.toString(responseEntity);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(responseStr);
|
||||||
|
return jsonObject.getString("url_link");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
generateWXAQRCode("wxe7ff26af70bfc37c", "5252fbbc68513bc77b7cc0052b9f9695", "trial", "pages/home/index?scenicId=3955650120997015552", "sxlj_t.jpg");
|
generateWXAQRCode("wxe7ff26af70bfc37c", "5252fbbc68513bc77b7cc0052b9f9695", "trial", "pages/home/index?scenicId=3955650120997015552", "sxlj_t.jpg");
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,10 @@
|
|||||||
face_detect_helper_threshold=#{faceDetectHelperThreshold},
|
face_detect_helper_threshold=#{faceDetectHelperThreshold},
|
||||||
store_type=#{storeType},
|
store_type=#{storeType},
|
||||||
store_config_json=#{storeConfigJson},
|
store_config_json=#{storeConfigJson},
|
||||||
broker_direct_rate=#{brokerDirectRate}
|
broker_direct_rate=#{brokerDirectRate},
|
||||||
|
watermark_type=#{watermarkType},
|
||||||
|
watermark_scenic_text=#{watermarkScenicText},
|
||||||
|
watermark_dt_format=#{watermarkDtFormat}
|
||||||
</set>
|
</set>
|
||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
</set>
|
</set>
|
||||||
where member_id = #{memberId} and face_id = #{faceId} and `type` = #{type}
|
where member_id = #{memberId} and face_id = #{faceId} and `type` = #{type}
|
||||||
</update>
|
</update>
|
||||||
|
<update id="updateWaterUrl">
|
||||||
|
update member_source
|
||||||
|
set water_url = #{waterUrl}
|
||||||
|
where member_id = #{memberId} and source_id = #{sourceId} and `type` = #{type}
|
||||||
|
</update>
|
||||||
<delete id="deleteById">
|
<delete id="deleteById">
|
||||||
delete from source where id = #{id}
|
delete from source where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user