Skip to content

Commit

Permalink
Support EXIF 2.32 (2019)
Browse files Browse the repository at this point in the history
Use local package github:szapp/piexif-ts-0232
  • Loading branch information
szapp committed Mar 8, 2024
1 parent bfd2725 commit 7feff88
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 347 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
"homepage": "https://github.com/szapp/heic-jpg-exif#readme",
"dependencies": {
"exifr": "^7.1.3",
"fraction.js": "^4.3.7",
"heic-convert": "^2.1.0",
"mathjs": "^12.4.0",
"piexif": "^0.0.2"
"piexif-ts-0232": "github:szapp/piexif-ts-0232"
},
"engines": {
"node": ">=14.0.0"
Expand Down
82 changes: 51 additions & 31 deletions src/convert.js
Original file line number Diff line number Diff line change
@@ -1,66 +1,86 @@
const exifr = require('exifr');
const fs = require('fs');
const heicConvert = require('heic-convert');
const piexif = require('piexif');
const { formatTypes } = require('./format.js')
const piexif = require('piexif-ts-0232');
const { formatTypes } = require('./format.js');

const convert = async (inputFile, outputPath = null, quality = 1) => {
const parseOptions = {
ifd0: true,
ifd1: true,
exif: true,
gps: true,
translateKeys: false,
translateValues: false,
reviveValues: false,
sanitize: true,
mergeOutput: false,
};

async function convert(inputFile, outputPath = null, quality = 1) {
if (outputPath && typeof outputPath !== 'string') {
let err = new Error('Invalid argument: outputPath is expected to be a string');
delete err.stack;
throw err;
}

const options = {
translateKeys: false,
translateValues: false,
reviveValues: false,
sanitize: false,
mergeOutput: false,
};
// Load file or buffer
const fileData = typeof inputFile === 'string' ? fs.readFileSync(inputFile) : inputFile;

// Parse metadata
const exr = new exifr.Exifr(parseOptions);
await exr.read(fileData);
let { ifd0, ifd1, exif, gps } = await exr.parse();

const exr = new exifr.Exifr(options);
await exr.read(inputFile);
var { ifd0, exif, gps } = await exr.parse();
// Check file type (parse calls setup to instantiate the parser)
if (!(exr.fileParser instanceof exifr.fileParsers.get('heic'))) {
if (exr.fileParser instanceof exifr.fileParsers.get('jpeg'))
throw new TypeError('Input is already a JPEG image');
throw new TypeError('Input is not a HEIC image');
}

const filterExifKeys = (tag, raw) => {
if (typeof raw === 'undefined') return {}
let filteredKeys = Object.values(piexif.TagValues[tag]).map(String);
return Object.keys(raw)
// Filter and format metadata tags
const filterTags = (field, tags) => {
if (typeof tags === 'undefined') return {}
let filteredKeys = Object.values(piexif.TagValues[field]).map(String);
return Object.keys(tags)
.filter(key => filteredKeys.includes(key))
.reduce((obj, key) => {
obj[key] = raw[key];
obj[key] = tags[key];
return obj;
}, {});
};

// Exclude image properties that will be set by conversion
ifd0 = filterExifKeys('ImageIFD', ifd0);
delete ifd0[piexif.TagValues.ImageIFD.Orientation];
delete ifd0[piexif.TagValues.ImageIFD.XResolution];
delete ifd0[piexif.TagValues.ImageIFD.YResolution];
delete ifd0[piexif.TagValues.ImageIFD.ResolutionUnit];
ifd0 = formatTypes('0th', ifd0);
ifd0 = filterTags('ImageIFD', ifd0);
ifd1 = filterTags('ImageIFD', ifd1);
exif = filterTags('ExifIFD', exif);
gps = filterTags('GPSIFD', gps);

exif = filterExifKeys('ExifIFD', exif);
ifd0 = formatTypes('0th', ifd0);
ifd1 = formatTypes('1th', ifd1);
exif = formatTypes('Exif', exif);

gps = filterExifKeys('GPSIFD', gps);
gps = formatTypes('GPS', gps);

var exifBytes = piexif.dump({'0th': ifd0, 'Exif': exif, 'GPS': gps});
// Conversion rotates the image upright
if (ifd0[piexif.TagValues.ImageIFD.Orientation] > 4) {
const xd = exif[piexif.TagValues.ExifIFD.PixelXDimension]
const yd = exif[piexif.TagValues.ExifIFD.PixelYDimension]
exif[piexif.TagValues.ExifIFD.PixelXDimension] = yd
exif[piexif.TagValues.ExifIFD.PixelYDimension] = xd
ifd0[piexif.TagValues.ImageIFD.Orientation] = 1
}

const exifBytes = piexif.dump({
'0th': ifd0,
'1th': ifd1,
Exif: exif,
GPS: gps,
});

// Convert HEIC to JPG
const fileData = typeof inputFile === 'string' ? fs.readFileSync(inputFile) : inputFile;
const outputBuffer = await heicConvert({
buffer: fileData,
format: 'JPEG',
quality: quality
quality: quality,
});

// Attach relevant metadata
Expand Down
Loading

0 comments on commit 7feff88

Please sign in to comment.