⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 exifmetadataprocessor.cs

📁 本系统是在asp版《在线文件管理器》的基础上设计制作
💻 CS
字号:
//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;

namespace CommunityServer.Galleries.Components
{
	public class ExifMetadataProcessor : IMetadataProcessor
	{

		#region Private Members

		private bool _isMotorollaByteOrder;
		private int TIFF_HEADER_START_OFFSET = 6;
		private const int TAG_EXIF_OFFSET = 0x8769;
		private const int TAG_INTEROP_OFFSET = 0xA005;

		#endregion

		#region Constructors

		public ExifMetadataProcessor() : base() { }

		public ExifMetadataProcessor(byte[] data) : base(data) { }

		public ExifMetadataProcessor(byte[] data, Hashtable metadata) : base(data, metadata) { }

		#endregion

		#region Public Methods

		public override void Extract() 
		{
			if(dataSegment == null) 
				return;

			// once we know there's some data, create the directory and start working on it
			if(dataSegment.Length <= 14) 
				return; //throw new Exception("Exif data segment must contain at least 14 bytes");

			if(!"Exif\0\0".Equals(Decode(0, 6)))
				return; //throw new Exception("Exif data segment doesn't begin with 'Exif'");

			// this should be either "MM" or "II"
			string byteOrderIdentifier = Decode(6, 2);
			if(!SetByteOrder(byteOrderIdentifier)) 
				return; //throw new Exception("Unclear distinction between Motorola/Intel byte ordering");

			// Check the next two values for correctness.
			if(Get16Bits(8) != 0x2a) 
				return; //throw new Exception("Invalid Exif start - should have 0x2A at offSet 8 in Exif header");

			int firstDirectoryOffSet = Get32Bits(10) + TIFF_HEADER_START_OFFSET;

			// David Ekholm sent an digital camera image that has this problem
			if(firstDirectoryOffSet >= dataSegment.Length - 1) 
			{
				//throw new Exception("First exif directory offSet is beyond end of Exif data segment");
				// First directory normally starts 14 bytes in -- try it here and catch another error in the worst case
				firstDirectoryOffSet = 14;
			}

			// 0th IFD (we merge with Exif IFD)
			Process(firstDirectoryOffSet);
		}

		#endregion

		#region Private Methods

		private void Process(int segmentOffset)
		{
			if (segmentOffset >= dataSegment.Length || segmentOffset < 0) 
				return; //throw new Exception("Ignored directory marked to start outside data segement");

			// First two bytes in the IFD are the tag count
			int dirTagCount = Get16Bits(segmentOffset);

			if (!isDirectoryLengthValid(segmentOffset)) 
				return; //throw new Exception("Illegally sized directory");


			// Handle each tag in this directory
			for (int dirEntry = 0; dirEntry < dirTagCount; dirEntry++)
			{
				try
				{
					int dirEntryOffSet = CalculateDirectoryEntryOffSet(segmentOffset, dirEntry);
					ExifProperty tagType = (ExifProperty)Get16Bits(dirEntryOffSet);
					MetaFormat format = (MetaFormat)Get16Bits(dirEntryOffSet + 2);

					// If it is an unknown format, then force it to be a string
					if((int)format > 12)
						format = MetaFormat.STRING;

					int componentCount = Get32Bits(dirEntryOffSet + 4);
					int byteCount = componentCount * BYTES_PER_FORMAT[(int)format];
					int tagValueOffset = CalculateTagValueOffSet(byteCount, dirEntryOffSet);

					// Calculate the aValue as an offSet for cases where the tag represents directory
					int subdirOffset = TIFF_HEADER_START_OFFSET + Get32Bits(tagValueOffset);

					switch((int)tagType)
					{
						case TAG_EXIF_OFFSET:
							Process(subdirOffset);
							break;
						case TAG_INTEROP_OFFSET:
							Process(subdirOffset);
							break;

						case (int)ExifProperty.WindowsAuthor:
						case (int)ExifProperty.WindowsComments:
						case (int)ExifProperty.WindowsKeywords:
						case (int)ExifProperty.WindowsSubject:
						case (int)ExifProperty.WindowsTitle:
							metadata.Add(tagType, Decode(tagValueOffset, componentCount, true));
							break;

						default:

						switch(format)
						{
							case MetaFormat.STRING:
							case MetaFormat.UNDEFINED:
								metadata.Add(tagType, DecodeStringValue(tagValueOffset, componentCount));
								break;

							case MetaFormat.URATIONAL:
							case MetaFormat.SRATIONAL:
								metadata.Add(tagType, new Rational( Get32Bits(tagValueOffset), Get32Bits(tagValueOffset + 4) ));
								break;

							case MetaFormat.BYTE:
							case MetaFormat.SBYTE:
								if(componentCount == 1)
									metadata.Add(tagType, dataSegment[tagValueOffset]);
								else
								{
									int[] bytes = new int[componentCount];
									for (int i = 0; i < componentCount; i++) 
										bytes[i] = dataSegment[tagValueOffset + i];
									metadata.Add(tagType, bytes);
								}
								break;

							case MetaFormat.SINGLE:
							case MetaFormat.DOUBLE:
								metadata.Add(tagType, (int)dataSegment[tagValueOffset]);
								break;

							case MetaFormat.USHORT:
							case MetaFormat.SSHORT:
								metadata.Add(tagType, (short)Get16Bits(tagValueOffset));
								break;

							case MetaFormat.SLONG:
							case MetaFormat.ULONG:
								metadata.Add(tagType, Get32Bits(tagValueOffset));
								break;
						}
							
							break;
					}
				}
				catch { }
			}
		}

		#endregion

		#region Helper Functions

		private int Get16Bits(int offset) 
		{
			if(offset < 0 || offset >= dataSegment.Length) 
				throw new IndexOutOfRangeException( string.Format( "attempt to read data outside of exif segment (index {0} where max index is {1}", offset, (dataSegment.Length-1) ) );

			if(_isMotorollaByteOrder)
				// Motorola big first
				return (dataSegment[offset] << 8 & 0xFF00) | (dataSegment[offset + 1] & 0xFF);
			else 
				// Intel ordering
				return (dataSegment[offset + 1] << 8 & 0xFF00) | (dataSegment[offset] & 0xFF);
		}

		private int Get32Bits(int offset) 
		{
			if(offset < 0 || offset >= dataSegment.Length) 
				throw new IndexOutOfRangeException( string.Format( "attempt to read data outside of exif segment (index {0} where max index is {1}", offset, (dataSegment.Length-1) ) );

			if(_isMotorollaByteOrder) 
				// Motorola big first
				return (int) ( ((uint)(dataSegment[offset] << 24 & 0xFF000000))
					| ((uint)(dataSegment[offset + 1] << 16 & 0xFF0000))
					| ((uint)(dataSegment[offset + 2] << 8 & 0xFF00))
					| ((uint)(dataSegment[offset + 3] & 0xFF)));
			else 
				// Intel ordering
				return (int) ( ((uint)(dataSegment[offset + 3] << 24 & 0xFF000000))
					| ((uint)(dataSegment[offset + 2] << 16 & 0xFF0000))
					| ((uint)(dataSegment[offset + 1] << 8 & 0xFF00))
					| ((uint)(dataSegment[offset] & 0xFF)));
		}

		private int CalculateTagValueOffSet(int byteCount, int dirEntryOffSet) 
		{
			if(byteCount > 4) 
			{
				// If its bigger than 4 bytes, the dir entry contains an offSet.
				// TODO if we're reading FujiFilm makernote tags, the offSet is relative to the start of the makernote itself, not the TIFF segment
				int offSetVal = Get32Bits(dirEntryOffSet + 8);
				if (offSetVal + byteCount > dataSegment.Length) 
				{
					// Bogus pointer offSet and / or bytecount aValue
					return -1; // signal error
				}
				return TIFF_HEADER_START_OFFSET + offSetVal;
			} 
			else 
				// 4 bytes or less and aValue is in the dir entry itself
				return dirEntryOffSet + 8;
		}

		private int CalculateDirectoryEntryOffSet(int ifdStartOffSet, int entryNumber)
		{
			return (ifdStartOffSet + 2 + (12 * entryNumber));
		}

		private bool isDirectoryLengthValid(int dirStartOffSet) 
		{
			int dirTagCount = Get16Bits(dirStartOffSet);
			int dirLength = (2 + (12 * dirTagCount) + 4);
			return !(dirLength + dirStartOffSet + TIFF_HEADER_START_OFFSET >= dataSegment.Length);
		}

		private bool SetByteOrder(string byteOrderIdentifier) 
		{
			if ("MM".Equals(byteOrderIdentifier)) 
				_isMotorollaByteOrder = true;
			else if ("II".Equals(byteOrderIdentifier)) 
				_isMotorollaByteOrder = false;
			else 
				return false;
			return true;
		}

		#endregion

	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -