HTML5+ CSS3+ Javascript

미니프로젝트 Ver_1.0

구자룡 2021. 4. 1. 09:09

미니프로젝트 Ver_1

자바스크립트를 이용한 웹페이지 만들기

 

 

#표지

표지는 버튼 이벤트를 이용하여 버튼 클릭시 해당 영상처리 파트로 넘어갈 수 있도록 하였습니다.

표지.html
0.00MB
2.png
0.28MB
18.png
0.02MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
    body {
        background-image: url(2.png);
        background-repeat: repeat-x;
        background-size: cover;
        text-align: center;
    }

    .button-wrapper {
        display: inline-block;
        margin: 20px 5px;
        padding: 40px;
        margin-top: 200px;
    }

    .dark-button,
    .dark-button-2 {
        background: #333;
    }

    .button {
        background: #fff;
        border: none;
        padding: 2px;
        cursor: pointer;
        display: block;
        position: relative;
        overflow: hidden;
        transition: all .35s ease-in-out .35s;
        margin: 0 auto;
        width: 155px;
        text-align: center;
    }

    .dark-button .button,
    .dark-button .button span {
        background: #8d781b;
        color: #fff;
    }

    .dark-button .button:after,
    .dark-button .button:before,
    .dark-button .button:hover span {
        background: #fff;
        color: rgb(17, 17, 16);
    }

    .dark-button-2 .button,
    .dark-button-2 .button span {
        background: rgb(94, 78, 9);
        color: #fff;
    }

    .dark-button-2 .button:after,
    .dark-button-2 .button:before,
    .dark-button-2 .button:hover span {
        background: #fff;
        color: rgb(12, 12, 11);
    }

    span {
        display: block;
        padding: 15px 30px;
        background: #fff;
        z-index: 100;
        position: relative;
        transition: all .35s ease-in-out .35s;
    }

    .button:hover span {
        background: #665912;
        color: #fff;
        transition: all .35s ease-in-out .35s;
    }

    .button:after {
        bottom: -100%;
        right: -100%;
        content: "";
        width: 100%;
        height: 100%;
        position: absolute;
        background: #36B4C7;
        transition: all .35s ease-in-out .5s;
    }

    .button:hover:after {
        right: 0;
        bottom: 0;
        transition: all ease-in-out .35s;
    }

    .button:before {
        top: -100%;
        left: -100%;
        content: "";
        width: 100%;
        height: 100%;
        position: absolute;
        background: #36B4C7;
        transition: all .35s ease-in-out .5s;
    }

    .button:hover:before {
        left: 0;
        top: 0;
        transition: all ease-in-out .35s;
    }

    .box {
        margin-top: 200px;
        font-size: 23px;
        margin-left: -50px;
        color: rgb(252, 252, 252);
        font-style: unset;
        border: 3px solid whitesmoke;
        border-style: groove;
        width: 480px;
        margin-left: 690px;
    }
</style>

<body onload="init()">
    <h1>
        <div class="wordArtEffectText"><img src="18.png" width="220">
    </h1>
    <hr>
    <div class="dark-button-2 button-wrapper">
        <div class="button" onclick="location.href='거울.html'">
            <span>
                Mirror (Paint)
            </span>
        </div>
    </div>

    <div class="dark-button button-wrapper">
        <div class="button" onclick="location.href='화소 점.html'">
            <span>
                Point processing
            </span>
        </div>
    </div>
    <div class="dark-button-2 button-wrapper">
        <div class="button" onclick="location.href='기하학.html'">
            <span>
                Geometric processing
            </span>
        </div>
    </div>
    <div class="dark-button button-wrapper">
        <div class="button" onclick="location.href='히스토.html'">
            <span>
                Histogram (Basic)
            </span>
        </div>
    </div>
    <div class="dark-button-2 button-wrapper">
        <div class="button" onclick="location.href='영상.html'">
            <span>
                pixel area processing
            </span>
        </div>
    </div>
    <br>

    <div class="box">
        <strong>Phone : 010-7736-8697</strong>
        <br>
        <strong>Insta : jaryong_s</strong>
    </div>

</body>

</html>

 

#Mirror (그림판 만들기)

그림판은 수업중 배운 내용과 검색을해서 추가 보완해봤습니다.

거울.html
0.01MB
40.png
0.29MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #canvas {
            border: 1px solid #EEE;
        }

        .options {
            display: flex;
            align-items: center;
        }

        body {
            background-image: url(40.png);
            background-repeat: repeat-x;
            background-size: cover;
            text-align: center;
        }

        .mir {
            font-size: 43px;
            margin-left: -80px;
            margin-top: -33px;
        }
    </style>
</head>

<body>
    <div class="mir">
        <dd><strong>
                <h3>Mirror</h3>
            </strong></dd>
    </div>
    <canvas id="canvas" width="1900" height="750"></canvas>
    <div class="options">
        <select id="type">
            <option value="stroke">실선</option>
            <option value="square">사각형</option>
            <option value="eraser">지우개</option>
        </select>
        <select id="strokeStyle">
            <option value="blue">파란색</option>
            <option value="red">빨간색</option>
            <option value="pink">분홍색</option>
            <option value="orange">주황색</option>
            <option value="green">초록색</option>
            <option value="black">검정색</option>
            <option value="skyblue">하늘색</option>
        </select>
        <select id="lineWidth">
            <option value="5">5px</option>
            <option value="10">10px</option>
            <option value="15">15px</option>
            <option value="20">20px</option>
        </select>
    </div>
    <script>
        let isAbleDraw = false;
        const options = {
            type: 'stroke',
            strokeStyle: 'white',
            lineWidth: 5,
        };
        const rects = [];
        let currentRect = null;
        document.getElementById('canvas').addEventListener('mousedown', () => {
            isAbleDraw = true;
            currentRect = {
                type: options.type,
                strokeStyle: options.strokeStyle,
                lineWidth: options.lineWidth,
                coordinates: [],
            };
        });
        document.getElementById('canvas').addEventListener('mousemove', (e) => {
            if (isAbleDraw) {
                const ctx = e.target.getContext('2d');
                const [x, y] = [e.offsetX, e.offsetY];
                currentRect.coordinates.push([x, y]);
                drawTools.clear();
                drawTools.execute(rects);
                if (currentRect.type === 'stroke') drawTools.stroke(currentRect.coordinates, 'rgba(255, 255, 0, .3)', currentRect.lineWidth);
                if (currentRect.type === 'eraser') drawTools.eraser(currentRect.coordinates, currentRect.lineWidth);
                if (currentRect.type === 'square') drawTools.square(currentRect.coordinates, 'rgba(255, 255, 0, .3)');
            }
        });
        document.getElementById('canvas').addEventListener('mouseup', () => {
            isAbleDraw = false;
            rects.push(currentRect);
            drawTools.clear();
            currentRect = null;
            drawTools.execute(rects);
            console.log(rects);
        })

        const drawTools = {
            clear() {
                // 캔버스 내용 제거
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            },
            stroke(coordinates, color, lineWidth) {
                // 마우스가 이동한 경로를 따라 실선 그리기
                if (coordinates.length > 0) {
                    const ctx = document.getElementById('canvas').getContext('2d');
                    const firstCoordinate = coordinates[0];
                    ctx.beginPath();
                    ctx.moveTo(firstCoordinate[0], firstCoordinate[1]);
                    for (let i = 1; i < coordinates.length; i += 1) {
                        ctx.lineTo(coordinates[i][0], coordinates[i][1]);
                    }
                    ctx.strokeStyle = color;
                    ctx.lineWidth = lineWidth;
                    ctx.stroke();
                    ctx.closePath();
                }
            },
            eraser(coordinates, lineWidth) {
                // 마우스가 이동한 좌표에 따라 하얀색으로 원을 그려서 지우개 기능처럼 동작
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                for (let i = 0; i < coordinates.length; i += 1) {
                    ctx.beginPath();
                    const coordinate = coordinates[i];
                    const [x, y] = coordinate;
                    ctx.fillStyle = 'white';
                    ctx.arc(x, y, lineWidth / 2, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            },
            execute(rects) {
                // rects 배열에 저장 된 도형을 기준으로 다시 캔버스에 그림
                for (let i = 0; i < rects.length; i += 1) {
                    const rect = rects[i];
                    const { type } = rect;
                    if (type === 'stroke') this.stroke(rect.coordinates, rect.strokeStyle, rect.lineWidth);
                    if (type === 'eraser') this.eraser(rect.coordinates, rect.lineWidth);
                    if (type === 'square') this.square(rect.coordinates, rect.strokeStyle);
                }
            },
            square(coordinates, color) {
                // 사각 도형을 그림
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                const start = coordinates[0];
                const end = coordinates[coordinates.length - 1];
                const [startX, startY] = start;
                const [endX, endY] = [end[0] - startX, end[1] - startY];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(startX, startY, endX, endY);
                ctx.closePath();
            },
        };
        document.getElementById('type').addEventListener('change', (e) => {
            options.type = e.target.value;
        });
        document.getElementById('strokeStyle').addEventListener('change', (e) => {
            options.strokeStyle = e.target.value;
        });
        document.getElementById('lineWidth').addEventListener('change', (e) => {
            options.lineWidth = e.target.value;
        });
    </script>
</body>

</html>

 

영상처리 부분 이미지 파일

영상처리 페이지마다 CSS를 이용하여 마우스를 이미지에 가져갈시 축소와 회전이 무한으로 가능한 애니메이션을 넣어줬습니다.

3.png
0.22MB
5.png
0.01MB

 

#화소 점 처리

화소 점 처리 페이지는 버튼 이벤트를 사용하였고 작은 그림판을 추가하였습니다.

화소 점.html
0.02MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript"
        src="https://www.jqueryscript.net/demo/jQuery-Plugin-For-Water-Ripple-Animation-ripples/js/jquery.ripples.js"></script>

    <script>
        $(document).ready(function () {
            try {
                $('.a,.b,.c').ripples({
                    resolution: 256,
                    perturbance: 0.04
                });
            }
            catch (e) {
                $('.error').show().text(e);
            }
        });
    </script>

    <style>
        body {
            margin: 0;
        }

        div {
            position: fixed;
            font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
        }

        .a {
            left: 40%;
            top: 70%;
            width: 300px;
            height: 300px;
            background-size: cover;
            margin-top: -250px;
            margin-bottom: -250px;
        }

        .error {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.8);
            color: #eee;
            padding: 20px;
            display: none;
        }


        #outCanvas:hover {
            -webkit-animation: rotation 1.5s infinite linear;
        }

        @-webkit-keyframes rotation {
            from {
                -webkit-transform: rotate(0deg);
            }

            to {
                -webkit-transform: rotate(359deg);
            }

        }

        #canvas {
            border: 1px solid rgb(17, 17, 17);
            margin: 0%;
            width: 250px;
            margin-top: 330px;
            float: right;
            margin-right: 90px;

        }

        .options {
            display: flex;
            align-items: center;
            float: left;
            margin-left: 1580px;
            margin-top: 500px;

        }

        body {
            background-image: url(3.png);
            background-repeat: repeat-x;
            background-size: cover;
            text-align: center;
        }

        .main {
            margin: 0 auto;
        }

        .canvas {
            padding: 0;
            margin: 0 auto;
            display: block;
            width: 100px;
            margin-top: 0px;
            transition: all ease 2s;
        }

        .canvas:hover {
            transform: scale(0);

        }


        .text {
            margin-top: -6px;
            margin-left: 1470px;
            float: left;
            color: rgb(17, 24, 27);
            font-size: 23px;
        }

        .text1 {
            margin-top: 300px;
            margin-left: 1540px;
            float: left;
            color: rgb(2, 13, 17);
            font-size: 20px;
        }

        .wrap {
            height: 10%;
            float: left;
            margin-left: 558px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 30px;
        }

        .button {
            width: 150px;
            height: 31px;
            font-family: 'Roboto', sans-serif;
            font-size: 20px;
            text-transform: uppercase;
            letter-spacing: 2.5px;
            font-weight: 500;
            color: rgb(253, 252, 249);
            background-color: rgb(138, 101, 22);
            border: none;
            border-radius: 45px;
            box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease 0s;
            cursor: pointer;
            outline: none;
            margin: 10px;

        }

        .button:hover {
            background-color: #5c400c;
            box-shadow: 0px 15px 20px rgba(32, 23, 116, 0.4);
            color: #fff;
            transform: translateY(-7px);
        }

        .wordArtEffectText {
            font-size: 55px;
            float: left;
            margin-left: 750px;
            margin-top: 0px;
        }

        .in {
            margin-left: 780px;
        }
    </style>
    <script>
        // 전역 변수 (중요한 변수들)
        var outCanvas, outCtx, inFile;  // 캔버스 관련
        var outPaper; // 캔버스에는 한점한점이 안찍힘. 대신 캔버스에 종이를 붙임.

        var inImageArray, outImageArray;  // 입력 파일 및 배열
        var inWidth, inHeight, outWidth, outHeight;  // 입력 영상의 폭과 높이
        function init() {
            outCanvas = document.getElementById('outCanvas');
            outCtx = outCanvas.getContext('2d');

        }
        function openImage() {
            inFile = document.getElementById('selectFile').files[0];
            // 중요! 코드 (영상의 크기를 파악)
            inWidth = inHeight = Math.sqrt(inFile.size);
            // 입력 2차원 배열을 준비
            inImageArray = new Array(inHeight); // 512짜리 1차원 배열
            for (var i = 0; i < inHeight; i++)
                inImageArray[i] = new Array(inWidth);
            // RAW 파일  --> 2차원 배열
            var reader = new FileReader();
            reader.readAsBinaryString(inFile);
            reader.onload = function () {
                var bin = reader.result; // 파일을 덩어리(bin)로 읽었음
                // 덩어리(bin)에서 한점한점씩 뽑아서, 배열에 넣기
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        var sPixel = (i * inHeight + k);
                        var ePixel = (i * inHeight + k) + 1;
                        inImageArray[i][k] = bin.slice(sPixel, ePixel); // 1개픽셀-->배열
                    }
                }

                equalImage();
            }

        }
        function displayImage() {
            // 캔버스 크기를 결정
            outCanvas.width = outWidth;
            outCanvas.height = outHeight;
            outPaper = outCtx.createImageData(outHeight, outWidth); //종이 붙였음.
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    var charValue = outImageArray[i][k].charCodeAt(0); // 깨진문자를 숫자로.
                    outPaper.data[(i * outWidth + k) * 4 + 0] = charValue; // R
                    outPaper.data[(i * outWidth + k) * 4 + 1] = charValue; // G
                    outPaper.data[(i * outWidth + k) * 4 + 2] = charValue; // B
                    outPaper.data[(i * outWidth + k) * 4 + 3] = 255; // Alpha
                }
            }
            outCtx.putImageData(outPaper, 0, 0);
        }
        function equalImage() {  // 동일 영상 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    outImageArray[i][k] = inImageArray[i][k];
                }
            }
            displayImage();
        }
        //영상처리 함수모음
        function addImage() {  // 영상 밝게하기 알고리즘
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outHeight; k++) {
                    //문자를 숫자로 바꿈
                    pixel = outImageArray[i][k].charCodeAt(0);
                    //(밝게하기)
                    pixel += 50;
                    outImageArray[i][k] = String.fromCharCode(pixel);
                }
            }
            displayImage();
        }
        function bwImageAvg() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            var hap = 0;
            for (var i = 0; i < inHeight; i++)
                for (var k = 0; k < inWidth; k++)
                    hap += inImageArray[i][k].charCodeAt(0);
            var value = hap / (inHeight * inWidth);

            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // 문자 --> 숫자
                    pixel = inImageArray[i][k].charCodeAt(0);
                    // **** 요기가 핵심 알고리즘. (흑백)
                    if (pixel > value)
                        pixel = 255;
                    else
                        pixel = 0;
                    // 숫자 --> 문자
                    outImageArray[i][k] = String.fromCharCode(pixel);
                }
            }
            displayImage();
        }
        function bwImage() { // 흑백영상 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            var value = parseInt(prompt("기준 값", "127"));
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // 문자 --> 숫자
                    pixel = inImageArray[i][k].charCodeAt(0);
                    // **** 요기가 핵심 알고리즘. (흑백)
                    if (pixel > value)
                        pixel = 255;
                    else
                        pixel = 0;
                    // 숫자 --> 문자
                    outImageArray[i][k] = String.fromCharCode(pixel);
                }
            }
            displayImage();
        }
    </script>
</head>

<body onload='init()'>


    <h1>
        <div class="wordArtEffectText">PHOTO# 변기
    </h1>
    <br>
    <br>
    <br>
    <br>
    <hr>
    <div class="in">
        <input style="border: 5px groove rgb(114, 93, 22);" type='file' id='selectFile' onchange='openImage()' />
    </div>
    </div>

    <div class="wrap">
        <botton class="button" type="button" id="photoEq" onclick="equalImage()"> reset </botton>
        <botton class="button" type="button" id="photoAdd" onclick="addImage()"> bright </botton>
        <botton class="button" type="button" id="photoBw" onclick="bwImageAvg()"> (avg)gray </botton>
        <botton class="button" type="button" id="photoBw1" onclick="bwImage()"> gray </botton>

    </div>
    <div class="main">
        <div class="text">
            <dd> 지난날들의 아픈기억 </dd>
            <br>
            <dd><strong>흑역사</strong>를 가져와서</dd>
            <br>
            <dd>변기속으로 시원하게 날려보내세요.</dd>
            <br>
            <dd>(마우스를 이미지에 가져가세요.)</dd>
        </div>
        <div class="a" style="background-image:url(5.png)">
            <div class="canvas">
                <canvas id='outCanvas' width="200" height="150" style='background-color:rgb(12, 12, 12)'></canvas>
            </div>
        </div>
    </div>
    <div class="text1">
        <dd><strong>그림판</strong> (reset=F5)</dd>
    </div>
    <canvas id="canvas" width="300" height="200"></canvas>
    <div class="options">
        <select id="type">
            <option value="stroke">실선</option>
            <option value="square">사각형</option>
            <option value="eraser">지우개</option>
        </select>
        <select id="strokeStyle">
            <option value="blue">파란색</option>
            <option value="green">초록색</option>
            <option value="pink">분홍색</option>
            <option value="orange">주황색</option>
        </select>
        <select id="lineWidth">
            <option value="5">5px</option>
            <option value="10">10px</option>
            <option value="15">15px</option>
            <option value="20">20px</option>
        </select>
    </div>
    <script>
        let isAbleDraw = false;
        const options = {
            type: 'stroke',
            strokeStyle: 'blue',
            lineWidth: 5,
        };
        const rects = [];
        let currentRect = null;
        document.getElementById('canvas').addEventListener('mousedown', () => {
            isAbleDraw = true;
            currentRect = {
                type: options.type,
                strokeStyle: options.strokeStyle,
                lineWidth: options.lineWidth,
                coordinates: [],
            };
        });
        document.getElementById('canvas').addEventListener('mousemove', (e) => {
            if (isAbleDraw) {
                const ctx = e.target.getContext('2d');
                const [x, y] = [e.offsetX, e.offsetY];
                currentRect.coordinates.push([x, y]);
                drawTools.clear();
                drawTools.execute(rects);
                if (currentRect.type === 'stroke') drawTools.stroke(currentRect.coordinates, 'rgba(255, 255, 0, .3)', currentRect.lineWidth);
                if (currentRect.type === 'eraser') drawTools.eraser(currentRect.coordinates, currentRect.lineWidth);
                if (currentRect.type === 'square') drawTools.square(currentRect.coordinates, 'rgba(255, 255, 0, .3)');
            }
        });
        document.getElementById('canvas').addEventListener('mouseup', () => {
            isAbleDraw = false;
            rects.push(currentRect);
            drawTools.clear();
            currentRect = null;
            drawTools.execute(rects);
            console.log(rects);
        })

        const drawTools = {
            clear() {
                // 캔버스 내용 제거
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            },
            stroke(coordinates, color, lineWidth) {
                // 마우스가 이동한 경로를 따라 실선 그리기
                if (coordinates.length > 0) {
                    const ctx = document.getElementById('canvas').getContext('2d');
                    const firstCoordinate = coordinates[0];
                    ctx.beginPath();
                    ctx.moveTo(firstCoordinate[0], firstCoordinate[1]);
                    for (let i = 1; i < coordinates.length; i += 1) {
                        ctx.lineTo(coordinates[i][0], coordinates[i][1]);
                    }
                    ctx.strokeStyle = color;
                    ctx.lineWidth = lineWidth;
                    ctx.stroke();
                    ctx.closePath();
                }
            },
            eraser(coordinates, lineWidth) {
                // 마우스가 이동한 좌표에 따라 하얀색으로 원을 그려서 지우개 기능처럼 동작
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                for (let i = 0; i < coordinates.length; i += 1) {
                    ctx.beginPath();
                    const coordinate = coordinates[i];
                    const [x, y] = coordinate;
                    ctx.fillStyle = 'white';
                    ctx.arc(x, y, lineWidth / 2, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            },
            execute(rects) {
                // rects 배열에 저장 된 도형을 기준으로 다시 캔버스에 그림
                for (let i = 0; i < rects.length; i += 1) {
                    const rect = rects[i];
                    const { type } = rect;
                    if (type === 'stroke') this.stroke(rect.coordinates, rect.strokeStyle, rect.lineWidth);
                    if (type === 'eraser') this.eraser(rect.coordinates, rect.lineWidth);
                    if (type === 'square') this.square(rect.coordinates, rect.strokeStyle);
                }
            },
            square(coordinates, color) {
                // 사각 도형을 그림
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                const start = coordinates[0];
                const end = coordinates[coordinates.length - 1];
                const [startX, startY] = start;
                const [endX, endY] = [end[0] - startX, end[1] - startY];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(startX, startY, endX, endY);
                ctx.closePath();
            },
        };
        document.getElementById('type').addEventListener('change', (e) => {
            options.type = e.target.value;
        });
        document.getElementById('strokeStyle').addEventListener('change', (e) => {
            options.strokeStyle = e.target.value;
        });
        document.getElementById('lineWidth').addEventListener('change', (e) => {
            options.lineWidth = e.target.value;
        });
    </script>
</body>

</html>

 

#기하학 처리

기하학 처리는 확대 및 축소와 회전을 넣어봤습니다.

기하학.html
0.02MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript"
        src="https://www.jqueryscript.net/demo/jQuery-Plugin-For-Water-Ripple-Animation-ripples/js/jquery.ripples.js"></script>

    <script>
        $(document).ready(function () {
            try {
                $('.a,.b,.c').ripples({
                    resolution: 256,
                    perturbance: 0.04
                });
            }
            catch (e) {
                $('.error').show().text(e);
            }
        });
    </script>

    <style>
        body {
            margin: 0;
        }

        div {
            position: fixed;
            font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
        }

        .a {
            left: 40%;
            top: 70%;
            width: 300px;
            height: 300px;
            background-size: cover;
            margin-top: -250px;
            margin-bottom: -250px;
        }

        .error {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.8);
            color: #eee;
            padding: 20px;
            display: none;
        }


        #outCanvas:hover {
            -webkit-animation: rotation 1.5s infinite linear;
        }

        @-webkit-keyframes rotation {
            from {
                -webkit-transform: rotate(0deg);
            }

            to {
                -webkit-transform: rotate(359deg);
            }

        }

        #canvas {
            border: 1px solid rgb(17, 17, 17);
            margin: 0%;
            width: 250px;
            margin-top: 330px;
            float: right;
            margin-right: 90px;

        }

        .options {
            display: flex;
            align-items: center;
            float: left;
            margin-left: 1580px;
            margin-top: 500px;

        }

        body {
            background-image: url(3.png);
            background-repeat: repeat-x;
            background-size: cover;
            text-align: center;
        }

        .main {
            margin: 0 auto;
        }

        .canvas {
            padding: 0;
            margin: 0 auto;
            display: block;
            width: 100px;
            margin-top: 0px;
            transition: all ease 2s;
        }

        .canvas:hover {
            transform: scale(0);

        }


        .text {
            margin-top: -6px;
            margin-left: 1470px;
            float: left;
            color: rgb(17, 24, 27);
            font-size: 23px;
        }

        .text1 {
            margin-top: 300px;
            margin-left: 1540px;
            float: left;
            color: rgb(2, 13, 17);
            font-size: 20px;
        }

        .wrap {
            height: 10%;
            float: left;
            margin-left: 568px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 30px;
        }

        .button {
            width: 120px;
            height: 35px;
            font-family: 'Roboto', sans-serif;
            font-size: 22px;
            text-transform: uppercase;
            letter-spacing: 2.5px;
            font-weight: 500;
            color: rgb(248, 248, 246);
            background-color: rgb(139, 90, 9);
            border: none;
            border-radius: 45px;
            box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease 0s;
            cursor: pointer;
            outline: none;
            margin: 10px;

        }

        .button:hover {
            background-color: #6b520d;
            box-shadow: 0px 15px 20px rgba(32, 23, 116, 0.4);
            color: #fff;
            transform: translateY(-7px);
        }

        .wordArtEffectText {
            font-size: 55px;
            float: left;
            margin-left: 750px;
            margin-top: 0px;
        }

        .in {
            margin-left: 780px;
        }
    </style>
    <script>
        // 전역 변수 (중요한 변수들)
        var outCanvas, outCtx, inFile;  // 캔버스 관련
        var outPaper; // 캔버스에는 한점한점이 안찍힘. 대신 캔버스에 종이를 붙임.

        var inImageArray, outImageArray;  // 입력 파일 및 배열
        var inWidth, inHeight, outWidth, outHeight;  // 입력 영상의 폭과 높이
        function init() {
            outCanvas = document.getElementById('outCanvas');
            outCtx = outCanvas.getContext('2d');

        }
        function openImage() {
            inFile = document.getElementById('selectFile').files[0];
            // 중요! 코드 (영상의 크기를 파악)
            inWidth = inHeight = Math.sqrt(inFile.size);
            // 입력 2차원 배열을 준비
            inImageArray = new Array(inHeight); // 512짜리 1차원 배열
            for (var i = 0; i < inHeight; i++)
                inImageArray[i] = new Array(inWidth);
            // RAW 파일  --> 2차원 배열
            var reader = new FileReader();
            reader.readAsBinaryString(inFile);
            reader.onload = function () {
                var bin = reader.result; // 파일을 덩어리(bin)로 읽었음
                // 덩어리(bin)에서 한점한점씩 뽑아서, 배열에 넣기
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        var sPixel = (i * inHeight + k);
                        var ePixel = (i * inHeight + k) + 1;
                        inImageArray[i][k] = bin.slice(sPixel, ePixel); // 1개픽셀-->배열
                    }
                }

                equalImage();
            }

        }
        function displayImage() {
            // 캔버스 크기를 결정
            outCanvas.width = outWidth;
            outCanvas.height = outHeight;
            outPaper = outCtx.createImageData(outHeight, outWidth); //종이 붙였음.
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    var charValue = outImageArray[i][k].charCodeAt(0); // 깨진문자를 숫자로.
                    outPaper.data[(i * outWidth + k) * 4 + 0] = charValue; // R
                    outPaper.data[(i * outWidth + k) * 4 + 1] = charValue; // G
                    outPaper.data[(i * outWidth + k) * 4 + 2] = charValue; // B
                    outPaper.data[(i * outWidth + k) * 4 + 3] = 255; // Alpha
                }
            }
            outCtx.putImageData(outPaper, 0, 0);
        }
        function equalImage() {  // 동일 영상 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    outImageArray[i][k] = inImageArray[i][k];
                }
            }
            displayImage();
        }

        function zoomInImage() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            var scale = parseInt("2");
            outHeight = inHeight * scale;
            outWidth = inWidth * scale;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // outImageArray를 초기화 시키기 (0으로 채우기)
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++)
                    outImageArray[i][k] = String.fromCharCode(0);

            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    // **** 요기가 핵심 알고리즘. (영상 확대)
                    outImageArray[i][k] = inImageArray[parseInt(i / scale)][parseInt(k / scale)];
                }
            }
            displayImage();
        }


        function zoomOutImage() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            var scale = parseInt("4");

            outHeight = parseInt(inHeight / scale);
            outWidth = parseInt(inWidth / scale);
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // **** 요기가 핵심 알고리즘. (영상 축소)
                    outImageArray[parseInt(i / scale)][parseInt(k / scale)] = inImageArray[i][k];
                }
            }
            displayImage();
        }
        function rotate1Image() {  // 회전 기본 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++)
                    outImageArray[i][k] = String.fromCharCode(0);

            //출력배열 초기화
            // ***** 진짜 영상처리 알고리즘 *****
            var degree = parseFloat(prompt("회전각도", 45));
            var radian = degree * Math.PI / 180.0; // degree -> radian

            // xd = cos * xs - sin * ys;
            // yd = sin * xs + cos * ys;
            var xd, yd, xs, ys;
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    xs = i;
                    ys = k;
                    xd = parseInt(Math.cos(radian) * xs - Math.sin(radian) * ys);
                    yd = parseInt(Math.sin(radian) * xs + Math.cos(radian) * ys);

                    // 회전 이후의 위치가 출력영상의 범위 안에 있니?
                    if ((0 <= xd && xd < outHeight) && (0 <= yd && yd < outWidth))
                        outImageArray[xd][yd] = inImageArray[xs][ys];
                }
            }
            displayImage();
        }
        function rotate2Image() {  // 회전(백워딩) 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++)
                    outImageArray[i][k] = String.fromCharCode(0);

            //출력배열 초기화
            // ***** 진짜 영상처리 알고리즘 *****
            var degree = parseFloat(prompt("회전각도", 45));
            var radian = degree * Math.PI / 180.0; // degree -> radian
            radian = -radian;
            // xd = cos * xs - sin * ys;
            // yd = sin * xs + cos * ys;
            var xd, yd, xs, ys;
            var cx = parseInt(inHeight / 2);
            var cy = parseInt(inWidth / 2);
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    xs = i;
                    ys = k;
                    xd = parseInt(Math.cos(radian) * (xs - cx) - Math.sin(radian) * (ys - cy) + cx);
                    yd = parseInt(Math.sin(radian) * (xs - cx) + Math.cos(radian) * (ys - cy) + cy);
                    // 회전 이후의 위치가 출력영상의 범위 안에 있니?
                    if ((0 <= xd && xd < outHeight) && (0 <= yd && yd < outWidth))
                        outImageArray[xs][ys] = inImageArray[xd][yd];
                    else
                        outImageArray[xs][ys] = String.fromCharCode(255);
                }
            }
            displayImage();
        }
    </script>
</head>

<body onload='init()'>
    <h1>
        <div class="wordArtEffectText">PHOTO# 변기
    </h1>
    <br>
    <br>
    <br>
    <br>
    <hr>
    <div class="in">
        <input style="border: 5px groove rgb(114, 93, 22);" type='file' id='selectFile' onchange='openImage()' />
    </div>
    </div>

    <div class="wrap">
        <botton class="button" type="button" id="photoEq" onclick="equalImage()"> reset </botton>
        <botton class="button" type="button" id="photoZoomIn" onclick="zoomInImage()"> big </botton>
        <botton class="button" type="button" id="photoZoomOut" onclick="zoomOutImage()"> small </botton>
        <botton class="button" type="button" id="photoRotate" onclick="rotate1Image()"> rotate </botton>
        <botton class="button" type="button" id="photoRotate1" onclick="rotate2Image()"> bwrota </botton>
    </div>
    <div class="main">
        <div class="text">
            <dd> 지난날들의 아픈기억 </dd>
            <br>
            <dd><strong>흑역사</strong>를 가져와서</dd>
            <br>
            <dd>변기속으로 시원하게 날려보내세요.</dd>
            <br>
            <dd>(마우스를 이미지에 가져가세요.)</dd>
        </div>
        <div class="a" style="background-image:url(5.png)">
            <div class="canvas">
                <canvas id='outCanvas' width="200" height="150" style='background-color:rgb(12, 12, 12)'></canvas>
            </div>
        </div>
    </div>
    <div class="text1">
        <dd><strong>그림판</strong> (reset=F5)</dd>
    </div>
    <canvas id="canvas" width="300" height="200"></canvas>
    <div class="options">
        <select id="type">
            <option value="stroke">실선</option>
            <option value="square">사각형</option>
            <option value="eraser">지우개</option>
        </select>
        <select id="strokeStyle">
            <option value="blue">파란색</option>
            <option value="green">초록색</option>
            <option value="pink">분홍색</option>
            <option value="orange">주황색</option>
        </select>
        <select id="lineWidth">
            <option value="5">5px</option>
            <option value="10">10px</option>
            <option value="15">15px</option>
            <option value="20">20px</option>
        </select>
    </div>
    <script>
        let isAbleDraw = false;
        const options = {
            type: 'stroke',
            strokeStyle: 'blue',
            lineWidth: 5,
        };
        const rects = [];
        let currentRect = null;
        document.getElementById('canvas').addEventListener('mousedown', () => {
            isAbleDraw = true;
            currentRect = {
                type: options.type,
                strokeStyle: options.strokeStyle,
                lineWidth: options.lineWidth,
                coordinates: [],
            };
        });
        document.getElementById('canvas').addEventListener('mousemove', (e) => {
            if (isAbleDraw) {
                const ctx = e.target.getContext('2d');
                const [x, y] = [e.offsetX, e.offsetY];
                currentRect.coordinates.push([x, y]);
                drawTools.clear();
                drawTools.execute(rects);
                if (currentRect.type === 'stroke') drawTools.stroke(currentRect.coordinates, 'rgba(255, 255, 0, .3)', currentRect.lineWidth);
                if (currentRect.type === 'eraser') drawTools.eraser(currentRect.coordinates, currentRect.lineWidth);
                if (currentRect.type === 'square') drawTools.square(currentRect.coordinates, 'rgba(255, 255, 0, .3)');
            }
        });
        document.getElementById('canvas').addEventListener('mouseup', () => {
            isAbleDraw = false;
            rects.push(currentRect);
            drawTools.clear();
            currentRect = null;
            drawTools.execute(rects);
            console.log(rects);
        })

        const drawTools = {
            clear() {
                // 캔버스 내용 제거
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            },
            stroke(coordinates, color, lineWidth) {
                // 마우스가 이동한 경로를 따라 실선 그리기
                if (coordinates.length > 0) {
                    const ctx = document.getElementById('canvas').getContext('2d');
                    const firstCoordinate = coordinates[0];
                    ctx.beginPath();
                    ctx.moveTo(firstCoordinate[0], firstCoordinate[1]);
                    for (let i = 1; i < coordinates.length; i += 1) {
                        ctx.lineTo(coordinates[i][0], coordinates[i][1]);
                    }
                    ctx.strokeStyle = color;
                    ctx.lineWidth = lineWidth;
                    ctx.stroke();
                    ctx.closePath();
                }
            },
            eraser(coordinates, lineWidth) {
                // 마우스가 이동한 좌표에 따라 하얀색으로 원을 그려서 지우개 기능처럼 동작
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                for (let i = 0; i < coordinates.length; i += 1) {
                    ctx.beginPath();
                    const coordinate = coordinates[i];
                    const [x, y] = coordinate;
                    ctx.fillStyle = 'white';
                    ctx.arc(x, y, lineWidth / 2, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            },
            execute(rects) {
                // rects 배열에 저장 된 도형을 기준으로 다시 캔버스에 그림
                for (let i = 0; i < rects.length; i += 1) {
                    const rect = rects[i];
                    const { type } = rect;
                    if (type === 'stroke') this.stroke(rect.coordinates, rect.strokeStyle, rect.lineWidth);
                    if (type === 'eraser') this.eraser(rect.coordinates, rect.lineWidth);
                    if (type === 'square') this.square(rect.coordinates, rect.strokeStyle);
                }
            },
            square(coordinates, color) {
                // 사각 도형을 그림
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                const start = coordinates[0];
                const end = coordinates[coordinates.length - 1];
                const [startX, startY] = start;
                const [endX, endY] = [end[0] - startX, end[1] - startY];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(startX, startY, endX, endY);
                ctx.closePath();
            },
        };
        document.getElementById('type').addEventListener('change', (e) => {
            options.type = e.target.value;
        });
        document.getElementById('strokeStyle').addEventListener('change', (e) => {
            options.strokeStyle = e.target.value;
        });
        document.getElementById('lineWidth').addEventListener('change', (e) => {
            options.lineWidth = e.target.value;
        });
    </script>
</body>

</html>

#히스토그램

히스토그램은 스트레칭과 엔드 인 그리고 평활화 처리를 하였습니다.

히스토.html
0.02MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript"
        src="https://www.jqueryscript.net/demo/jQuery-Plugin-For-Water-Ripple-Animation-ripples/js/jquery.ripples.js"></script>

    <script>
        $(document).ready(function () {
            try {
                $('.a,.b,.c').ripples({
                    resolution: 256,
                    perturbance: 0.04
                });
            }
            catch (e) {
                $('.error').show().text(e);
            }
        });
    </script>

    <style>
        body {
            margin: 0;
        }

        div {
            position: fixed;
            font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
        }

        .a {
            left: 40%;
            top: 70%;
            width: 300px;
            height: 300px;
            background-size: cover;
            margin-top: -250px;
            margin-bottom: -250px;
        }

        .error {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.8);
            color: #eee;
            padding: 20px;
            display: none;
        }


        #outCanvas:hover {
            -webkit-animation: rotation 1.5s infinite linear;
        }

        @-webkit-keyframes rotation {
            from {
                -webkit-transform: rotate(0deg);
            }

            to {
                -webkit-transform: rotate(359deg);
            }

        }

        #canvas {
            border: 1px solid rgb(17, 17, 17);
            margin: 0%;
            width: 250px;
            margin-top: 330px;
            float: right;
            margin-right: 90px;

        }

        .options {
            display: flex;
            align-items: center;
            float: left;
            margin-left: 1580px;
            margin-top: 500px;

        }

        body {
            background-image: url(3.png);
            background-repeat: repeat-x;
            background-size: cover;
            text-align: center;
        }

        .main {
            margin: 0 auto;
        }

        .canvas {
            padding: 0;
            margin: 0 auto;
            display: block;
            width: 100px;
            margin-top: 0px;
            transition: all ease 2s;
        }

        .canvas:hover {
            transform: scale(0);

        }


        .text {
            margin-top: -6px;
            margin-left: 1470px;
            float: left;
            color: rgb(17, 24, 27);
            font-size: 23px;
        }

        .text1 {
            margin-top: 300px;
            margin-left: 1540px;
            float: left;
            color: rgb(2, 13, 17);
            font-size: 20px;
        }

        .wrap {
            height: 10%;
            float: left;
            margin-left: 576px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 30px;
        }

        .button {
            width: 150px;
            height: 33px;
            font-family: 'Roboto', sans-serif;
            font-size: 20px;
            text-transform: uppercase;
            letter-spacing: 2.5px;
            font-weight: 500;
            color: rgb(248, 248, 246);
            background-color: rgb(117, 83, 8);
            border: none;
            border-radius: 45px;
            box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease 0s;
            cursor: pointer;
            outline: none;
            margin: 10px;

        }

        .button:hover {
            background-color: #553c06;
            box-shadow: 0px 15px 20px rgba(32, 23, 116, 0.4);
            color: #fff;
            transform: translateY(-7px);
        }

        .wordArtEffectText {
            font-size: 55px;
            float: left;
            margin-left: 750px;
            margin-top: 0px;
        }

        .in {
            margin-left: 780px;
        }
    </style>
    <script>
        // 전역 변수 (중요한 변수들)
        var outCanvas, outCtx, inFile;  // 캔버스 관련
        var outPaper; // 캔버스에는 한점한점이 안찍힘. 대신 캔버스에 종이를 붙임.

        var inImageArray, outImageArray;  // 입력 파일 및 배열
        var inWidth, inHeight, outWidth, outHeight;  // 입력 영상의 폭과 높이
        function init() {
            outCanvas = document.getElementById('outCanvas');
            outCtx = outCanvas.getContext('2d');

        }
        function openImage() {
            inFile = document.getElementById('selectFile').files[0];
            // 중요! 코드 (영상의 크기를 파악)
            inWidth = inHeight = Math.sqrt(inFile.size);
            // 입력 2차원 배열을 준비
            inImageArray = new Array(inHeight); // 512짜리 1차원 배열
            for (var i = 0; i < inHeight; i++)
                inImageArray[i] = new Array(inWidth);
            // RAW 파일  --> 2차원 배열
            var reader = new FileReader();
            reader.readAsBinaryString(inFile);
            reader.onload = function () {
                var bin = reader.result; // 파일을 덩어리(bin)로 읽었음
                // 덩어리(bin)에서 한점한점씩 뽑아서, 배열에 넣기
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        var sPixel = (i * inHeight + k);
                        var ePixel = (i * inHeight + k) + 1;
                        inImageArray[i][k] = bin.slice(sPixel, ePixel); // 1개픽셀-->배열
                    }
                }

                equalImage();
            }

        }
        function displayImage() {
            // 캔버스 크기를 결정
            outCanvas.width = outWidth;
            outCanvas.height = outHeight;
            outPaper = outCtx.createImageData(outHeight, outWidth); //종이 붙였음.
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    var charValue = outImageArray[i][k].charCodeAt(0); // 깨진문자를 숫자로.
                    outPaper.data[(i * outWidth + k) * 4 + 0] = charValue; // R
                    outPaper.data[(i * outWidth + k) * 4 + 1] = charValue; // G
                    outPaper.data[(i * outWidth + k) * 4 + 2] = charValue; // B
                    outPaper.data[(i * outWidth + k) * 4 + 3] = 255; // Alpha
                }
            }
            outCtx.putImageData(outPaper, 0, 0);
        }
        function equalImage() {  // 동일 영상 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    outImageArray[i][k] = inImageArray[i][k];
                }
            }
            displayImage();
        }
        function histoStretch() { // 히스토그램 스트래칭
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            //  out =  ( in - low ) / ( high - low ) * 255
            var low = inImageArray[0][0].charCodeAt(0);
            var high = inImageArray[0][0].charCodeAt(0);
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    pixel = inImageArray[i][k].charCodeAt(0);
                    if (pixel < low)
                        low = pixel;
                    if (pixel > high)
                        high = pixel
                }
            }
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // 문자 --> 숫자
                    inVal = inImageArray[i][k].charCodeAt(0);
                    // **** 요기가 핵심 알고리즘.
                    outVal = (inVal - low) / (high - low) * 255;
                    // 숫자 --> 문자
                    outImageArray[i][k] = String.fromCharCode(outVal);
                }
            }
            displayImage();
        }
        function endInSearch() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // ***** 진짜 영상처리 알고리즘 *****
            //  out =  ( in - low ) / ( high - low ) * 255
            var low = inImageArray[0][0].charCodeAt(0);
            var high = inImageArray[0][0].charCodeAt(0);
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    pixel = inImageArray[i][k].charCodeAt(0);
                    if (pixel < low)
                        low = pixel;
                    if (pixel > high)
                        high = pixel
                }
            }
            low += 50;
            high -= 50;
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // 문자 --> 숫자
                    inVal = inImageArray[i][k].charCodeAt(0);
                    // **** 요기가 핵심 알고리즘. (흑백)
                    outVal = (inVal - low) / (high - low) * 255;
                    if (outVal > 255)
                        outVal = 255;
                    else if (outVal < 0)
                        outVal = 0;

                    // 숫자 --> 문자
                    outImageArray[i][k] = String.fromCharCode(outVal);
                }
            }
            displayImage();
        }
        function histoEqual() {
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            // 1단계 : 히스토그램 생성
            histo = new Array(256);
            for (var i = 0; i < 256; i++)
                histo[i] = 0;
            for (var i = 0; i < inHeight; i++)
                for (var k = 0; k < inWidth; k++) {
                    value = inImageArray[i][k].charCodeAt(0);
                    histo[value]++;
                }
            // 2단계 : 누적 히스토그램 생성
            sumHisto = new Array(256);
            for (var i = 0; i < 256; i++)
                sumHisto[i] = 0;
            sumVal = 0;
            for (var i = 0; i < 256; i++) {
                sumVal += histo[i];
                sumHisto[i] = sumVal;
            }
            // 3단계 : 정규화된 누적히스토그램
            // ns = s * (1/픽셀총수) * 화소최대밝기
            normalHisto = new Array(256);
            for (var i = 0; i < 256; i++)
                normalHisto[i] = 0.0;
            for (var i = 0; i < 256; i++)
                normalHisto[i] = sumHisto[i] * (1 / (inWidth * inHeight)) * 255;

            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    // 문자 --> 숫자
                    inVal = inImageArray[i][k].charCodeAt(0);
                    // **** 요기가 핵심 알고리즘. (흑백)
                    outVal = normalHisto[inVal];
                    if (outVal > 255)
                        outVal = 255;
                    else if (outVal < 0)
                        outVal = 0;
                    else
                        outVal = parseInt(outVal);
                    // 숫자 --> 문자
                    outImageArray[i][k] = String.fromCharCode(outVal);
                }
            }
            displayImage();
        }
    </script>
</head>

<body onload='init()'>


    <h1>
        <div class="wordArtEffectText">PHOTO# 변기
    </h1>
    <br>
    <br>
    <br>
    <br>
    <hr>
    <div class="in">
        <input style="border: 5px groove rgb(114, 93, 22);" type='file' id='selectFile' onchange='openImage()' />
    </div>
    </div>

    <div class="wrap">
        <botton class="button" type="button" id="photoEq" onclick="equalImage()"> reset </botton>
        <botton class="button" type="button" id="photoHs" onclick="histoStretch()"> stretch </botton>
        <botton class="button" type="button" id="photoEs" onclick="endInSearch()"> end in </botton>
        <botton class="button" type="button" id="photoHe" onclick="histoEqual()"> smoothing </botton>
    </div>
    <div class="main">
        <div class="text">
            <dd> 지난날들의 아픈기억 </dd>
            <br>
            <dd><strong>흑역사</strong>를 가져와서</dd>
            <br>
            <dd>변기속으로 시원하게 날려보내세요.</dd>
            <br>
            <dd>(마우스를 이미지에 가져가세요.)</dd>
        </div>
        <div class="a" style="background-image:url(5.png)">
            <div class="canvas">
                <canvas id='outCanvas' width="200" height="150" style='background-color:rgb(12, 12, 12)'></canvas>
            </div>
        </div>
    </div>
    <div class="text1">
        <dd><strong>그림판</strong> (reset=F5)</dd>
    </div>
    <canvas id="canvas" width="300" height="200"></canvas>
    <div class="options">
        <select id="type">
            <option value="stroke">실선</option>
            <option value="square">사각형</option>
            <option value="eraser">지우개</option>
        </select>
        <select id="strokeStyle">
            <option value="blue">파란색</option>
            <option value="green">초록색</option>
            <option value="pink">분홍색</option>
            <option value="orange">주황색</option>
        </select>
        <select id="lineWidth">
            <option value="5">5px</option>
            <option value="10">10px</option>
            <option value="15">15px</option>
            <option value="20">20px</option>
        </select>
    </div>
    <script>
        let isAbleDraw = false;
        const options = {
            type: 'stroke',
            strokeStyle: 'blue',
            lineWidth: 5,
        };
        const rects = [];
        let currentRect = null;
        document.getElementById('canvas').addEventListener('mousedown', () => {
            isAbleDraw = true;
            currentRect = {
                type: options.type,
                strokeStyle: options.strokeStyle,
                lineWidth: options.lineWidth,
                coordinates: [],
            };
        });
        document.getElementById('canvas').addEventListener('mousemove', (e) => {
            if (isAbleDraw) {
                const ctx = e.target.getContext('2d');
                const [x, y] = [e.offsetX, e.offsetY];
                currentRect.coordinates.push([x, y]);
                drawTools.clear();
                drawTools.execute(rects);
                if (currentRect.type === 'stroke') drawTools.stroke(currentRect.coordinates, 'rgba(255, 255, 0, .3)', currentRect.lineWidth);
                if (currentRect.type === 'eraser') drawTools.eraser(currentRect.coordinates, currentRect.lineWidth);
                if (currentRect.type === 'square') drawTools.square(currentRect.coordinates, 'rgba(255, 255, 0, .3)');
            }
        });
        document.getElementById('canvas').addEventListener('mouseup', () => {
            isAbleDraw = false;
            rects.push(currentRect);
            drawTools.clear();
            currentRect = null;
            drawTools.execute(rects);
            console.log(rects);
        })

        const drawTools = {
            clear() {
                // 캔버스 내용 제거
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            },
            stroke(coordinates, color, lineWidth) {
                // 마우스가 이동한 경로를 따라 실선 그리기
                if (coordinates.length > 0) {
                    const ctx = document.getElementById('canvas').getContext('2d');
                    const firstCoordinate = coordinates[0];
                    ctx.beginPath();
                    ctx.moveTo(firstCoordinate[0], firstCoordinate[1]);
                    for (let i = 1; i < coordinates.length; i += 1) {
                        ctx.lineTo(coordinates[i][0], coordinates[i][1]);
                    }
                    ctx.strokeStyle = color;
                    ctx.lineWidth = lineWidth;
                    ctx.stroke();
                    ctx.closePath();
                }
            },
            eraser(coordinates, lineWidth) {
                // 마우스가 이동한 좌표에 따라 하얀색으로 원을 그려서 지우개 기능처럼 동작
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                for (let i = 0; i < coordinates.length; i += 1) {
                    ctx.beginPath();
                    const coordinate = coordinates[i];
                    const [x, y] = coordinate;
                    ctx.fillStyle = 'white';
                    ctx.arc(x, y, lineWidth / 2, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            },
            execute(rects) {
                // rects 배열에 저장 된 도형을 기준으로 다시 캔버스에 그림
                for (let i = 0; i < rects.length; i += 1) {
                    const rect = rects[i];
                    const { type } = rect;
                    if (type === 'stroke') this.stroke(rect.coordinates, rect.strokeStyle, rect.lineWidth);
                    if (type === 'eraser') this.eraser(rect.coordinates, rect.lineWidth);
                    if (type === 'square') this.square(rect.coordinates, rect.strokeStyle);
                }
            },
            square(coordinates, color) {
                // 사각 도형을 그림
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                const start = coordinates[0];
                const end = coordinates[coordinates.length - 1];
                const [startX, startY] = start;
                const [endX, endY] = [end[0] - startX, end[1] - startY];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(startX, startY, endX, endY);
                ctx.closePath();
            },
        };
        document.getElementById('type').addEventListener('change', (e) => {
            options.type = e.target.value;
        });
        document.getElementById('strokeStyle').addEventListener('change', (e) => {
            options.strokeStyle = e.target.value;
        });
        document.getElementById('lineWidth').addEventListener('change', (e) => {
            options.lineWidth = e.target.value;
        });
    </script>
</body>

</html>

#화소 영역 처리

화소 영역 처리는 엠보싱과 블러처리를 하였습니다.

영상.html
0.02MB

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script type="text/javascript"
        src="https://www.jqueryscript.net/demo/jQuery-Plugin-For-Water-Ripple-Animation-ripples/js/jquery.ripples.js"></script>

    <script>
        $(document).ready(function () {
            try {
                $('.a,.b,.c').ripples({
                    resolution: 256,
                    perturbance: 0.04
                });
            }
            catch (e) {
                $('.error').show().text(e);
            }
        });
    </script>

    <style>
        body {
            margin: 0;
        }

        div {
            position: fixed;
            font-family: "Helvetica Neue", "Helvetica", "Arial", sans-serif;
        }

        .a {
            left: 40%;
            top: 70%;
            width: 300px;
            height: 300px;
            background-size: cover;
            margin-top: -250px;
            margin-bottom: -250px;
        }

        .error {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            background: rgba(0, 0, 0, 0.8);
            color: #eee;
            padding: 20px;
            display: none;
        }


        #outCanvas:hover {
            -webkit-animation: rotation 1.5s infinite linear;
        }

        @-webkit-keyframes rotation {
            from {
                -webkit-transform: rotate(0deg);
            }

            to {
                -webkit-transform: rotate(359deg);
            }

        }
        .canvas {
            padding: 0;
            margin: 0 auto;
            display: block;
            width: 100px;
            margin-top: 0px;
            transition: all ease 2s;
        }

        .canvas:hover {
            transform: scale(0);
        }
        #canvas {
            border: 1px solid rgb(17, 17, 17);
            margin: 0%;
            width: 250px;
            margin-top: 330px;
            float: right;
            margin-right: 90px;

        }

        .options {
            display: flex;
            align-items: center;
            float: left;
            margin-left: 1580px;
            margin-top: 500px;
        }

        body {
            background-image: url(3.png);
            background-repeat: repeat-x;
            background-size: cover;
            text-align: center;
        }

        .main {
            margin: 0 auto;
        }

        .text {
            margin-top: -6px;
            margin-left: 1470px;
            float: left;
            color: rgb(17, 24, 27);
            font-size: 23px;
        }

        .text1 {
            margin-top: 300px;
            margin-left: 1540px;
            float: left;
            color: rgb(2, 13, 17);
            font-size: 20px;
        }
        .wrap {
            height: 10%;
            float: left;
            margin-left: 697px;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 30px;
        }
        .button {
            width: 120px;
            height: 35px;
            font-family: 'Roboto', sans-serif;
            font-size: 22px;
            text-transform: uppercase;
            letter-spacing: 2.5px;
            font-weight: 500;
            color: rgb(252, 251, 250);
            background-color: rgb(133, 97, 14);
            border: none;
            border-radius: 45px;
            box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease 0s;
            cursor: pointer;
            outline: none;
            margin: 10px;

        }
        .button:hover {
            background-color: #6b450b;
            box-shadow: 0px 15px 20px rgba(32, 23, 116, 0.4);
            color: #fff;
            transform: translateY(-7px);
        }

        .wordArtEffectText {
            font-size: 55px;
            float: left;
            margin-left: 750px;
            margin-top: 0px;
            color: rgb(14, 13, 13);
        }

        .in {
            margin-left: 780px;
        }
    </style>
    <script>
        // 전역 변수 (중요한 변수들)
        var outCanvas, outCtx, inFile;  // 캔버스 관련
        var outPaper; // 캔버스에는 한점한점이 안찍힘. 대신 캔버스에 종이를 붙임.

        var inImageArray, outImageArray;  // 입력 파일 및 배열
        var inWidth, inHeight, outWidth, outHeight;  // 입력 영상의 폭과 높이
        function init() {
            outCanvas = document.getElementById('outCanvas');
            outCtx = outCanvas.getContext('2d');

        }
        function openImage() {
            inFile = document.getElementById('selectFile').files[0];
            // 중요! 코드 (영상의 크기를 파악)
            inWidth = inHeight = Math.sqrt(inFile.size);
            // 입력 2차원 배열을 준비
            inImageArray = new Array(inHeight); // 512짜리 1차원 배열
            for (var i = 0; i < inHeight; i++)
                inImageArray[i] = new Array(inWidth);
            // RAW 파일  --> 2차원 배열
            var reader = new FileReader();
            reader.readAsBinaryString(inFile);
            reader.onload = function () {
                var bin = reader.result; // 파일을 덩어리(bin)로 읽었음
                // 덩어리(bin)에서 한점한점씩 뽑아서, 배열에 넣기
                for (var i = 0; i < inHeight; i++) {
                    for (var k = 0; k < inWidth; k++) {
                        var sPixel = (i * inHeight + k);
                        var ePixel = (i * inHeight + k) + 1;
                        inImageArray[i][k] = bin.slice(sPixel, ePixel); // 1개픽셀-->배열
                    }
                }
                equalImage();
            }

        }
        function displayImage() {
            // 캔버스 크기를 결정
            outCanvas.width = outWidth;
            outCanvas.height = outHeight;
            outPaper = outCtx.createImageData(outHeight, outWidth); //종이 붙였음.
            for (var i = 0; i < outHeight; i++) {
                for (var k = 0; k < outWidth; k++) {
                    var charValue = outImageArray[i][k].charCodeAt(0); // 깨진문자를 숫자로.
                    outPaper.data[(i * outWidth + k) * 4 + 0] = charValue; // R
                    outPaper.data[(i * outWidth + k) * 4 + 1] = charValue; // G
                    outPaper.data[(i * outWidth + k) * 4 + 2] = charValue; // B
                    outPaper.data[(i * outWidth + k) * 4 + 3] = 255; // Alpha
                }
            }
            outCtx.putImageData(outPaper, 0, 0);
        }
        function equalImage() {  // 동일 영상 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);
            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    outImageArray[i][k] = inImageArray[i][k];
                }
            }
            displayImage();
        }

        function embossImage() {  // 엠보싱 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            //// 화소 영역 처리
            var mask = [[-1., 0., 0.],
            [0., 0., 0.],
            [0., 0., 1.]]
            // 임시 입력 배열
            tempInputArray = new Array(inHeight + 2); // 2칸 큼
            for (var i = 0; i < inHeight + 2; i++)
                tempInputArray[i] = new Array(inWidth + 2);
            // 임시 입력 배열 초기화
            for (var i = 0; i < inHeight + 2; i++)
                for (var k = 0; k < inWidth + 2; k++)
                    tempInputArray[i][k] = String.fromCharCode(127);
            // 입력 배열 --> 임시 입력
            for (var i = 0; i < inHeight; i++)
                for (var k = 0; k < inWidth; k++) {
                    tempInputArray[i + 1][k + 1] = inImageArray[i][k];
                }
            // 임시 출력 배열
            tempOutputArray = new Array(outHeight); //
            for (var i = 0; i < outHeight; i++)
                tempOutputArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    var S = 0.0;
                    for (var m = 0; m < 3; m++) {
                        for (var n = 0; n < 3; n++) {
                            S += mask[m][n] * tempInputArray[i + m][k + n].charCodeAt(0);
                        }
                    }
                    tempOutputArray[i][k] = S;
                }
            }
            // 만약, 마스크의 합계가 0이면, 결과를 127 더하자.
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++)
                    tempOutputArray[i][k] += 127.0;

            // 임시 출력 --> 진짜 출력 배열
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++) {
                    var v = tempOutputArray[i][k];
                    if (v > 255.0)
                        v = 255.0;
                    if (v < 0)
                        v = 0.0;
                    outImageArray[i][k] = String.fromCharCode(v);
                }
            displayImage();
        }

        function blurrImage() {  // 블러링 알고리즘
            // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
            outHeight = inHeight;
            outWidth = inWidth;
            // 출력 2차원 배열을 준비
            outImageArray = new Array(outHeight); // 256짜리 1차원 배열
            for (var i = 0; i < outHeight; i++)
                outImageArray[i] = new Array(outWidth);

            //// 화소 영역 처리
            var mask = [[1 / 9., 1 / 9., 1 / 9.],
            [1 / 9., 1 / 9., 1 / 9.],
            [1 / 9., 1 / 9., 1 / 9.]]
            // 임시 입력 배열
            tempInputArray = new Array(inHeight + 2); // 2칸 큼
            for (var i = 0; i < inHeight + 2; i++)
                tempInputArray[i] = new Array(inWidth + 2);
            // 임시 입력 배열 초기화
            for (var i = 0; i < inHeight + 2; i++)
                for (var k = 0; k < inWidth + 2; k++)
                    tempInputArray[i][k] = String.fromCharCode(127);
            // 입력 배열 --> 임시 입력
            for (var i = 0; i < inHeight; i++)
                for (var k = 0; k < inWidth; k++) {
                    tempInputArray[i + 1][k + 1] = inImageArray[i][k];
                }
            // 임시 출력 배열
            tempOutputArray = new Array(outHeight); //
            for (var i = 0; i < outHeight; i++)
                tempOutputArray[i] = new Array(outWidth);

            // ***** 진짜 영상처리 알고리즘 *****
            for (var i = 0; i < inHeight; i++) {
                for (var k = 0; k < inWidth; k++) {
                    var S = 0.0;
                    for (var m = 0; m < 3; m++) {
                        for (var n = 0; n < 3; n++) {
                            S += mask[m][n] * tempInputArray[i + m][k + n].charCodeAt(0);
                        }
                    }
                    tempOutputArray[i][k] = S;
                }
            }
            // 만약, 마스크의 합계가 0이면, 결과를 127 더하자.
            // for(var i=0; i<outHeight; i++) 
            //     for (var k=0; k<outWidth; k++) 
            //         tempOutputArray[i][k] += 127.0;

            // 임시 출력 --> 진짜 출력 배열
            for (var i = 0; i < outHeight; i++)
                for (var k = 0; k < outWidth; k++) {
                    var v = tempOutputArray[i][k];
                    if (v > 255.0)
                        v = 255.0;
                    if (v < 0)
                        v = 0.0;
                    outImageArray[i][k] = String.fromCharCode(v);
                }
            displayImage();
        }
    </script>
</head>

<body onload='init()'>
    <h1>
        <div class="wordArtEffectText">PHOTO# 변기
    </h1>
    <br>
    <br>
    <br>
    <br>
    <hr>
    <div class="in">
        <input style="border: 5px groove rgb(114, 93, 22);" type='file' id='selectFile' onchange='openImage()' />
    </div>
    </div>

    <div class="wrap">
        <botton class="button" type="button" id="photoEq" onclick="equalImage()"> reset </botton>
        <botton class="button" type="button" id="photoEmboss" onclick="embossImage()"> emboss </botton>
        <botton class="button" type="button" id="photoBl" onclick="blurrImage()"> blurr </botton>
    </div>

    <div class="main">
        <div class="text">
            <dd> 지난날들의 아픈기억 </dd>
            <br>
            <dd><strong>흑역사</strong>를 가져와서</dd>
            <br>
            <dd>변기속으로 시원하게 날려보내세요.</dd>
            <br>
            <dd>(마우스를 이미지에 가져가세요.)</dd>
        </div>
        <div class="a" style="background-image:url(5.png)">
            <div class="canvas">
                <canvas id='outCanvas' width="200" height="150" style='background-color:rgb(12, 12, 12)'></canvas>
            </div>
        </div>
    </div>
    <div class="text1">
        <dd><strong>그림판</strong> (reset=F5)</dd>
    </div>
    <canvas id="canvas" width="300" height="200"></canvas>
    <div class="options">
        <select id="type">
            <option value="stroke">실선</option>
            <option value="square">사각형</option>
            <option value="eraser">지우개</option>
        </select>
        <select id="strokeStyle">
            <option value="blue">파란색</option>
            <option value="green">초록색</option>
            <option value="pink">분홍색</option>
            <option value="orange">주황색</option>
        </select>
        <select id="lineWidth">
            <option value="5">5px</option>
            <option value="10">10px</option>
            <option value="15">15px</option>
            <option value="20">20px</option>
        </select>
    </div>

    <script>
        let isAbleDraw = false;
        const options = {
            type: 'stroke',
            strokeStyle: 'blue',
            lineWidth: 5,
        };
        const rects = [];
        let currentRect = null;
        document.getElementById('canvas').addEventListener('mousedown', () => {
            isAbleDraw = true;
            currentRect = {
                type: options.type,
                strokeStyle: options.strokeStyle,
                lineWidth: options.lineWidth,
                coordinates: [],
            };
        });
        document.getElementById('canvas').addEventListener('mousemove', (e) => {
            if (isAbleDraw) {
                const ctx = e.target.getContext('2d');
                const [x, y] = [e.offsetX, e.offsetY];
                currentRect.coordinates.push([x, y]);
                drawTools.clear();
                drawTools.execute(rects);
                if (currentRect.type === 'stroke') drawTools.stroke(currentRect.coordinates, 'rgba(255, 255, 0, .3)', currentRect.lineWidth);
                if (currentRect.type === 'eraser') drawTools.eraser(currentRect.coordinates, currentRect.lineWidth);
                if (currentRect.type === 'square') drawTools.square(currentRect.coordinates, 'rgba(255, 255, 0, .3)');
            }
        });
        document.getElementById('canvas').addEventListener('mouseup', () => {
            isAbleDraw = false;
            rects.push(currentRect);
            drawTools.clear();
            currentRect = null;
            drawTools.execute(rects);
            console.log(rects);
        })

        const drawTools = {
            clear() {
                // 캔버스 내용 제거
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                ctx.clearRect(0, 0, canvas.width, canvas.height);
            },
            stroke(coordinates, color, lineWidth) {
                // 마우스가 이동한 경로를 따라 실선 그리기
                if (coordinates.length > 0) {
                    const ctx = document.getElementById('canvas').getContext('2d');
                    const firstCoordinate = coordinates[0];
                    ctx.beginPath();
                    ctx.moveTo(firstCoordinate[0], firstCoordinate[1]);
                    for (let i = 1; i < coordinates.length; i += 1) {
                        ctx.lineTo(coordinates[i][0], coordinates[i][1]);
                    }
                    ctx.strokeStyle = color;
                    ctx.lineWidth = lineWidth;
                    ctx.stroke();
                    ctx.closePath();
                }
            },
            eraser(coordinates, lineWidth) {
                // 마우스가 이동한 좌표에 따라 하얀색으로 원을 그려서 지우개 기능처럼 동작
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                for (let i = 0; i < coordinates.length; i += 1) {
                    ctx.beginPath();
                    const coordinate = coordinates[i];
                    const [x, y] = coordinate;
                    ctx.fillStyle = 'white';
                    ctx.arc(x, y, lineWidth / 2, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.closePath();
                }
            },
            execute(rects) {
                // rects 배열에 저장 된 도형을 기준으로 다시 캔버스에 그림
                for (let i = 0; i < rects.length; i += 1) {
                    const rect = rects[i];
                    const { type } = rect;
                    if (type === 'stroke') this.stroke(rect.coordinates, rect.strokeStyle, rect.lineWidth);
                    if (type === 'eraser') this.eraser(rect.coordinates, rect.lineWidth);
                    if (type === 'square') this.square(rect.coordinates, rect.strokeStyle);
                }
            },
            square(coordinates, color) {
                // 사각 도형을 그림
                const canvas = document.getElementById('canvas');
                const ctx = canvas.getContext('2d');
                const start = coordinates[0];
                const end = coordinates[coordinates.length - 1];
                const [startX, startY] = start;
                const [endX, endY] = [end[0] - startX, end[1] - startY];
                ctx.beginPath();
                ctx.fillStyle = color;
                ctx.fillRect(startX, startY, endX, endY);
                ctx.closePath();
            },
        };
        document.getElementById('type').addEventListener('change', (e) => {
            options.type = e.target.value;
        });
        document.getElementById('strokeStyle').addEventListener('change', (e) => {
            options.strokeStyle = e.target.value;
        });
        document.getElementById('lineWidth').addEventListener('change', (e) => {
            options.lineWidth = e.target.value;
        });
    </script>
</body>

</html>

 

'HTML5+ CSS3+ Javascript' 카테고리의 다른 글

10일차  (0) 2021.03.26
9일차  (0) 2021.03.26
8일차  (0) 2021.03.26
7일차  (0) 2021.03.26
6일차  (0) 2021.03.23