import changeDpi from './changeDpi'
/**
* 将base64转换为blob
* @param {*} base64Data
* @param {*} type 文件类型
* @returns
*/
export function base64ToBlob(base64Data, type) {
const bytes = window.atob(base64Data.split(',')[1])
const array = []
for (let i = 0; i < bytes.length; i++) {
array.push(bytes.charCodeAt(i))
}
return new Blob([new Uint8Array(array)], { type: type })
}
/**
* 将Blob转换为file
* @param {*} theBlob blob文件流
* @param {*} fileName 文件名
* @param {*} type 文件类型
* @returns
*/
export function blobToFile(theBlob, fileName, type) {
theBlob.lastModifiedDate = new Date()
return new File([theBlob], fileName, { type: type })
}
/**
* base64转file
* @param {*} base64Data
* @param {*} fileName
* @param {*} type 文件类型
* @returns
*/
export function base64ToFile(base64Data, fileName, type) {
const bytes = window.atob(base64Data.split(',')[1])
const array = []
for (let i = 0; i < bytes.length; i++) {
array.push(bytes.charCodeAt(i))
}
const theBlob = new Blob([new Uint8Array(array)], { type: type })
theBlob.lastModifiedDate = new Date()
return new File([theBlob], fileName, { type: type })
}
/**
* base64文件下载
* @param {*} base64Data
* @param {*} fileName
* @param {*} type
*/
export async function base64DownloadFile(base64Data, fileName, type) {
const blob = base64ToBlob(base64Data, type)
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = fileName
document.body.appendChild(link)
const evt = document.createEvent('MouseEvents')
evt.initEvent('click', false, false)
link.dispatchEvent(evt)
document.body.removeChild(link)
}
/**
* 图片旋转
* @param {*} imgUrl base64文件
* @param {*} angle 旋转角度
* @returns
*/
export async function imageRotate(imgUrl, angle) {
return new Promise((resolve, reject) => {
try {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
// 允许图片地址跨域
img.crossOrigin = 'anonymous'
img.src = imgUrl
img.onload = function() {
// 设置canvas宽高等于图片宽高
canvas.width = this.width
canvas.height = this.height
// 画布中心点(也是起始点)平移至中心(0,0)->(x,y)
ctx.translate(canvas.width / 2, canvas.height / 2)
// 画布旋转
ctx.rotate(angle * Math.PI / 180)
// 绘制图像 图像起始点需偏移负宽高,图片起始点
ctx.drawImage(img, -this.width / 2, -this.height / 2)
// 返回结果(base64)
const base64 = canvas.toDataURL('image/png')
// 默认canvas是96dpi,改为72dpi
const url = changeDpi.changeDpiDataUrl(base64, 72)
resolve(url)
}
} catch (error) {
reject(error)
}
})
}
/**
* 图片设置透明度
* @param {*} imgUrl base64文件
* @param {*} transparency 透明度 0-1
* @returns
*/
export async function setAlpha(imgUrl, transparency) {
return new Promise((resolve, reject) => {
try {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
// 允许图片地址跨域
img.crossOrigin = 'anonymous'
img.src = imgUrl
img.onload = function() {
// 设置canvas宽高,等于图片宽高
canvas.width = this.width
canvas.height = this.height
// 设置透明度
ctx.globalAlpha = transparency
ctx.drawImage(img, 0, 0, this.width, this.height)
const base64 = canvas.toDataURL('image/png')
// 默认canvas是96dpi,改为72dpi
const url = changeDpi.changeDpiDataUrl(base64, 72)
resolve(url)
}
} catch (error) {
reject(error)
}
})
}
/**
* 图片设置透明度,图片旋转
* @param {*} imgUrl base64文件
* @param {*} transparency 透明度 0-1
* @returns
*/
export async function setRotateAndSetAlpha(imgUrl, angle, transparency) {
return new Promise((resolve, reject) => {
try {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
// 允许图片地址跨域
img.crossOrigin = 'anonymous'
img.src = imgUrl
img.onload = function() {
// 设置canvas宽高等于图片宽高
canvas.width = this.width
canvas.height = this.height
// 设置透明度
ctx.globalAlpha = transparency
// 画布中心点(也是起始点)平移至中心(0,0)->(x,y)
ctx.translate(canvas.width / 2, canvas.height / 2)
// 画布旋转
ctx.rotate(angle * Math.PI / 180)
// 绘制图像 图像起始点需偏移负宽高,图片起始点
ctx.drawImage(img, -this.width / 2, -this.height / 2)
// 返回结果(base64)
const base64 = canvas.toDataURL('image/png')
// 默认canvas是96dpi,改为72dpi
const url = changeDpi.changeDpiDataUrl(base64, 72)
resolve(url)
}
} catch (error) {
reject(error)
}
})
}
修改图片dpi方法:
Object.defineProperty(exports, '__esModule', {
value: true
})
exports.changeDpiBlob = changeDpiBlob
exports.changeDpiDataUrl = changeDpiDataUrl
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i] } return arr2 } else { return Array.from(arr) } }
function createPngDataTable() {
/* Table of CRCs of all 8-bit messages. */
var crcTable = new Int32Array(256)
for (var n = 0; n < 256; n++) {
var c = n
for (var k = 0; k < 8; k++) {
c = c & 1 ? 0xedb88320 ^ c >>> 1 : c >>> 1
}
crcTable[n] = c
}
return crcTable
}
function calcCrc(buf) {
var c = -1
if (!pngDataTable) pngDataTable = createPngDataTable()
for (var n = 0; n < buf.length; n++) {
c = pngDataTable[(c ^ buf[n]) & 0xFF] ^ c >>> 8
}
return c ^ -1
}
var pngDataTable = void 0
var PNG = 'image/png'
var JPEG = 'image/jpeg'
// those are 3 possible signature of the physBlock in base64.
// the pHYs signature block is preceed by the 4 bytes of lenght. The length of
// the block is always 9 bytes. So a phys block has always this signature:
// 0 0 0 9 p H Y s.
// However the data64 encoding aligns we will always find one of those 3 strings.
// this allow us to find this particular occurence of the pHYs block without
// converting from b64 back to string
var b64PhysSignature1 = 'AAlwSFlz'
var b64PhysSignature2 = 'AAAJcEhZ'
var b64PhysSignature3 = 'AAAACXBI'
var _P = 'p'.charCodeAt(0)
var _H = 'H'.charCodeAt(0)
var _Y = 'Y'.charCodeAt(0)
var _S = 's'.charCodeAt(0)
function changeDpiBlob(blob, dpi) {
// 33 bytes are ok for pngs and jpegs
// to contain the information.
var headerChunk = blob.slice(0, 33)
return new Promise(function(resolve, reject) {
var fileReader = new FileReader()
fileReader.onload = function() {
var dataArray = new Uint8Array(fileReader.result)
var tail = blob.slice(33)
var changedArray = changeDpiOnArray(dataArray, dpi, blob.type)
resolve(new Blob([changedArray, tail], { type: blob.type }))
}
fileReader.readAsArrayBuffer(headerChunk)
})
}
function changeDpiDataUrl(base64Image, dpi) {
var dataSplitted = base64Image.split(',')
var format = dataSplitted[0]
var body = dataSplitted[1]
var type = void 0
var headerLength = void 0
var overwritepHYs = false
if (format.indexOf(PNG) !== -1) {
type = PNG
var b64Index = detectPhysChunkFromDataUrl(body)
// 28 bytes in dataUrl are 21bytes, length of phys chunk with everything inside.
if (b64Index >= 0) {
headerLength = Math.ceil((b64Index + 28) / 3) * 4
overwritepHYs = true
} else {
headerLength = 33 / 3 * 4
}
}
if (format.indexOf(JPEG) !== -1) {
type = JPEG
headerLength = 18 / 3 * 4
}
// 33 bytes are ok for pngs and jpegs
// to contain the information.
var stringHeader = body.substring(0, headerLength)
var restOfData = body.substring(headerLength)
var headerBytes = atob(stringHeader)
var dataArray = new Uint8Array(headerBytes.length)
for (var i = 0; i < dataArray.length; i++) {
dataArray[i] = headerBytes.charCodeAt(i)
}
var finalArray = changeDpiOnArray(dataArray, dpi, type, overwritepHYs)
var base64Header = btoa(String.fromCharCode.apply(String, _toConsumableArray(finalArray)))
return [format, ',', base64Header, restOfData].join('')
}
function detectPhysChunkFromDataUrl(data) {
var b64index = data.indexOf(b64PhysSignature1)
if (b64index === -1) {
b64index = data.indexOf(b64PhysSignature2)
}
if (b64index === -1) {
b64index = data.indexOf(b64PhysSignature3)
}
// if b64index === -1 chunk is not found
return b64index
}
function searchStartOfPhys(data) {
var length = data.length - 1
// we check from the end since we cut the string in proximity of the header
// the header is within 21 bytes from the end.
for (var i = length; i >= 4; i--) {
if (data[i - 4] === 9 && data[i - 3] === _P && data[i - 2] === _H && data[i - 1] === _Y && data[i] === _S) {
return i - 3
}
}
}
function changeDpiOnArray(dataArray, dpi, format, overwritepHYs) {
if (format === JPEG) {
dataArray[13] = 1 // 1 pixel per inch or 2 pixel per cm
dataArray[14] = dpi >> 8 // dpiX high byte
dataArray[15] = dpi & 0xff // dpiX low byte
dataArray[16] = dpi >> 8 // dpiY high byte
dataArray[17] = dpi & 0xff // dpiY low byte
return dataArray
}
if (format === PNG) {
var physChunk = new Uint8Array(13)
// chunk header pHYs
// 9 bytes of data
// 4 bytes of crc
// this multiplication is because the standard is dpi per meter.
dpi *= 39.3701
physChunk[0] = _P
physChunk[1] = _H
physChunk[2] = _Y
physChunk[3] = _S
physChunk[4] = dpi >>> 24 // dpiX highest byte
physChunk[5] = dpi >>> 16 // dpiX veryhigh byte
physChunk[6] = dpi >>> 8 // dpiX high byte
physChunk[7] = dpi & 0xff // dpiX low byte
physChunk[8] = physChunk[4] // dpiY highest byte
physChunk[9] = physChunk[5] // dpiY veryhigh byte
physChunk[10] = physChunk[6] // dpiY high byte
physChunk[11] = physChunk[7] // dpiY low byte
physChunk[12] = 1 // dot per meter....
var crc = calcCrc(physChunk)
var crcChunk = new Uint8Array(4)
crcChunk[0] = crc >>> 24
crcChunk[1] = crc >>> 16
crcChunk[2] = crc >>> 8
crcChunk[3] = crc & 0xff
if (overwritepHYs) {
var startingIndex = searchStartOfPhys(dataArray)
dataArray.set(physChunk, startingIndex)
dataArray.set(crcChunk, startingIndex + 13)
return dataArray
} else {
// i need to give back an array of data that is divisible by 3 so that
// dataurl encoding gives me integers, for luck this chunk is 17 + 4 = 21
// if it was we could add a text chunk contaning some info, untill desired
// length is met.
// chunk structur 4 bytes for length is 9
var chunkLength = new Uint8Array(4)
chunkLength[0] = 0
chunkLength[1] = 0
chunkLength[2] = 0
chunkLength[3] = 9
var finalHeader = new Uint8Array(54)
finalHeader.set(dataArray, 0)
finalHeader.set(chunkLength, 33)
finalHeader.set(physChunk, 37)
finalHeader.set(crcChunk, 50)
return finalHeader
}
}
}
module.exports = {
changeDpiDataUrl: changeDpiDataUrl,
changeDpiBlob: changeDpiBlob
}