qa-ifish7/web/Public/webuploader/runtime/html5/imagemeta/exif.js

310 lines
9.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 代码来自于https://github.com/blueimp/JavaScript-Load-Image
* 暂时项目中只用了orientation.
*
* 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.
* @fileOverview EXIF解析
*/
// Sample
// ====================================
// Make : Apple
// Model : iPhone 4S
// Orientation : 1
// XResolution : 72 [72/1]
// YResolution : 72 [72/1]
// ResolutionUnit : 2
// Software : QuickTime 7.7.1
// DateTime : 2013:09:01 22:53:55
// ExifIFDPointer : 190
// ExposureTime : 0.058823529411764705 [1/17]
// FNumber : 2.4 [12/5]
// ExposureProgram : Normal program
// ISOSpeedRatings : 800
// ExifVersion : 0220
// DateTimeOriginal : 2013:09:01 22:52:51
// DateTimeDigitized : 2013:09:01 22:52:51
// ComponentsConfiguration : YCbCr
// ShutterSpeedValue : 4.058893515764426
// ApertureValue : 2.5260688216892597 [4845/1918]
// BrightnessValue : -0.3126686601998395
// MeteringMode : Pattern
// Flash : Flash did not fire, compulsory flash mode
// FocalLength : 4.28 [107/25]
// SubjectArea : [4 values]
// FlashpixVersion : 0100
// ColorSpace : 1
// PixelXDimension : 2448
// PixelYDimension : 3264
// SensingMethod : One-chip color area sensor
// ExposureMode : 0
// WhiteBalance : Auto white balance
// FocalLengthIn35mmFilm : 35
// SceneCaptureType : Standard
define([
'../../../base',
'../imagemeta'
], function( Base, ImageMeta ) {
var EXIF = {};
EXIF.ExifMap = function() {
return this;
};
EXIF.ExifMap.prototype.map = {
'Orientation': 0x0112
};
EXIF.ExifMap.prototype.get = function( id ) {
return this[ id ] || this[ this.map[ id ] ];
};
EXIF.exifTagTypes = {
// byte, 8-bit unsigned int:
1: {
getValue: function( dataView, dataOffset ) {
return dataView.getUint8( dataOffset );
},
size: 1
},
// ascii, 8-bit byte:
2: {
getValue: function( dataView, dataOffset ) {
return String.fromCharCode( dataView.getUint8( dataOffset ) );
},
size: 1,
ascii: true
},
// short, 16 bit int:
3: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint16( dataOffset, littleEndian );
},
size: 2
},
// long, 32 bit int:
4: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint32( dataOffset, littleEndian );
},
size: 4
},
// rational = two long values,
// first is numerator, second is denominator:
5: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getUint32( dataOffset, littleEndian ) /
dataView.getUint32( dataOffset + 4, littleEndian );
},
size: 8
},
// slong, 32 bit signed int:
9: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getInt32( dataOffset, littleEndian );
},
size: 4
},
// srational, two slongs, first is numerator, second is denominator:
10: {
getValue: function( dataView, dataOffset, littleEndian ) {
return dataView.getInt32( dataOffset, littleEndian ) /
dataView.getInt32( dataOffset + 4, littleEndian );
},
size: 8
}
};
// undefined, 8-bit byte, value depending on field:
EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];
EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,
littleEndian ) {
var tagType = EXIF.exifTagTypes[ type ],
tagSize, dataOffset, values, i, str, c;
if ( !tagType ) {
Base.log('Invalid Exif data: Invalid tag type.');
return;
}
tagSize = tagType.size * length;
// Determine if the value is contained in the dataOffset bytes,
// or if the value at the dataOffset is a pointer to the actual data:
dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,
littleEndian ) : (offset + 8);
if ( dataOffset + tagSize > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid data offset.');
return;
}
if ( length === 1 ) {
return tagType.getValue( dataView, dataOffset, littleEndian );
}
values = [];
for ( i = 0; i < length; i += 1 ) {
values[ i ] = tagType.getValue( dataView,
dataOffset + i * tagType.size, littleEndian );
}
if ( tagType.ascii ) {
str = '';
// Concatenate the chars:
for ( i = 0; i < values.length; i += 1 ) {
c = values[ i ];
// Ignore the terminating NULL byte(s):
if ( c === '\u0000' ) {
break;
}
str += c;
}
return str;
}
return values;
};
EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,
data ) {
var tag = dataView.getUint16( offset, littleEndian );
data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,
dataView.getUint16( offset + 2, littleEndian ), // tag type
dataView.getUint32( offset + 4, littleEndian ), // tag length
littleEndian );
};
EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,
littleEndian, data ) {
var tagsNumber, dirEndOffset, i;
if ( dirOffset + 6 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid directory offset.');
return;
}
tagsNumber = dataView.getUint16( dirOffset, littleEndian );
dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
if ( dirEndOffset + 4 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid directory size.');
return;
}
for ( i = 0; i < tagsNumber; i += 1 ) {
this.parseExifTag( dataView, tiffOffset,
dirOffset + 2 + 12 * i, // tag offset
littleEndian, data );
}
// Return the offset to the next directory:
return dataView.getUint32( dirEndOffset, littleEndian );
};
// EXIF.getExifThumbnail = function(dataView, offset, length) {
// var hexData,
// i,
// b;
// if (!length || offset + length > dataView.byteLength) {
// Base.log('Invalid Exif data: Invalid thumbnail data.');
// return;
// }
// hexData = [];
// for (i = 0; i < length; i += 1) {
// b = dataView.getUint8(offset + i);
// hexData.push((b < 16 ? '0' : '') + b.toString(16));
// }
// return 'data:image/jpeg,%' + hexData.join('%');
// };
EXIF.parseExifData = function( dataView, offset, length, data ) {
var tiffOffset = offset + 10,
littleEndian, dirOffset;
// Check for the ASCII code for "Exif" (0x45786966):
if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {
// No Exif data, might be XMP data instead
return;
}
if ( tiffOffset + 8 > dataView.byteLength ) {
Base.log('Invalid Exif data: Invalid segment size.');
return;
}
// Check for the two null bytes:
if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {
Base.log('Invalid Exif data: Missing byte alignment offset.');
return;
}
// Check the byte alignment:
switch ( dataView.getUint16( tiffOffset ) ) {
case 0x4949:
littleEndian = true;
break;
case 0x4D4D:
littleEndian = false;
break;
default:
Base.log('Invalid Exif data: Invalid byte alignment marker.');
return;
}
// Check for the TIFF tag marker (0x002A):
if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {
Base.log('Invalid Exif data: Missing TIFF marker.');
return;
}
// Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );
// Create the exif object to store the tags:
data.exif = new EXIF.ExifMap();
// Parse the tags of the main image directory and retrieve the
// offset to the next directory, usually the thumbnail directory:
dirOffset = EXIF.parseExifTags( dataView, tiffOffset,
tiffOffset + dirOffset, littleEndian, data );
// 尝试读取缩略图
// if ( dirOffset ) {
// thumbnailData = {exif: {}};
// dirOffset = EXIF.parseExifTags(
// dataView,
// tiffOffset,
// tiffOffset + dirOffset,
// littleEndian,
// thumbnailData
// );
// // Check for JPEG Thumbnail offset:
// if (thumbnailData.exif[0x0201]) {
// data.exif.Thumbnail = EXIF.getExifThumbnail(
// dataView,
// tiffOffset + thumbnailData.exif[0x0201],
// thumbnailData.exif[0x0202] // Thumbnail data length
// );
// }
// }
};
ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );
return EXIF;
});