[html] 웹 페이지에 이미지 업로드 붙이기

 

 

index.html을 작성한다. 

이미지를 업로드 하면, 미리보기를 보여주는 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Upload with Image Preview</title>
    <!-- 외부 CSS 파일 불러오기 -->
    <link rel="stylesheet" href="uploader-styles.css">
</head>
<body>

    <h2>File Upload & Image Preview</h2>
    <p class="lead">No Plugins <b>Just Javascript</b></p>

    <!-- Upload  -->
    <form id="file-upload-form" class="uploader">
        <input id="file-upload" type="file" name="fileUpload" accept="image/*" />
        <label for="file-upload" id="file-drag">
            <img id="file-image" src="#" alt="Preview" class="hidden">
            <div id="start">
                <i class="fa fa-download" aria-hidden="true"></i>
                <div>Select a file or drag here</div>
                <div id="notimage" class="hidden">Please select an image</div>
                <span id="file-upload-btn" class="btn btn-primary">Select a file</span>
            </div>
            <div id="response" class="hidden">
                <div id="messages"></div>
                <progress class="progress" id="file-progress" value="0">
                    <span>0</span>%
                </progress>
            </div>
        </label>
    </form>

    <!-- 스크립트 파일 연결 -->
    <script src="script.js"></script>
</body>
</html>


2. 스타일시트를 정의한다. 
uploader-styles.css

/* Imports */
@import url(https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css);
@import url('https://fonts.googleapis.com/css?family=Roboto');

/* Vars and Reset */
$theme: #454cad;
$dark-text: #5f6982;

html,
body,
* {
  box-sizing: border-box;
  font-size: 16px;
}

html,
body {
  height: 100%;
  text-align: center;
}

body {
  padding: 2rem;
  background: #f8f8f8;
}

h2 {
  font-family: "Roboto", sans-serif;
  font-size: 26px;
  line-height: 1;
  color: #454cad;
  margin-bottom: 0;
}

p {
  font-family: "Roboto", sans-serif;
  font-size: 18px;
  color: #5f6982;
}

/* Upload Demo */
.uploader {
  display: block;
  clear: both;
  margin: 0 auto;
  width: 100%;
  max-width: 600px;
}

.uploader label {
  float: left;
  clear: both;
  width: 100%;
  padding: 2rem 1.5rem;
  text-align: center;
  background: #fff;
  border-radius: 7px;
  border: 3px solid #eee;
  transition: all 0.2s ease;
  user-select: none;
}

.uploader label:hover {
  border-color: #454cad;
}

.uploader label.hover {
  border: 3px solid #454cad;
  box-shadow: inset 0 0 0 6px #eee;
}

.uploader #start {
  float: left;
  clear: both;
  width: 100%;
}

.uploader #start.hidden {
  display: none;
}

.uploader #start i.fa {
  font-size: 50px;
  margin-bottom: 1rem;
  transition: all 0.2s ease-in-out;
}

.uploader #response {
  float: left;
  clear: both;
  width: 100%;
}

.uploader #response.hidden {
  display: none;
}

.uploader #response #messages {
  margin-bottom: 0.5rem;
}

.uploader #file-image {
  display: inline;
  margin: 0 auto 0.5rem auto;
  width: auto;
  height: auto;
  max-width: 180px;
}

.uploader #file-image.hidden {
  display: none;
}

.uploader #notimage {
  display: block;
  float: left;
  clear: both;
  width: 100%;
}

.uploader #notimage.hidden {
  display: none;
}

.uploader progress,
.uploader .progress {
  display: inline;
  clear: both;
  margin: 0 auto;
  width: 100%;
  max-width: 180px;
  height: 8px;
  border: 0;
  border-radius: 4px;
  background-color: #eee;
  overflow: hidden;
}

.uploader .progress[value]::-webkit-progress-bar {
  border-radius: 4px;
  background-color: #eee;
}

.uploader .progress[value]::-webkit-progress-value {
  background: linear-gradient(to right, darken(#454cad, 8%) 0%, #454cad 50%);
  border-radius: 4px;
}

.uploader .progress[value]::-moz-progress-bar {
  background: linear-gradient(to right, darken(#454cad, 8%) 0%, #454cad 50%);
  border-radius: 4px;
}

.uploader input[type="file"] {
  display: none;
}

.uploader div {
  margin: 0 0 0.5rem 0;
  color: #5f6982;
}

.uploader .btn {
  display: inline-block;
  margin: 0.5rem 0.5rem 1rem 0.5rem;
  clear: both;
  font-family: inherit;
  font-weight: 700;
  font-size: 14px;
  text-decoration: none;
  text-transform: initial;
  border: none;
  border-radius: 0.2rem;
  outline: none;
  padding: 0 1rem;
  height: 36px;
  line-height: 36px;
  color: #fff;
  transition: all 0.2s ease-in-out;
  box-sizing: border-box;
  background: #454cad;
  border-color: #454cad;
  cursor: pointer;
}

 

 

3. 자바스크립트 파일

script.js

// File Upload
// 
function ekUpload(){
	function Init() {
  
	  console.log("Upload Initialised");
  
	  var fileSelect    = document.getElementById('file-upload'),
		  fileDrag      = document.getElementById('file-drag'),
		  submitButton  = document.getElementById('submit-button');
  
	  fileSelect.addEventListener('change', fileSelectHandler, false);
  
	  // Is XHR2 available?
	  var xhr = new XMLHttpRequest();
	  if (xhr.upload) {
		// File Drop
		fileDrag.addEventListener('dragover', fileDragHover, false);
		fileDrag.addEventListener('dragleave', fileDragHover, false);
		fileDrag.addEventListener('drop', fileSelectHandler, false);
	  }
	}
  
	function fileDragHover(e) {
	  var fileDrag = document.getElementById('file-drag');
  
	  e.stopPropagation();
	  e.preventDefault();
  
	  fileDrag.className = (e.type === 'dragover' ? 'hover' : 'modal-body file-upload');
	}
  
	function fileSelectHandler(e) {
	  // Fetch FileList object
	  var files = e.target.files || e.dataTransfer.files;
  
	  // Cancel event and hover styling
	  fileDragHover(e);
  
	  // Process all File objects
	  for (var i = 0, f; f = files[i]; i++) {
		parseFile(f);
		uploadFile(f);
	  }
	}
  
	// Output
	function output(msg) {
	  // Response
	  var m = document.getElementById('messages');
	  m.innerHTML = msg;
	}
  
	function parseFile(file) {
  
	  console.log(file.name);
	  output(
		'<strong>' + encodeURI(file.name) + '</strong>'
	  );
	  
	  // var fileType = file.type;
	  // console.log(fileType);
	  var imageName = file.name;
  
	  var isGood = (/\.(?=gif|jpg|png|jpeg)/gi).test(imageName);
	  if (isGood) {
		document.getElementById('start').classList.add("hidden");
		document.getElementById('response').classList.remove("hidden");
		document.getElementById('notimage').classList.add("hidden");
		// Thumbnail Preview
		document.getElementById('file-image').classList.remove("hidden");
		document.getElementById('file-image').src = URL.createObjectURL(file);
	  }
	  else {
		document.getElementById('file-image').classList.add("hidden");
		document.getElementById('notimage').classList.remove("hidden");
		document.getElementById('start').classList.remove("hidden");
		document.getElementById('response').classList.add("hidden");
		document.getElementById("file-upload-form").reset();
	  }
	}
  
	function setProgressMaxValue(e) {
	  var pBar = document.getElementById('file-progress');
  
	  if (e.lengthComputable) {
		pBar.max = e.total;
	  }
	}
  
	function updateFileProgress(e) {
	  var pBar = document.getElementById('file-progress');
  
	  if (e.lengthComputable) {
		pBar.value = e.loaded;
	  }
	}
  
	function uploadFile(file) {
  
	  var xhr = new XMLHttpRequest(),
		fileInput = document.getElementById('class-roster-file'),
		pBar = document.getElementById('file-progress'),
		fileSizeLimit = 1024; // In MB
	  if (xhr.upload) {
		// Check if file is less than x MB
		if (file.size <= fileSizeLimit * 1024 * 1024) {
		  // Progress bar
		  pBar.style.display = 'inline';
		  xhr.upload.addEventListener('loadstart', setProgressMaxValue, false);
		  xhr.upload.addEventListener('progress', updateFileProgress, false);
  
		  // File received / failed
		  xhr.onreadystatechange = function(e) {
			if (xhr.readyState == 4) {
			  // Everything is good!
  
			  // progress.className = (xhr.status == 200 ? "success" : "failure");
			  // document.location.reload(true);
			}
		  };
  
		  // Start upload
		  xhr.open('POST', document.getElementById('file-upload-form').action, true);
		  xhr.setRequestHeader('X-File-Name', file.name);
		  xhr.setRequestHeader('X-File-Size', file.size);
		  xhr.setRequestHeader('Content-Type', 'multipart/form-data');
		  xhr.send(file);
		} else {
		  output('Please upload a smaller file (< ' + fileSizeLimit + ' MB).');
		}
	  }
	}
  
	// Check for the various File API support.
	if (window.File && window.FileList && window.FileReader) {
	  Init();
	} else {
	  document.getElementById('file-drag').style.display = 'none';
	}
  }
  ekUpload();

 

4. 티쳐블머신 모델을 가져온다. 
- 모델 다운로드 후, ftp로 /my_model/ 폴더에 넣어둔다. 
- webcam은 https가 있어야만 작동하므로 webcam 관련 코드를 삭제한다. 
- 브라우저 상에서 f12(개발자모드)로 들어가서, 업로드 이미지 위치를 찾아 인식분류 대상 이미지 위치로 코드를 수정한다. 


다음 영상을 참고하여, 코드를 삭제한다. 

https://www.youtube.com/watch?v=UzxqGnsNk1g

 

<div>Teachable Machine Image Model</div>
<button type="button" onclick="init()">Start</button>
<div id="webcam-container"></div>
<div id="label-container"></div>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/image@latest/dist/teachablemachine-image.min.js"></script>
<script type="text/javascript">
    // More API functions here:
    // https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image

    // the link to your model provided by Teachable Machine export panel
    const URL = "./my_model/";

    let model, webcam, labelContainer, maxPredictions;

    // Load the image model and setup the webcam
    async function init() {
        const modelURL = URL + "model.json";
        const metadataURL = URL + "metadata.json";

        // load the model and metadata
        // Refer to tmImage.loadFromFiles() in the API to support files from a file picker
        // or files from your local hard drive
        // Note: the pose library adds "tmImage" object to your window (window.tmImage)
        model = await tmImage.load(modelURL, metadataURL);
        maxPredictions = model.getTotalClasses();

        // Convenience function to setup a webcam
        const flip = true; // whether to flip the webcam
        webcam = new tmImage.Webcam(200, 200, flip); // width, height, flip
        await webcam.setup(); // request access to the webcam
        await webcam.play();
        window.requestAnimationFrame(loop);

        // append elements to the DOM
        document.getElementById("webcam-container").appendChild(webcam.canvas);
        labelContainer = document.getElementById("label-container");
        for (let i = 0; i < maxPredictions; i++) { // and class labels
            labelContainer.appendChild(document.createElement("div"));
        }
    }

    async function loop() {
        webcam.update(); // update the webcam frame
        await predict();
        window.requestAnimationFrame(loop);
    }

    // run the webcam image through the image model
    async function predict() {
        // predict can take in an image, video or canvas html element
        const prediction = await model.predict(webcam.canvas);
        for (let i = 0; i < maxPredictions; i++) {
            const classPrediction =
                prediction[i].className + ": " + prediction[i].probability.toFixed(2);
            labelContainer.childNodes[i].innerHTML = classPrediction;
        }
    }
</script>
반응형

'프로젝트' 카테고리의 다른 글

[html] CORB 위반  (0) 2024.04.11
[라즈베리파이-아두이노] 분리수거 휴지통 만들기  (0) 2023.07.10