<!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>
<style>
div {
font: normal 24px verdana;
background-color: rgb(189, 22, 22);
}
.wordArtEffectText {
color: rgb(251, 255, 192);
text-shadow: 3px 3px rgb(135, 235, 157);
}
body {
background-image: url(rea.png);
background-repeat: repeat-x;
background-size: cover;
}
</style>
<script> // 전역 변수(*중요*)
var inCanvas,
inCtx,
outCanvas,
outCtx,
GRCanvas,
GRCtx; // 입력 캔버스 관련
var inFile,
inImageArray,
outImageArray,
GRlmageArray; // 입력 파일 및 배열
var inWidth,
inHeight,
outWidth,
outHeight,
GRWidth,
GRHeight; // 입력 영상의 폭과 높이
var inPaper,
outPaper,
GRPaper; // 캔버스에는 한점한점이 안찍힘. 대신 캔버스에 종이를 붙임.
function init() {
inCanvas = document.getElementById('inCanvas');
inCtx = inCanvas.getContext('2d');
outCanvas = document.getElementById('outCanvas');
outCtx = outCanvas.getContext('2d');
GRCanvas = document.getElementById('GRCanvas');
GRCtx = GRCanvas.getContext('2d');
}
function readRawImage() {
inFile = document.getElementById('selectFile').files[0];
// 중요! 코드 (영상의 크기를 파악)
inWidth = inHeight = Math.sqrt(inFile.size);
// 입력 2차원 배열을 준비
inImageArray = new Array(inHeight); // 256짜리 1차원 배열
for (var i = 0; i < inHeight; i++) inImageArray[i] = new Array(inWidth);
// 캔버스 크기를 결정
inCanvas.width = inWidth;
inCanvas.height = inHeight;
// 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++) {
// 0,0 0,1 0,2 ...... 0,255
// 1,0 1,1, 1,2 .......1,255
// ....
// 255,0 255,1 ....... 255,255
var sPixel = (i * inHeight + k);
var ePixel = (i * inHeight + k) + 1;
inImageArray[i][k] = bin.slice(sPixel, ePixel); // 1개픽셀-->배열
}
}
// 화면에 출력하기 (사람용)
inPaper = inCtx.createImageData(inHeight, inWidth); //종이 붙였음.
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
var charValue = inImageArray[i][k].charCodeAt(0); // 깨진문자를 숫자로.
inPaper.data[(i * inWidth + k) * 4 + 0] = charValue; // R
inPaper.data[(i * inWidth + k) * 4 + 1] = charValue; // G
inPaper.data[(i * inWidth + k) * 4 + 2] = charValue; // B
inPaper.data[(i * inWidth + k) * 4 + 3] = 255; // Alpha
}
}
inCtx.putImageData(inPaper, 0, 0);
}
}
/////// 영상 처리 함수 모음 //////////
function printOutImage() {
// 캔버스 크기를 결정
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 ImageProcessing(selectNum) {
// 선택번호를 받음.
switch (selectNum.value) {
case "1": // 동일 영상
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("밝게할 값", "0"));
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
outImageArray[i][k] = inImageArray[i][k];
}
}
printOutImage();
break;
case "2": // 밝게 하기
// (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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("밝게할 값", "0"));
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
// 문자 --> 숫자
pixel = inImageArray[i][k].charCodeAt(0);
// **** 요기가 핵심 알고리즘. (밝게하기)
if (pixel + value > 255) pixel = 255;
else pixel += value;
// 숫자 --> 문자
outImageArray[i][k] = String.fromCharCode(pixel);
}
}
printOutImage();
break;
case "4": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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);
}
}
printOutImage();
break;
case "5": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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);
}
}
printOutImage();
break;
case "6": 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 < inHeight; k++) {
//문자를 숫자로 바꿈
pixel = inImageArray[i][k].charCodeAt(0);
//(색변환)
pixel = 255 - pixel;
inImageArray[i][k] = String.fromCharCode(pixel);
}
}
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
outImageArray[i][k] = inImageArray[i][k];
}
}
printOutImage();
break;
}
}
function ImageProcessing1(selectNum) {
// 선택번호를 받음.
switch (selectNum.value) {
case "21": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
var scale = parseInt(prompt("축소 배율(짝수)", "2"));
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];
}
}
printOutImage();
break;
case "22": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
var scale = parseInt(prompt("확대 배율(짝수)", "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)];
}
}
printOutImage();
break;
case "23": outHeight = inHeight;
outWidth = inWidth;
// 출력 2차원 배열을 준비
outImageArray = new Array(outHeight); // 256짜리 1차원 배열
for (var i = 0; i < outHeight; i++) outImageArray[i] = new Array(outWidth);
var aaa;
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth / 2; k++) {
aaa = inImageArray[i][k];
inImageArray[i][k] = inImageArray[i][inWidth - k - 1];
inImageArray[i][inWidth - k - 1] = aaa;
//문자를 숫자로 바꿈
}
}
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
outImageArray[i][k] = inImageArray[i][k];
}
}
printOutImage();
break;
case "24": outHeight = inHeight;
outWidth = inWidth;
// 출력 2차원 배열을 준비
outImageArray = new Array(outHeight); // 256짜리 1차원 배열
for (var i = 0; i < outHeight; i++) outImageArray[i] = new Array(outWidth);
var bbb;
for (var i = 0; i < inHeight / 2; i++) {
for (var k = 0; k < inWidth; k++) {
bbb = inImageArray[i][k];
inImageArray[i][k] = inImageArray[inHeight - i - 1][k];
inImageArray[inHeight - i - 1][k] = bbb;
//문자를 숫자로 바꿈
}
}
for (var i = 0; i < inHeight; i++) {
for (var k = 0; k < inWidth; k++) {
outImageArray[i][k] = inImageArray[i][k];
}
}
printOutImage();
break;
}
}
function ImageProcessing2(selectNum) {
// 선택번호를 받음.
switch (selectNum.value) {
case "41": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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);
}
}
printOutImage();
break;
case "42": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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) out = 0;
// 숫자 --> 문자
outImageArray[i][k] = String.fromCharCode(outVal);
}
}
printOutImage();
break;
case "43": // (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
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);
}
}
printOutImage();
break;
case "44":
var histo = new Array(256);
for (var i = 0; i < 256; i++)
histo[i] = 0;
for (var i = 0; i < GRHeight; i++) {
for (var k = 0; k < GRWidth; k++) {
// 문자 --> 숫자
value = inImageArray[i][k].charCodeAt(0);
// **** 요기가 핵심 알고리즘.
histo[value]++;
}
}
var max = 0;
var min = GRHeight * GRWidth;
for (var i = 0; i < 256; i++) {
if (histo[i] < min)
min = histo[i];
if (histo[i] > max)
max = histo[i];
}
var dif = max - min
var normalHisto = new Array(256);
for (var i = 0; i < 256; i++) {
normalHisto[i] = (histo[i] - min) * 255 / dif;
}
// (중요!) 출력 영상의 크기를 결정... 알고리즘에 따름.
GRHeight = inHeight;
GRWidth = inWidth;
// 출력 2차원 배열을 준비
GRImageArray = new Array(GRHeight);
for (var i = 0; i < GRHeight; i++)
GRImageArray[i] = new Array(GRWidth);
for (var i = 0; i < GRHeight; i++) {
for (var k = 0; k < GRWidth; k++) {
GRImageArray[i][k] = 255;
}
}
for (var i = 0; i < GRHeight; i++) {
for (var k = 0; k < normalHisto[i]; k++) {
GRImageArray[GRHeight - 1 - k][i] = 0;
}
}
for (var i = 0; i < GRHeight; i++) {
for (var k = 0; k < GRWidth; k++) {
// 숫자 --> 문자
GRImageArray[i][k] = String.fromCharCode(GRImageArray[i][k]);
}
}
printGRImage();
break;
}
}
</script>
</head>
<body onload='init()'>
<h1>
<div class="wordArtEffectText">PHOTO@@</div>
</h1>
<hr>
<form><input style="border: 5px groove rgb(255, 0, 0);" type='file' id='selectFile' onchange='readRawImage()' />
<br>
<label p style="border: 5px groove rgb(255, 153, 0)">화소점 처리</label>
<select name='imageAlgo' onchange="ImageProcessing(this.form.imageAlgo)"
style="border: 7px groove rgb(238, 255, 0);">
<option value=0>선택 하세요 </option>
<option value="1">동일 영상 처리</option>
<option value="2">영상 밝게 하기</option>
<option value="4">흑백 처리</option>
<option value="5">흑백 처리(평균)</option>
<option value="6">반대의 색</option>
</select>
<label p style="border: 5px groove rgb(0, 255, 21)">기하학 처리</label>
<select name='imageAlgo1' onchange="ImageProcessing1(this.form.imageAlgo1)"
style="border: 7px groove rgb(0, 17, 255);">
<option value="20">선택 하세요 </option>
<option value="21">축소 하기</option>
<option value="22">확대 하기</option>
<option value="23">좌/우 변경</option>
<option value="24">상/하 변경</option>
</select>
<br>
<label p style="border: 5px groove rgb(47, 0, 255)">히스토그램</label>
<select name='imageAlgo2' onchange="ImageProcessing2(this.form.imageAlgo2)"
style="border: 7px groove rgb(140, 0, 255);">
<option value="40">선택 하세요 </option>
<option value="41">히스토그램 스트래칭</option>
<option value="42">엔드-인 탐색</option>
<option value="43">평활화 </option>
<option value="44">히스토그램 차트 </option>
</select>
<br>
<canvas id='inCanvas' style='background-color:rgb(248, 209, 164)'></canvas>
<canvas id='outCanvas' style='background-color:rgb(164, 248, 192)'></canvas>
<br>
<canvas id='GRCanvas' style='background-color:rgb(164, 248, 192)'></canvas>
</form>
</body>
</html>