对使用 JavaScript 从外部 url 显示图像的不同方式感到困惑

Confusions about different ways of displaying images from an external url using JavaScript

我最近了解到似乎有多种方法可以在网页上显示图像。

第一种方式是直接将URL赋值给图像元素的URL

const img = new Image();

img.onload = () => {
  document.querySelector("#myImage").src = url;
};
img.onerror = () => {};

img.src = imageUrl;

我最近学到的另一种方法是使用 fetch

fetch(imageUrl)
    .then((response)=>response.blob())
    .then((blob)=>{
       const objectUrl = URL.createObjectURL(blob)
       document.querySelector("#myImage").src = objectUrl;
})

我对这两种方法有几个问题:

  1. 我熟悉fetch,但我通常用它来获取JSON。使用 fetch 获取图像的第二种方式在我看来就像我们通过 HTTP 获取该图像文件的原始二进制数据,而第一种方式我们委托浏览器启动 Get 请求获取该图像。但是从服务器的角度来看,它如何将图像发送下来没有区别?我理解的对吗?

  2. 在什么情况下我们应该偏爱一种方法而不是另一种方法?我觉得第二种方法会比第一种方法有很多 CORS 问题,但不确定具体原因。

  3. 还有其他方法可以在网页上显示图像吗?当人们谈论图像时,我经常听说 base64 encoding/decoding。 base64 是否与 response.blob() 相关,即第二种方法?或者它是不同的?如果是这样,有人可以给我一个使用base64显示图像的例子吗?

  4. 最后,我认为显示图像一直是我对前端或 Web 开发知识的一个漏洞。请随时推荐有关此主题的任何好的资源。

  1. 第二种方法称为Data URL,它允许在HTML/CSS中嵌入小文件,例如:

<img src="data:image/png;base64,iVBORw0KGgoAAA
ANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU
5ErkJggg==" alt="Red dot" />

该方法可以有效减少网页加载过程中的网络请求。

  1. 以下情况,数据URL适用:
  • 在html中嵌入文件以减少请求
  • 将所有资产嵌入一个 html 用于存档目的
  • 加载服务器动态生成的资源
  1. base64方式就是数据URL,另外还有这两个方式:
  • SVG 图像可以通过 <svg> 标签直接嵌入 HTML
  • 图像也可以使用<canvas>API
  • 动态渲染
  1. 给你推荐一本书The definitive guide to HTML5

首先,如果你想在网页上显示图片,我们有两种方法

  1. 将图像网络 URL 设置为 img 属性
  2. 将二进制代码设置为 img 属性

当您将图像作为文件存储到服务器文件夹时使用选项 1

当您将图像作为二进制 base64 存储到数据库时使用选项 2,以便您仅作为二进制代码检索,或者您从二进制代码创建图像,然后按照选项 1 进行设置

回答您的问题

  1. 它与服务器端基本相同,除了 headers 和浏览器可以发送的信息,而在 fetch 中你可以完全控制 headers
  2. fetch 方法可用于需要您可能在服务器中实施的请求或安全传输的更灵活或更多的参数。例如,要求 post 请求 header 或 body 包含特定数据以允许传输图像...或灵活传输,例如可以放入块中的数据稍后可以 assemble 并在呈现之前进行操作。
  3. 使用 base64 几乎与二进制相同,尽管它用于通过旨在传输文本的媒体传输 images/data。这是因为base64使用ascii数字和字母来表示任何数据。

在这里,你可以看到一个由base64字符串字符生成的图像,没有任何link

<img style="width:64px; height:64px;" src="data:image/png;base64,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"></img>

这也有助于将图像作为文本直接嵌入代码,将其作为 url 参数传递,或者您甚至可以将图像放入 JSON 文件。在某些情况下,它也比使用 gzip 等压缩的二进制图像表现更好。

直截了当。基本上,当您不希望人们看到 yow pic 的托管位置时,您需要获取图像而不是在 html 处添加 url 源。如果我右键单击图像并且你直接在 img 标签中有 url 字面意思 err body 将能够下载图像,而且不仅如此如果我使用它可能具有的可能参数我可以不仅获取图像,还获取其他图像。所以如果你不想暴露你的照片在哪里,你可以“隐藏”它。

您可以通过 4 种方式获取图像

  • html
  • css
  • 斑点
  • base64

但这4种方式可以分为两组。

  • 由浏览器处理

    • html
    • css
    • base64 ...种类
  • 由您处理

    • 斑点
    • base64 ...种类

第一组不相关,因为浏览器会在不需要时删除图像,在需要时显示它以及更多内容。

为什么 base64 可以包含在该组中? bcuz 如果图像不再需要它,浏览器会清理它使用的内存。所以你只需要将二进制文件解析为 base64,浏览器将释放图片使用的任何资源,但另一方面,blob 完全由你管理和处理。因此,如果您不释放 pic 使用的资源,换句话说,其他人将无法使用内存 process/program/app,您可能在想为什么 blob 优于 base64?

BLOB stands for Binary Large Object which could be anything - text, images, video, executable code, random bytes, etc. Most databases have a special BLOB type that allows storing this type of data.

Base64 is an encoding that lets you represent any data as plain text. It can be easily be shown on the screen and useful in cases where binary data could be difficult to work with. For example, I could copy/paste the Base64 in the text field here but I won’t be able to do that with binary data. Also, Base64URL encoding is often used in HTTP URLs.

不仅yow pic的来源被曝光,还变成了30%以上bigger/heavier

const fileSelect = document.getElementById("fileSelect"),
    fileElem = document.getElementById("fileElem"),
    fileList = document.getElementById("fileList");

fileSelect.addEventListener("click", function (e) {
  if (fileElem) {
    fileElem.click();
  }
  e.preventDefault(); // prevent navigation to "#"
}, false);

fileElem.addEventListener("change", handleFiles, false);

function handleFiles() {
  if (!this.files.length) {
    fileList.innerHTML = "<p>No files selected!</p>";
  } else {
    fileList.innerHTML = "";
    const list = document.createElement("ul");
    fileList.appendChild(list);
    for (let i = 0; i < this.files.length; i++) {
      const li = document.createElement("li");
      list.appendChild(li);

      const image = document.createElement("img");
      image.src = URL.createObjectURL(this.files[i]);
      image.onload = function() {
        image.setAttribute("src", this.result)
        URL.revokeObjectURL(this.result);
      }
      li.appendChild(img);
      const info = document.createElement("span");
      li.appendChild(info);
    }
  }
}
<input type="file" id="fileElem" multiple accept="image/*" style="display:none">
<button type="button" id="fileSelect">Select some files</button>
<div id="fileList">
  <p>No files selected!</p>
</div>

如果你 运行 这个例子,然后右键单击它们的图像,你会看到一个 url 创建的,尝试在另一个选项卡中打开它,你会看到图片是无法访问

直接回答

  1. 是的,服务器可以发送任何类型的数据(任何东西都只是数字的二进制连续,甚至是文本和字符)。是客户端试图理解内容,通常遵循特定标准。
  2. 如果您不需要操作图像,我建议您避免任何请求,因为浏览器可以为您处理。请注意,只有 fetch 几乎不受 CORS 的影响,因为它不发送跨域 cookie(请参阅 MDN - using fetch). If you need more control you can use XMLHTTPRequest。blob 的用法继承自旧的 Web 方法,那些时候 ArrayBuffer 是不是发明的,它是 Web 环境中唯一的二进制数据包装器。由于多种原因,它仍然受到支持。
  3. 实际上比你想象的要少(只有 1 个)!检查说明...
  4. 图像资源在很大程度上取决于您需要什么样的处理...只是显示图像? MDN and CSS-tricks 满满的攻略,搜索即可。如果您想改为处理图像,则需要进一步查看 canvas 元素,并且通常的资源很少或几乎与游戏制作有关(出于明显的原因),MDN 和 CSS-资源技巧。

说明

什么是图像?

我认为您对浏览器显示图像的概念有偏见。

那么图像究竟是什么? 二进制数据。

实际上,您的浏览器(或您的计算机)只有一种显示图像的方法,即使用一个字节数组,该数组是图像像素的平面视图。所以在一天结束时,你将 ALWAYS 需要向你的浏览器提供可解释为原始图像的二进制数据(通常是一组 rgb(a)像素)。

是的,只有 “一种” 方式可以在计算机上显示图像。但是我们可以用不同的方式来表示该图像。

编码

在低级别,不同的计算机以不同的方式表示数字,因此网络标准决定以所谓的 RGB8RGBA8[=192= 表示图像] 编码(红-绿-蓝(-Alpha)-NumBits,8 位 = 1 字节)。这意味着每个像素都由 4 个字节(数字)组成的数组表示,每个字节从 0 到 255 不等。这个数组是您的浏览器唯一看到的图像。

最后你的图片是这样的:

// using color(x, y) to describe the image pixels
[ red(0, 0), green(0, 0), blue(0, 0), alpha(0, 0), red(1, 0), ... ] =
[ 124, 12, 123, 255, 122, ... ]

现在您可以将图像视为线性像素阵列,我们可以决定如何将其写在纸上(我们的“代码”)。浏览器(通常和历史上)将在 HTML 文件中在网络上发送的每个数据包解析为纯文本,因此我们必须使用字符来描述我们的图像,标准是 ONLY 使用 UTF-8(字符编码,ASCII 的超集)。比如我们可以用JS写成一个数字数组。

但请看一下数字 255。每次在 newtork 上发送该数字时,您都会发送 3 个字符:'2'、'5'、'5'。 Web 仅与字符通信,所以...有没有一种方法可以紧凑地表示该数字,以便尽可能少地发送字节(拯救那些连接速度慢的人!)?

Base64 是最著名的编码,用于以最紧凑的方式描述线性数组,因为它将 255 个字符压缩为 1 或 2 个字符(取决于序列).我们可以去掉一些通常用作字母的字符来表示更多数字,而不是表示以 10 为底的数字。所以'11' become 'a', '12' => 'b', '13' => 'c', ..., '32' => 'a', ..., '63' => 'Z', '64' => '10', '65' => '11', ..., '128' => '20',依此类推。此外,该算法利用更多低级表示在一个字符中编码更多数字(这就是为什么您有时会在末尾看到一些“=”)。

查看同一图像的不同表示形式:

// JavaScript Array
[ /* pixel 1 */ 124, 12, 123, 255, /* pixel 2 */ 122, 12, 56, 255 ] // 67 characters
// (30 without spaces and comments)

// Base64
fAx7w796DDjDvw== // 16 characters
// Base32
3sc3r7v3qc1o7vAb== // 18 characters (always >= Base64)

很容易看出他们为什么选择 base64 作为通用算法(这个例子只计算 2 个像素)。

(Base32 image example)

格式

现在假设要在网络上发送一张尺寸为 3'656 × 2'664 的 4K 图片。这意味着您要在互联网上发送 9'739'584 个像素,每个像素 4 个字节,总计 38'958'336 个字节(~39MB)。此外想象一下,如果图像是全黑的(我们可以用一个像素来描述整个图像)是多么浪费……这太多了(特别是对于低连接),因此他们发明了一些算法,可以用一个像素来描述图像更紧凑的方式,我们称它们为图像格式。 PNG 和 JPEG/JPG 是压缩图像的格式示例(jpg 4k 图像~8MB,png 4k 图像可以从~2MB 到~22MB 不等,具体取决于某些参数和图像本身)。

有人将压缩的东西提升到一个新的水平,建立了 gzip 压缩标准格式(对已压缩图像或任何其他类型的文件的通用压缩算法)。

在浏览器上绘图

在本次旅程结束时,您只有两种不同的浏览器允许您绘制内容的方式:URIArrayBuffer

  • URI:您可以将它与<img>和css一起使用,通过设置元素的src 属性或设置任何样式属性 可以获取图像 URL 作为输入。
  • ArrayBuffer:通过操作<canvas>.context缓冲区(也就是我们上面讨论的线性数组)

显然浏览器也允许在这两种方式之间转换或切换。

URI

URI 是我们定义特定内容的方式,它可以是存储的资源(URL - 除了 data 之外的所有协议,例如 http(s)://ws(s)://file://) 或由字符串描述的正确缓冲区(data 协议)。

当您请求图像时,通过设置 src 属性,您的浏览器会解析 URL,如果它是远程内容,则请求检索它并以正确的方式(格式和编码)解析内容。同样,当您进行 fetch 调用时,您是在要求浏览器请求远程内容; fetch 函数有可能以不同的方式获得响应:

  • textual,就是一堆字符(通常用来解析JSON/DOM/XML)
  • 二进制数据,分为:
    • ArrayBuffer,也就是图像的线阵表示,我们上面讨论过
    • Blob,这是一个通用类文件对象的抽象表示(也封装了一个内部的ArrayBuffer)。 Blob 类似于指向浏览器缓存中类似文件的实体的指针,因此您不需要多次 download/request 同一个文件。
// ArrayBuffer from fetch:
fetch(myRequest).then(function(response) {
    return response.arrayBuffer();
})
// Blob from fetch
fetch(myRequest).then(function(response) {
    return response.blob();
})
// ArrayBuffer from Blob
blob.arrayBuffer();

所以现在你必须告诉浏览器如何理解你从响应中得到的内容。您需要将数据转换为可解析的 url:

var encodedURI = `data:${format};${encoding},` + encodeBuffer(new Uint8Array(arrayBuffer));
image.src = encodedURI

// for base64 encoding
var encodeBuffer = function(buffer) { return window.btoa(String.fromCharCode.apply(null, buffer)); } 

// for blobs
image.src = (window.URL || window.webkitURL).createObjectURL(blob);

请注意,浏览器支持其他编码,而不仅仅是 base64,base32 也可用,但正如我们在上面看到的那样,使用起来并不方便。也没有像 btoa 这样的内置函数来编码 base32 中的缓冲区。

另请注意,格式 值可以是任何一种 MIME type,例如 image/png|jpg|gif|svgtext/plain|html|xmlapplication/octet等。显然只有图像类型才会显示为图像。

当没有从远程服务器(使用 file://data 协议)请求资源时,通常会同步加载图像,因此一旦设置 URL,浏览器将读取、解码并将缓冲区放入图像中以显示。这有两个后果:

  1. 数据在本地管理(无互联网连接要求)
  2. 数据是同步处理的,所以如果图像很大,你的计算机会一直处理到最后(看看为什么对视频或大数据使用 data 协议是个坏习惯特殊部分,在最后)

URL 与 URI

URI 是资源的通用标识符,URL 是位置的标识符 where检索资源。通常在浏览器上下文中几乎是一个重叠的概念,我发现这张图片比千言万语解释得更好:

data实际上是一个URI,每个带有协议的请求实际上是一个URL

旁注

在您的问题中,您通过“设置图像元素 url”将此写为替代方法:

fetch(imageUrl)
    .then((response)=>response.blob())
    .then((blob)=>{
       const objectUrl = URL.createObjectURL(blob)
       document.querySelector("#myImage").src = objectUrl; // <-- setting url!
})

但请注意:您实际上设置了图像元素源 URL!

Canvas

<canvas> 元素使您可以完全控制图像缓冲区,还可以进一步处理它。您可以直接在其中绘制数组:

var canvas = document.getElementById('mycanvas');
// or offline canvas:
var canvas = document.createElement('canvas');
canvas.width = myWidth;
canvas.height = myHeight;

var context = canvas.getContext('2d');

// exemple from array buffer
var arrayBuffer = /* from fetch or Blob.arrayBuffer() or also with new ArrayBuffer(size) */
var buffer = new Uint8ClampedArray(arrayBuffer);
var imageData = new ImageData(buffer, width, height);
context.putImageData(iData, 0, 0);

// example image from array (2 pixels)
var data = [
//   R    G    B    A
    255, 255, 255, 255, // white pixel
    255,   0,   0, 255  // red pixel
];
var buffer = new Uint8ClampedArray(data);
var imageData = new ImageData(buffer, 2, 1);
context.putImageData(iData, 0, 0);

(注意ImageData需要一个RGBA数组)

要取回 ArrayBuffer(您也可以在 image.src 之后重新插入),您可以执行以下操作:

var imageData = context.getImageData(0, 0, canvas.width, canvas.heigth);
var buffer = imageData.data; // Uint8ClampedArray
var arrayBuffer = buffer.buffer; // ArrayBuffer

这是一个关于如何处理图像的例子:

// reading image
var image = document.getElementById('myimage');
image.onload = function() {
    // load image in canvas
    context.drawImage(image, 0, 0);
   
    // process your image
    context.fillRect(20, 20, 150, 100);
    var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
    imageData.data[0] = 255;

    // converting back to base64 url
    var resultUrl = window.btoa(String.fromCharCode.apply(null, imageData.data.buffer));
   
    // setting image url and disabling onload
    image.onload = null;
    image.src = resultUrl;
};

// note src setted after onload
image.src = 'ANY-URL';

关于这部分我建议你看看Canvas Tutorial - MDN

特别

音频和视频的处理方式相同,但您还必须以某种方式对时间和声音维度进行编码和格式化。你可以加载一个 audio/video from base64 string ( for videos) or display a video on a canvas