Extract GPS data from EXIF data in JavaScript - javascript

I would like to extract the GPS Exif tag from pictures using NodeJS. I got data in this format:
{
"gps": {
"GPSTimeStamp": [2147483647, 76, 41],
"GPSLongitude": [76, 41, 56.622],
"GPSLatitude": [30, 43, 8.754],
"GPSAltitude": 0,
"GPSDateStamp": "14615748802"
}
}
Is there any way to convert it into latitude and longitude?
When I am checking Exif data in Android it shows me proper latitude and longitude, but in NodeJS I am getting data in this format.

Oh, i just come to know the concept og digree,minute,seconds and direction.
i got three values in array as digree , minute and seconds
To parse your input use the following.
function ParseDMS(input) {
var parts = input.split(/[^\d\w]+/);
var lat = ConvertDMSToDD(parts[0], parts[1], parts[2], parts[3]);
var lng = ConvertDMSToDD(parts[4], parts[5], parts[6], parts[7]);
}
The following will convert your DMS to DD
function ConvertDMSToDD(degrees, minutes, seconds, direction) {
var dd = degrees + minutes/60 + seconds/(60*60);
if (direction == "S" || direction == "W") {
dd = dd * -1;
} // Don't do anything for N or E
return dd;
}
So your input would produce the following:
36°57'9" N = 36.9525000
110°4'21" W = -110.0725000

I know this may be already solved but I'd like to offer alternative solution, for the people stumbling upon this question.
It seems like you are using some Node.js library that gives you these raw lat/long data and it's up to you to convert them. There is a new library exifr that does this for you automatically. It's maintained, actively developed library with focus on performance and works in both nodejs and browser.
async function getExif() {
let output = await exifr.parse(imgBuffer)
console.log('gps', output.latitude, output.longitude)
}
You can also try out the library's playground and experiment with images and their output, or check out the repository and docs.

Related

Excel Javascript API - Add chart with Category Axis values

I am adding\inserting a Line chart to Excel via the following JS call:
var newSheet = ctx.workbook.worksheets.add();
newSheet.activate();
// populate grid
// category (axis)
var cell = newSheet.getCell(0, 0)
...
// values (axis)
cell = newSheet.getCell(0, 1)
...
var range = newSheet.getUsedRange();
newSheet.charts.add("Line", range);
My "range" data looks like this:
2012 10
2013 20
2014 30
2015 40
2016 50
The issue I'm having is each column is treated as an individual series, and 2 lines are rendered in the chart. I only want one line and the Category Axis to contain the years. Does anyone know if this is possible?
Screenshot:
Chris,
The current JavaScript API for Excel that you use to create the chart doesn't give you much control of how Excel should construct the series and axis for the chart. When using the ChartCollection.add() method, you are depending on the "smarts" of the Excel Recommended Charts algorithm, and in this particular case the, answer it comes up with as the first answer is not what you expect.
We have an item in our API backlog to provide more fine-grained control for charts similar to what is available in other Excel APIs. At this time I can't say when this will be available in the API. I encourage you to follow our open specification process to get a heads up, and an opportunity to give feedback on our designs.
As a workaround for your particular case, I would suggest that you try using date values for the first column instead of numbers. You can format the column to show only the year part of the dates:
async function run() {
try {
await Excel.run(async (context) => {
var sheet = context.workbook.worksheets.getActiveWorksheet();
let data = [
["Year", "Measure"],
["2010-12-31", 10],
["2011-12-31", 20],
["2012-12-31", 30],
["2013-12-31", 40],
["2014-12-31", 50],
];
let format = [
["#"],
["yyyy"],
["yyyy"],
["yyyy"],
["yyyy"],
["yyyy"]
];
let categories = sheet.getRange("A1:A6");
categories.numberFormat = format;
var range = sheet.getRange("A1:B6");
range.values = data;
sheet.charts.add(Excel.ChartType.line, range, Excel.ChartSeriesBy.columns);
await context.sync();
});
}
catch (error) {
OfficeHelpers.Utilities.log(error);
}
}
This snippet is written in TypeScript using async/await, but easily be translated to JavaScript.
Jakob

Format a date from a timestamp without BST in JavaScript

Consider the following timestamp I get back from the server:
2016-09-15T18:15:00.0000000
If I do the following:
function friendlyTime(timeslot) {
const time = timeslot,
timeDate = new Date(time),
timeHours = `0${timeDate.getHours().toString()}`.slice(-2),
timeMinutes = `0${timeDate.getMinutes().toString()}`.slice(-2);
return `${timeHours}:${timeMinutes}`;
}
const slot = friendlyTime('2016-09-15T18:15:00.0000000');
I get back:
19:15, when what I really want is a reflection of the timestamp without BST, like 18:15.
Is there an easy way to do this at all? My head explodes when it comes to dates and timezones in JavaScript.
It needs to look the same regardless of where anyone is in the world. It shouldn't be reflecting anyone's personal time settings.
Just manipulate the string, one possibility that would support 4 to 6 digit common spec years (or more).
function friendlyTime(timeslot) {
return timeslot.split('T').pop().split(':', 2).join(':');
}
console.log(friendlyTime('2016-09-15T18:15:00.0000000'));
Another, if you only need to support 4 digit years. (Javascript is spec'd for 4)
function friendlyTime(timeslot) {
return timeslot.slice(11, 16);
}
console.log(friendlyTime('2016-09-15T18:15:00.0000000'));
Instead of getHours() and getMinutes() use getUTCHours() and getUTCMinutes(). Also, as Mike McCaughan pointed out in comments, you have to add Z to the end of the string to make sure it will be parsed correctly in all browsers.
function friendlyTime(timeslot) {
const time = timeslot,
timeDate = new Date(time),
timeHours = `0${timeDate.getUTCHours().toString()}`.slice(-2),
timeMinutes = `0${timeDate.getUTCMinutes().toString()}`.slice(-2);
return `${timeHours}:${timeMinutes}`;
}
const slot = friendlyTime('2016-09-15T18:15:00.0000000Z');
console.log(slot);

Sorting and filtering on Date

I have a date column and need to be able to both sort and filter on it. The data comes in as strings like 2010-12-23 and can pre-processed as needed. It should be shown as 23.12.2010. Some internationalization will come later.
I wonder what's the proper internal representation:
a string like "23.12.2010" is bad for sorting (it could be done by sorting on function result, but it'd be slow)
a string like "2010-12-23" sorts correctly, can be formatted easily, but filtering for 23.12 does not work (it could be done, but it'd be slow)
Date would probably get sorted correctly, but filtering would be slow
moment could be the solution, no idea
My current idea is to create an object containing both milliseconds and the displayed string, so that all operations can be fast. But I'd bet that someone was that smart before me....
Let's assume that showing dates in the form like 2010-12-23 is unacceptable, otherwise the problem is solved. To summarize, the problem is that I need to
display and filter in the DD.MM.YYYY format
sort according to the numerical value (or equivalently, as if it was in th ISO format).
I think the method you're proposing wouldn't run in to too many performance issues, unless you're going for really old browsers or mobile devices.
I've mocked up an example to do a quick (performance) test. First, I'm defining an object that holds a value optimized for sorting, and a value optimized for display:
var MyDate = function(dateString) {
var date = new Date(dateString);
var displayValue = "{0}.{1}.{2}"
.replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))
.replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))
.replace("{2}", date.getUTCFullYear());
return {
sortKey: date.getTime(),
displayValue: displayValue
};
};
The prefixZeroIfNeeded method ensures we get the DD.MM format rather than the dd.mm one:
var prefixZeroIfNeeded = function(nr) {
return nr < 10 ? "0" + nr : "" + nr;
};
Then, we need some data to convert:
var data = [];
var myDates = data
.map(MyDate)
.sort(function(date1, date2) {
return date1.sortKey - date2.sortKey;
});
Finally, a quick example of a very basic search function:
var searchMyDates = function(str) {
return myDates.filter(function(myDate) {
return myDate.displayValue.indexOf(str) !== -1;
});
};
Now, we can create some mockup data and check how long it would actually take to A) map and sort the raw strings to the MyDate objects, and B) search for a string in our collection.
Here's how I generated the raw data:
for (var i = 0; i < 10000; i += 1) {
var y = Math.floor(Math.random() * 101) + 1900;
var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));
var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));
data.push(y + "-" + d + "-" + m);
}
Using console.time to measure, processing the data on my machine (A) takes around 40ms. Searching for the string .12. takes around 5-10ms.
Concluding: I think you were definitely on the right track and could continue work in the proposed direction. However, in my personal experience, I've learned that whenever I start work on a feature that involves dates and times, moment.js is the way to go. You'll eventually run in to daylight saving time, time zones, you name it and regret you thought it was simple...
Let me know if this is of any help.
Edit: the code in a snippet (check your browser console for output)
var data = [];
var prefixZeroIfNeeded = function(nr) {
return nr < 10 ? "0" + nr : "" + nr;
};
// Generate random data:
for (var i = 0; i < 10000; i += 1) {
var y = Math.floor(Math.random() * 101) + 1900;
var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));
var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));
data.push(y + "-" + d + "-" + m);
}
var MyDate = function(dateString) {
var date = new Date(dateString);
var displayValue = "{0}.{1}.{2}"
.replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))
.replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))
.replace("{2}", date.getUTCFullYear());
return {
sortKey: date.getTime(),
displayValue: displayValue
};
};
console.time("Map and sorting");
var myDates = data
.map(MyDate)
.sort(function(date1, date2) {
return date1.sortKey - date2.sortKey;
});
var searchMyDates = function(str) {
return myDates.filter(function(myDate) {
return myDate.displayValue.indexOf(str) !== -1;
});
};
console.timeEnd("Map and sorting");
console.time("Search");
console.log("Searching for the month 12, %d results.", searchMyDates(".12.").length);
console.timeEnd("Search");
This may help you a bit. I have used the same thing working with React. Here is a link for Moment.js -
http://momentjs.com/docs/#/displaying/format/
If you go under Display -> Format on the right menu bar, you'll see localized formats, you will need to use format L - pre defined format from moment which will show you 09/04/1986 (September 4, 1986); otherwise you can create your own using DD-MM-YYYY format.
For Example, The way I used in React for my exercise is
To define a variable using let:
let deadlineFormated = Moment(this.props.ToDoItem.deadline).format('llll');
Hope this helps for Angular!
Gist: Decouple sorting and filtering. Do sorting on the internal representation and filtering on the presentation.
Sort on internal representation that is in any naturally sortable format. Your raw YYYY-MM-DD date strings would work, so would parsing them into Date objects. The performance difference could be negligible unless you're dealing with lots and lots of rows -- but in that case you would already have other issues with latency and rendering performance.
It's more intuitive if free-text filtering is done on what's displayed (the presentation). So if you're formatting the dates as "May 7, 2016", do a substring match on that. If you're formatting the dates as DD.MM.YYYY, do a substring match on that.
If filtering is driven by actual date selections from controls like a date picker or a select field, you can do the filtering on the internal representation.
Try with this:
Get Unixtimestamp for date (i.e. Numeric format) and use jquery sort.
Please check this example for jquery sort. Regarding example replace your unixtimestamp to value.
<ul id="datelist">
<li value="1360013296">Date 1</li>
<li value="1360013297">Date 2</li>
<li value="1360013298">Date 3</li>
<li value="1360013299">Date 4</li>
</ul>
https://jsfiddle.net/ajaygokhale/bohgoq8o/
To reliably implement sorting converting it into a Date Object is recommended (new Date(str))
If you need to be flexible in formatting moment has formatting support (check moment.format()) as well. Moment has pretty deep locale support as well.
You can always keep it a Date Object as the source of truth and for filtering you could do Date.toString() just at the time of filtering. This returns a string you could then filter with.

how to add numbers with an infinite number of digits using column addition?

I am trying to develop the addition program using column addition in javascript, For e.g: 53,22 , we add numbers from the right 3+2 and 5+2 finally results in 75, the main problem is with large numbers i am trying to develop a program which can implement addition of large numbers.so that i don't get gibberish like 1.26E+9, when adding large numbers. i tried doing it by defining the code like below
function add(a,b)
{
return (Number(a) + Number(b)).toString();
}
console.log(add('58685486858601586', '8695758685'));
i am trying to get the added number without getting the gibberish like 5.8685496e+16
You can add them digit by digit.
function sumStrings(a, b) { // sum for any length
function carry(value, index) { // cash & carry
if (!value) { // no value no fun
return; // leave shop
}
this[index] = (this[index] || 0) + value; // add value
if (this[index] > 9) { // carry necessary?
carry.bind(this)(this[index] / 10 | 0, index + 1); // better know this & go on
this[index] %= 10; // remind me later
}
}
var array1 = a.split('').map(Number).reverse(), // split stuff and reverse
array2 = b.split('').map(Number).reverse(); // here as well
array1.forEach(carry, array2); // loop baby, shop every item
return array2.reverse().join(''); // return right ordered sum
}
document.write(sumStrings('58685486858601586', '8695758685') + '<br>');
document.write(sumStrings('999', '9') + '<br>');
document.write(sumStrings('9', '999') + '<br>');
document.write(sumStrings('1', '9999999999999999999999999999999999999999999999999999') + '<br>');
I would keep all values as numbers until done with all the calculations. When ready to display just format the numbers in any way you want. For example you could use toLocaleString.
There are several libraries for that
A good rule of thumb is to make sure you do research for libraries before you actually go ahead and create you're own proprietary implementation of it. Found three different libraries that all solve your issue
bignumber.js
decimal.js
big.js
Example
This is how to use all three of the libraries, BigNumber coming from the bignumber.js library, Decimal from decimal.js and Big from big.js
var bn1 = new BigNumber('58685486858601586');
var bn2 = new BigNumber('8695758685');
console.log(bn1.plus(bn2).toString());
bn1 = new Decimal('58685486858601586');
bn2 = new Decimal('8695758685');
console.log(bn1.plus(bn2).toString());
bn1 = new Big('58685486858601586');
bn2 = new Big('8695758685');
console.log(bn1.plus(bn2).toString());
The console's output is :
58685495554360271
58685495554360271
58685495554360271

How do I convert String to Number according to locale (opposite of .toLocaleString)?

If I do:
var number = 3500;
alert(number.toLocaleString("hi-IN"));
I will get ३,५०० in Hindi.
But how can I convert it back to 3500.
I want something like:
var str='३,५००';
alert(str.toLocaleNumber("en-US"));
So, that it can give 3500.
Is it possible by javascript or jquery?
I think you are looking for something like:
https://github.com/jquery/globalize
Above link will take you to git project page. This is a js library contributed by Microsoft.
You should give it one try and try to use formt method of that plugin. If you want to study this plugin, here is the link for the same:
http://weblogs.asp.net/scottgu/jquery-globalization-plugin-from-microsoft
I hope this is what you are looking for and will resolve your problem soon. If it doesn't work, let me know.
Recently I've been struggling with the same problem of converting stringified number formatted in any locale back to the number.
I've got inspired by the solution implemented in NG Prime InputNumber component. They use Intl.NumberFormat.prototype.format() (which I recommend) to format the value to locale string, and then create set of RegExp expressions based on simple samples so they can cut off particular expressions from formatted string.
This solution can be simplified with using Intl.Numberformat.prototype.formatToParts(). This method returns information about grouping/decimal/currency and all the other separators used to format your value in particular locale, so you can easily clear them out of previously formatted string. It seems to be the easiest solution, that will cover all cases, but you must know in what locale the value has been previously formatted.
Why Ng Prime didn't go this way? I think its because Intl.Numberformat.prototype.formatToParts() does not support IE11, or perhaps there is something else I didn't notice.
A complete code example using this solution can be found here.
Unfortunately you will have to tackle the localisation manually. Inspired by this answer , I created a function that will manually replace the Hindi numbers:
function parseHindi(str) {
return Number(str.replace(/[०१२३४५६७८९]/g, function (d) {
return d.charCodeAt(0) - 2406;
}).replace(/[०१२३४५६७८९]/g, function (d) {
return d.charCodeAt(0) - 2415;
}));
}
alert(parseHindi("३५००"));
Fiddle here: http://jsfiddle.net/yyxgxav4/
You can try this out
function ConvertDigits(input, source, target) {
var systems = {
arabic: 48, english: 48, tamil: 3046, kannada: 3302, telugu: 3174, hindi: 2406,
malayalam: 3430, oriya: 2918, gurmukhi: 2662, nagari: 2534, gujarati: 2790,
},
output = [], offset = 0, zero = 0, nine = 0, char = 0;
source = source.toLowerCase();
target = target.toLowerCase();
if (!(source in systems && target in systems) || input == null || typeof input == "undefined" || typeof input == "object") {
return input;
}
input = input.toString();
offset = systems[target] - systems[source];
zero = systems[source];
nine = systems[source] + 9;
for (var i = 0 ; i < input.length; i++) {
var char = input.charCodeAt(i);
if (char >= zero && char <= nine) {
output.push(String.fromCharCode(char + offset));
} else {
output.push(input[i]);
}
}
return output.join("");
}
var res = ConvertDigits('१२३४५६७८९', 'hindi', 'english');
I got it from here
If you need a jquery thing then please try this link
Use the Globalize library.
Install it
npm install globalize cldr-data --save
then
var cldr = require("cldr-data");
var Globalize = require("globalize");
Globalize.load(cldr("supplemental/likelySubtags"));
Globalize.load(cldr("supplemental/numberingSystems"));
Globalize.load(cldr("supplemental/currencyData"));
//replace 'hi' with appropriate language tag
Globalize.load(cldr("main/hi/numbers"));
Globalize.load(cldr("main/hi/currencies"));
//You may replace the above locale-specific loads with the following line,
// which will load every type of CLDR language data for every available locale
// and may consume several hundred megs of memory!
//Use with caution.
//Globalize.load(cldr.all());
//Set the locale
//We use the extention u-nu-native to indicate that Devanagari and
// not Latin numerals should be used.
// '-u' means extension
// '-nu' means number
// '-native' means use native script
//Without -u-nu-native this example will not work
//See
// https://en.wikipedia.org/wiki/IETF_language_tag#Extension_U_.28Unicode_Locale.29
// for more details on the U language code extension
var hindiGlobalizer = Globalize('hi-IN-u-nu-native');
var parseHindiNumber = hindiGlobalizer.numberParser();
var formatHindiNumber = hindiGlobalizer.numberFormatter();
var formatRupeeCurrency = hindiGlobalizer.currencyFormatter("INR");
console.log(parseHindiNumber('३,५००')); //3500
console.log(formatHindiNumber(3500)); //३,५००
console.log(formatRupeeCurrency(3500)); //₹३,५००.००
https://github.com/codebling/globalize-example
A common scenario for this problem is to display a float number to the user and then want it back as a numerical value.
In that case, javascript has the number in the first place and looses it when formatting it for display. A simple workaround for the parsing is to store the real float value along with the formatted value:
var number = 3500;
div.innerHTML = number.toLocaleString("hi-IN");
div.dataset.value = number;
Then get it back by parsing the data attribute:
var number = parseFloat(div.dataset.value);
This is a Columbus's egg style answer. It works provided the problem is an egg.
var number = 3500;
var toLocaleString = number.toLocaleString("hi-IN")
var formatted = toLocaleString.replace(',','')
var converted = parseInt(formatted)

Categories