将选中的图片下载到本地
img

1.先获取到图片信息

img

2.设置图片信息

img

3.图片下载实现原理解释

  • 首先,创建一个新的 Image 对象,并将图片的 URL 赋值给它。
  • 通过设置 crossOrigin 属性为 “Anonymous”,解决跨域访问的问题。
  • 当图片加载完成后,创建一个新的 canvas 元素,并将图片绘制到 canvas 上。
  • 创建一个新的 a元素作为下载链接,并设置下载的文件名为 imgName ,a.download = filename || url.split('/').pop() || 'downloaded_image.jpg'
  • 将 canvas 的数据转换为 Data URL,并将其赋值给下载链接的 href 属性。
  • 最后,模拟用户点击下载链接,触发图片下载的操作。

js代码

async function downloadImage(url, filename) {
      try {
        // 创建img元素
        const img = new Image();
        img.crossOrigin = 'Anonymous'; // 设置跨域
        
        // 加载图片
        await new Promise((resolve, reject) => {
          img.onload = resolve;
          img.onerror = reject;
          img.src = url + '?t=' + Date.now(); // 添加时间戳防止缓存
        });
        
        // 创建canvas并绘制图片
        const canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        
        // 转换为Blob并下载
        canvas.toBlob(blob => {
          const blobUrl = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = blobUrl;
          a.download = filename || url.split('/').pop() || 'downloaded_image.jpg';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(blobUrl);
        }, 'image/jpeg');
        
      } catch (error) {
        console.error('下载失败:', error);
        // alert('图片下载失败: ' + error.message);
      }
    }
    function downloadSelectedImages() {
      const selectedCheckboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
      
      if (selectedCheckboxes.length === 0) {
        alert('请先选择要下载的图片');
        return;
      }

      selectedCheckboxes.forEach(checkbox => {
        const img = checkbox.closest('.gallery-item').querySelector('img');
        const imgUrl = img.src;
        const filename = imgUrl.split('/').pop() || 'downloaded_image.jpg';
        downloadImage(imgUrl, filename);
      });
    }

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Image_Gallery图片采集</title>
  <style>
    /* 全局样式 */
    * {
      padding: 0;
      margin: 0;
    }

    body {
      font-family: Arial, sans-serif;
    }

    .imgMain {
      width: 99%;
      min-height: 100%;
      border: 1px solid #ccc;
      margin: 10px;
    }

    /* 标题样式 */
    .header {
      font-size: 20px;
      font-weight: bold;
      padding: 10px 10px;
      border-bottom: 1px solid #ccc;
    }

    /* 副标题样式 */
    .sub-header {
      width: 95%;
      font-size: 18px;
      font-weight: bold;
      margin: 20px auto;
      display: flex;
    }

    .sub-header-space {
      width: 500px;
      height: 2px;
      margin-top: 11px;
      border-bottom: 1px solid #ccc;
    }

    .sub-header-item {
      color: #ccc;
    }

    .sub-header-item-selected {
      color: #333;
    }

    /* 图片库样式 */
    .gallery {
      display: flex;
      flex-wrap: wrap;
      align-content: flex-start;
      width: 95%;
      height: 680px;
      margin: 0 auto;
      gap: 5px;
      overflow: auto;
    }

    /*滚动条样式*/
    .gallery::-webkit-scrollbar {
      width: 8px;
    }

    .gallery::-webkit-scrollbar,
    .gallery::-webkit-scrollbar-thumb {
      border-radius: 10px;
      -webkit-box-shadow: inset 0 0 5px rgba(63, 136, 219, 0.5);
      background: rgba(10, 109, 238, 0.5);
    }

    .gallery::-webkit-scrollbar,
    .gallery::-webkit-scrollbar-track {
      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
      border-radius: 0;
      background: rgba(0, 0, 0, 0.1);
    }

    .gallery-item {
      position: relative;
      width: 100px;
      height: 100px;
      margin: 5px;
    }

    .gallery-item img {
      width: 100%;
      height: 100%;
      object-fit: cover;
      cursor: pointer;
      border: 2px solid #2e8cf0;
      /* 添加默认边框线 */
      box-sizing: border-box;
      /* 确保边框不占用额外空间 */
    }

    .gallery-item img.selected {
      border-color: blue;
      /* 选中图片的边框颜色 */
    }

    .gallery-item input[type="checkbox"] {
      position: absolute;
      top: 5px;
      left: 5px;
      z-index: 1;
      width: 26px;
      height: 26px;
    }

    /* 模态框样式 */
    .modal {
      display: none;
      position: fixed;
      z-index: 1;
      padding-top: 60px;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      overflow: auto;
      background-color: rgba(0, 0, 0, 0.9);
    }

    .modal-content {
      margin: auto;
      display: block;
      max-width: 80%;
      max-height: 80%;
    }

    .close {
      position: absolute;
      top: 20px;
      right: 35px;
      color: #fff;
      font-size: 40px;
      font-weight: bold;
      transition: 0.3s;
      cursor: pointer;
    }

    .close:hover {
      color: #bbb;
    }

    .nextButtonBox {
      width: 100%;
      margin-top: 20px;
      border-top: 1px solid #ccc;
      height: 74px;
      position: relative;
      left: 0;
    }

    /* 下一步按钮样式 */
    .next-button {
      margin-top: 20px;
      padding: 10px 20px;
      background-color: #2d8cf0;
      color: white;
      border: none;
      cursor: pointer;
      position: absolute;
      right: 20px;
    }

    .next-button:disabled {
      background-color: #ccc;
      cursor: not-allowed;
    }

    /* 新增删除按钮样式 */
    .delete-btn {
      position: absolute;
      top: 2px;
      right: 2px;
      width: 20px;
      height: 20px;
      background: rgba(255, 0, 0, 0.8);
      border-radius: 50%;
      color: white;
      text-align: center;
      line-height: 20px;
      cursor: pointer;
      display: none;
      z-index: 2;
    }

    .delete-btn::after {
      content: "×";
      font-size: 18px;
    }

    .gallery-item:hover .delete-btn {
      display: block;
    }

    /* 步骤容器 */
    .step-container {
      display: none;
      padding: 10px;
    }

    .step-container.active {
      display: block;
    }

    /*滚动条样式*/
    .info-table::-webkit-scrollbar {
      width: 8px;
    }

    .info-table::-webkit-scrollbar,
    .info-table::-webkit-scrollbar-thumb {
      border-radius: 10px;
      -webkit-box-shadow: inset 0 0 5px rgba(63, 136, 219, 0.5);
      background: rgba(10, 109, 238, 0.5);
    }

    .info-table::-webkit-scrollbar,
    .info-table::-webkit-scrollbar-track {
      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
      border-radius: 0;
      background: rgba(0, 0, 0, 0.1);
    }

    /* 表格样式 */
    .info-table {
      width: 100%;
      border-collapse: collapse;
      margin: 20px 0;
    }

    /* 设置表头为块级元素,以便与tbody对齐 */
    .info-table thead,
    tbody tr {
      display: table;
      width: 100%;
      table-layout: fixed;
    }

    /* 设置tbody为块级元素,并限制高度 */
    .info-table tbody {
      display: block;
      min-height: 500px;
      max-height: 580px;
      /* 设置最大高度 */
      overflow-y: auto;
      /* 当内容超过高度时显示垂直滚动条 */
    }

    /* 设置表头的样式 */
    .info-table thead {
      width: calc(100% - 1em);
      /* 减去滚动条的宽度 */
    }

    .info-table tbody td select {
      width: 180px;
    }

    .info-table th,
    .info-table td {
      border: 1px solid #ddd;
      padding: 8px;
      text-align: left;
    }

    .info-table th {
      background-color: #f2f2f2;
      text-align: center;
    }

    .info-table input {
      width: 100%;
      padding: 5px;
      box-sizing: border-box;
    }

    .info-table tbody tr {
      min-height: 50px;
    }

    /* 操作按钮 */
    .action-buttons {
      display: flex;
      gap: 10px;
      position: relative;
      left: 0;
      min-width: 700px;
    }

    .error-msg {
      display: none;
      color: #515a6e;
      margin-top: 10px;
      position: absolute;
      padding: 10px;
      border-radius: 6px;
      top: 0;
      left: 50%;
      width: 800px;
      text-align: center;
      margin-left: -400px;
      background: #fff;
      /* border: 1px solid #ccc; */
    }
    .msg-success {
      border: 1px solid #8ce6b0;
      background-color: #edfff3;
    }
    
    .msg-error {
      border: 1px solid #ffb08f;
      background-color: #ffefe6;
    }
    /* 表头设置样式 */
    .header-setting {
      /* display: flex; */
      align-items: center;
      gap: 5px;
    }

    .header-setting input {
      width: 150px;
    }

    .header-setting button {
      padding: 5px 10px;
      background-color: #2d8cf0;
      color: white;
      border: none;
      cursor: pointer;
    }

    a {
      text-decoration: none;
      color: #444;
      transition: all .3s;
    }

    div,
    img,
    ul,
    li,
    em,
    p,
    span {
      margin: 0;
      padding: 0;
    }

    ul,
    li {
      list-style: none;
    }

    em,
    p,
    span,
    i {
      font-style: normal;
    }

    input,
    select,
    textarea,
    button {
      margin: 0;
      padding: 0;
      font-size: 14px;
      font-family: 'Source Han Sans SC', 'PingFang SC', 'Microsoft YaHei', Helvetica, Arial, sans-serif;
    }

    /*分页*/
    .mo-pagination {
      min-width: 800px;
      display: block;
      overflow: hidden;
    }

    .mo-pagination-btn {
      float: left;
      height: 30px;
      line-height: 28px;
      box-sizing: border-box;
      border: 1px solid #ddd;
      background: #fff;
      padding: 0 10px;
      margin: 0 5px 5px 0;
      display: block;
      overflow: hidden;
      cursor: pointer;
      transition: all .3s;
      border-radius: 6px;
    }

    .mo-pagination-btn:hover {
      color: #068EFF;
      border-color: #068EFF;
    }

    .mo-pagination-disabled {
      pointer-events: none;
      opacity: .5;
      cursor: not-allowed;
    }

    .mo-pagination-select {
      float: left;
      display: block;
      overflow: hidden;
      line-height: 30px;
      margin: 0 5px 5px 0;
    }

    .mo-pagination-select em {
      float: left;
    }

    .mo-pagination-select select {
      float: left;
      height: 30px;
      line-height: 28px;
      border: 1px solid #ddd;
      background: #fff;
      padding: 0 10px;
      margin: 0 5px;
      display: block;
      overflow: hidden;
      transition: all .3s;
      border-radius: 6px;
    }

    .mo-pagination-select select:hover {
      border-color: #068EFF;
    }

    .mo-pagination-mark {
      float: left;
      height: 30px;
      line-height: 30px;
      padding: 0 10px;
      margin: 0 5px 5px 0;
      display: block;
      overflow: hidden;
    }

    .mo-pagination-num {
      float: left;
      display: block;
      overflow: hidden;
      margin: 0 5px 5px 0;
    }

    .mo-pagination-num a {
      float: left;
      width: 30px;
      text-align: center;
      height: 30px;
      line-height: 28px;
      box-sizing: border-box;
      border: 1px solid #ddd;
      margin: 0 3px;
      display: block;
      overflow: hidden;
      cursor: pointer;
      border-radius: 50%;
    }

    .mo-pagination-num a.active {
      color: #068EFF;
      border-color: #068EFF;
    }

    .mo-pagination-enter {
      float: left;
      display: block;
      overflow: hidden;
      line-height: 30px;
    }

    .mo-pagination-enter em {
      float: left;
    }

    .mo-pagination-enter input {
      width: 50px;
      height: 30px;
      text-align: center;
      line-height: 28px;
      box-sizing: border-box;
      border: 1px solid #ddd;
      background: #fff;
      float: left;
      margin: 0 5px;
      transition: all .3s;
      border-radius: 6px;
    }

    .mo-pagination-enter input:hover {
      color: #068EFF;
      border-color: #068EFF;
    }

    .stepButtonBox {
      width: 100%;
      margin-top: 20px;
      border-top: 1px solid #ccc;
      height: 74px;
      position: relative;
      left: 0;
    }

    /* 下一步按钮样式 */
    .step-button {
      margin-top: 20px;
      padding: 10px 20px;
      background-color: #2d8cf0;
      color: white;
      border: none;
      cursor: pointer;
      position: absolute;
      right: 20px;
    }


  </style>
</head>

<body>
  <div class="imgMain">
    <!-- 步骤1:选择图片 -->
    <div id="step1" class="step-container active">
      <!-- 原有图片选择界面 -->

      <!-- 标题 -->
      <div class="header">图片采集 <span style="color: #2d8cf0;">/ 添加至侵权图库</span></div>

      <!-- 副标题:选择需保留的图片 -->
      <div class="sub-header">
        <div class="sub-header-item sub-header-item-selected">
          1.选择需保留的图片
        </div>
        <div class="sub-header-space"></div>
        <div class="sub-header-item">
          2.填写图片信息
        </div>
      </div>

      <!-- 图片库 -->
      <div class="gallery" id="gallery">
        <!-- Images will be dynamically inserted here -->
      </div>

      <!-- 模态框 -->
      <div id="myModal" class="modal">
        <span class="close">&times;</span>
        <img class="modal-content" id="img01">
      </div>

      <!-- 下一步按钮 -->
      <div class="nextButtonBox">
        <button class="next-button" style="right: 210px;" onclick="downloadSelectedImages()">下载选中图片</button>
        <button class="next-button" style="right: 120px;" onclick="toggleAll()">全选</button>
        <button id="nextButton" class="next-button" disabled>下一步</button>
      </div>
    </div>
  </div>
  <script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
  <script>
   

    const images = [
      'https://cbu01.alicdn.com/img/ibank/O1CN01qSXOXm1jPpTzR7GUs_!!2215737524541-0-cib.jpg_b.jpg',
      'http://10.100.1.200:8888/public/2023-09/22-20-08-37-666/6EE713438-DG.jpg',
      'http://10.100.1.200:8888/public/2019-06/06-20-20-51-764/7HH401674.jpg',
      'http://10.100.1.200:8888/public/2023-09/20-11-13-45-329/6EE713378-R.jpg',
      'http://10.100.1.200:8888/public/2023-11/16-17-22-54-092/1AG202989-E-S.jpg',
      'http://10.100.1.200:8888/public/2023-04/14-18-03-29-123/6EE107530-R.jpg',
      'http://10.100.1.200:8888/public/2022-09/19-14-12-31-471/8YY204605.jpg'
    ];


    const gallery = document.getElementById('gallery');
    const modal = document.getElementById('myModal');
    const modalImg = document.getElementById('img01');
    const nextButton = document.getElementById('nextButton');
    // 下载选中图片功能
    // async function downloadImage(url, filename) {
    //   try {
    //     // 方案1:使用图片代理(推荐)
    //     const proxyUrl = `https://cors-anywhere.herokuapp.com/${url}`;
    //     const response = await fetch(proxyUrl, {
    //       headers: new Headers({
    //         'Origin': window.location.origin,
    //         'Cache-Control': 'no-cache'
    //       })
    //     });
    //     // const response = await fetch(url + '?t=' + Date.now(), { // 添加时间戳防止缓存
    //     //   headers: new Headers({
    //     //     'Cache-Control': 'no-cache'
    //     //   })
    //     // });
    //     if (!response.ok && response.type !== 'opaque') {
    //       throw new Error(`HTTP error! status: ${response.status}`);
    //     }
    //     const blob = await response.blob();
    //     const blobUrl = window.URL.createObjectURL(blob);
    //     const a = document.createElement('a');
    //     a.href = blobUrl;
    //     a.download = filename;
    //     document.body.appendChild(a);
    //     a.click();
    //     window.URL.revokeObjectURL(blobUrl);
    //     document.body.removeChild(a);
    //   } catch (error) {
    //     console.error('下载失败:', error);
    //     // alert('部分图片下载失败,请检查控制台日志');
    //   }
    // }
    async function downloadImage(url, filename) {
      try {
        // 创建img元素
        const img = new Image();
        img.crossOrigin = 'Anonymous'; // 设置跨域
        
        // 加载图片
        await new Promise((resolve, reject) => {
          img.onload = resolve;
          img.onerror = reject;
          img.src = url + '?t=' + Date.now(); // 添加时间戳防止缓存
        });
        
        // 创建canvas并绘制图片
        const canvas = document.createElement('canvas');
        canvas.width = img.width;
        canvas.height = img.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        
        // 转换为Blob并下载
        canvas.toBlob(blob => {
          const blobUrl = URL.createObjectURL(blob);
          const a = document.createElement('a');
          a.href = blobUrl;
          a.download = filename || url.split('/').pop() || 'downloaded_image.jpg';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(blobUrl);
        }, 'image/jpeg');
        
      } catch (error) {
        console.error('下载失败:', error);
        // alert('图片下载失败: ' + error.message);
      }
    }
    function downloadSelectedImages() {
      const selectedCheckboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
      
      if (selectedCheckboxes.length === 0) {
        alert('请先选择要下载的图片');
        return;
      }

      selectedCheckboxes.forEach(checkbox => {
        const img = checkbox.closest('.gallery-item').querySelector('img');
        const imgUrl = img.src;
        const filename = imgUrl.split('/').pop() || 'downloaded_image.jpg';
        downloadImage(imgUrl, filename);
      });
    }

    let isAllSelected = false; // 全局状态记录全选状态

    function toggleAll() {
      const checkboxes = document.querySelectorAll('.gallery-item input[type="checkbox"]');
      isAllSelected = !isAllSelected; // 切换全选/反选状态
      
      checkboxes.forEach(checkbox => {
        checkbox.checked = isAllSelected;
      });
      
      updateNextButton(); // 更新下一步按钮状态
      updateButtonText(); // 更新按钮文字
    }

    function updateButtonText() {
      const btn = document.querySelector('.next-button[style*="right: 120px"]');
      btn.textContent = isAllSelected ? '反选' : '全选';
    }
    // 初始化数据
    var initialImages = [
      // "http://10.100.1.200:8888/public/2024-08/15-18-57-39-747/13AC1304299.jpg",
      // "http://10.100.1.200:8888/public/2024-08/28-10-16-59-448/2SS322764.jpg"
    ];

    // Function to update the next button state
    function updateNextButton() {
      const selectedImages = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
      nextButton.disabled = selectedImages.length === 0;
    }

    // Function to handle the next step
    function handleNextStep() {
      const selectedImages = document.querySelectorAll('.gallery-item input[type="checkbox"]:checked');
      const selectedImageUrls = Array.from(selectedImages).map(checkbox => {
        return checkbox.closest('.gallery-item').querySelector('img').src;
      });
      console.log("img", selectedImageUrls);
      initialImages = selectedImageUrls
      // alert('Selected Images: ' + selectedImageUrls.join(', '));
    }

    // 修改图片创建逻辑,增加删除按钮
    function createGalleryItems() {
      images.forEach((src, index) => {
        const galleryItem = document.createElement('div');
        galleryItem.className = `gallery-item Image_${index + 1}`;

        // 创建删除按钮
        const deleteBtn = document.createElement('div');
        deleteBtn.className = 'delete-btn';

        // 删除按钮点击事件
        deleteBtn.addEventListener('click', function (e) {
          e.stopPropagation(); // 阻止事件冒泡
          galleryItem.remove(); // 移除图片项
          updateNextButton(); // 更新按钮状态
        });

        const img = document.createElement('img');
        img.src = src;
        img.alt = `Image ${index + 1}`;

        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.addEventListener('change', updateNextButton);

        img.addEventListener('click', function () {
          // if (!checkbox.checked) {
          modal.style.display = 'block';
          modalImg.src = this.src;
          // }
        });

        galleryItem.appendChild(deleteBtn); // 添加删除按钮
        galleryItem.appendChild(checkbox);
        galleryItem.appendChild(img);
        gallery.appendChild(galleryItem);
      });
    }

    // Close modal when clicking the close button
    document.querySelector('.close').addEventListener('click', function () {
      modal.style.display = 'none';
    });

    // Handle next button click
    nextButton.addEventListener('click', handleNextStep);
    // 延迟两秒钟执行图片创建逻辑
    document.addEventListener('DOMContentLoaded', () => {
      setTimeout(() => {
        createGalleryItems();
      }, 1000); // 延迟两秒钟
    });

    // 全局数据存储
    let allData = [];
    let currentStep = 1;


    let currentPage = 1;
    let pageSize = 10;
    let totalImages = 0;

    // 步骤切换
    function goToStep(step) {
      console.log('步骤切换', step);
      document.querySelectorAll('.step-container').forEach(el => {
        el.classList.remove('active');
      });
      document.getElementById(`step${step}`).classList.add('active');
      // currentStep = step;

      if (step === 2) {
        initPagination();
        generateTable(initialImages);
      }
    }

    function goBack() {
      goToStep(1);
    }

    

    // 初始化
    document.addEventListener('DOMContentLoaded', () => {
      // 从第一步的下一步按钮调用
      document.getElementById('nextButton').addEventListener('click', () => {
        goToStep(2);
      });
    });

  </script>

</body>

</html>
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐