2

My custom server embeds meta data about an image in the PNG meta data fields. The image is loaded via a regular img tag. I'd like to access the meta data from JavaScript - any way to achieve this?

If not, what are the alternatives for serving additional information for an image? The images are generated on the fly and are relatively expensive to produce, so I'd like to serve the meta data and the image data in a single round trip to the server.

BuschnicK
  • 5,304
  • 8
  • 37
  • 49
  • what server setup do you have? apache/php??? – Professor Abronsius Jan 22 '16 at 16:24
  • 1
    A custom C++ one. Does it matter for the question? I know how to embed the extra info in the png, I just don't know how to get at it from JS. – BuschnicK Jan 23 '16 at 17:53
  • I ask because had it been the usual Apache with PHP setup that runs most of the web you'd have found you have access to some built-in functions within php for accessing meta data within images ( if you consider Exif data to be thus ) Javascript itself doesn't offer ( afaik ) any native means to do what you want. There are other C++ libraries out in the interwebs which you might be able to interface with ~ www.exiv2.org ? – Professor Abronsius Jan 23 '16 at 23:31
  • Yes, but neither PHP nor C++ help me at all on the _client_ side, which is what this question is about. The server is a solved problem, but how can I extract the embedded meta information from the png image in the browser? – BuschnicK Jan 25 '16 at 08:36
  • whether this https://github.com/exif-js/exif-js will help or not I don't know but might be worth investigating – Professor Abronsius Jan 25 '16 at 08:38

2 Answers2

4

i had a similar task. I had to write physical dimensions and additional metadata to PNG files. I have found some solutions and combined it into one small library. png-metadata

it could read PNG metadata from NodeJS Buffers, and create a new Buffers with new metadata.

Here how you can read PNG metadata in the Browser:

        function loadFileAsBlob(url){
            return new Promise((resolve, reject) => {
                var xhr = new XMLHttpRequest();
                xhr.open('GET', url, true);
                xhr.responseType = 'blob';
                xhr.onload = function(e) {
                    if (this.status === 200) {
                        resolve(this.response);
                        // myBlob is now the blob that the object URL pointed to.
                    }else{
                        reject(this.response);
                    }
                };
                xhr.send();
            })
        };

        const blob = await loadFileAsBlob('1000ppcm.png');
        metadata = readMetadataB(blob);
0

A couple of solutions I can think of:

Pass the metadata as headers, use XMLHttpRequest to load the image and display it by converting the raw bytes to a data uri, as talked about here. Looks roughly like this:

var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function() {
    var metadata = xhr.getResponseHeader("my-custom-header");
    image.src = window.URL.createObjectURL(xhr.response);
}
xhr.open('GET', 'http://whatever.com/wherever');
xhr.send();

Alternatively, write a little png parser in js (or compile libpng to javascript using something like emscripten), and do basically the same thing as above.

It probably wouldn't be too hard to write actually; since you don't care about the image data, you'd just have to write the chunk-traversing code. Read up on how chunks are laid out here, and figure out what chunk type you're storing the metadata in. Still, don't really recommend this if you can just use headers...

Community
  • 1
  • 1
Alex Guerra
  • 2,556
  • 3
  • 18
  • 24