split files
This commit is contained in:
@@ -30,6 +30,7 @@ private:
|
|||||||
int serverSocket;
|
int serverSocket;
|
||||||
int port;
|
int port;
|
||||||
bool running;
|
bool running;
|
||||||
|
std::string webRoot;
|
||||||
|
|
||||||
// Function to convert hex color string to Vec4
|
// Function to convert hex color string to Vec4
|
||||||
Vec4 hexToVec4(const std::string& hex) {
|
Vec4 hexToVec4(const std::string& hex) {
|
||||||
@@ -87,9 +88,8 @@ private:
|
|||||||
// Render to RGB image
|
// Render to RGB image
|
||||||
std::vector<uint8_t> imageData = grid.renderToRGB(width, height);
|
std::vector<uint8_t> imageData = grid.renderToRGB(width, height);
|
||||||
|
|
||||||
// Save as BMP
|
// Save as JXL
|
||||||
return JXLWriter::saveJXL(filename, imageData, width, height);
|
return JXLWriter::saveJXL(filename, imageData, width, height);
|
||||||
// return BMPWriter::saveBMP(filename, imageData, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read file content
|
// Read file content
|
||||||
@@ -104,6 +104,18 @@ private:
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get content type based on file extension
|
||||||
|
std::string getContentType(const std::string& filename) {
|
||||||
|
if (filename.find(".html") != std::string::npos) return "text/html";
|
||||||
|
if (filename.find(".css") != std::string::npos) return "text/css";
|
||||||
|
if (filename.find(".js") != std::string::npos) return "application/javascript";
|
||||||
|
if (filename.find(".jxl") != std::string::npos) return "image/jxl";
|
||||||
|
if (filename.find(".png") != std::string::npos) return "image/png";
|
||||||
|
if (filename.find(".jpg") != std::string::npos || filename.find(".jpeg") != std::string::npos) return "image/jpeg";
|
||||||
|
if (filename.find(".json") != std::string::npos) return "application/json";
|
||||||
|
return "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
// Send HTTP response
|
// Send HTTP response
|
||||||
void sendResponse(int clientSocket, const std::string& content, const std::string& contentType = "text/html", int statusCode = 200) {
|
void sendResponse(int clientSocket, const std::string& content, const std::string& contentType = "text/html", int statusCode = 200) {
|
||||||
std::string statusText = "OK";
|
std::string statusText = "OK";
|
||||||
@@ -121,9 +133,22 @@ private:
|
|||||||
std::string responseStr = response.str();
|
std::string responseStr = response.str();
|
||||||
send(clientSocket, responseStr.c_str(), responseStr.length(), 0);
|
send(clientSocket, responseStr.c_str(), responseStr.length(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serve static file
|
||||||
|
void serveStaticFile(int clientSocket, const std::string& filepath) {
|
||||||
|
std::string fullPath = webRoot + "/" + filepath;
|
||||||
|
std::string content = readFile(fullPath);
|
||||||
|
|
||||||
|
if (!content.empty()) {
|
||||||
|
sendResponse(clientSocket, content, getContentType(filepath));
|
||||||
|
} else {
|
||||||
|
sendResponse(clientSocket, "404 Not Found: " + filepath, "text/plain", 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SimpleHTTPServer(int port = 8080) : port(port), serverSocket(-1), running(false) {}
|
SimpleHTTPServer(int port = 8080, const std::string& webRoot = "web")
|
||||||
|
: port(port), serverSocket(-1), running(false), webRoot(webRoot) {}
|
||||||
|
|
||||||
~SimpleHTTPServer() {
|
~SimpleHTTPServer() {
|
||||||
stop();
|
stop();
|
||||||
@@ -171,6 +196,7 @@ public:
|
|||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
std::cout << "Server started on port " << port << std::endl;
|
std::cout << "Server started on port " << port << std::endl;
|
||||||
|
std::cout << "Web root: " << webRoot << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +239,11 @@ public:
|
|||||||
|
|
||||||
// Handle different routes
|
// Handle different routes
|
||||||
if (request.find("GET / ") != std::string::npos || request.find("GET /index.html") != std::string::npos) {
|
if (request.find("GET / ") != std::string::npos || request.find("GET /index.html") != std::string::npos) {
|
||||||
sendResponse(clientSocket, getHTML());
|
serveStaticFile(clientSocket, "index.html");
|
||||||
|
} else if (request.find("GET /style.css") != std::string::npos) {
|
||||||
|
serveStaticFile(clientSocket, "style.css");
|
||||||
|
} else if (request.find("GET /script.js") != std::string::npos) {
|
||||||
|
serveStaticFile(clientSocket, "script.js");
|
||||||
} else if (request.find("GET /gradient.jxl") != std::string::npos) {
|
} else if (request.find("GET /gradient.jxl") != std::string::npos) {
|
||||||
// Generate and serve the gradient image
|
// Generate and serve the gradient image
|
||||||
if (generateGradientImage("output/gradient.jxl")) {
|
if (generateGradientImage("output/gradient.jxl")) {
|
||||||
@@ -248,112 +278,6 @@ public:
|
|||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getHTML() {
|
|
||||||
return R"(
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>Dynamic Gradient Generator</title>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: 'Arial', sans-serif;
|
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
color: white;
|
|
||||||
text-align: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
max-width: 800px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
padding: 30px;
|
|
||||||
border-radius: 15px;
|
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
.image-container {
|
|
||||||
margin: 20px 0;
|
|
||||||
padding: 20px;
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
.controls {
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
background: #4CAF50;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
margin: 5px;
|
|
||||||
transition: background 0.3s;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
background: #45a049;
|
|
||||||
}
|
|
||||||
.info {
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: 15px;
|
|
||||||
background: rgba(255, 255, 255, 0.15);
|
|
||||||
border-radius: 8px;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
|
|
||||||
<div class="image-container">
|
|
||||||
<img id="gradientImage" src="gradient.jxl" alt="Dynamic Gradient">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function refreshImage() {
|
|
||||||
const img = document.getElementById('gradientImage');
|
|
||||||
const timestamp = new Date().getTime();
|
|
||||||
img.src = 'gradient.jxl?' + timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateNew() {
|
|
||||||
fetch('/generate')
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.status === 'success') {
|
|
||||||
refreshImage();
|
|
||||||
} else {
|
|
||||||
alert('Error generating new gradient');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
alert('Error generating new gradient');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-refresh every 30 seconds
|
|
||||||
setInterval(refreshImage, 30000);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
23
web/index.html
Normal file
23
web/index.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Dynamic Gradient Generator</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Dynamic Gradient Generator</h1>
|
||||||
|
|
||||||
|
<div class="controls">
|
||||||
|
<button onclick="refreshImage()">Refresh Image</button>
|
||||||
|
<button onclick="toggleAutoRefresh()" id="autoRefreshBtn">Start Auto-Refresh (30s)</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="image-container">
|
||||||
|
<img id="gradientImage" src="gradient.jxl" alt="Dynamic Gradient">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
43
web/script.js
Normal file
43
web/script.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
let autoRefreshInterval = null;
|
||||||
|
|
||||||
|
function refreshImage() {
|
||||||
|
const img = document.getElementById('gradientImage');
|
||||||
|
img.classList.add('loading');
|
||||||
|
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
img.src = 'gradient.jxl?' + timestamp;
|
||||||
|
|
||||||
|
img.onload = function() {
|
||||||
|
img.classList.remove('loading');
|
||||||
|
updateStatus('Image refreshed at ' + new Date().toLocaleTimeString());
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = function() {
|
||||||
|
img.classList.remove('loading');
|
||||||
|
updateStatus('Error loading image', 'error');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function toggleAutoRefresh() {
|
||||||
|
const button = document.getElementById('autoRefreshBtn');
|
||||||
|
|
||||||
|
if (autoRefreshInterval) {
|
||||||
|
clearInterval(autoRefreshInterval);
|
||||||
|
autoRefreshInterval = null;
|
||||||
|
button.textContent = 'Start Auto-Refresh (30s)';
|
||||||
|
button.classList.remove('danger');
|
||||||
|
updateStatus('Auto-refresh stopped');
|
||||||
|
} else {
|
||||||
|
autoRefreshInterval = setInterval(refreshImage, 30000);
|
||||||
|
button.textContent = 'Stop Auto-Refresh';
|
||||||
|
button.classList.add('danger');
|
||||||
|
updateStatus('Auto-refresh started (30s interval)');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Auto-refresh when page loads
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
refreshImage();
|
||||||
|
});
|
||||||
109
web/style.css
Normal file
109
web/style.css
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Arial', sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 15px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 20px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.loading {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 5px;
|
||||||
|
transition: background 0.3s, transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background: #45a049;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
button.secondary {
|
||||||
|
background: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.secondary:hover {
|
||||||
|
background: #1976D2;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger {
|
||||||
|
background: #f44336;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.danger:hover {
|
||||||
|
background: #d32f2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 15px;
|
||||||
|
background: rgba(255, 255, 255, 0.15);
|
||||||
|
border-radius: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info ul {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
margin: 10px 0;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user