반응형
1. HTML
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.area {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: stretch;
justify-content: flex-start;
}
.image-area {
width: 400px;
min-height: 400px;
border: 1px solid #ccc;
flex: 1;
position: relative;
}
.contents-area {
width: 300px;
/*height: 400px;*/
border: 1px solid #ccc;
flex: 1;
}
</style>
<script type="text/javascript"
src="${pageContext.request.contextPath}/resources/js/views/common/invisibledetectlog/invisibleDetectLogAddPop.js"></script>
</head>
<body>
<div class="dialogContent">
<div class="bwfull">
<div class="userImgContent bw80">
<div id="drag-and-drop-zone" class="uploader">
<label class="fileUploadBtn"><span>이미지 업로드</span><input
type="file" title='Click to add Files'/></label>
</div>
<button type="button" class="btn btn-primary" id="btnDetect">검출</button>
</div>
<div class="area">
<div class="image-area" id="image-area"></div>
<div class="contents-area" id="contents-area"></div>
</div>
</div>
</div>
<script>
const canvas = document.getElementById('image-area');
let startX, startY; // 시작점 좌표 저장
let isDrawing = false; // 드로잉 상태 플래그
let clickX = 0;
let clickY = 0;
let clickWidth = 0;
let clickHeight = 0;
canvas.addEventListener('click', function(event) {
const rect = canvas.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
if (!isDrawing) {
// 첫 번째 클릭(시작점) 처리
startX = x;
startY = y;
isDrawing = true;
} else {
// 두 번째 클릭(끝점) 처리 및 직사각형 그리기
drawRect(startX, startY, x, y);
isDrawing = false; // 드로잉 상태 리셋
}
});
function drawRect(x1, y1, x2, y2) {
const div = document.createElement('div');
div.classList.add('drawn-div');
// 시작점과 끝점의 좌표를 비교하여 직사각형의 위치와 크기 결정
clickX = Math.min(x1, x2);
clickY = Math.min(y1, y2);
clickWidth = Math.abs(x2 - x1);
clickHeight = Math.abs(y2 - y1);
// div 스타일 설정
div.style.left = clickX + 'px';
div.style.top = clickY + 'px';
div.style.width = clickWidth + 'px';
div.style.height = clickHeight + 'px';
$(".drawn-div").remove();
// 캔버스에 추가
canvas.appendChild(div);
}
</script>
</body>
</html>
2. javascript
let logseq = '';
let displayWidth = 0;
let displayHeight = 0;
let position = [];
$(function() {
setFileUploader();
bindEvent();
});
function bindEvent() {
$("#btnDetect").click(function() {
let param = {
logseq: logseq,
clickX: clickX,
clickY: clickY,
clickWidth: clickWidth,
clickHeight: clickHeight,
displayWidth: displayWidth,
displayHeight: displayHeight
};
console.table(param);
// ajax로 clickX, clickY, width, height, logseq 전송
$.ajax({
url: CONTEXT_PATH + '/common/invisibledetectlog/detect.json',
type: 'post',
data : {"jsonParam" : JSON.stringify(param)},
// datatype: 'json',
success: function(data) {
console.table(data);
let html = [];
html.push('<ul>');
if(data.securityCode === undefined) {
html.push(getLine('', g_msg('msg.noData')));
return;
}
html.push(getLine(g_msg('grid.securityCode'), data.securityCode));
if(data.logDt !== undefined) {
html.push(getLine(g_msg('grid.requestDateTime'), data.logDt));
}
if(data.userCode !== undefined) {
html.push(getLine('사용자 코드', data.userCode));
}
if(data.userId !== undefined) {
html.push(getLine(g_msg('label.userId'), data.userId));
}
if(data.userName !== undefined) {
html.push(getLine(g_msg('label.userName'), data.userName));
}
if(data.deptName !== undefined) {
html.push(getLine(g_msg('label.deptName'), data.deptName));
}
if(data.deptPath !== undefined) {
html.push(getLine(g_msg('grid.userDeptPathName'), data.deptPath));
}
if(data.positionName !== undefined) {
html.push(getLine(g_msg('label.positionName'), data.positionName));
}
if(data.clientIp !== undefined) {
html.push(getLine(g_msg('label.clientIp'), data.clientIp));
}
if(data.commName !== undefined) {
html.push(getLine(g_msg('label.computerName'), data.commName));
}
if(data.osVersion !== undefined) {
html.push(getLine(g_msg('grid.osVersion'), data.osVersion));
}
if(data.macList !== undefined) {
html.push(getLine(g_msg('label.macAddress'), data.macList));
}
html.push('</ul>');
$("#contents-area").html(html.join(''));
},
error: function(e) {
console.log(e);
}
});
});
}
function getLine(label, value) {
let html = [];
html.push('<li class="inputGroup">');
html.push(' <span class="inputListTitle">' + label + '</span>');
html.push(' <span>' + value + '</span>');
html.push('</li>');
return html.join('');
}
function setFileUploader(){
$("#drag-and-drop-zone").dmUploader({
url: CONTEXT_PATH + '/common/invisibledetectlog/upload.json',
auto: true,
multiple: false,
queue: false,
dataType: 'json',
extFilter : ["png", "jpg", "jpeg"],
onDragEnter: function(){
this.addClass('active');
},
onDragLeave: function(){
this.removeClass('active');
},
onInit: function(){
this.find('input[type="text"]').val(g_msg('msg.noSelectFile')); //선택된 파일이 없습니다.
},
onComplete: function(){
},
onNewFile: function(id, file){
uploadID = id;
// When a new file is added using the file selector or the DnD area
this.find('input[type="text"]').val(file.name);
},
onUploadError: function(id, xhr, status, errorThrown) {},
onBeforeUpload: function(id){},
onUploadProgress: function(id, percent){},
onUploadSuccess: function(id, data){
console.table(data);
if('fail' === data.result) {
alertMessage(data.reason);
}
else {
$("#image-area").html('<img src="' + data.url + '" alt="image" class="img-thumbnail">');
logseq = data.logseq;
// image area에 이미지가 로딩되면 이미지 영역의 크기를 구해서 설정
var img = new Image();
img.src = data.url;
img.onload = function() {
$img = $(".img-thumbnail");
displayWidth = $img.width();
displayHeight = $img.height();
}
}
},
onUploadError: function(id, xhr, status, message){},
onFallbackMode: function(){},
onFileSizeError: function(file){},
onFileTypeError: function(file){},
onFileExtError: function(file){
// 파일 타입 틀린 경우
alertMessage(g_msg("msg.onlyXXFileUpload", "png, jpg, jpeg"));
}
});
}
3. java
public DetectDto detect(HttpServletRequest request) throws IOException {
DetectDto detect = null;
Map<String, Object> paramMap = requestUtil.getRequestJsonToMap(request, "jsonParam");
Long logseq = Long.parseLong(paramMap.get("logseq").toString());
Optional<PcTbInvisibleDetectLog> opt = pcRepository.findById(logseq);
if (opt.isEmpty()) {
return new DetectDto();
}
PcTbInvisibleDetectLog detectLog = opt.get();
String filePath = detectLog.getImagePath() + "/" + detectLog.getImageName();
String ext = filePath.substring(filePath.lastIndexOf(".") + 1);
BufferedImage image = ImageIO.read(new File(filePath));
// 원본 width, height
int originalWidth = image.getWidth();
int originalHeight = image.getHeight();
log.info("원본 width : " + originalWidth);
log.info("원본 height : " + originalHeight);
// 사용자가 클릭한 영역의 좌표
int clientLeft = paramMap.get("clickX") == null ? 0 : Integer.parseInt(paramMap.get("clickX").toString());
int clientTop = paramMap.get("clickY") == null ? 0 : Integer.parseInt(paramMap.get("clickY").toString());
// 사용자가 클릭한 영역의 width, height
int clickWidth = paramMap.get("clickWidth") == null ? 0 : Integer.parseInt(paramMap.get("clickWidth").toString());
int clickHeight = paramMap.get("clickHeight") == null ? 0 : Integer.parseInt(paramMap.get("clickHeight").toString());
// UI에 표시된 이미지의 width, height
double displayWidth = paramMap.get("displayWidth") == null ? 0 : Double.parseDouble(paramMap.get("displayWidth").toString());
double displayHeight = paramMap.get("displayHeight") == null ? 0 : Double.parseDouble(paramMap.get("displayHeight").toString());
// UI에 표시된 이미지의 width, height를 기준으로 사용자가 클릭한 영역의 좌표를 계산
int left = (int) ((double) clientLeft / displayWidth * originalWidth);
int top = (int) ((double) clientTop / displayHeight * originalHeight);
int width = (int) ((double) clickWidth / displayWidth * originalWidth);
int height = (int) ((double) clickHeight / displayHeight * originalHeight);
log.info("x : " + left);
log.info("y : " + top);
log.info("w : " + width);
log.info("h : " + height);
// 계산된 좌표만큼 이미지 자르기
BufferedImage cropImage = image.getSubimage(left, top, width, height);
ImageIO.write(cropImage, "jpg", new File("d:/crop." + ext));
return detect;
}
728x90
반응형
'웹 개발' 카테고리의 다른 글
[Tomcat에러] Invalid byte tag in constant pool (0) | 2022.11.16 |
---|---|
HTTP에서 localhost 호출 시 CORS 에러 발생하는 이유 (0) | 2022.10.29 |
Spring Security에서 접근 권한 해제 방법 (0) | 2022.07.19 |
spring boot pageable start from 1 (0) | 2022.06.07 |
AOP에서의 모든 메서드 로깅과 Custom Annotation을 활용한 No Logging 처리 (0) | 2022.05.01 |