Skip to content

Instantly share code, notes, and snippets.

@zazaulola
Created June 15, 2022 21:08
Show Gist options
  • Save zazaulola/44aa030102dcc55a270852b034a854ba to your computer and use it in GitHub Desktop.
Save zazaulola/44aa030102dcc55a270852b034a854ba to your computer and use it in GitHub Desktop.
/** @format */
/**
* Функция отчищает JPEG-картинку от метаданных
*
* @param {ArrayBuffer} buf буфер с изображением
* @returns {Blob|null}
*/
function clearJpegMetadata(buf) {
if (!(buf instanceof ArrayBuffer)) {
console.error('buf = ', buf);
throw new TypeError('Wrong ArrayBuffer specified');
}
const dv = new DataView(buf);
const length = dv.byteLength;
const SOI = dv.getUint16(0, false);
const EOI = dv.getUint16(length - 2, false);
if (SOI != 0xffd8 || EOI != 0xffd9) {
console.error('SOI = ', SOI);
console.error('EOI = ', EOI);
throw new ReferenceError('Not valid JPEG image');
}
const p = [];
let r = 0;
for (const { type, ofs, len } of readJpegSegments(buf)) {
if (type == 0xe1) {
p.push([r, ofs - 2]);
r = ofs + len;
} else if (type == 0xda) {
p.push([r]);
break;
}
}
return p.length
? new Blob(
p.map(a => buf.slice(...a)),
{ type: 'image/jpeg' }
)
: null;
}
/** @format */
/**
* Функция читает из буфера JPEG-картинки ориентацию и размеры в пикселях
*
* @param {ArrayBuffer} buf буфер с изображением
* @returns {{orientation:Number,width:Number,height:Number}}
*/
function readJpegRect(buf) {
if (!(buf instanceof ArrayBuffer)) {
console.error('buf = ', buf);
throw new TypeError('Wrong ArrayBuffer specified');
}
const dv = new DataView(buf);
const length = dv.byteLength;
const SOI = dv.getUint16(0, false);
const EOI = dv.getUint16(length - 2, false);
if (SOI != 0xffd8 || EOI != 0xffd9) {
console.error('SOI = ', SOI);
console.error('EOI = ', EOI);
throw new ReferenceError('Not valid JPEG image');
}
let width=0,height=0,orientation=0;
for (let { type, ofs } of readJpegSegments(buf)) {
if (type == 0xe1) {
if (dv.getUint32(ofs, false) != 0x45786966 || dv.getUint16(ofs + 4, false) != 0) {
throw new Error('Wrong Exif format');
}
ofs += 6;
const isLE = dv.getUint16(ofs, false) == 0x4949;
ofs += dv.getUint32(ofs + 4, isLE);
const tagCount = dv.getUint16(ofs, isLE);
ofs += 2;
for (let i = 0; i < tagCount; i++){
if (dv.getUint16(ofs + i * 12, isLE) == 0x0112) {
orientation = dv.getUint16(ofs + i * 12 + 8, isLE);
}
}
} else if (0xc0 <= type && type <= 0xcf) {
ofs += 1;
height = Math.max(height, dv.getUint16(ofs, false));
ofs += 2;
width = Math.max(width, dv.getUint16(ofs, false));
}
}
if (!orientation) {
orientation = 1;
}
return { orientation, width, height };
}
/**
* Читает сегменты из JPEG буфера
* @param {ArrayBuffer} buf
* @yields {type: Number, ofs: Number, len: Number}
*/
function* readJpegSegments(buf) {
if (!(buf instanceof ArrayBuffer)) {
console.error('buf = ', buf);
throw new TypeError('Wrong ArrayBuffer specified');
}
const dv = new DataView(buf);
const length = dv.byteLength;
const SOI = dv.getUint16(0, false);
const EOI = dv.getUint16(length - 2, false);
if (SOI != 0xffd8 || EOI != 0xffd9) {
console.error('SOI = ', SOI);
console.error('EOI = ', EOI);
throw new ReferenceError('Not valid JPEG image');
}
let idx = 2;
while (idx < size - 2) {
if (0xff != dv.getUint8(idx++)) {
throw new RangeError('Not valid JPEG image');
}
const type = dv.getUint8(idx++);
const ofs = idx;
const len = dv.getUint16(idx, false);
idx += len;
yield { type, ofs, len };
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment