Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions 01_Example/xiaozhi-esp32/components/app_bsp/server_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@ esp_err_t static_resource_unified_handler(httpd_req_t *req) {
break;
}
}
} else if(strstr(uri,"heic2any.min.js")) { // /heic2any.min.js
resp_str = (char *) heap_caps_malloc(SEND_LEN_MAX + 1, MALLOC_CAP_SPIRAM);
httpd_resp_set_type(req, "text/javascript");
while(1) {
str_len = SDPort_->SDPort_ReadOffset("/sdcard/03_sys_ap_html/heic2any.min.js",resp_str,SEND_LEN_MAX,str_respLen);
if (str_len) {
httpd_resp_send_chunk(req, resp_str, str_len);
str_respLen += str_len;
} else {
break;
}
}
} else if(strstr(uri,"script.min.js")) { // /script.min.js
resp_str = (char *) heap_caps_malloc(SEND_LEN_MAX + 1, MALLOC_CAP_SPIRAM);
httpd_resp_set_type(req, "text/javascript");
Expand Down
1 change: 1 addition & 0 deletions 02_SDCARD/03_sys_ap_html/heic2any.min.js

Large diffs are not rendered by default.

241 changes: 194 additions & 47 deletions 02_SDCARD/03_sys_ap_html/index.html
Original file line number Diff line number Diff line change
@@ -1,72 +1,219 @@
<!DOCTYPE html>
<html data-bs-theme="light" lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, shrink-to-fit=no">
<title>ESP32-S3-PhotoPainter</title>
<link rel="stylesheet" href="bootstrap.min.css">
<link rel="stylesheet" href="styles.min.css">
</head>

<body>
<div class="vw-100 vh-100 p-5 bg-body-secondary d-flex flex-column">
<h1 class="text-center fw-bold mb-4">ESP32-S3-PhotoPainter Operating interface</h1>
<div class="d-flex justify-content-between gap-5 w-100 mx-auto">
<div class="d-flex gap-2 align-items-center">
<button class="btn btn-success" id="Input_Button" type="button">
Input
</button>
<button class="btn btn-success" id="Rotate_Button" type="button">
Rotate:
</button>
</div>
<div class="d-flex gap-2 align-items-center">
<div class="d-flex align-items-center gap-2 ms-5">
<span>NetworkMode:</span>
<div class="btn-group">
<a data-mode="AP" class="btn btn-outline-success active">AP</a>
<a data-mode="STA" class="btn btn-outline-success">STA</a>
<div class="vw-100 vh-100 p-3 p-md-5 bg-body-secondary d-flex flex-column overflow-auto">
<div class="mb-4">
<h1 class="text-center fw-bold mb-4">ESP32-S3-PhotoPainter Operating interface</h1>
<div class="d-flex align-items-center justify-content-between">
<!-- Group 1: High-Frequency Action (Left) -->
<div class="d-flex align-items-center flex-shrink-0">
<button class="btn btn-success px-5 fw-bold shadow-sm" id="Input_Button" type="button">🖼️ Open
Image</button>
</div>

<!-- Group 2: Low-Frequency Settings (Right) -->
<div class="d-flex align-items-center ms-auto">
<!-- Connection Tips (Shifted left of Network, smaller font) -->
<div id="tips" class="text-secondary pe-3 me-3 border-end"
style="min-width: 500px; font-size: 0.72rem; line-height: 1.3;">
<div id="tips-AP" class="text-end">
The settings will take effect after a restart. For AP mode, connect to SSID:
<b>esp_network</b><br>
(pass: 1234567890), then visit: http://192.168.4.1/index.html
</div>
<div id="tips-STA" class="text-end d-none">
The settings will take effect after a restart. For STA mode, configure via Mode 3,<br>
then visit: http://esp32-s3-photopainter.local/index.html
</div>
</div>

<!-- Network Mode (Absolute Far Right) -->
<div class="d-flex align-items-center gap-2 flex-shrink-0">
<span>NetworkMode:</span>
<div class="btn-group">
<a data-mode="AP" class="btn btn-outline-success active" style="width: 60px;">AP</a>
<a data-mode="STA" class="btn btn-outline-success" style="width: 60px;">STA</a>
</div>
</div>
</div>
<button class="btn btn-success" id="Send_Button" type="button" style="min-width: 200px;">
Send
</button>
</div>
</div>
<div id="tips" class="mt-2">
<div id="tips-AP" class="text-end">
The settings will take effect after a restart. For AP mode, first connect to the SSID: esp_network (password: 1234567890), then access the address: http://192.168.4.1/index.html
</div>
<div id="tips-STA" class="text-end d-none">
The settings will take effect after a restart. For STA mode, first configure the network using Mode 3, then access the address: http://esp32-s3-photopainter.local/index.html
</div>
</div>

<div class="d-flex m-auto gap-5 h-75 w-100">
<div class="flex-fill bg-white border border-success w-50 rounded-2 d-flex flex-column align-items-center">
<!-- Left Column: Original Image -->
<div
class="flex-fill bg-white border border-success w-50 rounded-2 d-flex flex-column align-items-center p-3">
<div class="d-flex justify-content-between align-items-center w-100 mb-2">
<div class="fs-4 fw-bold">Original Image</div>
<div class="d-flex flex-wrap gap-2 align-items-center justify-content-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary" style="width: 30px;" id="Src_Rotate_L"
type="button" title="Rotate Left">↺</button>
<button class="btn btn-outline-secondary" style="width: 30px;" id="Src_Rotate_R"
type="button" title="Rotate Right">↻</button>
<button class="btn btn-outline-secondary" style="width: 30px;" id="Src_Mirror" type="button"
title="Mirror Horizontally">↔</button>
</div>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-secondary w-50" id="Zoom_Out" type="button"
title="Zoom Out">-</button>
<button class="btn btn-outline-secondary w-50" id="Zoom_In" type="button"
title="Zoom In">+</button>
</div>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-secondary dropdown-toggle"
data-bs-toggle="dropdown" aria-expanded="false" id="Ratio_Dropdown">
Ratio: 5:3
</button>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#" data-ratio="1.666666">5:3</a></li>
<li><a class="dropdown-item" href="#" data-ratio="0.6">3:5</a></li>
<li><a class="dropdown-item" href="#" data-ratio="1">1:1</a></li>
<li><a class="dropdown-item" href="#" data-ratio="free">Free</a></li>
</ul>
</div>
</div>
</div>
<input type="file" class="sysInputFile d-none" id="File_Input">
<div class="fs-3 my-3">Original image</div>
<img src="placeholder.svg" class="m-auto" id="Image_Input" alt="Original_image" style="max-height: 80%; max-width: 80%;">
</div>
<div class="flex-fill bg-white border border-success w-50 rounded-2 d-flex flex-column align-items-center">
<div class="fs-3 my-3">Processed image</div>
<img src="placeholder.svg" class="m-auto" id="Image_Processed" alt="Processed_image" style="max-height: 80%; max-width: 80%;">
<div id="Image_Wrapper"
style="position: relative; width: 100%; flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center; background-color: #f8f9fa; overflow: hidden;">
<!-- Replaced img with canvas for better performance -->
<img id="Image_Placeholder" src="placeholder.svg" alt="Placeholder"
style="max-width: 100%; max-height: 100%; object-fit: contain;">
<canvas id="Image_Input_Canvas"
style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"></canvas>
<div id="Crop_Box" class="crop-box" style="display: none; position: absolute;">
<div class="crop-grid"></div>
</div>
</div>
</div>
</div>
</div>
<script src="bootstrap.min.js"></script>
<script src="script.min.js"></script>
</body>
</html>







<!-- Right Column: Processed Image -->
<div
class="flex-fill bg-white border border-success w-50 rounded-2 d-flex flex-column align-items-center p-3">
<div class="d-flex justify-content-between align-items-center w-100 mb-2">
<div class="fs-4 fw-bold">Processed Image</div>
<div class="d-flex gap-2 align-items-center">
<!-- Background Color Controls -->
<div class="input-group input-group-sm" style="width: auto;">
<button class="btn btn-outline-secondary" type="button" id="Btn_Bg_Black"
style="background-color: black; color: white; width: 30px;">B</button>
<button class="btn btn-outline-secondary" type="button" id="Btn_Bg_White"
style="background-color: white; color: black; width: 30px;">W</button>
<input type="text" class="form-control border-secondary" id="Bg_Color_Text" value="#FFFFFF"
style="width: 80px; text-transform: uppercase;" placeholder="#FFFFFF">
</div>
<button class="btn btn-outline-secondary btn-sm me-2" id="Orientation_Toggle" type="button"
title="Switch Screen Orientation">
<span id="Orientation_Text" class="d-none d-sm-inline">Landscape</span>
</button>
<button class="btn btn-success" id="Send_Button" type="button">🚀 Send</button>
</div>
</div>

<div
style="position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background-color: #f8f9fa; border-radius: 0.5rem; overflow: hidden;">
<img src="placeholder.svg" id="Image_Processed" alt="Processed_image"
style="max-width: 100%; max-height: 100%; object-fit: contain;">

<!-- E-Ink Simulation Masks -->
<div id="Ink_Simulation_Tint" class="paper-tint active"></div>
<div id="Ink_Simulation_Mask" class="ink-mask active"></div>

<!-- Settings Trigger (SVG Gear) - Always visible now -->
<div id="E6_Settings_Trigger"
class="position-absolute top-0 end-0 m-2 settings-trigger border shadow-sm">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z">
</path>
</svg>
</div>

<!-- E6 Mode Settings (Auto-hide Overlay) -->
<div id="E6_Settings_Panel"
class="position-absolute top-0 end-0 m-1 p-2 border rounded shadow settings-overlay"
style="width: 260px; background-color: rgba(255, 255, 255, 0.95); backdrop-filter: blur(8px); z-index: 1000; font-size: 0.75rem;">
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="fw-bold text-primary"><i class="bi bi-sliders"></i> Settings</div>
<div class="btn-group btn-group-xs" id="Preset_Group">
<button class="btn btn-outline-primary btn-xs p-1" data-preset="natural"
style="font-size: 0.7rem;">Nat</button>
<button class="btn btn-outline-primary btn-xs p-1" data-preset="portrait"
style="font-size: 0.7rem;">Por</button>
<button class="btn btn-outline-primary btn-xs p-1" data-preset="landscape"
style="font-size: 0.7rem;">Lan</button>
<button class="btn btn-outline-primary btn-xs p-1" data-preset="art"
style="font-size: 0.7rem;">Art</button>
</div>
</div>

<div class="row g-2">
<div class="col-12">
<div class="d-flex justify-content-between mb-0"><span>Gamma</span><span id="Val_Gamma"
class="fw-bold">1.1</span></div>
<input type="range" class="form-range form-range-sm" id="Slider_Gamma" min="0.5"
max="2.0" step="0.1" value="1.1">
</div>
<div class="col-6">
<div class="d-flex justify-content-between mb-0"><span>Contrast</span><span
id="Val_Contrast" class="fw-bold">0.4</span></div>
<input type="range" class="form-range form-range-sm" id="Slider_Contrast" min="0"
max="1.0" step="0.1" value="0.4">
</div>
<div class="col-6">
<div class="d-flex justify-content-between mb-0"><span>Sat</span><span
id="Val_Saturation" class="fw-bold">1.2</span></div>
<input type="range" class="form-range form-range-sm" id="Slider_Saturation" min="1.0"
max="2.0" step="0.1" value="1.2">
</div>
<div class="col-6">
<div class="d-flex justify-content-between mb-0"><span>Dither</span><span
id="Val_Dither" class="fw-bold">0.7</span></div>
<input type="range" class="form-range form-range-sm" id="Slider_Dither" min="0"
max="1.0" step="0.05" value="0.7">
</div>
<div class="col-6">
<div class="d-flex justify-content-between mb-0"><span>Thr</span><span
id="Val_Threshold" class="fw-bold">10</span></div>
<input type="range" class="form-range form-range-sm" id="Slider_Threshold" min="0"
max="50" step="1" value="10">
</div>
<div class="col-12 border-top pt-2 mt-2">
<div class="form-check form-switch p-0 d-flex justify-content-between align-items-center mb-1"
title="Visual E-Ink texture simulation">
<label class="form-check-label fw-bold text-secondary" for="Ink_Sim_Toggle">E-Ink
Simulation</label>
<input class="form-check-input ms-0" type="checkbox" id="Ink_Sim_Toggle" checked>
</div>
<div class="form-check form-switch p-0 d-flex justify-content-between align-items-center"
title="Advanced Optimization Algorithm">
<label class="form-check-label fw-bold text-secondary" for="Algo_Toggle">E6
Optimization</label>
<input class="form-check-input ms-0" type="checkbox" id="Algo_Toggle" checked>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<script src="bootstrap.min.js"></script>
<script src="heic2any.min.js"></script>
<script src="script.min.js"></script>
</body>

</html>
Loading