使用前端js库pica压缩图片

pica

浏览器中的高质量图像大小调整

在浏览器中调整图像大小,无需像素化,速度相当快。自动选择最好的可用技术:webworkers、webassembly、createImageBitmap、纯JS。

简单使用

<script src="./plugins/pica.min.js"></script>

<script>
  function resizeImage(img_path, file_name) {
    const img = new Image();
    img.src = img_path;
    img.onload = function () {
      const canvas = document.createElement("canvas");
      canvas.width = img.width;
      canvas.height = img.height;

      const pica = window.pica({ features: ["all"] });
      pica
        .resize(img, canvas)
        .then((result) => pica.toBlob(result, "image/jpeg", 0.9))
        .then((blob) => {
          const blob_obj = new Blob([blob], {
            type: "image/jpeg",
          });
          const link = document.createElement("a");
          link.href = window.URL.createObjectURL(blob_obj);
          link.download = file_name + ".jpg";
          link.click();
          window.URL.revokeObjectURL(link.href);
        });
    };
  }

  resizeImage("./images/1.jpg", "download");
</script>

批量压缩文件域选择的图片并打包下载

<script src="./plugins/pica.min.js"></script>
<script src="./plugins/jszip.min.js"></script>
<script src="./plugins/FileSaver.js"></script>
<input type="file" id="files" multiple onchange="previewImages(this)" accept="image/*" />
<div id="con-obj" class="container"></div>
<div id="con-data" class="container"></div>
<div id="con-resize" class="container"></div>
<script>
  function previewImages(this_obj) {
    const elem_con_obj = document.querySelector("#con-obj");
    const elem_con_data = document.querySelector("#con-data");
    const elem_con_resize = document.querySelector("#con-resize");

    const file_list = [];
    for (let i in this_obj.files) {
      const file = this_obj.files[i];
      if (["image/jpeg", "image/png"].indexOf(file.type) < 0) continue;
      file_list.push(file);
    }

    Promise.all(
      file_list.map((file) => {
        return new Promise((resolve, reject) => {
          //预览
          const elem_img = document.createElement("img");
          elem_img.src = window.URL.createObjectURL(file);
          elem_con_obj.append(elem_img);
          console.log(elem_img.src);//blob:http://localhost:3000/80e8fa2c-caa1-4a23-a6d2-01bdac2843e2

          const file_reader = new FileReader();
          file_reader.readAsDataURL(file);
          file_reader.onload = (e) => {
            const img = new Image();
            img.src = e.target.result;
            img.onload = function () {
              //预览
              elem_con_data.append(img);
              console.log(img.src);//data:image/png;base64,iVBORw0...

              const canvas = document.createElement("canvas");
              canvas.width = img.width;
              canvas.height = img.height;

              //压缩
              const pica = window.pica({ features: ["all"] });
              pica
                .resize(img, canvas)
                .then((result) => pica.toBlob(result, "image/jpeg", 0.9))
                .then((blob) => {
                  resolve({ blob: blob, file_name: file.name });

                  //预览
                  const elem_img_resize = document.createElement("img");
                  elem_img_resize.src = window.URL.createObjectURL(blob);
                  elem_con_resize.append(elem_img_resize);
                  console.log(elem_img_resize.src);//blob:http://localhost:3000/d2868663-aef0-48a2-8bdc-5e6d9f168a2e
                });
            };
            img.onerror = function () {
              reject("not a image");
            };
          };
          file_reader.onerror = function () {
            reject("read error");
          };
        });
      })
    )
      .then((images) => {
        console.log(images);
        const zip = new JSZip();
        for (let i in images) {
          zip.file(images[i]["file_name"], images[i]["blob"]);
        }
        zip.generateAsync({ type: "blob" }).then((blob) => {
          saveAs(blob, "compress.zip");
        });
      })
      .catch((err) => {
        console.error("Error packaging images:", err);
      });
  }
</script>

 以上方法由于使用了Promise.all 保证了所有图片压缩完成后进行打包下载,然而由于Promise.all的特性,若图片中出现伪装成图片的文件会导致当前Promise走向reject,进一步导致了Promise.all 的失败。

尝试解决这个问题,使用Promise.allSettled 改写上面的代码。

<script>
  function previewImages(this_obj) {
    const elem_con_obj = document.querySelector("#con-obj");
    const elem_con_data = document.querySelector("#con-data");
    const elem_con_resize = document.querySelector("#con-resize");

    const file_list = [];
    for (let i in this_obj.files) {
      const file = this_obj.files[i];
      if (["image/jpeg", "image/png"].indexOf(file.type) < 0) continue;
      file_list.push(file);
    }

    Promise.allSettled(
      file_list.map((file) => {
        return new Promise((resolve, reject) => {
          //预览
          const elem_img = document.createElement("img");
          elem_img.src = window.URL.createObjectURL(file);
          elem_con_obj.append(elem_img);

          const file_reader = new FileReader();
          file_reader.readAsDataURL(file);
          file_reader.onload = (e) => {
            const img = new Image();
            img.src = e.target.result;
            img.onload = function () {
              //预览
              elem_con_data.append(img);

              const canvas = document.createElement("canvas");
              canvas.width = img.width;
              canvas.height = img.height;

              //压缩
              const pica = window.pica({ features: ["all"] });
              pica
                .resize(img, canvas)
                .then((result) => pica.toBlob(result, "image/jpeg", 0.9))
                .then((blob) => {
                  resolve({ blob: blob, file_name: file.name });

                  //预览
                  const elem_img_resize = document.createElement("img");
                  elem_img_resize.src = window.URL.createObjectURL(blob);
                  elem_con_resize.append(elem_img_resize);
                });
            };
            img.onerror = function () {
              reject("not a image");
            };
          };
          file_reader.onerror = function () {
            reject("read error");
          };
        });
      })
    )
      .then((images) => {
        console.log(images);
        const zip = new JSZip();
        for (let i in images) {
          if (images[i]["status"] == "rejected") continue;

          const image = images[i]["value"];
          zip.file(image["file_name"], image["blob"]);
        }
        zip.generateAsync({ type: "blob" }).then((blob) => {
          saveAs(blob, "compress.zip");
        });
      })
      .catch((err) => {
        console.error("Error packaging images:", err);
      });
  }

    
</script>

即可保证所有真正的图片可以正常压缩和打包下载。 

posted @ 2024-08-14 16:20  carol2014  阅读(4)  评论(0编辑  收藏  举报