Невозможно загрузить (сохранить изображение как) элемент холста в мобильном Интернете (ReactJS) - PullRequest
0 голосов
/ 11 октября 2019

Цель: отобразить QRCode (на холсте) как в Интернете, так и в мобильном Интернете, и позволить пользователям щелкнуть правой кнопкой мыши -> Сохранить как изображение.

Это работает как на настольных ПК Google Chrome, так и в Safari, но не для мобильных устройств. Браузеры Chrome и Safari.

Два вопроса:

1) Почему это возможно в сети с использованием существующего кода, но не для мобильного Интернета? Может ли Chrome / Safari для настольных компьютеров автоматически определять холст как изображение через капли? HTMLCanvasElement.toBlob ()

2) Если да, есть ли способ обойти эту проблему без использования window.open? Я пробовал решения в здесь и здесь .

Я разветвил и изменил существующую библиотеку, cssivision / qrcode-реаги * . Основным отличием от оригинала является то, что я создал состояние для хранения значения dataUrl в компоненте класса QRCode (и вместо этого возвращает изображение), но imageUrl всегда не определено. Любая идея, как я могу обойти проблему элемента холста, не обнаруженного как изображение для мобильного Интернета, используя React?



const React = require('react')
const PropTypes = require('prop-types')
const ReactDOM = require('react-dom')
const qr = require('qr.js')

function getBackingStorePixelRatio(ctx) {
  return (
    ctx.webkitBackingStorePixelRatio
    || ctx.mozBackingStorePixelRatio
    || ctx.msBackingStorePixelRatio
    || ctx.oBackingStorePixelRatio
    || ctx.backingStorePixelRatio
    || 1
  )
}

let getDOMNode
if (/^0\.14/.test(React.version)) {
  getDOMNode = function (ref) {
    return ref
  }
} else {
  getDOMNode = function (ref) {
    return ReactDOM.findDOMNode(ref)
  }
}

class QRCode extends React.Component {
  constructor(props) {
    super()
    this.state = {
      imageUrl: '',
    }
  }
  shouldComponentUpdate(nextProps) {
    const that = this
    return Object.keys(QRCode.propTypes).some(k => that.props[k] !== nextProps[k])
  }

  componentDidMount() {
    this.update()
  }

  componentDidUpdate() {
    this.update()
  }

  utf16to8(str) {
    let out; let i; let len; let c
    out = ''
    len = str.length
    for (i = 0; i < len; i++) {
      c = str.charCodeAt(i)
      if ((c >= 0x0001) && (c <= 0x007F)) {
        out += str.charAt(i)
      } else if (c > 0x07FF) {
        out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F))
        out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F))
        out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F))
      } else {
        out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F))
        out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F))
      }
    }
    return out
  }

  update() {
    const value = this.utf16to8(this.props.value)
    const qrcode = qr(value)
    const canvas = getDOMNode(this.refs.canvas)

    const ctx = canvas.getContext('2d')
    const cells = qrcode.modules
    const tileW = this.props.size / cells.length
    const tileH = this.props.size / cells.length
    const scale = (window.devicePixelRatio || 1) / getBackingStorePixelRatio(ctx)
    canvas.height = canvas.width = this.props.size * scale
    ctx.scale(scale, scale)

    cells.forEach(function (row, rdx) {
      row.forEach(function (cell, cdx) {
        ctx.fillStyle = cell ? this.props.fgColor : this.props.bgColor
        const w = (Math.ceil((cdx + 1) * tileW) - Math.floor(cdx * tileW))
        const h = (Math.ceil((rdx + 1) * tileH) - Math.floor(rdx * tileH))
        ctx.fillRect(Math.round(cdx * tileW), Math.round(rdx * tileH), w, h)
      }, this)
    }, this)

    if (this.props.logo) {
      const self = this
      const { size } = this.props
      const image = document.createElement('img')
      image.src = this.props.logo
      image.onload = function () {
        // (originalLogoWidth / originalQRSize = 100 / 220 = 0.4545)
        const dwidth = self.props.logoWidth || size * 0.45
        const dheight = self.props.logoHeight || image.height / image.width * dwidth
        const dx = (size - dwidth) / 2
        const dy = (size - dheight) / 2
        image.width = dwidth
        image.height = dheight
        ctx.drawImage(image, dx, dy, dwidth, dheight)
      }
    }
    const img = canvas.toDataURL("image/png") // this works
    this.setState({ imageUrl: img }) // not assigned here
    console.log('img base64', this.state.imageUrl); // undefined
  }

  render() {
     // this does not return anything
     return React.createElement('img', {
       src: `data:image/png;base64,${this.state.imageUrl}`,
       style: { height: '100%', width: '100%' },
     })
  }
}

QRCode.propTypes = {
  value: PropTypes.string.isRequired,
  size: PropTypes.number,
  bgColor: PropTypes.string,
  fgColor: PropTypes.string,
  logo: PropTypes.string,
  logoWidth: PropTypes.number,
  logoHeight: PropTypes.number,
}

QRCode.defaultProps = {
  size: 128,
  bgColor: '#FFFFFF',
  fgColor: '#000000',
}

module.exports = QRCode

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...