| <div class="ai-tool-container"> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.11/katex.min.css"> |
| <link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@100&display=swap" rel="stylesheet"> |
| <div class="container"> |
| <h3>Image to sketch</h3> |
| <form id="remakeai-form"> |
| <div class="form-group"> |
| <label for="file" class="custom-file-upload"> |
| <i class="fa fa-cloud-upload"></i> Upload Image |
| </label> |
| <input type="file" id="file" name="file" required> |
| <span id="file-name"></span> |
| </div> |
|
|
| |
|
|
| <button type="submit" class="btn-submit">Submit</button> |
| </form> |
| <div class="result"></div> |
| <div class="progress-container"> |
| <div class="progress-bar" id="progress-bar"></div> |
| </div> |
| </div> |
| </div> |
| |
|
|
|
|
|
|
|
|
|
|
| |
|
|
| <script> |
| |
| document.addEventListener("DOMContentLoaded", function() { |
| const form = document.getElementById("remakeai-form"); |
| const fileInput = document.getElementById('file'); |
| const fileNameSpan = document.getElementById('file-name'); |
| const progressBar = document.getElementById('progress-bar'); |
| const progressContainer = document.querySelector('.progress-container'); |
| const resultDiv = document.querySelector(".result"); |
| |
| let simulatedProgressInterval; |
| let simulatedProgress = 0; |
| |
| fileInput.addEventListener('change', function() { |
| fileNameSpan.textContent = this.files[0].name; |
| }); |
| |
| form.addEventListener("submit", async function(event) { |
| event.preventDefault(); |
| |
| const file = fileInput.files[0]; |
| const compressedFile = await compressImage(file); |
| |
| const formData = new FormData(); |
| formData.append('file', compressedFile, file.name); |
| |
| |
| progressBar.style.width = '0%'; |
| progressContainer.style.display = 'block'; |
| simulatedProgress = 0; |
| |
| |
| resultDiv.innerHTML = ''; |
| |
| const xhr = new XMLHttpRequest(); |
| xhr.open("POST", "/upload/", true); |
| xhr.responseType = 'json'; |
| |
| xhr.upload.onprogress = function(event) { |
| if (event.lengthComputable) { |
| const percentComplete = (event.loaded / event.total) * 100; |
| updateProgressBar(percentComplete); |
| } |
| }; |
| |
| xhr.onloadstart = function() { |
| |
| simulateBackendProcessingProgress(); |
| }; |
| |
| xhr.onload = function() { |
| clearInterval(simulatedProgressInterval); |
| if (xhr.status === 200) { |
| const response = xhr.response; |
| |
| if (response.error) { |
| resultDiv.innerHTML = `<p class="error-message">${response.error}</p>`; |
| } else { |
| const originalURL = URL.createObjectURL(file); |
| const sketchImageBase64 = response.sketch_image_base64; |
| |
| resultDiv.innerHTML = ` |
| <h2>Result</h2> |
| <div class="result-images"> |
| <img src="${originalURL}" alt="Original Image" class="result-image"> |
| <span class="arrow">↓</span> |
| <img src="${sketchImageBase64}" alt="Sketch Image" class="result-image"> |
| </div> |
| `; |
| |
| |
| const downloadButton = document.createElement('a'); |
| downloadButton.href = sketchImageBase64; |
| downloadButton.download = 'result.jpg'; |
| downloadButton.textContent = 'Download Result'; |
| downloadButton.className = 'btn-download'; |
| resultDiv.appendChild(downloadButton); |
| |
| updateProgressBar(100); |
| } |
| } else { |
| resultDiv.innerHTML = `<p class="error-message">Error: ${xhr.statusText}</p>`; |
| updateProgressBar(0); |
| } |
| |
| setTimeout(() => { |
| progressContainer.style.display = 'none'; |
| }, 1000); |
| }; |
| |
| xhr.onerror = function() { |
| clearInterval(simulatedProgressInterval); |
| resultDiv.innerHTML = `<p class="error-message">Error: Network Error</p>`; |
| updateProgressBar(0); |
| |
| setTimeout(() => { |
| progressContainer.style.display = 'none'; |
| }, 1000); |
| }; |
| |
| xhr.send(formData); |
| }); |
| |
| async function compressImage(file) { |
| return new Promise((resolve, reject) => { |
| const reader = new FileReader(); |
| reader.onload = function(event) { |
| const img = new Image(); |
| img.src = event.target.result; |
| img.onload = function() { |
| const canvas = document.createElement('canvas'); |
| const ctx = canvas.getContext('2d'); |
| |
| const maxWidth = 1000; |
| const maxHeight = 1000; |
| let width = img.width; |
| let height = img.height; |
| if (width > height) { |
| if (width > maxWidth) { |
| height *= maxWidth / width; |
| width = maxWidth; |
| } |
| } else { |
| if (height > maxHeight) { |
| width *= maxHeight / height; |
| height = maxHeight; |
| } |
| } |
| |
| canvas.width = width; |
| canvas.height = height; |
| |
| ctx.drawImage(img, 0, 0, width, height); |
| |
| canvas.toBlob((blob) => { |
| resolve(blob); |
| }, 'image/jpeg', 0.7); |
| } |
| } |
| |
| reader.readAsDataURL(file); |
| }); |
| } |
| |
| function updateProgressBar(percentComplete) { |
| progressBar.style.width = percentComplete + '%'; |
| updateProgressBarColor(percentComplete); |
| } |
| |
| function updateProgressBarColor(percentComplete) { |
| const startColor = "#ff0000"; |
| const endColor = "#0056b3"; |
| const currentColor = interpolateColor(startColor, endColor, percentComplete / 100); |
| progressBar.style.backgroundColor = currentColor; |
| } |
| |
| function interpolateColor(color1, color2, factor) { |
| const result = color1.slice(1).match(/.{2}/g).map((hex, i) => { |
| return Math.round(parseInt(hex, 16) * (1 - factor) + parseInt(color2.slice(1).match(/.{2}/g)[i], 16) * factor); |
| }); |
| return `#${result.map(val => val.toString(16).padStart(2, '0')).join('')}`; |
| } |
| |
| function simulateBackendProcessingProgress() { |
| simulatedProgressInterval = setInterval(() => { |
| simulatedProgress += 1; |
| if (simulatedProgress < 90) { |
| updateProgressBar(simulatedProgress); |
| } else { |
| clearInterval(simulatedProgressInterval); |
| } |
| }, 200); |
| } |
| }); |
| </script> |
| |
| <style> |
| |
| .ai-tool-container body{ |
| font-family: 'Barlow Condensed', sans-serif; |
| background: linear-gradient(135deg, #f5f7fa, #c3cfe2); |
| margin: 0; |
| padding: 0; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| height: 100vh; |
| direction: ltr; |
| } |
| |
| .ai-tool-container { |
| background: #fff; |
| border-radius: 10px; |
| box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); |
| padding: 20px; |
| max-width: 500px; |
| width: 100%; |
| text-align: center; |
| direction: ltr; |
| } |
| |
| .ai-tool-container h3 { |
| font-size: 24px; |
| margin-bottom: 20px; |
| color: #333; |
| } |
| |
| .ai-tool-container .form-group { |
| margin-bottom: 15px; |
| text-align: left; |
| } |
| |
| .ai-tool-container |
| input[type="file"] { |
| display: none; |
| } |
| |
| .ai-tool-container .custom-file-upload { |
| display: inline-block; |
| padding: 10px 20px; |
| cursor: pointer; |
| background-color: #007bff; |
| color: #fff; |
| border-radius: 5px; |
| transition: background 0.3s; |
| } |
| |
| .ai-tool-container .custom-file-upload:hover { |
| background-color: #0056b3; |
| } |
| |
| .ai-tool-container #file-name { |
| display: block; |
| margin-top: 10px; |
| font-size: 14px; |
| color: #555; |
| } |
| |
| .ai-tool-container .radio-group { |
| display: flex; |
| justify-content: space-around; |
| align-items: center; |
| } |
| |
| .ai-tool-container .btn-submit { |
| background: #007bff; |
| color: #fff; |
| padding: 10px 20px; |
| border: none; |
| border-radius: 5px; |
| cursor: pointer; |
| transition: background 0.3s; |
| } |
| |
| .ai-tool-container .btn-submit:hover { |
| background: #0056b3; |
| } |
| |
| .ai-tool-container .result { |
| margin-top: 20px; |
| } |
| |
| .ai-tool-container .result h2 { |
| font-size: 20px; |
| color: #333; |
| } |
| |
| .ai-tool-container .result-image { |
| max-width: 100%; |
| border-radius: 10px; |
| box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); |
| transition: transform 0.3s; |
| } |
| |
| .ai-tool-container .result-image:hover { |
| transform: scale(1.05); |
| } |
| |
| .ai-tool-container .error-message { |
| color: red; |
| font-size: 16px; |
| } |
| |
| |
| |
| .ai-tool-container .progress-container { |
| width: 100%; |
| background-color: #f3f3f3; |
| border-radius: 5px; |
| overflow: hidden; |
| margin-top: 20px; |
| display: none; |
| } |
| |
| .ai-tool-container .progress-bar { |
| height: 10px; |
| width: 0%; |
| transition: width 0.4s ease, background-color 0.4s ease; |
| } |
| .ai-tool-container .result-images { |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| } |
| .ai-tool-container .result-images { |
| display: flex; |
| flex-direction: column; |
| align-items: center; |
| justify-content: center; |
| } |
| |
| .ai-tool-container .result-image { |
| max-width: 100%; |
| max-height: 300px; |
| border-radius: 10px; |
| box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1); |
| transition: transform 0.3s; |
| margin: 10px 0; |
| } |
| |
| .ai-tool-container .result-image:hover { |
| transform: scale(1.05); |
| } |
| |
| .ai-tool-container .arrow { |
| font-size: 24px; |
| color: #333; |
| margin: 10px 0; |
| } |
| |
| .ai-tool-container .btn-download { |
| display: inline-block; |
| margin-top: 20px; |
| padding: 10px 20px; |
| background-color: #708090; |
| color: #fff; |
| border-radius: 5px; |
| text-decoration: none; |
| transition: background 0.3s; |
| } |
| |
| .ai-tool-container .btn-download:hover { |
| background-color: #218838; |
| } |
| </style> |
| </div> |
|
|