Khởi tạo dự án 3dtours
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
const fs = require('fs');
|
||||
const exifr = require('exifr');
|
||||
const piexif = require('piexifjs');
|
||||
|
||||
/**
|
||||
* Parses GPS coordinates from an image file using exifr
|
||||
* @param {string} filePath - Path to the image file
|
||||
* @returns {Promise<{lat: number, lng: number}|null>} GPS coordinates or null if not found
|
||||
*/
|
||||
const getGPSCoordinates = async (filePath) => {
|
||||
try {
|
||||
const gps = await exifr.gps(filePath);
|
||||
if (gps && typeof gps.latitude === 'number' && typeof gps.longitude === 'number') {
|
||||
return {
|
||||
lat: gps.latitude,
|
||||
lng: gps.longitude
|
||||
};
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.warn(`Could not read EXIF GPS from ${filePath}: ${error.message}`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts decimal degrees to Degrees, Minutes, Seconds rational format for piexifjs
|
||||
* @param {number} deg - Decimal degrees coordinate
|
||||
* @returns {Array} Array of rational numbers [[D, 1], [M, 1], [S * 100, 100]]
|
||||
*/
|
||||
const degToDmsRational = (deg) => {
|
||||
const absolute = Math.abs(deg);
|
||||
const d = Math.floor(absolute);
|
||||
const m = Math.floor((absolute - d) * 60);
|
||||
const s = Math.round((absolute - d - m / 60) * 3600 * 100) / 100;
|
||||
return [
|
||||
[d, 1],
|
||||
[m, 1],
|
||||
[Math.round(s * 100), 100]
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Injects GPS coordinates into a JPEG image file using piexifjs
|
||||
* @param {string} filePath - Path to the JPEG file
|
||||
* @param {number} lat - Latitude
|
||||
* @param {number} lng - Longitude
|
||||
*/
|
||||
const injectGPSCoordinates = async (filePath, lat, lng) => {
|
||||
try {
|
||||
const jpegBinary = fs.readFileSync(filePath).toString('binary');
|
||||
|
||||
let exifObj = { "0th": {}, "Exif": {}, "GPS": {} };
|
||||
try {
|
||||
exifObj = piexif.load(jpegBinary);
|
||||
} catch (e) {
|
||||
// No existing EXIF, start clean
|
||||
}
|
||||
|
||||
const latRef = lat >= 0 ? 'N' : 'S';
|
||||
const lngRef = lng >= 0 ? 'E' : 'W';
|
||||
|
||||
exifObj["GPS"][piexif.GPSIFD.GPSLatitudeRef] = latRef;
|
||||
exifObj["GPS"][piexif.GPSIFD.GPSLatitude] = degToDmsRational(lat);
|
||||
exifObj["GPS"][piexif.GPSIFD.GPSLongitudeRef] = lngRef;
|
||||
exifObj["GPS"][piexif.GPSIFD.GPSLongitude] = degToDmsRational(lng);
|
||||
|
||||
const exifBytes = piexif.dump(exifObj);
|
||||
const newJpegBinary = piexif.insert(exifBytes, jpegBinary);
|
||||
|
||||
fs.writeFileSync(filePath, Buffer.from(newJpegBinary, 'binary'));
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to inject EXIF GPS: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getGPSCoordinates,
|
||||
injectGPSCoordinates
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
const sharp = require('sharp');
|
||||
|
||||
/**
|
||||
* Resizes an image to standard 8K resolution (8192x4096) with 2:1 ratio and saves as JPEG
|
||||
* @param {string} inputPath - Path to the original uploaded file
|
||||
* @param {string} outputPath - Path to save the processed 8K JPEG image
|
||||
*/
|
||||
const resizeTo8K = async (inputPath, outputPath) => {
|
||||
try {
|
||||
await sharp(inputPath)
|
||||
.resize(8192, 4096, {
|
||||
fit: 'fill' // Ensures the output is exactly 8192x4096
|
||||
})
|
||||
.jpeg({ quality: 90 })
|
||||
.toFile(outputPath);
|
||||
} catch (error) {
|
||||
throw new Error(`Sharp image processing failed: ${error.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
resizeTo8K
|
||||
};
|
||||
Reference in New Issue
Block a user