# 图片相关

# 1、获取图片的原生尺寸

参数支持传入url或者一个HTMLImageElement, 返回Promise

function getImgRawSize(img) {
  let _image = img;
  return new Promise((resolve, reject) => {
    if (!_image) {
      reject(new Error('Please provide img param!'));
      return;
    }
    if (_image instanceof HTMLImageElement) {
      if (_image.naturalWidth) {
        // 推荐使用 naturalWidth ,因为该值返回的是原始值,不会被属性影响
        resolve({
          width: _image.naturalWidth,
          height: _image.naturalHeight
        });
        return;
      }
      if (_image.complete) {
        // 如果没有 naturalWidth 且图片已加载完成,那么很大几率是不支持
        // 为了防止被属性影响,我们要用空白的标签重新加载
        img = img.src;
      } else {
        // 没有的话直接用
        _image = img;
      }
    }
    if (typeof img === 'string') {
      _image = new Image();
      _image.src = img;
    }
    _image.onload = function () {
      resolve({
        width: _image.naturalWidth || _image.width,
        height: _image.naturalHeight || _image.height
      });
    };
    _image.onerror = function (event) {
      reject(event);
    };
  });
}		

# 2、旋转图片

function rotateBase64Img(src, edg, callback) {
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('2d');
  var imgW; //图片宽度
  var imgH; //图片高度
  var size; //canvas初始大小
  if (edg % 90 != 0) {
    console.error('旋转角度必须是90的倍数!');
    throw '旋转角度必须是90的倍数!';
  }
  edg < 0 && (edg = (edg % 360) + 360);
  const quadrant = (edg / 90) % 4; //旋转象限
  const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 }; //裁剪坐标
  var image = new Image();
  image.crossOrigin = 'anonymous';
  image.src = src;
  image.onload = function() {
    imgW = image.width;
    imgH = image.height;
    size = imgW > imgH ? imgW : imgH;
    canvas.width = size * 2;
    canvas.height = size * 2;
    switch (quadrant) {
      case 0:
        cutCoor.sx = size;
        cutCoor.sy = size;
        cutCoor.ex = size + imgW;
        cutCoor.ey = size + imgH;
        break;
      case 1:
        cutCoor.sx = size - imgH;
        cutCoor.sy = size;
        cutCoor.ex = size;
        cutCoor.ey = size + imgW;
        break;
      case 2:
        cutCoor.sx = size - imgW;
        cutCoor.sy = size - imgH;
        cutCoor.ex = size;
        cutCoor.ey = size;
        break;
      case 3:
        cutCoor.sx = size;
        cutCoor.sy = size - imgW;
        cutCoor.ex = size + imgH;
        cutCoor.ey = size + imgW;
        break;
    }
    ctx.translate(size, size);
    ctx.rotate((edg * Math.PI) / 180);
    ctx.drawImage(image, 0, 0);
    var imgData = ctx.getImageData(
      cutCoor.sx,
      cutCoor.sy,
      cutCoor.ex,
      cutCoor.ey
    );
    if (quadrant % 2 == 0) {
      canvas.width = imgW;
      canvas.height = imgH;
    } else {
      canvas.width = imgH;
      canvas.height = imgW;
    }
    ctx.putImageData(imgData, 0, 0);
    callback(canvas.toDataURL('image/png'));
  };
}

# 3、图片压缩

下面是一个图片压缩的方法。或者可以借助一些三方库, 比如

compressorjs (opens new window)

应当会比下面的方法考虑更加全面一些

function compress(file, compress, callback) {
  const reader = new FileReader()
  reader.onload = function(evt) {
    if (compress === false) {
      callback(file)
      return
    }

    // 启用压缩的分支
    const img = new Image()
    img.onload = function() {
      const ratio = detectVerticalSquash(img)
      const orientation = getOrientation(dataURItoBuffer(img.src))
      const canvas = document.createElement('canvas')
      const ctx = canvas.getContext('2d')

      const maxW = compress.width
      const maxH = compress.height
      let w = img.width
      let h = img.height
      let dataURL

      if (w < h && h > maxH) {
        w = parseInt((maxH * img.width) / img.height)
        h = maxH
      } else if (w >= h && w > maxW) {
        h = parseInt((maxW * img.height) / img.width)
        w = maxW
      }

      canvas.width = w
      canvas.height = h

      if (orientation > 0) {
        orientationHelper(canvas, ctx, orientation)
      }
      ctx.drawImage(img, 0, 0, w, h / ratio)

      if (/image\/jpeg/.test(file.type) || /image\/jpg/.test(file.type)) {
        dataURL = canvas.toDataURL('image/jpeg', compress.quality)
      } else {
        dataURL = canvas.toDataURL(file.type)
      }

      if (/;base64,null/.test(dataURL) || /;base64,$/.test(dataURL)) {
        // 压缩出错,以文件方式上传的,采用原文件上传
        console.warn(
          'Compress fail, dataURL is ' +
            dataURL +
            '. Next will use origin file to upload.'
        )
        callback(file)
      } else {
        const blob = dataURItoBlob(dataURL)
        blob.name = file.name
        callback(blob)
      }
    }
    img.src = evt.target.result
  }
  reader.readAsDataURL(file)
}
function getOrientation(buffer) {
  const view = new DataView(buffer)
  if (view.getUint16(0, false) != 0xffd8) return -2
  const length = view.byteLength
  let offset = 2
  while (offset < length) {
    const marker = view.getUint16(offset, false)
    offset += 2
    if (marker == 0xffe1) {
      if (view.getUint32((offset += 2), false) != 0x45786966) return -1
      const little = view.getUint16((offset += 6), false) == 0x4949
      offset += view.getUint32(offset + 4, little)
      const tags = view.getUint16(offset, little)
      offset += 2
      for (let i = 0; i < tags; i++)
        if (view.getUint16(offset + i * 12, little) == 0x0112)
          return view.getUint16(offset + i * 12 + 8, little)
    } else if ((marker & 0xff00) != 0xff00) break
    else offset += view.getUint16(offset, false)
  }
  return -1
}

function detectVerticalSquash(img) {
  // 拍照在IOS7或以下的机型会出现照片被压扁的bug
  let data
  const ih = img.naturalHeight
  const canvas = document.createElement('canvas')
  canvas.width = 1
  canvas.height = ih
  const ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0)
  try {
    data = ctx.getImageData(0, 0, 1, ih).data
  } catch (err) {
    console.log('Cannot check verticalSquash: CORS?')
    return 1
  }
  let sy = 0
  let ey = ih
  let py = ih
  while (py > sy) {
    const alpha = data[(py - 1) * 4 + 3]
    if (alpha === 0) {
      ey = py
    } else {
      sy = py
    }
    py = (ey + sy) >> 1 // py = parseInt((ey + sy) / 2)
  }
  const ratio = py / ih
  return ratio === 0 ? 1 : ratio
}

# 4、图片的延迟加载的一些方式

function loadImage(obj, url, callback) {
  var img = new Image();
  img.src = url;
  // 判断图片是否在缓存中
  if (img.complete) {
    callback.call(img, obj);
    return;
  }
  // 图片加载到浏览器的缓存中回调函数
  img.onload = function () {
    callback.call(img, obj);
  };
}
function showImage(obj) {
  obj.src = this.src;
}
var imgs = document.querySelectorAll('img');
for (var i = 0; i < imgs.length; i++) {
  var url = imgs[i].dataset.src;
  loadImage(imgs[i], url, showImage);
}

就是先用img元素占位, 可以给一个默认的占位的图片, 这个资源可以比较小,真实的url可以保存在data-src中, 然后在一些load或者mount的钩子回调中执行这样子的一个操作。提供一种思路吧。 或者上划加载更多的懒加载方式,或者判断位置的那种可见再加载。

# 5、在网页中实现图片的放大预览

上次更新: 1/22/2025, 9:39:13 AM