按画廊中的图像分辨率排序

2024-03-06

我不久前制作了这个画廊:https://jsfiddle.net/5e9L09Ly/ https://jsfiddle.net/5e9L09Ly/

别担心它不会上传任何东西。

我让你可以按文件大小排序,但我想按图像分辨率排序。问题是并非所有图像都会加载到页面上,所以我不知道它们的大小是多少。

图库本身非常基本,它要求一个目录,然后它将显示该目录中的所有图像和视频。

目前仅适用于 Chrome,只需点击最顶部的“浏览”即可。浏览前的数字是选择目录时应显示或加载的图像数量。

我不知道如何解决这个问题......

我想到的一件事是这样的:

imgLoad.attr("src", url);
imgLoad.unbind("load");
imgLoad.bind("load", function() {
    console.log(url+' size: '+(this.width + this.height));
});

这样做的问题是,它会加载它加载的每个图像,如果你有很多图像,比如你要加载 20k 个图像,它会给硬盘和浏览器带来很大的压力。

所以是的...任何建议都会很棒。

我不会在这里发布代码,因为代码太多,请查看小提琴。


理论上,可以通过从上传文件的 arrayBuffer 表示中提取这些值来稍微利用浏览器的处理。

大多数图像格式都有包含媒体尺寸的可读元数据,因此我们可以访问它,而无需要求浏览器实际解析和计算图像数据(解压缩、解码等)。

这是一个非常粗略的概念证明,使用ExifReader 库 https://github.com/mattiasw/ExifReader 我没有测试太多,对于 jpeg 图像。

/* 
	Rough proof of concept of getting image files width & height
		by reading their metadata directly in arrayBuffer, instead of loading it
	Should support most jpeg png gif and bmp image files
  (though all versions of these formats have NOT been tested)

	@input A fileList.
	@output A promise 
		whose fulfillment handler receives an Array containing successfully parsed files.
*/
function getImageSizes(files) {
  /* Attaches a buffer of the size specified to the File object */
  function getBuffer(fileList, size) {

    return new Promise((resolve, reject) => {

      const fr = new FileReader();
      const toLoad = fileList.length;
      if (!toLoad) { // an empty list
        resolve(fileList);
        return;
      }
      let arr = [];
      let loaded = 0;
      let current = fileList[loaded];
      let chunk = current.slice(0, size || current.size); // get only the required bytes
      fr.onload = e => {
        fileList[loaded].buf = fr.result;

        if (++loaded < toLoad) {
          current = fileList[loaded];
          chunk = current.slice(0, size || current.size);
          fr.readAsArrayBuffer(chunk);
        } else { // once all the list has been treated
          resolve(fileList);
        }
      };

      fr.readAsArrayBuffer(chunk);

    });

  }

  /* png is easy, IHDR starts at 16b, and 8 first bytes are 32bit width & height */
  // You can read https://www.w3.org/TR/PNG-Chunks.html for more info on each numeric value
  function getPNGSizes(pngArray) {
    let view;
    // Little endian only
    function readInt16(offset) {
      return view[offset] << 24 |
        view[offset + 1] << 16 |
        view[offset + 2] << 8 |
        view[offset + 3];
    }

    pngArray.forEach(o => {
      view = new Uint8Array(o.buf);
      o.meta = {
        width: readInt16(16),
        height: readInt16(20),
        bitDepth: view[24],
        colorType: view[25],
        compressionMethod: view[26],
        filterMethod: view[27],
        interlaceMethod: view[28]
      };
      o.width = o.meta.width;
      o.height = o.meta.height;
    });
    return pngArray;
  }

  function getJPEGSizes(jpegArray) {
    /* the EXIF library seems to have some difficulties */
    let failed = [];
    let retry = [];
    let success = [];
    // EXIF data can be anywhere in the file, so we need to get the full arrayBuffer
    return getBuffer(jpegArray).then(jpegArray => {
      jpegArray.forEach(o => {
        try {
          const tags = ExifReader.load(o.buf);
          if (!tags || !tags.PixelXDimension) {
            throw 'no EXIF';
          }
          o.meta = tags; // since OP said he wanted it
          o.width = tags.PixelXDimension.value;
          o.height = tags.PixelYDimension.value;
          success.push(o);
        } catch (e) {
          failed.push(o);
          return;
        }
      });
      // if some have failed, we will retry with the ol'good img way
      retry = failed.map((o) => {
        return new Promise((resolve, reject) => {
          let img = new Image();
          img.onload = e => {
            URL.revokeObjectURL(img.src);
            o.width = img.width;
            o.height = img.height;
            resolve(o);
          };
          img.onerror = e => {
            URL.revokeObjectURL(img.src);
            reject(o);
          };
          img.src = URL.createObjectURL(o);
        });
      });

      return Promise.all(retry)
        // concatenate the no-exif ones with the exif ones.
        .then(arr => success.concat(arr))
    });
  }

  function getGIFSizes(gifArray) {
    gifArray.forEach(o => {
      let view = new Uint8Array(o.buf);
      o.width = view[6] | view[7] << 8;
      o.height = view[8] | view[9] << 8;
    });
    return gifArray;
  }

  function getBMPSizes(bmpArray) {
    let view;

    function readInt(offset) {
      // I probably have something wrong in here...
      return Math.abs(view[offset] |
        view[offset + 1] << 8 |
        view[offset + 2] << 16 |
        view[offset + 3] << 24
      );
    }
    bmpArray.forEach(o => {
      view = new Uint8Array(o.buf);
      o.meta = {
        width: readInt(18),
        height: readInt(22)
      }
      o.width = o.meta.width;
      o.height = o.meta.height;
    });
    return bmpArray;
  }

  // only based on MIME-type string, to avoid all non-images
  function simpleImageFilter(files) {
    return Promise.resolve(
      Array.prototype.filter.call(files, f => f.type.indexOf('image/') === 0)
    );
  }

  function filterType(list, requestedType) {
    // A more robust MIME-type check
    // see http://stackoverflow.com/questions/18299806/how-to-check-file-mime-type-with-javascript-before-upload
    function getHeader(buf) {
      let type = 'unknown';
      let header = Array.prototype.map.call(
        new Uint8Array(buf.slice(0, 4)),
        v => v.toString(16)
      ).join('')

      switch (header) {
        case "89504e47":
        case "0D0A1A0A":
          type = "image/png";
          break;
        case "47494638":
          type = "image/gif";
          break;
        case "ffd8ffe0":
        case "ffd8ffe1":
        case "ffd8ffe2":
          type = "image/jpeg";
          break;
        default:
          switch (header.substr(0, 4)) {
            case "424d":
              type = 'image/bmp';
              break;
          }
          break;
      }
      return type;
    }

    return Array.prototype.filter.call(
      list,
      o => getHeader(o.buf) === requestedType
    );

  }

  function getSizes(fileArray) {
    return getJPEGSizes(filterType(fileArray, 'image/jpeg'))
      .then(jpegs => {
        let pngs = getPNGSizes(filterType(fileArray, 'image/png'));
        let gifs = getGIFSizes(filterType(fileArray, 'image/gif'));
        let bmps = getBMPSizes(filterType(fileArray, 'image/bmp'));
        return gifs.concat(pngs.concat(bmps.concat(jpegs)));
      });
  }

  return simpleImageFilter(files)
    .then(images => getBuffer(images, 30))
    .then(getSizes);
}


// our callback
function sort(arr) {

  arr.sort(function(a, b) {
    return a.width * a.height - b.width * b.height;
  });

  output.innerHTML = '';
  arr.forEach(f => {
    // ugly table generation
    let t = '<td>',
      tt = '</td>' + t,
      ttt = '</td></tr>';
    output.innerHTML += '<tr>' + t + f.name + tt + f.width + tt + f.height + ttt;
  })
}
f.onchange = e => {
  getImageSizes(f.files)
    .then(sort)
    .catch(e => console.log(e));
  output.innerHTML = '<tr><td colspan="3">Processing, please wait...</td></tr>';
}
table {
  margin-top: 12px;
  border-collapse: collapse;
}

td,
th {
  border: 1px solid #000;
  padding: 2px 6px;
}

tr {
  border: 0;
  margin: 0;
}
<script src="https://rawgit.com/mattiasw/ExifReader/master/dist/exif-reader.js"></script>
<input type="file" id="f" webkitdirectory accepts="image/*">
<table>
  <thead>
    <tr>
      <th>file name</th>
      <th>width</th>
      <th>height</th>
    </tr>
  </thead>
  <tbody id="output">
    <tr>
      <td colspan="3">Please choose a folder to upload</td>
    </tr>
  </tbody>
</table>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

按画廊中的图像分辨率排序 的相关文章

  • Telegram 授权无默认按钮

    使用 Telegram 第 3 方授权的唯一有记录的方法是使用其提供的脚本https core telegram org widgets login https core telegram org widgets login 这个脚本 正如
  • 在 HTML 中移动选取框/下移文本

    我正在尝试向下移动或移动 HTML 中的文本 但我似乎无法将其移动到任何地方 我添加了一个颜色命令来更改文本的颜色 但似乎只是移动了 它一直到顶部
  • 使用 jQuery 仅从字符串末尾修剪空格

    我知道 jQuery trim 函数 但我需要的是一种仅从字符串末尾修剪空格的方法 而不是开头 So str this is a string 会成为 str this is a string 有什么建议么 Thanks 您可以使用正则表达
  • 带 CSS 网格的等宽侧边栏列

    是否可以让左右列具有相同的宽度 而中间列占据剩余空间 我不想设置像这样的百分比grid template columns 20 60 20 因为并不总是确定这些列的内容是什么 Flexbox 和表格似乎没有解决这个问题的方法 所以我再次尝试
  • 专用网络:web3.eth.getAccounts() 始终发送空数组

    我正在运行一个私人以太坊网络 我确实用https aws amazon com blockchain templates 整个设置已经完成 AWS 上的设置看起来正确 现在 我正在尝试创建帐户并检索所有这些帐户 为此 我使用以下方法 Web
  • ReactJS:从没有 onChange 事件的 props 中选择默认值?

    所以 我只是想知道我是否绝对需要在 React 中的选择组件上有一个 onChange 事件处理程序 我有一个道具传递我想要选择的选项的默认值 如果我有的话 它就没有问题
  • Chrome Javascript 调试器暂停时不会重新加载页面

    有时 当我在 Chrome 中调试某些 javascript 并且暂停了 javascript 时 如果我尝试重新加载页面 chrome 只会 继续 调试器 单步执行到下一个断点 似乎没有任何方法可以强制 javascript 完全停止运行
  • 使用 onBlur 事件上的值更新 React 输入文本字段

    我有以下输入字段 在模糊时 该函数调用服务来更新服务器的输入值 完成后 它会更新输入字段 我怎样才能让它发挥作用 我可以理解为什么它不允许我更改字段 但我能做些什么才能使其工作 我无法使用defaultValue因为我会将这些字段更改为其他
  • Javascript 选择 onchange='this.form.submit()'

    我有一个带有选择和一些文本输入的表单 我希望在更改选择时提交表单 使用以下方法可以正常工作 onchange this form submit 但是 如果表单还包含提交按钮 则当选择更改时 表单不会提交 我猜有某种冲突 我在这里有什么选择
  • 如何在 angularjs 中修剪()字符串?

    有角度特定的方法吗 如果没有 我应该使用内置的jquery 来做到这一点吗 如果我应该使用内置的jquery 如何在不使用 的情况下访问trim 函数 或者这是必要的 编辑 是的 我知道 str trim 对不起 我需要这个才能在 IE 8
  • 理论上防止 WebSocket 中第一个收到的消息丢失

    服务器端代码发送消息立即地连接打开后 它向客户端发送初始配置 问候语 以下代码是在客户端 var sock new WebSocket url sock addEventListener error processError sock ad
  • Meteor.js 登录事件

    因此 我对 Meteor 框架和 JavaScript 总体来说还很陌生 但我正在使用该框架开发一个小项目 以尝试让自己达到标准 基本上我正在开发一个微博客网站 目前 用户可以通过多种服务登录 fb google 等 我通过插入所需 url
  • Excel 类似 HTML 表格,可在 x 轴(完整表格)和 y 轴(标题固定)上滚动

    我想建立一个具有固定宽度列的表格 在大多数情况下 表数据会水平和垂直溢出 如果列的宽度大于视图宽度 则需要水平滚动条来滚动并查看所有表列 同时滚动标题和数据 如果数据的高度大于可用视图 则会出现垂直滚动框 但在滚动时保持标题固定 以便用户关
  • 使用 jQuery Tablesorter 操作后如何恢复当前页面?

    我正在使用 tablesorter 但无法找到有关插件 tablesorter 寻呼机的任何文档 问题是我有一个显示一些数据的表 并且在每一行中都有一个删除链接 该链接附加了要删除的元素的唯一标识符 显然 是否可以保存我正在删除的页面 然后
  • Dojo/on 和捕获阶段

    有没有办法用 dojo on 在捕获阶段 而不是冒泡阶段 触发事件 我最终在这里寻找有关 on 的前身 dojo connect 的信息 就其价值而言 dojo connect 似乎不支持捕获阶段的事件侦听器 它的工作原理是将事件处理程序作
  • 有没有办法防止输入 type=“number” 获得多个点值?

    我只想得到十进制值 如 1 5 0 56 等 但它允许多个点 有什么办法可以预防吗 您可以使用pattern属性
  • Quartz 2D/OpenGLES 图像上的几何变形(最好使用 CGImage)

    实现诸如收缩 鱼眼等几何变形的首选方法是什么 使用iPhone SDK 我知道 OSX 的 Core Image 库内置了所有这些类型的过滤器 但 iPhone SDK 没有 我可以在给定原始源位图数据的特定位置和半径处创建位移图 但我不确
  • 如何清除隐藏上的引导模式

    如何在关闭 隐藏 关闭时清除引导模式 我有以下模态定义
  • 如何在 JavaScript 中获取浮点数的小数位?

    我想要的是与 Number prototype toPrecision 几乎相反的 这意味着当我有数字时 它有多少位小数 例如 12 3456 getDecimals 4 对于任何想知道如何更快地完成此操作 无需转换为字符串 的人 这里有一
  • 使用 Lodash 将对象键转换为具有键值数量的数组[重复]

    这个问题在这里已经有答案了 我有一个产品对象 products bread 1 milk 2 cheese 2 chicken 1 我想要一个包含产品名称的数组 如下所示 products bread milk milk cheese ch

随机推荐

  • 实体框架上下文中的复杂类型是什么

    现在我正在从 Pluralsight 上的视频中学习很多有关实体框架的知识 所以请原谅我的问题 它可能看起来很新 但我无法理解复杂类型是什么或为什么我需要它们 我确实知道我必须通过注释或 Fluent Api 来映射它们 如下所示 mode
  • .Net Core、便携式、标准、紧凑、UWP 和 PCL 之间的区别?

    我听说过 Net核心 Net 便携式 Net标准 Net 紧凑型 通用Windows平台 便携式类库 所有这些都向我解释为 完整 Net 的子集 允许您针对多个平台 所以我的问题是 有什么不同 如果我想编写一个可供尽可能多的受众使用的库 哪
  • 如何在 Windows 中将文件上传到 Solr?

    我需要验证文本提取在 Windows Server 2003 上安装的 Solr 上是否正常工作 我找到的将文件上传到 Solr 的所有示例都使用如下的curl curl http localhost 8983 solr update ex
  • 检查点是否位于自定义网格几何体内部

    检查点是否位于自定义 不规则 网格几何图形内部的最简单方法是什么 如果你的网格是特写的 您可以使用 THREE js 内置光线投射器 示例代码如下 const point new THREE Vector3 2 2 2 Your point
  • 在 iPhone 上合并音频文件

    我想将 caf 文件和 mp3 文件合并为 iPhone 上的 mp3 文件 或者我可以将它们转换为 aac 然后合并它们 我该怎么做 就像Kala OK一样 我想将我的声音和音乐融合在一起 您需要将两个文件解码为 LPCM 普通旧整数 将
  • PHP 脚本抓取整行

    感谢您花时间阅读本文 无论内容的质量如何 我都会感激每一个回复 我正在尝试创建一个在文本文件中搜索特定文本的 php 脚本 用户在 HTML 表单中输入特定文本 PHP 脚本应在文本文件中搜索该特定文本 HTML表单的输入字段的值为 use
  • 解析从云代码向特定用户发送推送通知

    我想从解析云代码向特定用户发送推送通知 因此 我在解析表的安装类中创建了一个用户部分 并将用户对象 ID 保存在那里 以便我可以通过 ID 定位用户并从云代码发送推送 https www dropbox com s dvedyza4bz3z
  • last-of-type 不适用于 IE11 和 Edge 中的自定义元素

    foo bar last of type background color red div class foo div
  • 使用 NHibernate 持久保存 Blob 流

    如果我有一个类声明为 public class MyPersistentClass public int ID get set public Stream MyData get set 如何使用 NHibernate 的映射将 MyData
  • 如何使用字符串按名称动态调用Python函数?

    我有一个 Python 函数调用 如下所示 import torchvision model torchvision models resnet18 pretrained configs use trained models 效果很好 如果
  • 如何在 Linux 中重新启动 IDLE Python Shell?

    在Windows的IDLE中 菜单栏上有一个Shell菜单 Shell 菜单上的项目之一是 重新启动 Shell Shell 菜单在 Linux 上的 IDLE 中不可用 当您对模块进行更改并希望在 shell 中再次运行该模块时 重新启动
  • Java注释的默认值是否被编译成字节码?

    我尝试对 Java 字节码实现几种静态分析 他们尝试计算某个方法是否具有特定属性 例如是一个工厂方法 由于这些分析很难测试 我决定编写一些 Java 代码并直接使用正确的属性注释方法 运行分析后 很容易自动检查计算的属性和注释的属性是否相同
  • 如何将 32 位 RGBA 图像转换为保留 alpha 的灰度

    我想在代码中按需将 32 位 RGBA 图像对象 最初是 32 位 PNG 转换为其 32 位灰度对应对象 我已经read https stackoverflow com questions 2265910 c convert image
  • 如何在 CodeIgniter 中测试我的 MySQL 更新查询是否成功? [复制]

    这个问题在这里已经有答案了 我有一个模型函数可以在我的 CodeIgniter 应用程序中更新用户 updates first of a user return true if successful false if not public
  • Scala Play 表单验证:一个案例类有不同的表单 - 这可能吗?

    我正在寻找一种方法 为一个案例类使用两种不同的形式 我试图用额外的构造函数来做到这一点 但失败了 看一下代码片段 case class LoginDetails password String field3 Option Int field
  • bean验证命令的默认参数?

    我目前正在尝试使用 bean 验证提供自定义验证消息 目前使用 spring mvc 3 1 1 apache bean 验证 在我的 bean 中 我指定 Size min 1 max 50 private String title 在我
  • Kafka 和 Spark 之间的 SSL

    我们正在使用 Kafka Spark Streaming 并将数据加载到 Cassandra 需要在运行kafka的节点和运行spark的节点之间实现安全层 有关如何在 kafka 和 Spark 节点之间实施 SSL 的任何指导吗 谢谢
  • PostgreSQL:重复的键值违反了 UPDATE 命令的唯一约束

    执行 UPDATE 查询时 我们收到以下错误消息 ERROR duplicate key value violates unique constraint tableA pkey DETAIL Key id 47470 already ex
  • YAML 中的继承更复杂?

    YAML 具有继承性 我见过的最清晰的例子在这里 http blog 101ideas cz posts dry your yaml files html https web archive org web 20130213112648 h
  • 按画廊中的图像分辨率排序

    我不久前制作了这个画廊 https jsfiddle net 5e9L09Ly https jsfiddle net 5e9L09Ly 别担心它不会上传任何东西 我让你可以按文件大小排序 但我想按图像分辨率排序 问题是并非所有图像都会加载到