import changeDpi from './changeDpi' /** * Convert base64 to blob * @param {*} base64Data * @param {*} type file 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 }) } /** * Convert Blob to file * @param {*} theBlob blob file stream * @param {*} fileName file name * @param {*} type file type * @returns */ export function blobToFile(theBlob, fileName, type) { theBlob. lastModifiedDate = new Date() return new File([theBlob], fileName, { type: type }) } /** * base64 to file * @param {*} base64Data * @param {*} fileName * @param {*} type file 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 file download * @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) } /** * Image rotation * @param {*} imgUrl base64 file * @param {*} angle rotation 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() // Allow image URLs to cross-domain img.crossOrigin = 'anonymous' img.src = imgUrl img.onload = function() { // Set the width and height of the canvas to be equal to the width and height of the image canvas.width = this.width canvas.height = this.height // The center point of the canvas (also the starting point) is translated to the center (0,0)->(x,y) ctx. translate(canvas. width / 2, canvas. height / 2) // canvas rotation ctx.rotate(angle * Math.PI / 180) // Draw the image. The starting point of the image needs to be offset by a negative width and height, and the starting point of the image ctx.drawImage(img, -this.width/2, -this.height/2) // Return the result (base64) const base64 = canvas.toDataURL('image/png') // The default canvas is 96dpi, change to 72dpi const url = changeDpi.changeDpiDataUrl(base64, 72) resolve(url) } } catch (error) { reject(error) } }) } /** * Image set transparency * @param {*} imgUrl base64 file * @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() // Allow image URLs to cross-domain img.crossOrigin = 'anonymous' img.src = imgUrl img.onload = function() { // Set the width and height of the canvas, which is equal to the width and height of the image canvas.width = this.width canvas.height = this.height // set transparency ctx.globalAlpha = transparency ctx. drawImage(img, 0, 0, this. width, this. height) const base64 = canvas.toDataURL('image/png') // The default canvas is 96dpi, change to 72dpi const url = changeDpi.changeDpiDataUrl(base64, 72) resolve(url) } } catch (error) { reject(error) } }) } /** * Image setting transparency, image rotation * @param {*} imgUrl base64 file * @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() // Allow image URLs to cross-domain img.crossOrigin = 'anonymous' img.src = imgUrl img.onload = function() { // Set the width and height of the canvas to be equal to the width and height of the image canvas.width = this.width canvas.height = this.height // set transparency ctx.globalAlpha = transparency // The center point of the canvas (also the starting point) is translated to the center (0,0)->(x,y) ctx. translate(canvas. width / 2, canvas. height / 2) // canvas rotation ctx.rotate(angle * Math.PI / 180) // Draw the image. The starting point of the image needs to be offset by a negative width and height, and the starting point of the image ctx.drawImage(img, -this.width/2, -this.height/2) // Return the result (base64) const base64 = canvas.toDataURL('image/png') // The default canvas is 96dpi, change to 72dpi const url = changeDpi.changeDpiDataUrl(base64, 72) resolve(url) } } catch (error) { reject(error) } }) }
Modify the image dpi method:
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 signatures of the physBlock in base64. // the PHYs signature block is preceded 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 allows us to find this particular occurrence 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 & amp; & amp; data[i - 3] === _P & amp; & amp; data[i - 2] === _H & amp; & amp; data[i - 1] === _Y & amp; & amp; 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 & amp; 0xff // dpiX low byte dataArray[16] = dpi >> 8 // dpiY high byte dataArray[17] = dpi & amp; 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 very high byte physChunk[6] = dpi >>> 8 // dpiX high byte physChunk[7] = dpi & amp; 0xff // dpiX low byte physChunk[8] = physChunk[4] // dpiY highest byte physChunk[9] = physChunk[5] // dpiY very high 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 containing some info, untill desired // length is met. // chunk structure 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 }