首页 > 编程语言 >JavaScript修改修改图片dpi

JavaScript修改修改图片dpi

时间:2022-11-05 22:36:38浏览次数:44  
标签:const physChunk JavaScript 修改 let dpi data dataArray

欢迎关注前端早茶,与广东靓仔携手共同进阶

JavaScript修改修改图片dpi_ide

前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~

 

一、原理

changeDPI 提供了 2 个实用函数,可以更改画布生成的图像的 dpi,无论是 dataUrl 还是 Blob 格式。这些函数用于将标题与图像数据分离,仅转换和操作标题,然后将标题粘贴回文件上。通过这种方式,可以快速转换非常大的图像,而无需转换图像文件的全部内容。这个过程是非破坏性的——图像数据在这个过程中不会被修改。

 

二、使用

安装

npm install --save changedpi

方式一、从画布元素 dataUrl:

// create the dataUrl at standard 72dpi
var dataUrl = canvas.toDataURL('image/jpeg', 0.92);
var daurl150dpi = changeDpiDataUrl(dataUrl, 150);

 

方式二、从画布元素 blob:

// create the blob at standard 72dpi
canvas.toBlob(function(blob) {
changeDpiBlob(blob, 300).then(function(blob){
// use your changed blob
})
},'image/jpeg', 0.92);

 

三、源代码

function createPngDataTable() {
/* Table of CRCs of all 8-bit messages. */
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) {
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;
}

let pngDataTable;

const PNG = 'image/png';
const 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
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, dpi) {
// 33 bytes are ok for pngs and jpegs
// to contain the information.
const headerChunk = blob.slice(0, 33);
return new Promise((resolve, reject) => {
const fileReader = 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, dpi) {
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);
// 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.
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) {
let 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) {
const 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 (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, 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) {
const 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....

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 = 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
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;
}
}
}

 

欢迎关注前端早茶,与广东靓仔携手共同进阶

JavaScript修改修改图片dpi_ide

前端早茶专注前端,一起结伴同行,紧跟业界发展步伐~

 



标签:const,physChunk,JavaScript,修改,let,dpi,data,dataArray
From: https://blog.51cto.com/feng/5826218

相关文章

  • 游戏修改-Dome Keeper
    FileName=..\domekeeper.exePathList\0000\Descrip=add-jmpPathList\0000\NewHex=E916FE4400909090PathList\0000\Offset=01691815;PathList\0000\OldHex=48......
  • 游戏修改-Crimson.Dawn.Build.9772117
    FileName=..\CrimsonDawn_Data\Managed\Assembly-CSharp.dllPathList\0000\Descrip=DropItem__ResetPathList\0000\NewHex=1APathList\0000\Offset=00007637;0......
  • 游戏修改-Against the Storm - Experimental
    FileName=..\AgainsttheStorm-Experimental_Data\Managed\Assembly-CSharp.dllPathList\0000\Descrip=CornerstonesService__RerollPathList\0000\NewHex=7B85......
  • 在网页中加载闪存文件系统中的图片、css和javascript
    在网页中加载闪存文件系统中的图片、CSS和JavaScript–太极创客(taichi-maker.com)index.html:ESP8266开发板建立的网站首页main.css:控制网页的css(层叠样式表)JavaS......
  • 如何修改子组件的内部样式
    scoped是一个样式作用域:  1.可以让当前这个组件独享这个样式  2.对子组件的根元素样式同样有效果  3.对子组件的内部没有效果 原理:  当是我......
  • JavaScript之字符串的方法
    JavaScript字符串用于存储和处理文本。String(字符串)可以存储一系列字符,如"JavaScript之字符串的方法"。String也是基础数据类型。接下来查看String常用方法,如有不足和......
  • TypeScript与JavaScript区别
    TypeScript是JavaScript的一个超集,支持ECMAScript6标准。TypeScript由微软开发的自由和开源的编程语言。TypeScript设计目标是开发大型应用,它可以编译成纯JavaS......
  • Linux中redis启动修改密码操作
    启动在redis.conf同层目录下执行redis-serverredis.conf即可启动执行ps-ef|grepredis查看redis启动是否成功kill-985117停止redis redis-cli#连接本地r......
  • JavaScript数组的reduce()方法
    参考文章:Array.prototype.reduce()——MDN一、介绍reduce()方法对数组中的每个元素按顺序执行一个由您提供的reducer函数,每一次运行reducer都会将先前元素的......
  • 修改服务器ssh端口
    最近,访问公司虚拟机都需要通过堡垒机才能访问了,是挺麻烦。要想不受该规则限制,也可以通过修改虚拟机ssh端口,绕过限制。下面做个介绍。1.通过堡垒机登录虚拟机2.修改虚......