didi / mand-mobile

💰 A mobile UI toolkit, based on Vue.js 2, designed for financial scenarios.

Home Page:https://didi.github.io/mand-mobile

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

imageProcessor处理ios 竖直图片时,导致图片变形的问题

pengkai0113 opened this issue · comments

先上源码

/* istanbul ignore next */
function getImageSize(img, orientation, maxWidth, maxHeight) {
  const ret = {
    width: img.width,
    height: img.height,
  }

  if ('5678'.indexOf(orientation) > -1) {
    ret.width = img.height
    ret.height = img.width
  }

  // 如果原图小于设定,采用原图
  if (ret.width < maxWidth || ret.height < maxHeight) {
    return ret
  }

  const scale = ret.width / ret.height

  if (maxWidth && maxHeight) {
    if (scale >= maxWidth / maxHeight) {
      if (ret.width > maxWidth) {
        ret.width = maxWidth
        ret.height = Math.ceil(maxWidth / scale)
      }
    } else {
      if (ret.height > maxHeight) {
        ret.height = maxHeight
        ret.width = Math.ceil(maxHeight * scale)
      }
    }
  } else if (maxWidth) {
    if (maxWidth < ret.width) {
      ret.width = maxWidth
      ret.height = Math.ceil(maxWidth / scale)
    }
  } else if (maxHeight < ret.height) {
    ret.width = Math.ceil(maxHeight * scale)
    ret.height = maxHeight
  }

  // 超过这个值base64无法生成,在IOS上
  if (ret.width >= 3264 || ret.height >= 2448) {
    ret.width *= 0.8
    ret.height *= 0.8
  }

  return ret
}
/* istanbul ignore next */
function makeCanvas(img, orientation, maxWidth, maxHeight, quality) {
  const {width, height} = getImageSize(img, orientation, maxWidth, maxHeight)
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')

  canvas.width = width
  canvas.height = height
  ctx.drawImage(img, 0, 0, width, height)

  let base64 = null
  if (CSS && CSS.supports && !CSS.supports('image-orientation:none')) {
    switch (orientation) {
      case 3:
        ctx.rotate(180 * Math.PI / 180)
        ctx.drawImage(img, -width, -height, width, height)
        break
      case 6:
        ctx.rotate(90 * Math.PI / 180)
        ctx.drawImage(img, 0, -width, height, width)
        break
      case 8:
        ctx.rotate(270 * Math.PI / 180)
        ctx.drawImage(img, -height, 0, height, width)
        break
      case 2:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.drawImage(img, 0, 0, width, height)
        break
      case 4:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(180 * Math.PI / 180)
        ctx.drawImage(img, -width, -height, width, height)
        break
      case 5:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(90 * Math.PI / 180)
        ctx.drawImage(img, 0, -width, height, width)
        break
      case 7:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(270 * Math.PI / 180)
        ctx.drawImage(img, -height, 0, height, width)
        break
      default:
        ctx.drawImage(img, 0, 0, width, height)
    }
  } else {
    ctx.drawImage(img, 0, 0, width, height)
  }

  if ((UA.oldIOS || UA.oldAndroid || UA.mQQBrowser || !navigator.userAgent) && window.JPEGEncoder) {
    /* global JPEGEncoder */
    const encoder = new JPEGEncoder()
    const newImg = ctx.getImageData(0, 0, canvas.width, canvas.height)
    base64 = encoder.encode(newImg, quality * 100)
  } else {
    base64 = canvas.toDataURL('image/jpeg', quality)
  }

  return base64
}

getImageSize函数会处理图片的宽高,makeCanvas会根据这个宽高在canvas中绘制图片。

场景:ios 处理竖直图片

竖直图片在getImageSize 中 ('5678'.indexOf(orientation) > -1为true,所以会被宽高互换
CSS && CSS.supports && !CSS.supports('image-orientation:none')判断为fasle,所以makeCanvas会按错误的宽高直接绘制图片。
这个地方应该判断判断一下

if (CSS && CSS.supports && !CSS.supports('image-orientation:none')) {
    switch (orientation) {
      case 3:
        ctx.rotate(180 * Math.PI / 180)
        ctx.drawImage(img, -width, -height, width, height)
        break
      case 6:
        ctx.rotate(90 * Math.PI / 180)
        ctx.drawImage(img, 0, -width, height, width)
        break
      case 8:
        ctx.rotate(270 * Math.PI / 180)
        ctx.drawImage(img, -height, 0, height, width)
        break
      case 2:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.drawImage(img, 0, 0, width, height)
        break
      case 4:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(180 * Math.PI / 180)
        ctx.drawImage(img, -width, -height, width, height)
        break
      case 5:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(90 * Math.PI / 180)
        ctx.drawImage(img, 0, -width, height, width)
        break
      case 7:
        ctx.translate(width, 0)
        ctx.scale(-1, 1)
        ctx.rotate(270 * Math.PI / 180)
        ctx.drawImage(img, -height, 0, height, width)
        break
      default:
        ctx.drawImage(img, 0, 0, width, height)
    }
  } else {
    //交换过宽高的图片要按交换过的大小绘制图片
    if('5678'.indexOf(orientation) > -1){
      ctx.drawImage(img, 0, 0, height, width)
    }else{
      ctx.drawImage(img, 0, 0, width, height)
    }
  }

兼容方案

对ios的竖直图片进行旋转处理,转成水平的图片,再经过imageProcessor压缩就可以了