javascripthtmlexifexif-js

Exif-js doesn't seem to work with local photos


I'm having a bit of a weird problem with my javascript code...

It basically consists of a script that accesses the exif of a photo and then shows it on an HTML page, more specifically the latitude and longitude of it.

The idea is to then use both the latitude and longitude on a Google maps iframe to then show the location that photo was taken...

That's all working but, until now, I've been using a picture that's stored on the cloud to make the testing...

If I try to make it work with the same exact picture stored locally, no EXIF info will appear on the page...

(I've also tried with some of my own pictures that have exif info and it still doesn't work...)

Why does it seem like Exif-js only works with images stored on a server?

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>EXIF</title>
    <style>
        img{
            width: 500px;
            max-height: auto;
        }   
    </style>    
</head>

<body>

    <!-- If I use this it works: -->

    <img src="https://c1.staticflickr.com/5/4867/30883801817_bf122bc498_o.jpg" id="img1" />

    <!-- If I use this it DOESN'T work: -->

    <img src="image3.jpg" id="img1"/> <!-- IT'S THE SAME IMAGE AND IT DOES HAVE EXIF-->

    <iframe id="mapa_google" src="" width="640" height="480"></iframe>


    <h1>Latitude Exif</h1>
    <p id="local_lat"></p>

    <h1>Longitude Exif</h1>
    <p id="local_lon"></p>

    <h1>Latitude Final</h1>
    <p id="local_lat_final"></p>

    <h1>Longitude Final</h1>
    <p id="local_lon_final"></p>

    <script src="exif.js"></script>

    <script>

        var toDecimal = function (number) {


            var d = Math.floor(number[0]);
            var m = Math.floor(number[1]);
            var s = ((number[1]%1)*60);

            var dms= d+(m/60)+(s/3600);

            return dms

        };


        window.onload=getExif;

        function getExif() {
            img1 = document.getElementById("img1");
            EXIF.getData(img1, function() {

            latitude = EXIF.getTag(this, "GPSLatitude");
            longitude = EXIF.getTag(this, "GPSLongitude");  

            local_lat = document.getElementById("local_lat");
            local_lon = document.getElementById("local_lon");

            local_lat.innerHTML = `${latitude}`;
            local_lon.innerHTML = `${longitude}`;


            latitude_final = toDecimal(latitude);
            local_lat_final = document.getElementById("local_lat_final");
            local_lat_final.innerHTML = `${latitude_final}`;

            longitude_final = toDecimal(longitude);
            local_lon_final = document.getElementById("local_lon_final");
            local_lon_final.innerHTML = `${longitude_final}`;   

            document.getElementById("mapa_google").src = "https://www.google.com/maps/embed/v1/place?key=AIzaSyDQSbRMCIv1gDsT2qRsY8HvLyZP11hte_Y&q="+latitude_final+"+"+longitude_final;        

            });

        }

        getExif();


    </script>

</body>
</html>

Solution

  • This is a CORS problem.

    Exif-js uses an ajax request to retrieve the image. Ajax calls require CORS access. Pages loaded via file:// URIs don't contain the headers that CORS depends on, and the same-origin policy for these files is implementation-dependent but the safest assumption is to treat every file as having its own unique origin -- which means that loading files without a webserver isn't a good enough way to test anything that involves XHR calls.

    Similarly, the site you mentioned in comments as also having this problem is denying CORS access:

    [Error] Origin null is not allowed by Access-Control-Allow-Origin.

    [Error] XMLHttpRequest cannot load https://myriad-online.com/images/forum/IMG_4692.jpg due to access control checks.

    as can be seen by watching the developer console (always a good idea when testing js code...) while running this code snippet:

    function getExif() {
      img1 = document.getElementById("img1");
      EXIF.getData(img1, function() {
        // won't be reached in this example
        console.log(this);
      });
    }
    
    getExif();
    <script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
    <img src="http://myriad-online.com/images/forum/IMG_4692.jpg" id="img1" />

    You won't be able to run exif-js on files that are hosted by sites which explicitly deny CORS access, but for local testing the simplest solution is going to be to spin up a local webserver and test your files via http:// instead of file:// URIs.