предисловие
Эта статья объясняет концепцию двоичного файла простым способом с помощью изображений и текстов.Предыдущие описания концепции скучны, но очень важны! Надеюсь, все будут терпеливо смотреть вниз, сзади будут сюрпризы, которые точно заставят вас трепетать~😉
Blob
Blob
Представляет большой объект двоичного типа, обычно файл изображения, звука или мультимедиа. В javaScript Blob представляет собой неизменяемый примитивный объект, похожий на файл данных.
Его конструктор выглядит следующим образом:
new Blob(blobParts, options);
-
lobParts
: Тип массива, может хранить любое количествоArrayBuffer, ArrayBufferView, BlobилиDOMString(будут закодированы как UTF-8), объедините их, чтобы сформировать данные объекта Blob. -
options
: необязательный, используется для установки свойств объекта blob, вы можете указать следующие два свойства:- тип: содержимое массива, хранящегося в большом двоичном объектеMIMEТип (по умолчанию "").
- окончания: используется для указания того, как записываются строки, содержащие окончания строк \n. значениеnativeУказывает, что признак конца строки будет изменен на символ новой строки, подходящий для файловой системы основной операционной системы (по умолчаниюtransparentУказывает, что терминатор, сохраненный в большом двоичном объекте, останется неизменным)
DOMString 是一个UTF-16字符串。由于JavaScript已经使用了这样的字符串,所以DOMString直接映射到 一个String。
ArrayBuffer(二进制数据缓冲区)、ArrayBufferView(二进制数据缓冲区的array-like视图)
Пример ниже👇
- Создайте объект большого двоичного объекта, содержащий объект domstring.
const blob = new Blob(['<div>john</div>'], { type: 'text/xml' });
console.log(blob); // Blob {size: 15, type: "text/xml"}
- Создайте объект большого двоичного объекта, содержащий объекты массива буферов.
var abf = new ArrayBuffer(8);
const blob = new Blob([abf], { type: 'text/plain' });
console.log(blob); // Blob {size: 8, type: "text/plain"}
- Создайте объект большого двоичного объекта, содержащий объекты arraybufferview.
var abf = new ArrayBuffer(8);
var abv = new Int16Array(abf);
const blob = new Blob(abv, { type: 'text/plain' });
console.log(blob); // Blob {size: 4, type: "text/plain"}
Атрибуты
Объект Blob имеет два свойства, см. следующую таблицу👇:
Имя свойства | описывать |
---|---|
size | Размер данных, содержащихся в объекте Blob. Байт - это единица измерения. Только чтение. |
type | Строка, указывающая тип MIME данных, содержащихся в этом объекте большого двоичного объекта. Если тип неизвестен, значением является пустая строка. Только чтение. |
метод
-
slice(start:number, end:number, contentType:DOMString)
: подобный массивуsliceметод, который делит исходный объект большого двоичного объекта на новые объекты больших двоичных объектов в соответствии с указанным диапазоном и возвращает их, что можно использовать в качестве загрузки фрагмента- start: начальный индекс, по умолчанию 0
- end: конечный индекс, по умолчанию последний индекс
- ContentType: Тип MIME новый BLOB, пустая строка по умолчанию
-
stream()
: возвращает большой двоичный объект, который может прочитать содержимое большого двоичного объекта.ReadableStream. -
text()
: возвращаетPromiseобъект и содержит все содержимое большого двоичного объекта в формате UTF-8.USVString. -
arrayBuffer()
: возвращаетPromiseобъект и содержит все содержимое большого двоичного объекта в двоичном форматеArrayBuffer.
Сохраните двоичный файл большого двоичного объекта (или файла) вformData
Сделайте сетевой запрос (URL-адрес изображения, который можно получить позже, можно использовать для отображения изображения или последующей передачиwebsocket
пришлите адрес фото)
File
File
Объект представляет собой специальный объект Blob, который наследует все свойства и методы Blob.Конечно, он также может использоваться в качестве загрузки бинарного файла formData.
Получение файла:
Ниже мы используем методы ввода и перетаскивания для выбора нескольких изображений соответственно👇:
- ввод получить локальный файл
<input type="file" multiple id="f" />
<script>
var elem = document.getElementById('f');
elem.onchange = function (event) {
var files = event.target.files;
console.log(files); // [{{name: "1.jpg",lastModified: 1594369580771...},{name:'2.jpg',lastModified: 1596012406708...}]
var file = files[0];
console.log(file); // {name: "1.jpg",lastModified: 1594369580771,size: 22344,type: "image/jpeg"...}
console.log(file instanceof File); //true
console.log(files instanceof FileList); // true
/* File继承Blob */
console.log(file.__proto__.__proto__); // Blob {size: 22344, type: ""}
};
</script>
- Перетащите приобретение
<div id="content" ondrop="drop(event)" ondragover="allowDrop(event);" /> <script> function allowDrop(ev) { ev.preventDefault(); } function drop(ev) { ev.preventDefault(); const files = ev.dataTransfer.files; console.log(files); // [{{name: "1.jpg",lastModified: 1594369580771...},{name:'2.jpg',lastModified: 1596012406708...}] console.log(files instanceof FileList); // true } </script> <style type="text/css"> #content { width: 500px; height: 500px; border: 1px solid brown; } </style>
добавить к элементу ввода
multiple
Атрибут позволяет пользователю выбирать несколько файлов.Каждый файл, выбранный пользователем, является файловым объектом, а объект FileList представляет собой список этих файловых объектов, представляющих все файлы, выбранные пользователем, который представляет собой набор файловых объектов.
Атрибуты
Свойства файлового объекта см. ниже:
Имя свойства | описывать |
---|---|
lastModified | Дата последнего изменения ссылочного документа |
name | имя файла или путь к файлу |
size | Возвращает размер файла в байтах |
type | MIME-тип файла |
метод
Объект File не имеет собственного метода экземпляра, поскольку он наследуется от объекта Blob, поэтому можно использовать метод slice() экземпляра Blob.
буфер данных
от
XHR
,File API
,Canvas
В разных местах я читаю большую строку байтовых потоков, если я использую массив в JS для ее хранения, это расточительно и неэффективно. В программировании,数据缓冲区
(или просто буфер) — это область хранения в физической памяти для манипулирования двоичными данными (быстрее, чем доступ к жесткому диску), используемая для хранения временных данных при их перемещении из одного места в другое,解释器
Строки считываются с помощью буфера памяти, в котором хранятся двоичные данные. В основной памяти есть работающий файл, и если интерпретатору придется вернуться к файлу, чтобы прочитать каждый бит, выполнение займет много времени. Чтобы предотвратить это, JavaScript использует буфер данных, который хранит некоторые биты вместе, а затем отправляет все биты вместе интерпретатору. Таким образом, интерпретатору JavaScript не нужно беспокоиться об извлечении файла из файловых данных. Такой подход экономит время выполнения и ускоряет работу приложения. Различные классы буферов выполняют эффективные бинарные операции с данными, в том числеFile
,Blob
,ArrayBuffer
а такжеArray
. Выбранный метод определяет внутреннюю структуру буфера в памяти.
Buffer
Buffer
даNode.js
Предоставленный объект, интерфейс не имеет. Он обычно используется вIO操作
Например, при получении данных внешнего запроса область буфера, предназначенная для хранения двоичных данных, может быть создана с помощью связанного с буфером API для интеграции полученных внешних данных.Буфер похож на целочисленный массив, но он соответствуетV8
Часть необработанной памяти за пределами кучи памяти.
Аррайбуффер, ArrayBufferView
ArrayBuffer
ArrayBuffer
выражать固定长度
Оригинальный буфер двоичных данных, его функция заключается в выделении непрерывной области памяти, в которой могут храниться данные, поэтому он намного быстрее, чем Array в JS, для операций доступа с высокой плотностью (таких как аудиоданные).ArrayBuffer существует Смысл в том, что он заранее записывается в память как источник данных, поэтому его длина фиксирована
Давайте в общих чертах рассмотрим функции ArrayBuffer:
Конструктор объекта ArrayBuffer выглядит следующим образом (length указывает длину ArrayBuffer)👇:
ArrayBuffer(length);
Разница между Array и ArrayBuffer👇:
Array | ArrayBuffer |
---|---|
Может поставить номера, строки, логические значения, объекты и массивы и т. Д. | Может хранить только двоичные данные, состоящие из 0 и 1 |
данные в куче | Данные помещаются в стек, что ускоряет выборку данных |
свободно увеличивать или уменьшать | Только для чтения, фиксированный размер после инициализации, независимо от того, пуст буфер или нет, его можно записать только с помощью TypedArrays и Dataview |
Атрибуты
Свойства объекта ArrayBuffer смотрите в следующей таблице👇:
Имя свойства | описывать |
---|---|
byteLength | Указывает размер ArrayBuffer |
метод
-
slice
: Есть два параметра 👉beginуказывает на начало,endУказывает конечную точку. Метод возвращает новый ArrayBuffer, содержимое которого является байтовой копией этого ArrayBuffer, от начала (включительно) до конца (исключительно).
ArrayBuffer нельзя манипулировать напрямую, но черезTypedArray
илиDataView
Они преобразуют данные в буфере в массивы данных различных типов и считывают и записывают содержимое буфера через эти форматы. 👇
ArrayBufferView
Поскольку объект ArrayBuffer не предоставляет никаких методов для прямого чтения и записи памяти, а
ArrayBufferView
Объект фактически основан на объекте ArrayBuffer.视图
, который указывает原始二进制数据
Базовый блок обработки объекта ArrayBufferView для чтения содержимого объекта ArrayBuffer. TypedArrays и DataView являются экземплярами ArrayBufferView.
TypedArrays
типизированный массив (TypedArrays
) — это новая концепция в JavaScript, предназначенная для доступа к необработанным двоичным данным.По сути, типизированные массивы такие же, как ArrayBuffers, за исключением того, что они имеют функции чтения и записи.
Типы типизированных массивов: 👇:
имя | размер (в байтах) | иллюстрировать |
---|---|---|
Int8Array | 1 | 8-битное целое число со знаком |
Uint8Array | 1 | 8-битное целое число без знака |
Int16Array | 2 | 16-битное целое число со знаком |
Uint16Array | 2 | 16-битное целое число без знака |
Int32Array | 4 | 32-битное целое число со знаком |
Uint32Array | 4 | 32-битное целое число без знака |
Float32Array | 4 | 32-битное число с плавающей запятой |
Float64Array | 8 | 64-битная с плавающей запятой |
Преобразование типа, как показано ниже:Вот несколько примеров кода, показывающих, как конвертировать:
// 创建一个8字节的ArrayBuffer
var b = new ArrayBuffer(8);
// 创建一个指向b的视图v1,采用Int32类型,开始于默认的字节索引0,直到缓冲区的末尾
var v1 = new Int32Array(b); // Int32Array(2) [0, 0]
v1[0] = 1
console.log(v1); // Int32Array(2) [1, 0]
// 创建一个指向b的视图v2,采用Uint8类型,开始于字节索引2,直到缓冲区的末尾
var v2 = new Uint8Array(b, 2); // Uint8Array(6) [0, 0, 0, 0, 0, 0]
// 创建一个指向b的视图v3,采用Int16类型,开始于字节索引2,长度为2
var v3 = new Int16Array(b, 2, 2); // Int16Array(2) [0, 0]
Поскольку обычные массивы Javascript используют метод поиска по хешу, а типизированные массивы напрямую обращаются к фиксированной памяти, скорость очень хорошая, быстрее, чем у традиционных массивов! В то же время типизированные массивы по своей природе обрабатывают двоичные данные, что полезно для
XMLHttpRequest
,canvas
,webGL
и другие технологии имеют неотъемлемые преимущества.
TypedArray的应用如何拼接两个音频文件
fetch请求音频资源 -> ArrayBuffer -> TypedArray -> 拼接成一个 TypedArray -> ArrayBuffer -> Blob -> Object URL
DataView
DataView
Объекты могут считывать и хранить различные типы двоичных данных в любом месте ArrayBuffer.
Синтаксис создания DataView следующий:
var dataView = new DataView(DataView(buffer, byteOffset[可选], byteLength[可选]);
Атрибуты
Объект DataView имеет три свойства, см. следующую таблицу👇:
Имя свойства | описывать |
---|---|
buffer | Представляет ArrayBuffer |
byteOffset | Относится к смещению от начала буфера |
byteLength | Относится к длине буферной секции |
метод
-
setint8()
:отDataViewНачальная позиция хранит 8-битное число (один байт) с указанным смещением (byteOffset), считая в байтах. -
getint8()
:отDataViewПолучить 8-битное число (один байт) по указанному смещению (byteOffset) в байтах от начальной позиции
Кроме того, есть getInt16, getUint16, getInt32, getUint32... Методы использования одинаковы, поэтому я не буду перечислять их здесь по одному.
Использование следующее👇:
let buffer = new ArrayBuffer(32);
let dataView = new DataView(buffer,0);
dataView.setInt16(1,56);
dataView.getInt16(1); // 56
FileReader
Мы не можем получить прямой доступ к содержимому объектов Blob или файлов. Если вы хотите прочитать их и преобразовать в другие форматы, вы можете использовать
FileReader
API объекта для работы
-
readAsText(Blob)
: преобразовать BLOB-объект в текстовую строку. -
readAsArrayBuffer(Blob)
: преобразование данных формата Blob в ArrayBuffer. -
readAsDataURL()
: конвертировать Blob в DataURL в формате Base64.
Используйте следующие 👇:
const blob = new Blob(['<xml>foo</xml>'], { type: 'text/xml' });
console.log(blob); // Blob(14) {size: 14, type: "text/xml"}
const reader = new FileReader();
reader.onload = () => {
console.log(reader.result);
};
reader.readAsText(blob); // <xml>foo</xml>
reader.readAsArrayBuffer(blob); // ArrayBuffer(14) {}
reader.readAsDataURL(blob); // data:text/xml;base64,PHhtbD5mb288L3htbD4
Попробуем прочитать содержимое файла в виде строки:
<input type="file" id='f' />
<script>
document.getElementById('f').addEventListener('change', function (e) {
var file = this.files[0];
// 首先,需要创建一个FileReader的实例。
const reader = new FileReader();
reader.onload = function () {
// 在加载完成时回调
const content = reader.result;
console.log(content);
}
reader.readAsText(file); // 将blob转化为文本字符串读取
}, false);
</script>
Результаты чтения следующие👇:
BlobURL
BlobURL
(ObjectURL) является伪协议
, может быть сгенерирован только внутри браузера, мы знаемscript/img/video/iframe
Атрибут src тега и URL-адрес фона могут отображаться с помощью URL-адреса и base64. Мы также можем преобразовать большой двоичный объект или файл в URL-адрес, чтобы сгенерировать BlobURL для отображения изображений. BlobURL позволяет использовать объекты Blob и File в качестве изображений, URL-адресов для загрузка бинарных данных по ссылкам и др. источнику.
Отображение изображения👇:
<div id="content">
<input type="file" multiple id="f" />
</div>
<script>
const elem = document.getElementById('f');
const content = document.getElementById('content');
// 根据不同浏览器封装一个转换BlobUrl的方法:file可以是File对象也可以是Blob对象
const getObjectURL = (file) => {
let url;
if (window.createObjectURL) {
url = window.createObjectURL(file);
} else if (window.URL) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL) {
url = window.webkitURL.createObjectURL(file);
}
return url;
};
elem.onchange = function (event) {
const files = event.target.files;
const file = files[0];
const img = document.createElement('img');
img.src = getObjectURL(file);
content.appendChild(img);
};
</script>
Когда мы посмотрим на элемент изображения mm на демонстрационной странице, мы обнаружим, что его URL-адрес не является ни традиционным HTTP-адресом, ни URL-адресом Base64, а строкой, начинающейся с blob:, которую можно проверить, поместив ее в адресную строку.
Загрузка файла👇:
<body>
<button onclick="download()">download.txt</button>
<script>
const getObjectURL = (file) => {
let url;
if (window.createObjectURL) {
url = window.createObjectURL(file);
} else if (window.URL) {
url = window.URL.createObjectURL(file);
} else if (window.webkitURL) {
url = window.webkitURL.createObjectURL(file);
}
return url;
};
function download() {
const fileName = 'download.txt';
const myBlob = new Blob(['johnYu'], { type: 'text/plain' });
downloadFun(fileName, myBlob);
}
function downloadFun(fileName, blob) {
const link = document.createElement('a');
link.href = getObjectURL(blob);
link.download = fileName;
link.click();
link.remove();
URL.revokeObjectURL(link.href);
}
</script>
</body>
Нажмите кнопку, чтобы загрузить документ, содержание документа:johnYu
сюда не звонилиrevokeObjectURL
посещениеchrome://blob-internals/
Вы можете увидеть текущий список внутренних файлов больших двоичных объектов:BlobUrls, которые больше не используются, будут автоматически удалены позже (закрытие браузера также автоматически очистит), но лучше всего использовать
URL.revokeObjectURL(url)
Очистите их вручную:
URL.revokeObjectURL('blob:http://127.0.0.1:5500/d2a9a812-0dbf-41c5-a96b-b6384d33f281');
вернуться после казниchrome://blob-internals/
Вы можете видеть, что файл был очищен
dataURL
dataURL
Позволяет создателям контента встраивать файлы меньшего размера в документы. Аналогично обычным вариантам использования URL
Его синтаксический формат выглядит следующим образом:
data:[<mediatype>][;base64],data
-
data
: приставка -
mediatype
Указывает тип данных, являетсяMIMEВведите строку, например image/jpeg для файла изображения JPEG. Если опущено, по умолчаниюtext/plain;charset=US-ASCII. -
base64
:flags (необязательно, если текст) -
data
: сами данные
Как получить DataUrl
- Метод readAsDataURL(), используемый в приведенном выше примере, предназначен для преобразования BLOB-объектов в DataUrl в формате Base64;
- использовать родной
Web API
кодировать декодировать
В Javascript есть две функции, отвечающие за кодирование и декодирование строк base64: atob и btoa. Оба обрабатывают данные только в URL-адресе данных.
btoa('<xml>foo</xml>') // "PHhtbD5mb288L3htbD4="
atob('PHhtbD5mb288L3htbD4=') // "<xml>foo</xml>"
- atob(): отвечает за декодирование строки в кодировке base64.
- btoa(): преобразовать двоичную строку в кодировку base64.
ASCII
нить.
- Метод toDataURL холста:
Canvas предоставляет метод toDataURL для получения содержимого рисунка холста и преобразования его в формат base64.
<body>
<canvas id="canvas" width="200" height="50"></canvas>
<textarea id="content" style="width: 200px; height: 200px"></textarea>
<script>
var canvas = document.getElementById('canvas');
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
// canvas的绘制
ctx.font = 'Bold 20px Arial';
ctx.textAlign = 'left';
ctx.fillStyle = 'purple';
ctx.fillText('johnYu', 10, 30);
// 获取 Data URL
document.getElementById('content').value = canvas.toDataURL();
}
</script>
</body>
Как показано на рисунке ниже, содержимое текстового поля представляет собой формат base64 содержимого, отображаемого на холсте.
Если мы вернем результат предыдущегоdata:text/xml;base64,PHhtbD5mb288L3htbD4=
Вставьте его в адресную строку вашего браузера, и вы увидите, что отображается.
Использование DataUrl
- Поскольку его можно использовать вместо URL-адреса, DataURL можно использовать в атрибуте src таких тегов, как script/img/video/iframe, и в фоновом URL-адресе, таком как BlobUrl. Использование в основном такое же, как и у BlobUrl.
elem.onchange
Сделайте следующее преобразование
<body>
<div id="content">
<input type="file" multiple id="f" />
</div>
<script>
const elem = document.getElementById('f');
const content = document.getElementById('content');
elem.onchange = function (event) {
const files = event.target.files;
const file = files[0];
const img = document.createElement('img');
- img.src = getObjectURL(file);
+ const reader = new FileReader();
+ reader.onload = function () {
+ img.src = reader.result;
+ };
+ reader.readAsDataURL(file);
content.appendChild(img);
};
</script>
</body>
- Поскольку сами данные представлены URL-адресом, их можно сохранить в файле cookie и передать на сервер.
- Когда размер изображения слишком мал, использование HTTP-сессии не очень целесообразно.
- Когда доступ к внешним ресурсам затруднен или ограничен
- DataUrl не будет кешироваться браузером, но небольшая часть будет кешироваться css.В следующем примере использование DataUrl полностью соответствует сцене. Это позволяет избежать того, чтобы это маленькое фоновое изображение генерировало HTTP-запрос само по себе, и это маленькое изображение также может кэшироваться браузером вместе с файлом CSS и повторно использоваться вместо загрузки каждый раз, когда оно используется. Пока изображение не очень большое и не используется повторно в файле CSS, метод DataUrl может отображать изображение, чтобы сократить время загрузки страницы и улучшить работу пользователя при просмотре.
background-image: url("data:image/gif;base64,R0lGODlhAwADAIAAAP///8zMzCH5BAAAAAAALAAAAAADAAMAAAIEBHIJBQA7");
- Использовать как ссылку для скачивания
<script>
const createDownload = (fileName, content) => {
const blob = new Blob([content]);
const reader = new FileReader();
const link = document.createElement('a');
link.innerHTML = fileName;
link.download = fileName;
reader.onload = () => {
link.href = reader.result;
document.getElementsByTagName('body')[0].appendChild(link);
};
reader.readAsDataURL(blob);
};
createDownload('download.txt', 'johnYu');
</script>
Нажав на тег a, загрузите txt-файл с текстовым содержимым johnYu, то же самое можно сделать в следующем BlobURL👇
разница
Основное использование BlobURL такое же, как и у DataUrl, оба можно проверить, поместив его в адресную строку, а также можно использовать как обычный URL-адрес.
Однако имеются следующие отличия.
- BlobUrl всегда является уникальной строкой, даже если вы каждый раз передаете один и тот же Blob, каждый раз будет генерироваться другой BlobUrl; значение DataUrl меняется вместе с blob;
- Что касается BlobUrl, то он не представляет сами данные, данные хранятся в браузере, а BlobUrl — это просто ключ для доступа к ним. Данные будут оставаться действительными до тех пор, пока браузер не будет закрыт или очищен вручную. А DataUrl — это непосредственно закодированные данные. Таким образом, даже передача BlobUrl на сервер и т. д. не может получить доступ к данным. После закрытия браузера DataUrl по-прежнему доступен в адресной строке, но доступ к BlobUrl недоступен.
- Длина BlobUrl, как правило, относительно короткая, а DataUrl часто бывает очень длинной, потому что он непосредственно хранит данные изображения в кодировке base64 (объем данных в кодировке Base64 обычно на 1/3 больше, чем у изображения в двоичном формате. ), поэтому, когда большое изображение отображается явно, используйте BlobUrl для лучших возможностей, скорости и эффективности использования памяти, чем DataUrl
- BlobUrl может легко использовать источник получения данных XMLHttpRequest (xhr.responseType = 'blob'). Для DataUrl не все браузеры поддерживают получение исходных данных через XMLHttpRequest.
<body>
<button onclick="download1()">XMLHttpRequest下载</button>
<button onclick="download2()">fetch下载</button>
<img id="img" />
<script>
var eleAppend = document.getElementById('forAppend');
const url = 'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/9ecb4e119c26e64b8b4ec5258f159b3b~300x300.image';
const pingan = document.querySelector('#pingan');
function download1() {
const xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'blob';
xhr.onload = function () {
if (this.status == 200) {
renderImage(this.response);
}
};
xhr.send(null);
}
function download2() {
fetch(url)
.then((res) => {
return res.blob();
})
.then((myBlob) => {
renderImage(myBlob);
});
}
function renderImage(blob) {
window.URL = window.URL || window.webkitURL;
var img = document.getElementById('img');
img.onload = function (e) {
window.URL.revokeObjectURL(img.src); // 清除释放
};
img.src = window.URL.createObjectURL(blob);
}
</script>
</body>
- Помимо того, что BlobUrl может использоваться в качестве сетевого адреса ресурсов изображения, BlobUrl также может использоваться в качестве сетевого адреса других ресурсов, таких как файлы html, файлы json и т. д. Чтобы браузер мог правильно анализировать файл тип, возвращаемый BlobUrl, необходимо создать объект Blob, когда укажите соответствующий тип
const createDownload = (fileName, content) => {
const blob = new Blob([content], { type: 'text/html' });
const link = document.createElement('a');
link.innerHTML = fileName;
link.download = fileName;
link.href = getObjectURL(blob);
document.getElementsByTagName('body')[0].appendChild(link);
};
createDownload('download.html', '<button>foo</button>');
6. DataUrl не кэшируется браузером, а значит загружается каждый раз при посещении такой страницы. Это проблема эффективности использования, особенно когда изображение активно используется на всем сайте. Но небольшая часть может быть кэширована css
canvas
Canvas
Элементы объекта отвечают за установку области на странице, после чего вы можете динамически рисовать графику в этой области через JavaScript.
метод
-
toDataURL(type, encoderOptions))
: возвращает DataUrl в указанном формате, этот метод принимает два необязательных параметра.- тип: указывает формат изображения, по умолчанию — image/png
- encoderOptions: Указывает качество изображения.Если задан формат изображения image/jpeg или image/webp, качество изображения можно выбрать от 0 до 1. Если он превышает диапазон значений, будет использоваться значение по умолчанию 0,92, а другие параметры будут игнорироваться.
-
toBlob(callback, type, encoderOptions)
: создание объекта Blob для отображения изображений на холсте. Тип изображения по умолчанию — image/png, а разрешение —96dpi- обратный вызов: параметр является функцией обратного вызова объекта blob.
-
getImageData(x,y,width,height)
: возвращает объект ImageData, который копирует пиксельные данные указанного прямоугольника холста.- x: Координата x верхнего левого положения для начала копирования.
- y: Y-координата положения верхнего левого угла для начала копирования.
- ширина: ширина прямоугольной области, которая будет скопирована.
- высота: высота прямоугольной области, которая будет скопирована.
-
putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
: поместите данные изображения (из указанного объекта ImageData) обратно на холст.- imgData: указывает объект ImageData, который нужно вернуть на холст.
- x: координата x верхнего левого угла объекта ImageData в пикселях.
- y: координата y верхнего левого угла объекта ImageData в пикселях.
- грязныйX: необязательно. Горизонтальное значение (x) в пикселях, где разместить изображение на холсте.
- Грязный: необязательно. Горизонтальное значение (Y), в пикселях, где разместить изображение на холсте.
- грязная ширина: необязательно. Ширина изображения, нарисованного на используемом холсте.
- грязная высота: необязательно. Высота, используемая для рисования изображения на холсте.
Сценарии применения
Когда нам нужно получить содержимое холста, мы можем использоватьtoDataURL
а такжеtoBlob
Атрибуты (могут использоваться для подписи, обрезки изображения, сжатия изображения и других сценариев),putImageData
,getImageData
Его можно использовать для оттенков серого или копирования изображений (см. главу о сценариях использования ниже 👇)
Получить контент:
<body>
<div id="content">
<button onclick="drawnImg()">绘制图像</button>
<button onclick="getImg()">获取图像</button>
<canvas style="border: 1px solid black" id="drawing" width="200" height="200">A drawing of something.</canvas>
<img src="./timg.jpg" alt="" />
</div>
<script>
var drawing = document.getElementById('drawing');
var quality = 0.3;
const imgType = 'image/jpeg';
var drawnImg = function () {
if (drawing.getContext) {
var context = drawing.getContext('2d');
//取得图像的数据 URI
var image = document.images[0];
context.drawImage(image, 20, 20, 100, 100);
}
};
var getImg = async function () {
const content = getContent('base64');
console.log(content);
const content1 = await getContent('file');
console.log(content1);
};
var getContent = function (type) {
switch (type) {
case 'base64':
{
const imgURL = drawing.toDataURL(imgType, quality);
return imgURL;
}
break;
case 'file':
{
// 转为文件格式
return new Promise((resolve) => {
drawing.toBlob(
(blob) => {
resolve(blob);
},
imgType,
quality
);
});
}
break;
}
};
</script>
</body>
Отношения и трансформации
строка → Uint8Array
var str = 'ab';
console.log(Uint8Array.from(str.split(''), (e) => e.charCodeAt(0))); // Uint8Array(2) [97, 98]
Uint8Array → строка
var u8 = Uint8Array.of(97, 98);
console.log(Array.from(u8, (e) => String.fromCharCode(e)).join('')); // ab
строка → URL-адрес данных
var str = 'ab';
console.log('data:application/octet-stream;base64,' + btoa(str)); // data:application/octet-stream;base64,YWI=
URL-адрес данных -> строка
var data = 'data:application/octet-stream;base64,YWI=';
console.log(atob(data.split(',')[1])); // ab
Uint8Array -> ArrayBuffer
var u8 = Uint8Array.of(1, 2);
console.log(u8.buffer); // ArrayBuffer(2) {}
ArrayBuffer -> Uint8Array
var buffer = new ArrayBuffer(2);
console.log(new Uint8Array(buffer)); // Uint8Array(2) [0, 0]
ArrayBuffer -> DataView
var buffer = new ArrayBuffer(2);
var dataView = new DataView(buffer, 0); // DataView(2) {}
DataView -> ArrayBuffer
console.log(dataView.buffer); // ArrayBuffer(2) {}
ArrayBuffer → Большой двоичный объект
var buffer = new ArrayBuffer(32);
var blob = new Blob([buffer]); // Blob {size: 32, type: ""}
UintXXArray → Большой двоичный объект
var u8 = Uint8Array.of(97, 32, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33);
var blob = new Blob([u8]);
строка → капля
var blob = new Blob(['Hello World!'], {type: 'text/plain'}); // Blob {size: 12, type: "text/plain"}
Вышеупомянутое использование new Blob() для преобразования blob
DataUrl -> blob
var data = 'data:application/octet-stream;base64,YWI=';
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
console.log(dataURLtoBlob(data)); // Blob {size: 2, type: "application/octet-stream"}
Клякса →
Необходимо использовать API FileReader для преобразования readAsText (Blob), readAsArrayBuffer (Blob), readAsDataURL(), но его необходимо выполнять асинхронно.
var blob = new Blob(['a Hello world!'], { type: 'text/plain' });
var reader = new FileReader();
reader.readAsText(blob, 'utf-8');
reader.onload = function (e) {
console.info(reader.result); // a Hello world!
};
reader.onerror = function (e) {
console.error(reader.error);
};
Вы можете выполнять несколько преобразований с обещаниями
var blob = new Blob(['a Hello world!'], { type: 'text/plain' });
function read(blob) {
var fr = new FileReader();
var pr = new Promise((resolve, reject) => {
fr.onload = (eve) => {
resolve(fr.result);
};
fr.onerror = (eve) => {
reject(fr.error);
};
});
return {
arrayBuffer() {
fr.readAsArrayBuffer(blob);
return pr;
},
binaryString() {
fr.readAsBinaryString(blob);
return pr;
},
dataURL() {
fr.readAsDataURL(blob);
return pr;
},
text() {
fr.readAsText(blob);
return pr;
},
};
}
var pstr1 = read(blob).binaryString();
var pstr2 = read(blob)
.arrayBuffer()
.then((e) => Array.from(new Uint8Array(e), (e) => String.fromCharCode(e)).join(''));
Promise.all([pstr1, pstr2]).then((e) => {
console.log(e[0]); // a Hello world!
console.log(e[0] === e[1]); // true
});
Сценарии применения
изображение в градациях серого
В основном используется здесь
canvas
а такжеimageData
преобразование
<body>
<button onclick="drawngray()">黑白图片</button>
<img src="./syz.jpg" alt="" />
<canvas id="myCanvas">canvas</canvas>
<script>
var drawngray = function () {
var myCanvas = document.getElementById('myCanvas');
if (myCanvas.getContext) {
var context = myCanvas.getContext('2d');
var image = document.images[0];
// 动态设置canvas的大小
myCanvas.width = image.width;
myCanvas.height = image.height;
var imageData, data, i, len, average, red, green, blue, alpha;
//绘制原始图像
context.drawImage(image, 0, 0);
//取得图像数据
imageData = context.getImageData(0, 0, image.width, image.height);
data = imageData.data;
for (i = 0, len = data.length; i < len; i += 4) {
red = data[i];
green = data[i + 1];
blue = data[i + 2];
// alpha = data[i + 3];
//求得 rgb 平均值
average = Math.floor((red + green + blue) / 3);
//设置颜色值,透明度不变
data[i] = average;
data[i + 1] = average;
data[i + 2] = average;
}
//回写图像数据并显示结果
imageData.data = data;
context.putImageData(imageData, 0, 0);
}
};
</script>
</body>
除次之外getImageData和putImageData还可以用作cavas图片复制:https://www.w3school.com.cn/tiy/t.asp?f=html5_canvas_getimagedata
Сжатие изображения
Чтобы добиться сжатия изображения во внешнем интерфейсе, мы можем использовать метод toDataURL(), предоставляемый объектом Canvas.
compress.js
const MAX_WIDTH = 800; // 图片最大宽度
function compress(base64, quality, mimeType) {
let canvas = document.createElement('canvas');
let img = document.createElement('img');
img.crossOrigin = 'anonymous';
return new Promise((resolve, reject) => {
img.src = base64;
img.onload = () => {
let targetWidth, targetHeight;
if (img.width > MAX_WIDTH) {
targetWidth = MAX_WIDTH;
targetHeight = (img.height * MAX_WIDTH) / img.width;
} else {
targetWidth = img.width;
targetHeight = img.height;
}
canvas.width = targetWidth;
canvas.height = targetHeight;
let ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// 通过toDataURL压缩后的base64
let imageData = canvas.toDataURL(mimeType, quality / 100);
resolve(imageData);
};
});
}
test.html
<body>
<input type="file" accept="image/*" onchange="loadFile(event)" />
<script src="./compress.js"></script>
<script>
function dataUrlToBlob(base64) {
var arr = base64.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
function uploadFile(url, blob) {
let formData = new FormData();
let request = new XMLHttpRequest();
// 封装到FormData中进行文件的上传
formData.append('image', blob);
request.open('POST', url, true);
request.send(formData);
}
const loadFile = function (event) {
const reader = new FileReader();
reader.onload = async function () {
let compressedDataURL = await compress(reader.result, 90, 'image/jpeg');
// 压缩后将base64转为Blob 对象减少传输数据量
let compressedImageBlob = dataUrlToBlob(compressedDataURL);
uploadFile('https://httpbin.org/post', compressedImageBlob);
};
// 获取用户选取的图片文件,通过FileReader转化成base64
reader.readAsDataURL(event.target.files[0]);
};
</script>
</body>
Частичная загрузка
<body>
<input type="file" name="file" onchange="selfile();" />
<script>
const url = 'https://httpbin.org/post';
/**
* @param file 原始文件
* @param chunkSize 默认每次上传分片大小
*/
async function chunkedUpload(file, chunkSize = 1024 * 1024 * 5) {
// 将文件拆分成chunkSize大小的分块,然后每次请求只需要上传这一个部分的分块即可
for (let start = 0; start < file.size; start += chunkSize) {
// File对象继承自Blob对象,因此可以使用slice方法对大文件进行切
const chunk = file.slice(start, start + chunkSize + 1);
const fd = new FormData();
fd.append('data', chunk);
await fetch(url, { method: 'post', body: fd })
.then((res) => res.text())
.then((res) => console.log(res)); // 打印上传结果
}
}
function selfile() {
let file = document.querySelector('[name=file]').files[0];
// 自定义分片大小
const LENGTH = 1024 * 1024 * 1;
chunkedUpload(file, LENGTH);
}
</script>
</body>
После того, как сервер получит эти слайсы, их можно склеить вместе.Ниже приведен пример кода сплайсинга PHP-слайсов:
$filename = './upload/' . $_POST['filename'];//确定上传的文件名
//第一次上传时没有文件,就创建文件,此后上传只需要把数据追加到此文件中
if(!file_exists($filename)){
move_uploaded_file($_FILES['file']['tmp_name'],$filename);
}else{
file_put_contents($filename,file_get_contents($_FILES['file']['tmp_name']),FILE_APPEND);
echo $filename;
}
Не забудьте изменить конфигурацию сервера nginx при тестировании, иначе большой файл может вызвать ошибку 413 Request Entity Too Large.
server {
// ...
client_max_body_size 50m;
}
Справочная статья 📜
❤️Понимание типов данных DOMString, Document, FormData, Blob, File, ArrayBuffer.
❤️Расскажите о бинарном семействе JS: Blob, ArrayBuffer и Buffer.
❤️Капли, о которых вы не знали
расширение 🏆
Если эта статья окажется для вас полезной, вы можете ознакомиться с другими моими статьями ❤️:
👍Боевые заметки vue3 | Быстрый старт 🚀
👍10 простых приемов, которые сделают ваш код vue.js более элегантным 🍊
👍Контакт с нулевым расстоянием с веб-сокетом 🚀
👍5 шаблонов проектирования, которые вы должны знать о веб-разработке
👍Структуры данных, которые должны знать веб-разработчики
👍Как получить размер экрана, окна и веб-страницы в JavaScript