카테고리 없음

초간단 썸네일 편집기를 사용하여 멋진 썸네일을 쉽게 만드는 방법

알세지 2024. 7. 28. 00:24
이 간단한 썸네일 편집기를 사용하면 이미지를 업로드하고, 사용자 정의 텍스트를 추가하고, 다양한 스타일을 실시간으로 적용할 수 있습니다. 글꼴 크기, 텍스트 색상을 쉽게 조정하고 굵게, 기울임꼴, 밑줄 및 윤곽선 효과를 추가할 수 있습니다. 실시간 미리보기 기능을 통해 변경 사항을 즉시 확인할 수 있습니다. 만족스러우면 다운로드 또는 공유할 수 있는 고품질 썸네일 이미지를 생성하세요. 시각적 콘텐츠를 쉽게 향상시키려는 콘텐츠 제작자, 마케팅 담당자 및 디자이너에게 적합합니다.

 

 

이 썸네일 편집기는 아주 간단한 편집만 가능합니다.

텍스트를 입력하고, 크기, 색깔, 외곽선 등을 간편하게 편집할 수 있습니다.

고급 기능은 없고, 간단 - 대량 - 신속 생산에 적합합니다.

 

 

 

 

이번 편집기는 v1입니다. 고급 기능은 차츰 추가해 가면서 나만의 이미지 편집기로 만들어 갈 계획입니다.

그리고, 다음편에서는 이미지 생성을 AI에게 요청하는 형태로 업데이트 하는 것과

파일 저장 등의 기능 등을 반영할 계획입니다 

 

자바스크립트로 만들었고, 파일 구성은 다음과 같습니다. 

index.html - style.css - script.js 

파이썬 fastapi로 만들다가 생각보다 좋은 결과물이 안나와서 급히 자바스크립트로 변경해 만들었습니다.

index는 부트스트랩 스타일로 간단하게 바꿨습니다. 

 

아래는 코드 전문입니다. 

 

Index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Thumbnail Editor</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container mt-5">
        <div class="row">
            <div class="col text-center">
                <h1 class="mb-4">Thumbnail Editor</h1>
            </div>
        </div>
        <div class="row">
            <div class="col text-center">
                <input type="file" id="imageUpload" accept="image/*" class="form-control-file mb-3">
            </div>
        </div>
        <div class="row mt-4">
            <div class="col-md-6 text-center">
                <h2>Original Image</h2>
                <div class="image-preview">
                    <img id="originalImage" src="" alt="Original Image">
                </div>
            </div>
            <div class="col-md-6 text-center">
                <h2>Edited Image</h2>
                <div class="image-preview">
                    <canvas id="imageCanvas"></canvas>
                </div>
            </div>
        </div>
        <div class="row mt-4">
            <div class="col text-center">
                <h2>Text Settings</h2>
                <div class="form-group">
                    <label for="textInput">Text:</label>
                    <input type="text" id="textInput" placeholder="Enter your text here" class="form-control mb-3">
                </div>
                <div class="form-group row">
                    <div class="col-md-4">
                        <label for="fontSizeInput">Font Size:</label>
                        <input type="number" id="fontSizeInput" value="30" min="10" max="100" class="form-control mb-3">
                    </div>
                    <div class="col-md-4">
                        <label for="fontFamilyInput">Font Family:</label>
                        <select id="fontFamilyInput" class="form-control mb-3">
                            <option value="Arial">Arial</option>
                            <option value="Verdana">Verdana</option>
                            <option value="Times New Roman">Times New Roman</option>
                            <option value="Courier New">Courier New</option>
                            <option value="Georgia">Georgia</option>
                        </select>
                    </div>
                    <div class="col-md-4">
                        <label for="textColorInput">Text Color:</label>
                        <input type="color" id="textColorInput" value="#ffffff" class="form-control mb-3">
                    </div>
                </div>
                <div class="form-group row">
                    <div class="col-md-3">
                        <label for="outlineCheckbox">Outline:</label>
                        <div class="form-check">
                            <input type="checkbox" id="outlineCheckbox" class="form-check-input" checked>
                            <label for="outlineCheckbox" class="form-check-label">Enable</label>
                        </div>
                    </div>
                    <div class="col-md-3">
                        <label for="outlineColorInput">Outline Color:</label>
                        <input type="color" id="outlineColorInput" value="#000000" class="form-control mb-3">
                    </div>
                    <div class="col-md-2">
                        <label for="boldCheckbox">Bold:</label>
                        <div class="form-check">
                            <input type="checkbox" id="boldCheckbox" class="form-check-input">
                            <label for="boldCheckbox" class="form-check-label">Enable</label>
                        </div>
                    </div>
                    <div class="col-md-2">
                        <label for="italicCheckbox">Italic:</label>
                        <div class="form-check">
                            <input type="checkbox" id="italicCheckbox" class="form-check-input">
                            <label for="italicCheckbox" class="form-check-label">Enable</label>
                        </div>
                    </div>
                    <div class="col-md-2">
                        <label for="underlineCheckbox">Underline:</label>
                        <div class="form-check">
                            <input type="checkbox" id="underlineCheckbox" class="form-check-input">
                            <label for="underlineCheckbox" class="form-check-label">Enable</label>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <div class="row mt-5">
            <div class="col text-center">
                <button id="generateButton" class="btn btn-primary mb-5">Generate Thumbnail</button>
            </div>
        </div>
    </div>
    <script src="script.js"></script>
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
</body>
</html>

 

style.css

.image-preview {
    width: 100%;
    padding-top: 56.25%; /* 16:9 Aspect Ratio */
    position: relative;
    background-color: #f0f0f0;
    border: 1px solid #ddd;
    margin-top: 20px;
}

.image-preview img, .image-preview canvas {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

 

script.js

document.getElementById('imageUpload').addEventListener('change', handleImageUpload);
document.getElementById('textInput').addEventListener('input', updateCanvas);
document.getElementById('fontSizeInput').addEventListener('input', updateCanvas);
document.getElementById('fontFamilyInput').addEventListener('change', updateCanvas);
document.getElementById('textColorInput').addEventListener('input', updateCanvas);
document.getElementById('outlineCheckbox').addEventListener('change', updateCanvas);
document.getElementById('outlineColorInput').addEventListener('input', updateCanvas);
document.getElementById('boldCheckbox').addEventListener('change', updateCanvas);
document.getElementById('italicCheckbox').addEventListener('change', updateCanvas);
document.getElementById('underlineCheckbox').addEventListener('change', updateCanvas);
document.getElementById('generateButton').addEventListener('click', generateThumbnail);

let uploadedImage;

function handleImageUpload(event) {
    const file = event.target.files[0];
    if (file) {
        const reader = new FileReader();
        reader.onload = function (e) {
            const img = new Image();
            img.onload = function () {
                const originalImage = document.getElementById('originalImage');
                originalImage.src = img.src;

                const canvas = document.getElementById('imageCanvas');
                const ctx = canvas.getContext('2d');
                canvas.width = 600;
                canvas.height = 337.5; // 600 / (16/9)
                ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
                uploadedImage = img;
                updateCanvas();
            };
            img.src = e.target.result;
        };
        reader.readAsDataURL(file);
    }
}

function updateCanvas() {
    if (!uploadedImage) return;
    const canvas = document.getElementById('imageCanvas');
    const ctx = canvas.getContext('2d');
    
    // Clear the canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // Redraw the uploaded image
    ctx.drawImage(uploadedImage, 0, 0, canvas.width, canvas.height);

    const text = document.getElementById('textInput').value;
    const fontSize = document.getElementById('fontSizeInput').value;
    const fontFamily = document.getElementById('fontFamilyInput').value;
    const textColor = document.getElementById('textColorInput').value;
    const outline = document.getElementById('outlineCheckbox').checked;
    const outlineColor = document.getElementById('outlineColorInput').value;
    const bold = document.getElementById('boldCheckbox').checked;
    const italic = document.getElementById('italicCheckbox').checked;
    const underline = document.getElementById('underlineCheckbox').checked;
    
    // Construct the font style
    let fontStyle = '';
    if (bold) fontStyle += 'bold ';
    if (italic) fontStyle += 'italic ';
    fontStyle += `${fontSize}px ${fontFamily}`;

    ctx.font = fontStyle;
    ctx.fillStyle = textColor;
    ctx.textAlign = 'center';
    
    const maxWidth = canvas.width - 20; // 10px padding on each side
    const lineHeight = parseInt(fontSize) + 10;
    const x = canvas.width / 2;
    const y = canvas.height / 2;

    wrapText(ctx, text, x, y, maxWidth, lineHeight, outline, outlineColor, underline);
}

function generateThumbnail() {
    if (!uploadedImage) return;
    updateCanvas();
    
    // Show the image in a pop-up
    const canvas = document.getElementById('imageCanvas');
    const imageUrl = canvas.toDataURL('image/png');
    const popupWindow = window.open('', '_blank');
    popupWindow.document.write('<img src="' + imageUrl + '" />');
}

function wrapText(ctx, text, x, y, maxWidth, lineHeight, outline, outlineColor, underline) {
    const words = text.split(' ');
    let line = '';
    let testLine = '';
    let testWidth = 0;
    
    for (let n = 0; n < words.length; n++) {
        testLine = line + words[n] + ' ';
        testWidth = ctx.measureText(testLine).width;
        if (testWidth > maxWidth && n > 0) {
            if (outline) {
                ctx.strokeStyle = outlineColor;
                ctx.lineWidth = 2;
                ctx.strokeText(line, x, y);
            }
            ctx.fillText(line, x, y);
            if (underline) {
                const textWidth = ctx.measureText(line).width;
                ctx.beginPath();
                ctx.moveTo(x - textWidth / 2, y + 5);
                ctx.lineTo(x + textWidth / 2, y + 5);
                ctx.stroke();
            }
            line = words[n] + ' ';
            y += lineHeight;
        } else {
            line = testLine;
        }
    }
    if (outline) {
        ctx.strokeStyle = outlineColor;
        ctx.lineWidth = 2;
        ctx.strokeText(line, x, y);
    }
    ctx.fillText(line, x, y);
    if (underline) {
        const textWidth = ctx.measureText(line).width;
        ctx.beginPath();
        ctx.moveTo(x - textWidth / 2, y + 5);
        ctx.lineTo(x + textWidth / 2, y + 5);
        ctx.stroke();
    }
}