Blob objects and web page file export and download

Blob objects and web page file export and download

This article compiles and records the use of Blob objects in Web Api and how to use Blob objects and URL interfaces to implement the download function of file streams. It also introduces the front-end downloading of CSV files and the compressed downloading process of images.

1.Blob object

A Blob object represents an immutable, raw data file-like object. Blobs do not necessarily represent data in JavaScript's native format. The File interface is based on Blob, inheriting the functions of blob and extending it to support files on the user system.

To construct a Blob from other non-blob objects and data, use the Blob() constructor.

Blob constructor

The Blob() constructor returns a new Blob object. The contents of the blob consist of the concatenation of the values ​​given in the parameter array.

grammar:

var aBlob = new Blob( array, options );

Among the parameters:

  • Array: It is an Array composed of ArrayBuffer, ArrayBufferView, Blob, DOMString and other objects, or a mixture of other similar objects, which will be put into the Blob. DOMStrings will be encoded as UTF-8.
  • options: is an optional BlobPropertyBag dictionary, which may specify the following two attributes:
    • type: The default value is "", which represents the MIME type of the array content that will be placed into the blob.
    • endings, the default value is "transparent", used to specify how strings containing the line terminator \n are written. It is one of the following two values:
      • "native" means that the line terminators will be changed to newlines appropriate for the host operating system's file system, or
      • "transparent" means that the terminator saved in the blob will be kept unchanged.

like:

var aFileParts = ['<a id="a"><b id="b">hey!</b></a>']; // 一个包含DOMString的数组
var oMyBlob = new Blob(aFileParts, {
    
    type : 'text/html'}); // 得到 blob

Blob properties

Blob.size

Read only . The size, in bytes, of the data contained in the Blob object.

Blob.type

Read only . A string indicating the MIME type of the data contained in this Blob object. If the type is unknown, the value is an empty string.

method

Blob.slice([start[, end[, contentType]]])

Returns a new Blob object containing the data in the specified range of the source Blob object.

Blob.close()

Close the Blob object so that the underlying resources can be released.

Compatibility

IE requires IE10 and above, and mobile terminals are basically fully compatible.

To be on the safe side, you can also perform compatibility processing and the compatibility processing function:

/**
 * 获取blob对象的兼容性写法
 * @param buffer
 * @param format
 * @returns {*}
 */
function getBlob(buffer, format) {
    
    
    try {
    
    
        return new Blob(buffer, {
    
    type: format});
    } catch (e) {
    
    
        var bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder);
        buffer.forEach(function(buf) {
    
    
            bb.append(buf);
        });
        return bb.getBlob(format);
    }
}

*Multiple upload

In fact, it means dividing the file into multiple blob files and uploading them one by one. like:

const BYTES_PER_CHUNK = 1024 * 1024; // 每个文件切片大小定为1MB .
let blob = document.getElementById('file').files[0],	// 有个input,id叫file
	slices = Math.ceil(blob.size / BYTES_PER_CHUNK);
let blobs = [];
slices.forEach(function(item, index) {
    
    
    blobs.push(blob.slice(index,index + 1));
});

// ajax上传...

2. Common file types (MIME Type)

MIME (Multipurpose Internet Mail Extensions) is an Internet standard for describing the content type of a message, that is, the media type of the file. The browser can distinguish files based on it and then decide what content to display in what form.

suffix MIME Type
.html text/html
.txt text/plain
.csv text/plain
.rtf application/rtf
.gif image/gif
.ipeg,.jpg image/jpeg
.au audio/basic
.mid, .midi audio/midi, audio/x-midi
.ra,.ram audio/x-pn-realaudio
.avi video/x-msvideo
.doc application/msword
.docx application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls application/vnd.ms-excel
.xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.ppt application/vnd.ms-powerpoint
.pptx application/vnd.openxmlformats-officedocument.presentationml.presentation
.gz application/x-gzip
.tar application/x-tar

More types can be found at http://tool.oschina.net/commons/ or https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types

3. Implement a front-end CSV file download

*CSV file

Comma-Separated Values ​​(CSV), sometimes called character-separated values ​​because the separator character does not have to be a comma, are files that store tabular data (numbers and text) in plain text. Plain text means that the file is a sequence of characters and contains no data that must be interpreted like a binary number. A CSV file consists of any number of records, separated by some kind of newline character; each record consists of fields, and the separators between fields are other characters or strings, most commonly commas or tabs. Typically, all records have exactly the same sequence of fields. Usually these are plain text files. It is recommended to use WORDPAD or Notepad to open it, and then save a new file first and then open it with EXCEL. This is also one of the methods.

Simply put, it is a data set file format.

arrayToCSV

We all know that whether the interface returns or local data, the js data format is mostly JSON format, so the method of converting JSON to CSV string is particularly important.

Go directly to the function:

/**
 * @function arrayToCSV
 * @param {array} arr 
 * @param {string} delimiter 
 */
export function arrayToCSV(arr, delimiter = ',') {
    
    
    return arr.map(v => v.map(x => `"${
      
      x}"`).join(delimiter)).join('\n');
}

For example, there is now such data:

let data = [
	['tit', 'val', 'date'],
	['csv', '10', '2019-10-18'],
	['jpg', '8', '2019-10-17'],
	['docx', '1', '2019-10-16'],
];

arrayToCSV(data);	// '"tit","val","date"\n"csv","10","2019-10-18"\n"jpg","8","2019-10-17"\n"docx","1","2019-10-16"'

Generate files using Blobs

let dataString = arrayToCSV(data);
let blobContent = new Blob(
        [dataString],
        {
    
    type: `text/plain`}	// csv的MIME TYPE
    );

After the file is generated, the download event of the browser needs to be triggered. At this time, the help of the following URL interface is needed.

Chinese encoding

When it comes to Chinese in the data content, you need to pay attention to Chinese encoding. The solution at this time is to set the charset and add the identification prefix. like

let blobContent = new Blob(
        ['ufeff' + dataString],	// 添加前缀
        {
    
    type: 'text/plain,charset=utf-8'}	// utf-8
    );

URL interface object

The URL interface is an object containing several static methods for creating URLs. (When using a user agent that does not implement this constructor, this object can be accessed through the Window.URL property (browsers based on Webkit and Blink kernels can use Window.webkitURL instead).)

URL.createObjectURL()

The URL.createObjectURL() static method creates a DOMString containing a URL representing the object given in the argument. The life cycle of this URL is bound to the document in the window in which it was created. This new URL object represents the specified File object or Blob object.

grammar:

objectURL = window.URL.createObjectURL(object);
URL.revokeObjectURL()

The URL.revokeObjectURL() static method is used to release a previously existing URL object created by calling URL.createObjectURL(). When you are finished using a URL object, you should call this method to let the browser know that you no longer need to keep a reference to the file in memory.

You can call revokeObjectURL() at any time after the sourceopen is processed. This is because createObjectURL() simply means associating the src attribute of a media element to a MediaSource object. Calling revokeObjectURL() returns the underlying object to its original location, allowing the platform to perform garbage collection at the appropriate time.

grammar:

window.URL.revokeObjectURL(objectURL);

Use URL interface object and a tag to implement downloading

let blobUrl = window.URL.createObjectURL(blobContent);	// 之前生成的字符串
let eleLink = document.createElement('a');

if (!('download' in eleLink)) return false;	// 是否支持a标签下载

eleLink.download = `test.csv`;	// 文件名
eleLink.style.display = 'none';
eleLink.href = blobUrl;

document.body.appendChild(eleLink);
eleLink.click();	// 模拟点击事件
document.body.removeChild(eleLink)

4. Implement an image compression and download

Image Compression

With the help of canvas. There are two solutions: one is to reduce the size of the image, and the other is to weaken the accuracy of the color value of the image. Go directly to the function:

/**
 * @function compressImg
 * @param {image object} img
 * @param {number} rate
 * @return {string} image base64
 */
export function compressImg(img, rate = 0.9) {
    
    
  let canvas = document.createElement("canvas"),
	  ctx = canvas.getContext('2d');
  
  let tCanvas = document.createElement("canvas"),
	  tctx = tCanvas.getContext("2d");

  let width = img.width;
  let height = img.height;
  
  // 如果图片过大,缩小
  let ratio;
  if ((width > 700 || height > 700) && (ratio = width * height / 500000) > 1) {
    
    
    ratio = Math.sqrt(ratio);
    width /= ratio;
    height /= ratio;
  } else {
    
    
    ratio = 1;
  }
  
  let count;
  
  canvas.width = width;
  canvas.height = height;
  
  ctx.fillStyle = "#fff";	// 铺底色
  ctx.fillRect(0, 0, width, height);
  if ((count = width * height / 600000) > 1) {
    
    
    count = ~~(Math.sqrt(count) + 1); // 分成多少块瓦片
    // 每块瓦片的宽和高
    let nw = ~~(width / count);
    let nh = ~~(height / count);
    tCanvas.width = nw;
    tCanvas.height = nh;
    for (var i = 0; i < count; i++) {
    
    
      for (var j = 0; j < count; j++) {
    
    
        tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
        ctx.drawImage(tCanvas, i * nw, j * nh);
      }
    }
  } else {
    
    
    ctx.drawImage(img, 0, 0, width, height);
  }
  
  let ndata = canvas.toDataURL('image/jpeg', rate);

  tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
  return ndata;
}

For example, such a picture link: http://blog.michealwayne.cn/images/icons/js.png, the call is as follows

let _img = new Image();
_img.onload = () => {
    
    
	let base64 = compressImg(_img, 0.8);	// 压缩后的图片base64
}
_img.src = 'http://blog.michealwayne.cn/images/icons/js.png'

If you are inputting an uploaded image file, you need to use URL.createObjectURL() to convert it to a URL first, and then convert it to base64.

Convert base64 to image blob

You need to use the window.atob and Uint8Array() functions, see "base64 encoding and decoding in the browser"

let text = window.atob(base64.split(',')[1]);
let buffer = new Uint8Array(text.length);

for (let i = 0; i < text.length; i++) {
    
    
    buffer[i] = text.charCodeAt(i);
}

let blobContent = new Blob([buffer], 'image/jpeg');

Realize download

let blobUrl = window.URL.createObjectURL(blobContent);	// 之前生成的字符串
let eleLink = document.createElement('a');

if (!('download' in eleLink)) return false;

eleLink.download = `test.jpg`;	// 文件名
eleLink.style.display = 'none';
eleLink.href = blobUrl;

document.body.appendChild(eleLink);
eleLink.click();	// 模拟点击事件
document.body.removeChild(eleLink)

Get it done and call it a day.


Related Links

Guess you like

Origin blog.csdn.net/qq_24357165/article/details/102719483