Strip EXIF data from image (node-js, addressing a possible bug in the original version)

2.7k Views Asked by At

This is a server-side version of the following:

Strip EXIF data from image

http://jsfiddle.net/mowglisanu/frhwm2xe/3/

Although the main logic should be unaltered (except trace messages and a data-structure change), it is unable to process a file more than once.

So I suspect the bug exist in the original version but the original fiddle lets the file pass through the second time unprocessed.

./exifrm.js

/**
    remove: GPS Information, Camera Info, etc..
    <code>
        var f = fs.readFileSync('exif.jpg')
        fs.writeFileSync('exifclean.jpg', remove(f))
    </code>
    @arg {Buffer} imageArrayBuffer image/jpeg
    @return {Buffer} image/jpeg
*/
function remove(imageArrayBuffer) {
    if(!Buffer.isBuffer(imageArrayBuffer))
        throw new TypeError('Expecting Buffer for parameter: imageArrayBuffer')

    if(!imageArrayBuffer.buffer)
        throw new TypeError('Expecting Buffer to contain ArrayBuffer property: imageArrayBuffer.buffer (check node version)')

    const pieces = [];
    const dv = new DataView(imageArrayBuffer.buffer);
    let offset = 0, recess = 0;
    let i = 0;

    // jpeg magic bytes 0xffd8
    console.log('dv.getUint16(offset) == 0xffd8', dv.getUint16(offset) == 0xffd8)
    if (dv.getUint16(offset) == 0xffd8){
        offset += 2;
        let app1 = dv.getUint16(offset);
        offset += 2;
        console.log('offset < dv.byteLength', offset < dv.byteLength)
        while (offset < dv.byteLength){
            if (app1 == 0xffe1){
                console.log('app1 == 0xffe1', app1 == 0xffe1)
                pieces[i] = {recess: recess, offset: offset -  2};
                recess = offset + dv.getUint16(offset);
                i++;
            }
            else if (app1 == 0xffda){
                console.log('app1 == 0xffda', app1 == 0xffda)
                break;
            }
            offset += dv.getUint16(offset);
            app1 = dv.getUint16(offset);
            offset += 2;
        }
        console.log('pieces.length > 0', pieces.length > 0)
        if (pieces.length > 0){
            const newPieces = [];
            pieces.forEach(function(v){
                newPieces.push(imageArrayBuffer.slice(v.recess, v.offset));
            }, this);
            newPieces.push(imageArrayBuffer.slice(recess));
            return Buffer.concat(newPieces)
        }
    }
}

module.exports = {remove}

Test as follows. Save the above code as exifrm.js then run:

wget http://www.suodenjoki.dk/images/news/2008/water.jpg

node
> var f1, f2
> var exif = require('./exifrm.js')

> f1 = exif.remove(fs.readFileSync('./water.jpg'))
dv.getUint16(offset) == 0xffd8 true
offset < dv.byteLength true
app1 == 0xffe1 true
app1 == 0xffe1 true
app1 == 0xffda true
pieces.length > 0 true
<Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 02 01 00 f0 00 f0 00 00 ff ed 21 82 50 68 6f 74 6f 73 68 6f 70 20 33 2e 30 00 38 42 49 4d 04 04 00 00 00 00 00 35 ... >

> f2 = exif.remove(f1)
dv.getUint16(offset) == 0xffd8 true
offset < dv.byteLength true
app1 == 0xffda true
pieces.length > 0 false
undefined

The expected output is f2.length === 57817.

0

There are 0 best solutions below