2020最新国产在线不卡a-爱看女同中文字幕av-国产大秀视频在线一区二区-大香蕉手机在线最新视频

旗下品牌:
石家莊網(wǎng)站開發(fā) 石家莊網(wǎng)站開發(fā)公司

資訊動(dòng)態(tài)

察而思、思而行、行而后語(yǔ)、知行合一

合影功能實(shí)現(xiàn)

發(fā)布時(shí)間:2025-08-15 熱度:

設(shè)計(jì)一個(gè)具有合影功能的網(wǎng)頁(yè),允許用戶拍照、合并多張照片并下載最終合影。

設(shè)計(jì)思路:

  • 使用攝像頭捕獲實(shí)時(shí)視頻

  • 實(shí)現(xiàn)拍照功能并展示縮略圖

  • 提供照片合并功能

  • 實(shí)現(xiàn)下載最終合影功能

  • 添加簡(jiǎn)潔美觀的UI設(shè)計(jì)

實(shí)現(xiàn)方案:

  • 使用HTML5的getUserMedia API訪問攝像頭

  • 利用Canvas進(jìn)行圖像捕獲和處理

  • 使用Flexbox布局創(chuàng)建響應(yīng)式界面

下面是完整的實(shí)現(xiàn)代碼:

<!DOCTYPE html> <html> <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>在線合影制作工具</title>     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">     <style>         * {             margin: 0;             padding: 0;             box-sizing: border-box;             font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;         }                  body {             background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);             min-height: 100vh;             display: flex;             justify-content: center;             align-items: center;             padding: 20px;             color: #333;         }                  .container {             width: 100%;             max-width: 1200px;             background: rgba(255, 255, 255, 0.9);             border-radius: 20px;             box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);             overflow: hidden;             display: flex;             flex-direction: column;         }                  header {             background: linear-gradient(to right, #4a00e0, #8e2de2);             color: white;             padding: 20px;             text-align: center;         }                  header h1 {             font-size: 2.5rem;             margin-bottom: 10px;         }                  header p {             font-size: 1.1rem;             opacity: 0.9;         }                  .content {             display: flex;             flex-wrap: wrap;             padding: 20px;             gap: 20px;         }                  .camera-section {             flex: 1;             min-width: 300px;             background: white;             border-radius: 15px;             padding: 20px;             box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);         }                  .preview-section {             flex: 1;             min-width: 300px;             background: white;             border-radius: 15px;             padding: 20px;             box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);             display: flex;             flex-direction: column;         }                  .section-title {             font-size: 1.5rem;             margin-bottom: 15px;             color: #4a00e0;             display: flex;             align-items: center;             gap: 10px;         }                  .section-title i {             background: #4a00e0;             color: white;             width: 36px;             height: 36px;             border-radius: 50%;             display: flex;             align-items: center;             justify-content: center;         }                  .camera-container {             width: 100%;             height: 300px;             background: #f0f0f0;             border-radius: 10px;             overflow: hidden;             margin-bottom: 20px;             position: relative;             display: flex;             justify-content: center;             align-items: center;         }                  #video {             width: 100%;             height: 100%;             object-fit: cover;         }                  .controls {             display: flex;             gap: 10px;             flex-wrap: wrap;         }                  .btn {             padding: 12px 24px;             border: none;             border-radius: 50px;             font-size: 1rem;             font-weight: 600;             cursor: pointer;             display: flex;             align-items: center;             gap: 8px;             transition: all 0.3s ease;         }                  .btn-primary {             background: linear-gradient(to right, #4a00e0, #8e2de2);             color: white;             box-shadow: 0 4px 10px rgba(74, 0, 224, 0.3);         }                  .btn-primary:hover {             transform: translateY(-3px);             box-shadow: 0 6px 15px rgba(74, 0, 224, 0.4);         }                  .btn-success {             background: linear-gradient(to right, #00b09b, #96c93d);             color: white;             box-shadow: 0 4px 10px rgba(0, 176, 155, 0.3);         }                  .btn-success:hover {             transform: translateY(-3px);             box-shadow: 0 6px 15px rgba(0, 176, 155, 0.4);         }                  .btn-danger {             background: linear-gradient(to right, #ff416c, #ff4b2b);             color: white;             box-shadow: 0 4px 10px rgba(255, 65, 108, 0.3);         }                  .btn-danger:hover {             transform: translateY(-3px);             box-shadow: 0 6px 15px rgba(255, 65, 108, 0.4);         }                  .captured-photos {             display: flex;             gap: 15px;             margin: 20px 0;             flex-wrap: wrap;             min-height: 120px;         }                  .photo-thumb {             width: 100px;             height: 100px;             border-radius: 10px;             overflow: hidden;             position: relative;             box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);             border: 3px solid #8e2de2;         }                  .photo-thumb img {             width: 100%;             height: 100%;             object-fit: cover;         }                  .photo-thumb .remove {             position: absolute;             top: 5px;             right: 5px;             background: rgba(255, 255, 255, 0.8);             border-radius: 50%;             width: 22px;             height: 22px;             display: flex;             align-items: center;             justify-content: center;             cursor: pointer;             color: #ff416c;             font-size: 14px;         }                  .result-container {             flex: 1;             background: #f8f9fa;             border-radius: 10px;             display: flex;             justify-content: center;             align-items: center;             margin-top: 20px;             overflow: hidden;             min-height: 300px;         }                  #result {             max-width: 100%;             max-height: 100%;             display: none;         }                  .placeholder {             color: #6c757d;             text-align: center;             padding: 20px;         }                  .placeholder i {             font-size: 3rem;             margin-bottom: 15px;             color: #adb5bd;         }                  .download-btn {             margin-top: 20px;             align-self: center;             padding: 12px 30px;             font-size: 1.1rem;         }                  .instructions {             background: #eef2ff;             border-left: 4px solid #4a00e0;             padding: 15px;             border-radius: 0 8px 8px 0;             margin: 20px 0;         }                  .instructions h3 {             margin-bottom: 10px;             color: #4a00e0;         }                  .instructions ol {             padding-left: 20px;         }                  .instructions li {             margin-bottom: 8px;         }                  footer {             text-align: center;             padding: 20px;             background: #f8f9fa;             color: #6c757d;             font-size: 0.9rem;         }                  @media (max-width: 768px) {             .content {                 flex-direction: column;             }                          header h1 {                 font-size: 2rem;             }         }                  .flash {             position: absolute;             top: 0;             left: 0;             width: 100%;             height: 100%;             background-color: white;             opacity: 0;             pointer-events: none;         }                  @keyframes flash {             0% { opacity: 0; }             50% { opacity: 0.8; }             100% { opacity: 0; }         }     </style> </head> <body>     <div>         <header>             <h1><i class="fas fa-camera"></i> 在線合影制作工具</h1>             <p>拍攝照片,合并多張圖片,創(chuàng)建完美的合影</p>         </header>                  <div>             <div>                 <h2><i class="fas fa-video"></i> 拍照區(qū)域</h2>                                  <div>                     <div id="flash"></div>                     <video id="video" autoplay playsinline></video>                     <div id="camera-placeholder">                         <p>正在請(qǐng)求攝像頭權(quán)限...</p>                     </div>                 </div>                                  <div>                     <button id="capture-btn" class="btn btn-primary">                         <i class="fas fa-camera"></i> 拍照                     </button>                     <button id="reset-btn" class="btn btn-danger">                         <i class="fas fa-trash-alt"></i> 重置所有照片                     </button>                 </div>                                  <div>                     <h3>使用說明:</h3>                     <ol>                         <li>點(diǎn)擊"允許"按鈕授權(quán)訪問您的攝像頭</li>                         <li>調(diào)整位置,點(diǎn)擊"拍照"按鈕拍攝照片</li>                         <li>拍攝多張照片后,點(diǎn)擊"合并照片"創(chuàng)建合影</li>                         <li>最后點(diǎn)擊"下載合影"保存最終圖片</li>                     </ol>                 </div>                                  <h3><i class="fas fa-images"></i> 已拍攝照片</h3>                 <div id="photos-container">                     <div>                         <i class="fas fa-image"></i>                         <p>尚未拍攝照片</p>                     </div>                 </div>                                  <button id="merge-btn" class="btn btn-success">                     <i class="fas fa-object-group"></i> 合并照片                 </button>             </div>                          <div>                 <h2><i class="fas fa-file-image"></i> 合影預(yù)覽</h2>                                  <div>                     <div id="result-placeholder">                         <i class="fas fa-users"></i>                         <p>合并后的合影將顯示在這里</p>                     </div>                     <img id="result" alt="合并后的合影">                 </div>                                  <button id="download-btn" class="btn btn-primary download-btn">                     <i class="fas fa-download"></i> 下載合影                 </button>             </div>         </div>                  <footer>             <p>? 2023 在線合影工具 | 使用HTML5技術(shù)實(shí)現(xiàn) | 兼容Chrome、Firefox、Edge等現(xiàn)代瀏覽器</p>         </footer>     </div>     <script>         document.addEventListener('DOMContentLoaded', function() {             // 獲取DOM元素             const video = document.getElementById('video');             const captureBtn = document.getElementById('capture-btn');             const resetBtn = document.getElementById('reset-btn');             const mergeBtn = document.getElementById('merge-btn');             const downloadBtn = document.getElementById('download-btn');             const photosContainer = document.getElementById('photos-container');             const resultImg = document.getElementById('result');             const resultPlaceholder = document.getElementById('result-placeholder');             const flash = document.getElementById('flash');             const cameraPlaceholder = document.getElementById('camera-placeholder');                          // 存儲(chǔ)拍攝的照片             let capturedPhotos = [];                          // 訪問攝像頭             async function initCamera() {                 try {                     const stream = await navigator.mediaDevices.getUserMedia({                          video: {                              width: { ideal: 1280 },                              height: { ideal: 720 },                             facingMode: 'user'                          }                      });                     video.srcObject = stream;                     cameraPlaceholder.style.display = 'none';                 } catch (err) {                     console.error("攝像頭訪問錯(cuò)誤:", err);                     cameraPlaceholder.innerHTML = `<p style="color:red;">攝像頭訪問失敗: ${err.message}</p>`;                 }             }                          // 拍照功能             function capturePhoto() {                 const canvas = document.createElement('canvas');                 canvas.width = video.videoWidth;                 canvas.height = video.videoHeight;                                  const ctx = canvas.getContext('2d');                 ctx.drawImage(video, 0, 0, canvas.width, canvas.height);                                  // 添加閃光效果                 flash.style.animation = 'flash 0.5s';                 setTimeout(() => {                     flash.style.animation = '';                 }, 500);                                  // 生成數(shù)據(jù)URL                 const dataURL = canvas.toDataURL('image/png');                                  // 添加到照片數(shù)組                 capturedPhotos.push(dataURL);                                  // 更新照片縮略圖                 updatePhotoThumbnails();             }                          // 更新照片縮略圖             function updatePhotoThumbnails() {                 if (capturedPhotos.length === 0) {                     photosContainer.innerHTML = `                         <div>                             <i class="fas fa-image"></i>                             <p>尚未拍攝照片</p>                         </div>                     `;                     return;                 }                                  photosContainer.innerHTML = '';                                  capturedPhotos.forEach((photo, index) => {                     const thumbDiv = document.createElement('div');                     thumbDiv.className = 'photo-thumb';                                          const img = document.createElement('img');                     img.src = photo;                     img.alt = `照片 ${index + 1}`;                                          const removeBtn = document.createElement('div');                     removeBtn.className = 'remove';                     removeBtn.innerHTML = '<i class="fas fa-times"></i>';                     removeBtn.onclick = () => removePhoto(index);                                          thumbDiv.appendChild(img);                     thumbDiv.appendChild(removeBtn);                     photosContainer.appendChild(thumbDiv);                 });             }                          // 移除照片             function removePhoto(index) {                 capturedPhotos.splice(index, 1);                 updatePhotoThumbnails();             }                          // 重置所有照片             function resetPhotos() {                 if (capturedPhotos.length === 0) return;                                  if (confirm('確定要?jiǎng)h除所有照片嗎?')) {                     capturedPhotos = [];                     updatePhotoThumbnails();                     resultImg.style.display = 'none';                     resultPlaceholder.style.display = 'flex';                 }             }                          // 合并照片             function mergePhotos() {                 if (capturedPhotos.length === 0) {                     alert('請(qǐng)先拍攝至少一張照片!');                     return;                 }                                  // 計(jì)算畫布尺寸                 const maxWidth = 800;                 const thumbWidth = Math.floor(maxWidth / Math.min(capturedPhotos.length, 4));                 const thumbHeight = Math.floor(thumbWidth * 0.75);                 const rows = Math.ceil(capturedPhotos.length / 4);                                  const canvas = document.createElement('canvas');                 canvas.width = Math.min(capturedPhotos.length, 4) * thumbWidth;                 canvas.height = rows * thumbHeight;                                  const ctx = canvas.getContext('2d');                 ctx.fillStyle = '#ffffff';                 ctx.fillRect(0, 0, canvas.width, canvas.height);                                  // 繪制所有照片                 let col = 0, row = 0;                                  for (let i = 0; i < capturedPhotos.length; i++) {                     const img = new Image();                     img.src = capturedPhotos[i];                                          ctx.drawImage(                         img,                          col * thumbWidth,                          row * thumbHeight,                          thumbWidth,                          thumbHeight                     );                                          // 繪制照片邊框                     ctx.strokeStyle = 'rgba(142, 45, 226, 0.5)';                     ctx.lineWidth = 2;                     ctx.strokeRect(                         col * thumbWidth,                          row * thumbHeight,                          thumbWidth,                          thumbHeight                     );                                          col++;                     if (col >= 4) {                         col = 0;                         row++;                     }                 }                                  // 添加標(biāo)題                 ctx.fillStyle = '#4a00e0';                 ctx.font = 'bold 24px Arial';                 ctx.textAlign = 'center';                 ctx.fillText('美好回憶', canvas.width / 2, 30);                                  // 添加日期                 const now = new Date();                 const dateStr = now.toLocaleDateString();                 ctx.fillStyle = '#6c757d';                 ctx.font = '16px Arial';                 ctx.fillText(dateStr, canvas.width / 2, canvas.height - 20);                                  // 顯示結(jié)果                 resultImg.src = canvas.toDataURL('image/png');                 resultImg.style.display = 'block';                 resultPlaceholder.style.display = 'none';             }                          // 下載合影             function downloadResult() {                 if (!resultImg.src || resultImg.style.display === 'none') {                     alert('請(qǐng)先合并照片!');                     return;                 }                                  const link = document.createElement('a');                 link.download = `合影-${new Date().getTime()}.png`;                 link.href = resultImg.src;                 link.click();             }                          // 事件監(jiān)聽             captureBtn.addEventListener('click', capturePhoto);             resetBtn.addEventListener('click', resetPhotos);             mergeBtn.addEventListener('click', mergePhotos);             downloadBtn.addEventListener('click', downloadResult);                          // 初始化攝像頭             initCamera();                          // 初始更新縮略圖             updatePhotoThumbnails();         });     </script> </body> </html>

功能說明

這個(gè)合影工具具有以下功能:

  1. 攝像頭訪問:請(qǐng)求用戶攝像頭權(quán)限并顯示實(shí)時(shí)視頻

  2. 拍照功能:點(diǎn)擊"拍照"按鈕可捕獲當(dāng)前視頻幀為照片

  3. 照片管理:

    1. 顯示所有拍攝照片的縮略圖

    2. 可刪除單張照片

    3. 可重置所有照片

  4. 合影制作:

    1. 將多張照片合并為一張合影

    2. 自動(dòng)排列照片(每行最多4張)

    3. 添加標(biāo)題和日期水印

  5. 下載功能:將合并后的合影下載為PNG圖片

使用說明

  1. 打開頁(yè)面后允許瀏覽器訪問您的攝像頭

  2. 調(diào)整位置,點(diǎn)擊"拍照"按鈕拍攝照片

  3. 可拍攝多張照片(顯示在下方區(qū)域)

  4. 點(diǎn)擊"合并照片"按鈕創(chuàng)建合影

  5. 點(diǎn)擊"下載合影"保存最終圖片

這個(gè)應(yīng)用使用了現(xiàn)代Web API(getUserMedia, Canvas)實(shí)現(xiàn),不需要任何外部庫(kù),在大多數(shù)現(xiàn)代瀏覽器中都能正常工作。

注意:由于安全限制,該頁(yè)面需要在HTTPS環(huán)境或localhost下運(yùn)行才能訪問攝像頭。

 

 

 

 

 

 

聯(lián)系尚武科技
客戶服務(wù)
石家莊APP開發(fā)
400-666-4864
為您提供售前購(gòu)買咨詢、解決方案推薦等1V1服務(wù)!
技術(shù)支持及售后
石家莊APP開發(fā)公司
0311-66682288
為您提供從產(chǎn)品到服務(wù)的全面技術(shù)支持 !
客戶服務(wù)
石家莊小程序開發(fā)
石家莊小程序開發(fā)公司
加我企業(yè)微信
為您提供售前購(gòu)買咨詢、
解決方案推薦等1V1服務(wù)!
石家莊網(wǎng)站建設(shè)公司
咨詢相關(guān)問題或預(yù)約面談,可以通過以下方式與我們聯(lián)系。
石家莊網(wǎng)站制作
在線聯(lián)系:
石家莊Web開發(fā)
石家莊軟件開發(fā)
石家莊軟件開發(fā)公司
ADD/地址:
河北·石家莊
新華區(qū)西三莊大街86號(hào)河北互聯(lián)網(wǎng)大廈B座二層
Copyright ? 2008-2025尚武科技 保留所有權(quán)利。 冀ICP備12011207號(hào)-2 石家莊網(wǎng)站開發(fā)冀公網(wǎng)安備 13010502001294號(hào)《互聯(lián)網(wǎng)平臺(tái)公約協(xié)議》
Copyright ? 2025 dachencms.com, Inc. All rights reserved