|
@@ -0,0 +1,197 @@
|
|
|
+
|
|
|
+ * var dataUrl = canvas.toDataURL('image/jpeg', 0.92);
|
|
|
+ * var daurl150dpi = changeDpiDataUrl(dataUrl, 150);
|
|
|
+ *
|
|
|
+ * canvas.toBlob(function(blob) {
|
|
|
+ * changeDpiBlob(blob, 300).then(function(blob){
|
|
|
+ *
|
|
|
+ * })
|
|
|
+ * },'image/jpeg', 0.92);
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+let pngDataTable: any;
|
|
|
+
|
|
|
+const PNG = 'image/png';
|
|
|
+const JPEG = 'image/jpeg';
|
|
|
+function createPngDataTable() {
|
|
|
+
|
|
|
+ const crcTable = new Int32Array(256);
|
|
|
+ for (let n = 0; n < 256; n++) {
|
|
|
+ let c = n;
|
|
|
+ for (let k = 0; k < 8; k++) {
|
|
|
+ c = (c & 1) ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
|
+ }
|
|
|
+ crcTable[n] = c;
|
|
|
+ }
|
|
|
+ return crcTable;
|
|
|
+}
|
|
|
+
|
|
|
+function calcCrc(buf: any) {
|
|
|
+ let c = -1;
|
|
|
+ if (!pngDataTable) pngDataTable = createPngDataTable();
|
|
|
+ for (let n = 0; n < buf.length; n++) {
|
|
|
+ c = pngDataTable[(c ^ buf[n]) & 0xFF] ^ (c >>> 8);
|
|
|
+ }
|
|
|
+ return c ^ -1;
|
|
|
+}
|
|
|
+
|
|
|
+function searchStartOfPhys(data: any[]) {
|
|
|
+ const length = data.length - 1;
|
|
|
+
|
|
|
+
|
|
|
+ for (let 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: any, dpi: any, format: any, overwritepHYs?: any) {
|
|
|
+ if (format === JPEG) {
|
|
|
+ dataArray[13] = 1;
|
|
|
+ dataArray[14] = dpi >> 8;
|
|
|
+ dataArray[15] = dpi & 0xff;
|
|
|
+ dataArray[16] = dpi >> 8;
|
|
|
+ dataArray[17] = dpi & 0xff;
|
|
|
+ return dataArray;
|
|
|
+ }
|
|
|
+ if (format === PNG) {
|
|
|
+ const physChunk = new Uint8Array(13);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ dpi *= 39.3701;
|
|
|
+ physChunk[0] = _P;
|
|
|
+ physChunk[1] = _H;
|
|
|
+ physChunk[2] = _Y;
|
|
|
+ physChunk[3] = _S;
|
|
|
+ physChunk[4] = dpi >>> 24;
|
|
|
+ physChunk[5] = dpi >>> 16;
|
|
|
+ physChunk[6] = dpi >>> 8;
|
|
|
+ physChunk[7] = dpi & 0xff;
|
|
|
+ physChunk[8] = physChunk[4];
|
|
|
+ physChunk[9] = physChunk[5];
|
|
|
+ physChunk[10] = physChunk[6];
|
|
|
+ physChunk[11] = physChunk[7];
|
|
|
+ physChunk[12] = 1;
|
|
|
+
|
|
|
+ const crc = calcCrc(physChunk);
|
|
|
+
|
|
|
+ const crcChunk = new Uint8Array(4);
|
|
|
+ crcChunk[0] = crc >>> 24;
|
|
|
+ crcChunk[1] = crc >>> 16;
|
|
|
+ crcChunk[2] = crc >>> 8;
|
|
|
+ crcChunk[3] = crc & 0xff;
|
|
|
+
|
|
|
+ if (overwritepHYs) {
|
|
|
+ const startingIndex: any = searchStartOfPhys(dataArray);
|
|
|
+ dataArray.set(physChunk, startingIndex);
|
|
|
+ dataArray.set(crcChunk, startingIndex + 13);
|
|
|
+ return dataArray;
|
|
|
+ } else {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ const chunkLength = new Uint8Array(4);
|
|
|
+ chunkLength[0] = 0;
|
|
|
+ chunkLength[1] = 0;
|
|
|
+ chunkLength[2] = 0;
|
|
|
+ chunkLength[3] = 9;
|
|
|
+
|
|
|
+ const finalHeader = new Uint8Array(54);
|
|
|
+ finalHeader.set(dataArray, 0);
|
|
|
+ finalHeader.set(chunkLength, 33);
|
|
|
+ finalHeader.set(physChunk, 37);
|
|
|
+ finalHeader.set(crcChunk, 50);
|
|
|
+ return finalHeader;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const b64PhysSignature1 = 'AAlwSFlz';
|
|
|
+const b64PhysSignature2 = 'AAAJcEhZ';
|
|
|
+const b64PhysSignature3 = 'AAAACXBI';
|
|
|
+
|
|
|
+const _P = 'p'.charCodeAt(0);
|
|
|
+const _H = 'H'.charCodeAt(0);
|
|
|
+const _Y = 'Y'.charCodeAt(0);
|
|
|
+const _S = 's'.charCodeAt(0);
|
|
|
+
|
|
|
+export function changeDpiBlob(blob: any, dpi: any) {
|
|
|
+
|
|
|
+
|
|
|
+ const headerChunk = blob.slice(0, 33);
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const fileReader: any = new FileReader();
|
|
|
+ fileReader.onload = () => {
|
|
|
+ const dataArray = new Uint8Array(fileReader.result);
|
|
|
+ const tail = blob.slice(33);
|
|
|
+ const changedArray = changeDpiOnArray(dataArray, dpi, blob.type);
|
|
|
+ resolve(new Blob([changedArray, tail], { type: blob.type }));
|
|
|
+ };
|
|
|
+ fileReader.readAsArrayBuffer(headerChunk);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+export function changeDpiDataUrl(base64Image: any, dpi: any) {
|
|
|
+ const dataSplitted = base64Image.split(',');
|
|
|
+ const format = dataSplitted[0];
|
|
|
+ const body = dataSplitted[1];
|
|
|
+ let type;
|
|
|
+ let headerLength;
|
|
|
+ let overwritepHYs = false;
|
|
|
+ if (format.indexOf(PNG) !== -1) {
|
|
|
+ type = PNG;
|
|
|
+ const b64Index = detectPhysChunkFromDataUrl(body);
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ const stringHeader = body.substring(0, headerLength);
|
|
|
+ const restOfData = body.substring(headerLength);
|
|
|
+ const headerBytes = atob(stringHeader);
|
|
|
+ const dataArray = new Uint8Array(headerBytes.length);
|
|
|
+ for (let i = 0; i < dataArray.length; i++) {
|
|
|
+ dataArray[i] = headerBytes.charCodeAt(i);
|
|
|
+ }
|
|
|
+ const finalArray = changeDpiOnArray(dataArray, dpi, type, overwritepHYs);
|
|
|
+ const base64Header = btoa(String.fromCharCode(...finalArray));
|
|
|
+ return [format, ',', base64Header, restOfData].join('');
|
|
|
+}
|
|
|
+
|
|
|
+function detectPhysChunkFromDataUrl(data: any) {
|
|
|
+ let b64index = data.indexOf(b64PhysSignature1);
|
|
|
+ if (b64index === -1) {
|
|
|
+ b64index = data.indexOf(b64PhysSignature2);
|
|
|
+ }
|
|
|
+ if (b64index === -1) {
|
|
|
+ b64index = data.indexOf(b64PhysSignature3);
|
|
|
+ }
|
|
|
+
|
|
|
+ return b64index;
|
|
|
+}
|