How to implement image downloading on the front end

1. Introduction

? In my work some time ago, I encountered a scenario where I clicked a button to download a picture. This is a very common scenario in business, but what is special is that this time I need to browse on the mobile terminal. Click-to-download can be realized in scenarios such as browsers and WeChat internal browsers. After many explorations and practices, I finally found that with my current ability and available information, in today’s complex domestic mobile browser environment (Baidu Browser, QQ Browser, UC Browser, Quark Browser) and the built-in browsers of major mobile phone manufacturers, etc.), each of them has different security strategies. It is impossible to implement a universal click-to-download covering all mainstream browsers on the mobile terminal, because The various implementation methods I know basically rely on the tag or the

form for downloading. However, in most mobile browsers, This behavior will be intercepted by default, making downloading impossible.

? And another point is: under any scheme, the front end cannot bypass cross-domain restrictions, so the server where the image is located needs to have permissions for your current domain name, otherwise it will not be downloadable. Do view pictures.

? The final solution is: After communicating with the demander and the product, we decided to modify the page logic and prompt the user to press and hold to save the image to enable downloading. Of course, if anyone has a good solution to achieve click-to-download on the mobile terminal, you are welcome to share your advice in the comment area.

? Of course, the exploration of various solutions I did in the early stage is naturally not in vain. These solutions can be used normally on the PC side, but various problems will occur on the mobile side, which is why I have this blog. , sharing a variety of image downloading methods.

2. Specific plans

1. Directly use the download attribute of the tag (recommended)

? This is the first solution I tried. The advantage of this solution is that the code is simple and clear. You only need to add the download attribute to the tag and add the image Just assign the address to the href attribute. The disadvantage is that this method can only download files with the same origin URL or blob:, data: protocol. For images from non-original sources, it can only Implement viewing.

? The pictures I want to download in my business are placed under another resource server and are not under the same domain name, so I gave up the plan.

Implementation code:

<a href="https://example.com/image.jpg" download="image.jpg">Download image</a>
2. canvas object + tag (recommended)

? This is the solution I implemented on the PC before. Convert the image to base64 format through the canvas object, and then assign it to the href< of the tag. /code> attribute, trigger download through click event. This solution can be used on the PC to download same-original images or non-original images but images with CORS set on the server side. However, on the mobile end, it is found that the image cannot be downloaded from Xiaomi (Redmi). ), Huawei, vivo and other mobile phones can be downloaded in the native browser, but major browsers will intercept the download behavior of the tag. The specific manifestations are different, but ultimately the download cannot be achieved.

Implementation code:

function download(item) {<!-- -->
  //Create a picture Image object
  let image = new Image();
  // Use CORS to request this picture. The server needs to set CORS to cooperate.
  image.setAttribute("crossOrigin", "anonymous");
  //Operate after the image is loaded
  image.onload = function () {<!-- -->
    // Generate canvas image
    let canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    let context = canvas.getContext("2d");
    context.drawImage(image, 0, 0, image.width, image.height);
    // Get the base64 encoded data of the image
    let url = canvas.toDataURL("image/png");
    // Generate an a element
    let a = document.createElement("a");
     //Create a click event
    let event = new MouseEvent("click");
    //Set the download attribute, which is the file name after downloading
    a.download = item.diplomaCode || "photo";
    // Set the generated base64 encoded data to the a.href attribute
    a.href = url;
    // Trigger the click event of a to download
    a.dispatchEvent(event);
  };
  //Set the image address and start loading
  image.src = item.imgUrl;
}
3. ajax request (blob or base64 format) + tag (recommended)

? This solution is to obtain the image file stream in blob or base64 format through an ajax request, and then download it through the tag. This method can normally download same-original images or non-original images with CORS set on the server side on the PC side, but it will also be viewed by major browsers on the mobile side. The server intercepts the download behavior of the tag, so that the download cannot be realized in the end.

? If you want to obtain blob type data, you only need to configure the responseType attribute of the ajax request on the front end, without back-end cooperation. If you want to obtain data in base64 format, you need the backend to cooperate in modifying the data, and the frontend does not need to do any special configuration.

Implementation code:

// Get blob type data for download
function download2(item) {<!-- -->
  //Create ajax request
  var xhr = new XMLHttpRequest();
  xhr.open("GET", item.imgUrl, true);
  //Set the response data of the request to blob type
  xhr.responseType = "blob";
// After the request is successful
  xhr.onload = function () {<!-- -->
    if (this.status === 200) {<!-- -->
      // Convert response data into blob object
      var blob = new Blob([this.response], {<!-- --> type: "image/jpeg" });
      // Convert the blob into a url object
      var url = URL.createObjectURL(blob);
      //Create a tag and click to download
      var a = document.createElement("a");
      a.href = url;
      a.download = item.diplomaCode || "photo";
      a.click();
      // Clear the temporary url object to free up memory
      URL.revokeObjectURL(url);
    }
  };
\t// send request
  xhr.send();
}
4. domtoimage + tag (not recommended)

? This method is what I found after the above practice, which is to convert the data into base64 or blob type data, and then download it through the tag, and then I thought of it. , after rendering the image on the page, then use the domtoimage dependency package to convert the dom element of the image into a base64 format image, and then download it.
Facts have proved that this solution is somewhat suspicious of taking off your pants and farting. Of course, due to the same restrictions as above, it cannot be rendered on the mobile side and cannot download cross-domain images.

Implementation code:

<img src="//i2.wp.com/..." alt="" id="ZS1" />

<script>
function download3() {<!-- -->
  // Generate images in base64 format by relying on DOM elements rendered based on images.
  domtoimage.toPng(document.querySelector(`#ZS1`)).then((dataUrl) => {<!-- -->
    //Create an a element
    let a = document.createElement("a");
    //Set the download attribute
    a.download = "xkw certificate";
    // Set the generated base64 to the a.href attribute
    a.href = dataUrl;
    // click to download
    a.click();
  });
}
</script>
5. form form (not verified, for reference only)

? This solution uses the form form element to implement image downloading. The server needs to set the value of the response header Content-Disposition of the image stream, which is equivalent to attaching the image as a file. Download in the form, please see the second and third articles in the reference document for specific related content.

? However, this solution requires the cooperation of the server and will affect other projects that use the image. Therefore, I have not conducted actual verification. If there are experts who have verified it, you can say it in the comment area.

Implementation code:

function download4() {<!-- -->
//Create a hidden form
const form = document.createElement('form');
form.style.display = 'none';
  //The request address is the image address
form.action = '/imgurl....';
//Set the submission request to post
form.method = 'post';
form.target = '_blank';
document.body.appendChild(form);
const params = {<!-- -->;
name: 'test.jpg';
};
// Create input to pass parameters
for (let key in params) {<!-- -->;
let input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = params[key];
form.appendChild(input);
};
  //Make a submission request
form.submit();
form.remove();
}
6. iframe (not verified, not recommended)

? This solution is only supported in IE. You need to use the document.execCommand('SaveAs') command to open and save the image through iframe. The image is required to be the same source.

Implementation code:

function download5(item) {<!-- -->
  const iframe = document.createElement("iframe");
  iframe.style.display = "none";
  iframe.onload = () => {<!-- -->
    iframe.contentWindow.document.execCommand("SaveAs");
    document.body.removeChild(iframe);
  };
  iframe.src = item.imgUrl;
  document.body.appendChild(iframe);
}

3. Reference documents

MDN’s a tag documentation

Reference blog

Content-Disposition

syntaxbug.com © 2021 All Rights Reserved.