/*******************************************
- Title : Munjanara Image Editor ¥±
- Date : 2025.04.25
- Author : KKH
- Email : vsharp12@naver.com
*******************************************/
var version = "1.22.25.6.13.12";
var imageMax = 3;
var canvasWidth = 400;
var canvasHeight = 600;
var limitWidth = 1500;
var limitHeight = 1440;
var limitByte = 300; // K
var minWidth = 40; // ÃÖ¼Ò Æø
var minHeight = 40; // ÃÖ¼Ò ³ôÀÌ
var alpha = 0.3;
var prevScaleX, prevScaleY;
var backImageWidth, backImageHeight;
var locText = 0;
var scaleAll = 1; // ÀúÀå½Ã ¸ðµç ¿ä¼ÒÀÇ Å©±â¸¦ ¹Ý¿µ
var imageWidth, imageHeight, fileName;
var jobIndex = 0;
var canvas, activeObj;
var img, cropper;
var imageInfo = [];
var parentImg = [];
function initEditor(){
if(imageInfo.length > 0){
if(!confirm("¸ðµç ¿ä¼Ò¸¦ »èÁ¦Çϰí ÃʱâÈ ÇÕ´Ï´Ù.")) return;
document.location.reload();
}
}
function initPage(){
if(!imageInfo[jobIndex].src) return;
deleteCropper();
addJsonToCanvas(imageInfo[jobIndex].src);
}
function deleteObject() {
if(cropper) return;
var objects = canvas.getObjects();
// ±âº» À̹ÌÁöÀÏ °æ¿ì
if (objects.length == 1) {
Alert("±âº» À̹ÌÁö´Â »èÁ¦ÇÒ ¼ö ¾ø½À´Ï´Ù.");
return;
}
var activeObj = canvas.getActiveObject();
if(!activeObj){
Alert("»èÁ¦ÇÑ ¿ä¼Ò¸¦ ¼±ÅÃÇØÁÖ¼¼¿ä.");
return;
}
// ÀÏ¹Ý ¿ÀºêÁ§Æ® »èÁ¦
if (activeObj && !activeObj.isEditing) {
canvas.remove(activeObj);
canvas.discardActiveObject();
canvas.requestRenderAll();
objects = canvas.getObjects();
if(objects.length > 1) canvas.setActiveObject(objects[objects.length - 1]);
}
}
function deleteThumbnail(idx) {
if(idx == "null") idx = jobIndex;
var thumbnails = document.querySelectorAll('.thumbnail');
imageInfo.splice(idx, 1);
for (var i = idx; i < thumbnails.length - 1; i++) {
thumbnails[i].innerHTML = thumbnails[i + 1].innerHTML;
thumbnails[i].title = thumbnails[i + 1].title;
var currentBtn = thumbnails[i].querySelector('.close-button');
if (currentBtn) {
currentBtn.onclick = function (e) {
e.stopPropagation();
deleteThumbnail($('.close-button').index(this));
};
}
}
thumbnails[thumbnails.length - 1].innerHTML = '';
canvas.clear();
document.querySelector('#image-overlay').style.display = "flex";
thumbnails[thumbnails.length - 1].title = "À§Ä¡ ¼±ÅÃÀº ¸¶¿ì½º ¿À¸¥ÂÊ ¹öưÀ» ´©¸£¼¼¿ä.";
jobIndex = imageInfo.length;
if(jobIndex > imageMax) jobIndex = imageMax - 1;
console.log('deleteThumbnail() job index : ', jobIndex, idx);
}
function highlightAppliedFilters(obj) {
document.querySelectorAll('.filter-buttons button')
.forEach(btn => btn.classList.remove('active-filter'));
if (!obj || obj.type !== 'image' || !obj.filters) return;
obj.filters.forEach(filter => {
var filterType = filter?.type;
if (!filterType) return;
var btn = document.querySelector(`.filter-buttons button[data-filter="${filterType}"]`);
if (btn) btn.classList.add('active-filter');
});
}
function toggleFilter(filterType) {
if (cropper) return;
if (!img) {
Alert("±âº» À̹ÌÁö°¡ ¼±ÅõÇÁö ¾Ê¾Ò½À´Ï´Ù.");
return;
}
activeObj = canvas.getActiveObject();
if (!activeObj || activeObj.type !== "image") {
activeObj = canvas.getObjects()[0];
if (!activeObj) return;
}
var obj = activeObj;
if (filterType === 'FlipX') {
obj.flipX = !obj.flipX;
canvas.requestRenderAll();
return;
}
var existing = obj.filters.find(f => f.type === filterType);
if (existing) {
obj.filters = obj.filters.filter(f => f.type !== filterType);
} else {
var filter;
switch (filterType) {
case 'Grayscale': filter = new fabric.Image.filters.Grayscale(); break;
case 'Sepia': filter = new fabric.Image.filters.Sepia(); break;
case 'Invert': filter = new fabric.Image.filters.Invert(); break;
case 'Brightness': filter = new fabric.Image.filters.Brightness({ brightness: 0.2 }); break;
case 'Contrast': filter = new fabric.Image.filters.Contrast({ contrast: 0.3 }); break;
case 'Noise': filter = new fabric.Image.filters.Noise({ noise: 180 }); break;
case 'Pixelate': filter = new fabric.Image.filters.Pixelate({ blocksize: 4 }); break;
case 'Blur': filter = new fabric.Image.filters.Blur({ blur: 0.07 }); break;
case 'Saturation': filter = new fabric.Image.filters.Saturation({ saturation: 0.5 }); break;
case 'Vignette': filter = new fabric.Image.filters.Vignette({ darkness: 0.5, offset: 0.5 }); break;
default: return;
}
if (filter) obj.filters.push(filter);
}
obj.applyFilters();
highlightAppliedFilters(obj);
canvas.requestRenderAll();
}
function removeFilters() {
if(cropper) return;
activeObj = canvas.getActiveObject();
if (!activeObj) activeObj = canvas._objects[0];
// ±×·ì ¶Ç´Â ´ÙÁß ¼±ÅÃÀÏ °æ¿ì
var objs = activeObj.type === 'activeSelection' || activeObj.type === 'group'
? activeObj.getObjects()
: [activeObj];
objs.forEach(obj => {
if (obj.type === 'image' && obj.filters) {
obj.filters = [];
obj.applyFilters?.();
}
highlightAppliedFilters(obj);
});
canvas.renderAll();
}
function rotateObject() {
if(cropper) return;
if(!img){
Alert("´ë»óÀÌ ¼±ÅõÇÁö ¾Ê¾Ò½À´Ï´Ù.");
return;
}
activeObj = canvas.getActiveObject();
if(!activeObj) activeObj = canvas._objects[0];
var angle = ((Math.floor(activeObj.angle / 90) * 90) + 90 ) % 360;
activeObj.rotate(angle);
activeObj.setCoords();
canvas.renderAll();
}
function startCrop() {
var objects = canvas.getObjects();
if(!img || !cropper && objects.length > 1){
Alert("ÀÚ¸£±â´Â ¹è°æÀ̹ÌÁö¸¸ Á¸ÀçÇÒ¶§ °¡´ÉÇÕ´Ï´Ù.");
return;
}
var center = canvas.getCenter();
if (cropper){
//canvas.remove(cropper);
//cropper = null;
applyCrop();
}else{
cropper = new fabric.Rect({
left: center.left - 50,
top: center.top - 50,
width: 100,
height: 100,
fill: 'rgba(0, 0, 125, 0.2)',
stroke: 'gray',
strokeWidth: 0.1,
lockRotation: true, // ȸÀü °¡´É
selectable: true
});
canvas.add(cropper);
canvas.setActiveObject(cropper);
}
}
function applyCrop() {
var rect = canvas.getActiveObject();
if (!rect || rect.type !== 'rect') {
startCrop();
return;
}
if (!img) {
alert("À߸± À̹ÌÁö°¡ ¾ø½À´Ï´Ù.");
return;
}
var bgImg = canvas.getObjects('image')[0];
var scaleX = bgImg.scaleX || 1;
var scaleY = bgImg.scaleY || 1;
var rectBounds = rect.getBoundingRect();
var imgBounds = bgImg.getBoundingRect();
var cropX = (rectBounds.left - imgBounds.left) / scaleX;
var cropY = (rectBounds.top - imgBounds.top) / scaleY;
var cropW = rect.getScaledWidth() / scaleX;
var cropH = rect.getScaledHeight() / scaleY;
// ÀÚ¸¥ °á°ú¸¦ Àӽà ĵ¹ö½º·Î ·»´õ¸µ
var tempCanvas = document.createElement('canvas');
tempCanvas.width = cropW;
tempCanvas.height = cropH;
var ctx = tempCanvas.getContext('2d');
ctx.drawImage(
bgImg.getElement(),
cropX, cropY, cropW, cropH, // source
0, 0, cropW, cropH // destination
);
// »õ À̹ÌÁö °´Ã¼·Î º¯È¯
var dataURL = tempCanvas.toDataURL('image/jpeg');
canvas.clear();
addImageToCanvasFromDataURL(dataURL);
}
function deleteCropper() {
if(cropper){
canvas.remove(cropper);
cropper = null;
}
}
// ¿ÀºêÁ§Æ® °æ°è °è»ê
function getImageBounds(canvas) {
canvas.renderAll();
var imageObjects = canvas.getObjects().filter(obj => obj.type === 'image');
if (imageObjects.length === 0) {
return { left: 0, top: 0, right: 0, bottom: 0 };
}
if (scaleAll) {
return imageObjects.reduce((acc, obj) => {
var rect = obj.getBoundingRect(true); // ȸÀü, ½ºÄÉÀÏ Æ÷ÇÔµÈ Àý´ë ¹Ù¿îµå
acc.left = Math.min(acc.left, rect.left);
acc.top = Math.min(acc.top, rect.top);
acc.right = Math.max(acc.right, rect.left + rect.width);
acc.bottom = Math.max(acc.bottom, rect.top + rect.height);
return acc;
}, { left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity });
} else {
var obj = imageObjects[0];
var rect = obj.getBoundingRect(true);
return {
left: rect.left,
top: rect.top,
right: rect.left + rect.width,
bottom: rect.top + rect.height
};
}
}
function setInfoArea(idx){
var infoArea = document.getElementById("info-area");
var str = "";
str += `
Ver : ${version}
`;
infoArea.innerHTML = str;
}
function saveImagesSequentially(idx, delay) {
if(cropper) canvas.remove(cropper);
if(!idx) idx = 0;
if(!delay) delay = 0;
if(idx == 0 && imageInfo.length > 0){
for(var i=1;i<=imageMax;i++){
if(i == 1) tail = "";
else tail = i;
opener.PutInitImage(tail);
}
var objects = canvas.getObjects();
if(objects.length > 0){
imageInfo[jobIndex].wrk = canvas.toJSON();
imageInfo[jobIndex].durl = makeDataURL(idx);
}
Alert('ó¸®Áß ÀÔ´Ï´Ù. Àá½Ã¸¸ ±â´Ù·ÁÁÖ¼¼¿ä..');
}
if (idx >= imageInfo.length){
self.close();
return;
}
console.log(idx, delay, imageInfo[idx].durl.length);
var durl = imageInfo[idx].durl;
if (durl != null) {
setTimeout(function() {
saveImage(idx, function() {
saveImagesSequentially(idx + 1, delay); // ´ÙÀ½ À̹ÌÁö ó¸®
});
}, delay);
delay += 400;
}
}
// ¼¹ö Àü¼Û
function saveImage(idx, callback) {
if(imageInfo[idx].filename == null) {
imageInfo[idx].filename = 'm20250619200820_' + idx + '.jpg';
}
var formData = new FormData();
formData.append("data", imageInfo[idx].durl);
formData.append("image_width", imageInfo[idx].width);
formData.append("image_height", imageInfo[idx].height);
formData.append("image_size", imageInfo[idx].durl.length);
formData.append("image_name", imageInfo[idx].filename);
$.ajax({
type: 'POST',
url: '/image_editor/save.htm',
data: formData,
processData: false,
contentType: false,
async: false,
success: function (data) {
var [url, name, size] = data.split("|");
opener.PutImage(opener.document.send_msg, url, name, size);
opener.MoveScrollObject('hp_top', -80);
}
});
if(callback) callback();
}
function makeDataURL(idx) {
if(idx == "") idx = jobIndex;
var objects = canvas.getObjects();
if (objects.length === 0) return;
var bounds = getImageBounds(canvas);
var userImageWidth = bounds.right - bounds.left;
var userImageHeight = bounds.bottom - bounds.top;
// ±âº» À̹ÌÁö(¹è°æ À̹ÌÁö)ÀÇ Å©±â
var exportWidth = backImageWidth;
var exportHeight = backImageHeight;
// ȸÀü ¿©ºÎ ÆÇ´Ü
var baseImage = objects.find(obj => obj.type === 'image');
var isRotated = baseImage && baseImage.angle % 180 !== 0;
// ȸÀü ½Ã ÀúÀå ¿µ¿ªµµ Àüȯ
if (isRotated) {
[exportWidth, exportHeight] = [backImageHeight, backImageWidth];
}
// ÀúÀå Å©±â Á¦ÇÑ Ã³¸®
if (exportWidth > limitWidth || exportHeight > limitHeight) {
var scale = Math.min(limitWidth / exportWidth, limitHeight / exportHeight);
exportWidth *= scale;
exportHeight *= scale;
}
var scaleX = exportWidth / userImageWidth;
var scaleY = exportHeight / userImageHeight;
// Àӽà ĵ¹ö½º »ý¼º
var tempCanvasEl = document.createElement("canvas");
tempCanvasEl.width = exportWidth;
tempCanvasEl.height = exportHeight;
var tempCanvas = new fabric.Canvas(tempCanvasEl, {
backgroundColor: 'white'
});
objects.forEach(obj => {
var clone = fabric.util.object.clone(obj);
// ±âÁØÁ¡°ú ½ºÄÉÀÏ Àû¿ë
clone.originX = 'center';
clone.originY = 'center';
clone.scaleX *= scaleX;
clone.scaleY *= scaleY;
// Á᫐ ÁÂÇ¥ °è»ê
var center = obj.getCenterPoint();
clone.left = (center.x - bounds.left) * scaleX;
clone.top = (center.y - bounds.top) * scaleY;
clone.setCoords();
tempCanvas.add(clone);
});
tempCanvas.renderAll();
var dataURL = tempCanvas.toDataURL({
format: "jpeg",
quality: 0.7
});
tempCanvas.dispose();
imageInfo[idx].width = exportWidth;
imageInfo[idx].height = exportHeight;
return dataURL;
}
function addText() {
if(cropper) return;
if(!img){
Alert("±âº» À̹ÌÁö°¡ ¼±ÅõÇÁö ¾Ê¾Ò½À´Ï´Ù.");
return;
}
if(locText > 10) locText = 0;
var bgImage = canvas._objects[0];
var text = new fabric.Textbox("³»¿ëÃß°¡", {
left: canvas.getWidth() / 2 + (locText * 7) + 8,
top: canvas.getHeight() / 2 - (locText * 7),
width: bgImage.width * bgImage.scaleX - 25,
fontSize: document.getElementById('font-size-select').value,
fill: document.getElementById('text-color').value,
fontFamily: document.getElementById('font-family-select').value,
fontWeight: "bold",
backgroundColor: Hex2Rgba(document.getElementById('text-bgcolor').value, alpha),
selectable: true,
editable: true,
padding: 0,
lineHeight: 1.4,
originX: "center", // Á᫐ ±âÁØ ¹èÄ¡
originY: "top", // Ä¿¼°¡ Á¤»ó À§Ä¡¿¡ ¿Àµµ·Ï Á¶Á¤
textAlign: document.getElementById('font-align-select').value,
objectCaching: false, // Ãß°¡ Á÷ÈÄ¿£ ºñȰ¼ºÈ
strokeWidth: 16, // ¿Ü°û¼± µÎ²²
});
text.setControlsVisibility({
mt: false, // top middle
mb: false, // bottom middle
//ml: false, // middle left
//mr: false, // middle right
tl: false, // top left
tr: false, // top right
bl: false, // bottom left
br: false, // bottom right
//mtr: false // rotation control (middle top rotate)
});
document.fonts.ready.then(() => {
canvas.add(text);
text.setCoords();
text.set({
dirty: true,
objectCaching: false
});
canvas.setActiveObject(text);
var textCount = canvas.getObjects().filter(obj => obj.type === 'textbox').length;
if(textCount == 1){
text.enterEditing();
text.selectAll();
}
canvas.requestRenderAll();
});
locText++;
}
function applyToTextbox(callback) {
if(cropper) return;
activeObj = canvas.getActiveObject();
if (activeObj?.type === 'activeSelection') {
activeObj.getObjects().forEach(obj => {
if (obj.type === 'textbox') callback(obj);
});
} else if (activeObj?.type === 'textbox') {
callback(activeObj);
} else {
var allObjects = canvas.getObjects();
var recentTextbox = [...allObjects].reverse().find(obj => obj.type === 'textbox');
if (recentTextbox) {
canvas.setActiveObject(recentTextbox);
callback(recentTextbox);
} else {
addText();
}
}
canvas.renderAll();
}
function setImageAttr(){
if(!img){
Alert("±âº» À̹ÌÁö°¡ ¼±ÅõÇÁö ¾Ê¾Ò½À´Ï´Ù.");
return;
}
document.querySelector('#image-overlay').style.display = "none";
var center = canvas.getCenter();
var images = canvas.getObjects('image');
img.set({
originX: 'center',
originY: 'center',
left: center.left + images.length * 8,
top: center.top + images.length * 8,
lockRotation: false, // ȸÀü °¡´É
lockScalingX: false, // XÃà Å©±âÁ¶Àý °¡´É
lockScalingY: false, // YÃà Å©±âÁ¶Àý °¡´É
hasControls: true, // ÄÁÆ®·Ñ ¹Ú½º º¸À̱â
lockScalingFlip: true, // À½¼ö ½ºÄÉÀÏ ¹æÁö (µÚÁýÈû ¹æÁö)
hoverCursor: 'move',
selectable: true, // ¼±Åà °¡´É
evented: true // ¸¶¿ì½º À̺¥Æ® Ȱ¼º
});
if (images.length == 1) {
console.log('base image : ', images.length);
var orgSrc = cropper ? imageInfo[jobIndex].src : null;
imageInfo[jobIndex] = {src:null, wrk:null, durl:null, width:null, height:null, filename:null};
img.set({
lockMovementX: true,
lockMovementY: true,
hasControls: false,
selectable: false,
evented: false
});
backImageWidth = img.width;
backImageHeight = img.height;
imageWidth = img.width * img.scaleX;
imageHeight = img.height * img.scaleY;
canvas.discardActiveObject();
var jsonData = canvas.toJSON();
if(!orgSrc){
imageInfo[jobIndex].src = jsonData;
addImageToThumbnail(img.toDataURL(), jobIndex);
}else{
imageInfo[jobIndex].src = orgSrc;
}
imageInfo[jobIndex].wrk = jsonData;
}else{
var baseImg = canvas._objects[0];
if (baseImg) {
var scaleRatioX = (baseImg.scaleX || 1) * 0.5;
var scaleRatioY = (baseImg.scaleY || 1) * 0.5;
img.scaleX = scaleRatioX;
img.scaleY = scaleRatioY;
}
canvas.setActiveObject(img); // Ȱ¼ºÈ
}
img.setCoords();
if(cropper) cropper = null;
}
function addImageToCanvasFromDataURL(dataURL) {
fabric.Image.fromURL(dataURL, function (image) {
image._originalElement = image.getElement();
img = image;
var widthRatio = canvasWidth / img.width;
var heightRatio = canvasHeight / img.height;
var scaleRatio = Math.min(widthRatio, heightRatio, 1);
img.scale(scaleRatio);
img.setCoords();
img.backgroundColor;
imageWidth = img.width * img.scaleX;
imageHeight = img.height * img.scaleY;
canvas.add(img);
setImageAttr();
canvas.renderAll();
imageInfo[jobIndex].durl = makeDataURL(jobIndex);
console.log("job index : ", jobIndex , ", image info : ", imageInfo[jobIndex]);
});
}
function addImageToCanvas(file) {
deleteCropper();
if(!document.getElementById('multi-image').checked){
var texts = canvas.getObjects().find(obj => obj.type === 'textbox');
if(texts && !confirm("ÀÔ·Â ÁßÀ̽бÛÀÌ ÀÖ½À´Ï´Ù.\n»õ·Î¿î ÀÛ¾÷À» ÁøÇàÇϽðڽÀ´Ï±î?")){
return
}
canvas.clear();
}
var reader = new FileReader();
var fileSizeKB = (file.size / 1024).toFixed(2);
reader.onload = function (event) {
addImageToCanvasFromDataURL(event.target.result);
};
reader.readAsDataURL(file);
document.querySelector('#image-overlay').style.display = "none";
}
function addJsonToCanvas(jdata, callback){
canvas.clear();
canvas.loadFromJSON(jdata, function () {
img = canvas.getObjects().find(obj => obj.type === 'image');
img.set({
lockMovementX: true,
lockMovementY: true,
hasControls: false,
selectable: false,
evented: false
});
canvas.renderAll();
canvas.setActiveObject(img); // Ȱ¼ºÈ
if(callback) callback();
});
}
function addImageToThumbnail(src, idx){
var div = document.getElementById('thumbnail' + idx);
if(!div) document.location.reload();
//if(!div) return;
div.style.position = 'relative';
var im = document.createElement('img');
im.src = src;
im.style.width = '100%';
im.style.height = 'auto';
im.style.display = 'block';
im.title = "";
var closeBtn = document.createElement('button');
closeBtn.className = 'close-button';
closeBtn.innerText = '¥¹';
closeBtn.style.fontSize = '12px';
closeBtn.style.position = 'absolute';
closeBtn.style.top = '1px';
closeBtn.style.right = '0px';
closeBtn.style.backgroundColor = 'rgba(0, 0, 0, 0.4)';
closeBtn.style.color = 'white';
closeBtn.style.border = 'none';
closeBtn.style.borderRadius = '50%';
closeBtn.style.width = '20px';
closeBtn.style.height = '20px';
closeBtn.style.cursor = 'pointer';
closeBtn.title = '';
$(closeBtn).click(function (e) {
e.stopPropagation();
deleteThumbnail($('.close-button').index(this));
});
div.replaceChildren(im, closeBtn);
}
function callImageFromServer(url, callback) {
if(!url) return;
url = url.replace('_1.jpg', '.jpg');
fetch(url)
.then(response => response.blob())
.then(blob => {
// BlobÀ» Fileó·³ »ç¿ë
var fileName = url.substring(url.lastIndexOf('/') + 1);
var file = new File([blob], fileName, { type: blob.type });
addImageToCanvas(file);
if(callback) callback();
})
.catch(err => {
console.error("À̹ÌÁö ºÒ·¯¿À±â ½ÇÆÐ:", err);
Alert("À̹ÌÁö¸¦ ºÒ·¯¿ÀÁö ¸øÇß½À´Ï´Ù.");
return;
});
}
function loadImagesSequentially(idx, delay) {
if(!idx) idx = 0;
if(!delay) delay = 500;
if (idx >= parentImg.length) return;
if (parentImg[idx]) {
setTimeout(function() {
jobIndex = idx;
callImageFromServer(parentImg[idx].src, function() {
loadImagesSequentially(idx + 1, delay); // ´ÙÀ½ À̹ÌÁö ó¸®
});
}, delay);
delay += 200;
}
}
window.onload = function() {
if(!opener){
alert("¸ÞÀÎâ°ú Åë½ÅÀÌ ²÷°å½À´Ï´Ù. âÀ» ´Ù½Ã ¿©¼¼¿ä.");
return;
}
document.addEventListener("keydown", function (e) {
//console.log(e.key);
if (e.key === "Delete" || e.key === "Backspace") {
deleteObject();
}
if (e.key === "Enter"){
if(cropper){
applyCrop();
return;
}
if(img && !canvas.getActiveObject()){
e.preventDefault();
addText();
}
}
});
document.addEventListener("click", function (e) {
activeObj = canvas.getActiveObject();
if (!activeObj) highlightAppliedFilters(canvas._objects[0]);
});
document.getElementById("upload").addEventListener("change", function (e) {
var file = e.target.files[0];
if (file && file.type.startsWith("image/")) {
addImageToCanvas(file);
}
$('#upload').val(''); // ÀÔ·Â ÃʱâÈ
});
// ±ÛÀÚ »ö º¯°æ
document.getElementById('text-color').addEventListener('input', function () {
applyToTextbox(obj => obj.set('fill', this.value));
});
// ±ÛÀÚ ¹è°æ»ö º¯°æ
document.getElementById('text-bgcolor').addEventListener('input', function () {
var bgColor = Hex2Rgba(this.value, alpha || 0.3);
applyToTextbox(obj => obj.set('backgroundColor', bgColor));
});
// ±ÛÀÚ Åõ¸íµµ Åä±Û
document.getElementById('text-alpha').addEventListener('click', function () {
applyToTextbox(obj => {
var bgColor = obj.backgroundColor;
if (!bgColor) return;
var rgbaMatch = bgColor.match(/rgba?\(([^)]+)\)/);
if (!rgbaMatch) return;
var parts = rgbaMatch[1].split(',').map(p => p.trim());
if (parts.length < 3) return;
var [r, g, b, a] = parts;
a = parts.length === 4 ? parseFloat(a) : alpha;
alpha = a > 0 ? 0 : 0.3;
obj.set('backgroundColor', `rgba(${r}, ${g}, ${b}, ${alpha})`);
});
});
// ÆùÆ® º¯°æ
document.getElementById('font-family-select').addEventListener('change', function () {
applyToTextbox(obj => obj.set('fontFamily', this.value));
});
// ±ÛÀÚ Á¤·Ä
document.getElementById('font-align-select').addEventListener('change', function () {
applyToTextbox(obj => obj.set('textAlign', this.value));
});
// ±ÛÀÚ »çÀÌÁî º¯°æ
document.getElementById('font-size-select').addEventListener('input', function () {
applyToTextbox(obj => obj.set('fontSize', parseFloat(this.value)));
//console.log(parseFloat(this.value));
});
document.getElementById('font-lineheight-select').addEventListener('input', function () {
applyToTextbox(obj => obj.set('lineHeight', parseFloat(this.value)));
//console.log(parseFloat(this.value));
});
setTimeout(function() {
var canvasContainer = document.getElementById('canvas-container');
canvas = new fabric.Canvas("canvas", {
width: canvasContainer.offsetWidth,
height: canvasContainer.offsetHeight,
});
canvas.on('object:moving', function (e) {
var obj = e.target;
// °´Ã¼ÀÇ °æ°è
obj.setCoords();
if (obj.type == 'textbox' || obj.type == 'rect'){
var bounds = getImageBounds(canvas); // À̹ÌÁö °æ°è
var rect = obj.getBoundingRect(true); // ½ÇÁ¦ È¸é °æ°è
var dx = obj.left - rect.left;
var dy = obj.top - rect.top;
let newLeft = obj.left;
let newTop = obj.top;
if (rect.left < bounds.left) {
newLeft += bounds.left - rect.left;
}
if (rect.left + rect.width > bounds.right) {
newLeft -= (rect.left + rect.width) - bounds.right;
}
if (rect.top < bounds.top) {
newTop += bounds.top - rect.top;
}
if (rect.top + rect.height > bounds.bottom) {
newTop -= (rect.top + rect.height) - bounds.bottom;
}
obj.set({
left: newLeft,
top: newTop
});
obj.setCoords(); // ´Ù½Ã °è»ê
}else{
var boundingBox = obj.getBoundingRect(true); // true: ½ºÄÉÀÏ/ȸÀü ¹Ý¿µ
// ÁÂ¿ì °æ°è Á¦ÇÑ
if (boundingBox.left < 0) {
obj.left -= boundingBox.left;
} else if (boundingBox.left + boundingBox.width > canvas.getWidth()) {
obj.left -= (boundingBox.left + boundingBox.width - canvas.getWidth());
}
// »óÇÏ °æ°è Á¦ÇÑ
if (boundingBox.top < 0) {
obj.top -= boundingBox.top;
} else if (boundingBox.top + boundingBox.height > canvas.getHeight()) {
obj.top -= (boundingBox.top + boundingBox.height - canvas.getHeight());
}
}
});
canvas.on('object:scaling', function (e) {
var obj = e.target;
if (obj.type !== 'textbox' && obj.type !== 'rect' ) return;
// ¿øÁ¡ÀÌ ¿ÞÂÊ »ó´ÜÀÌ µÇµµ·Ï ¼³Á¤ (Ãʱ⠼³Á¤¿¡¼µµ °°ÀÌ ÇØÁÖ´Â °Ô ÁÁÀ½)
obj.set({ originX: 'left', originY: 'top' });
var bounds = getImageBounds(canvas);
var rect = obj.getBoundingRect(true);
var newScaleX = obj.scaleX;
var newScaleY = obj.scaleY;
var newLeft = obj.left;
var newTop = obj.top;
var objWidth = obj.width * newScaleX;
var objHeight = obj.height * newScaleY;
// ¿ÞÂÊ °æ°è
if (rect.left < bounds.left) {
var diff = bounds.left - rect.left;
newLeft = bounds.left;
var maxWidth = objWidth - diff;
newScaleX = Math.max(1, maxWidth / obj.width);
}
// À§ÂÊ °æ°è
if (rect.top < bounds.top) {
var diff = bounds.top - rect.top;
newTop = bounds.top;
var maxHeight = objHeight - diff;
newScaleY = Math.max(1, maxHeight / obj.height);
}
// ¿À¸¥ÂÊ °æ°è
if (rect.left + rect.width > bounds.right) {
var diff = (rect.left + rect.width) - bounds.right;
var maxWidth = objWidth - diff;
newScaleX = Math.max(1, maxWidth / obj.width);
}
// ¾Æ·¡ÂÊ °æ°è
if (rect.top + rect.height > bounds.bottom) {
var diff = (rect.top + rect.height) - bounds.bottom;
var maxHeight = objHeight - diff;
newScaleY = Math.max(1, maxHeight / obj.height);
}
obj.set({
scaleX: newScaleX,
scaleY: newScaleY,
left: newLeft,
top: newTop
});
obj.setCoords();
});
canvas.on('mouse:down', function (e) {
var obj = e.target;
if (obj && obj.type === 'textbox') {
obj.bringToFront();
}
/* ÇØÁ¦¸øÇϰÔ
if(cropper){
canvas.setActiveObject(cropper);
}
*/
// ÀÚµ¿ÇØÁ¦
if(!obj){
deleteCropper();
}
});
document.getElementById("image-overlay").addEventListener("dragover", function (e) {
e.preventDefault();
});
document.getElementById("image-overlay").addEventListener("drop", function (e) {
e.preventDefault();
canvas.upperCanvasEl.style.border = "none";
var file = e.dataTransfer.files[0];
if (file && file.type.startsWith("image/")) {
addImageToCanvas(file);
}
});
canvas.upperCanvasEl.addEventListener("dragover", function (e) {
e.preventDefault();
});
canvas.upperCanvasEl.addEventListener("drop", function (e) {
e.preventDefault();
canvas.upperCanvasEl.style.border = "none";
var file = e.dataTransfer.files[0];
if (file && file.type.startsWith("image/")) {
imageInfo[jobIndex].filename = file.name;
addImageToCanvas(file);
}
});
canvas.on('selection:created', function (e) {
var obj = e.selected[0];
highlightAppliedFilters(obj);
});
canvas.on('selection:updated', function (e) {
var obj = e.selected[0];
highlightAppliedFilters(obj);
});
canvas.on('selection:cleared', function () {
document.querySelectorAll('.filter-buttons button')
.forEach(btn => btn.classList.remove('active-filter'));
});
}, 0);
setInfoArea();
// ¸ÞÀÎâ »ùÇà ¹× ¼Ó¼ºÁöÁ¤
parentImg = opener.document.querySelectorAll('.photo_list_image');
var tnList = document.getElementById('thumbnail-container');
for(var i=0;i= imageMax) jobIndex = imageMax - 1;
document.getElementById('upload').click();
$('#image-overlay').show();
}else{
var jsonData;
if(idx == jobIndex){
if(!confirm('À̹ÌÁö¸¦ ºÒ·¯¿À°Ú½À´Ï±î?')) return;
document.getElementById('upload').click();
return;
}
var objects = canvas.getObjects();
if(objects.length) {
imageInfo[jobIndex].wrk = canvas.toJSON();
imageInfo[jobIndex].durl = makeDataURL(jobIndex);
}
jobIndex = idx;
jsonData = imageInfo[jobIndex].wrk;
addJsonToCanvas(jsonData);
$('#image-overlay').hide();
}
console.log('job index : ', jobIndex, ', click index : ', idx);
};
$(div).on('contextmenu', function(e) {
e.preventDefault();
var objects = canvas.getObjects();
if(objects.length) {
imageInfo[jobIndex].wrk = canvas.toJSON();
imageInfo[jobIndex].durl = makeDataURL(jobIndex);
}
jobIndex = $('.thumbnail').index(this);
if(imageInfo[jobIndex] == null){
canvas.clear();
// ¼±Åà À§Ä¡°¡ ¾Æ´Ñ ¸Ç ¾Õ ºó°ø°£
jobIndex = imageInfo.length;
if(jobIndex >= imageMax) jobIndex = imageMax - 1;
$('#image-overlay').show();
this.title = "À§Ä¡ ¼±ÅÃÀº ¿À¸¥ÂÊ ¹öưÀ» ´©¸£¼¼¿ä.";
}
});
}
loadImagesSequentially();
};