Цель: отобразить 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