`
java-admin
  • 浏览: 1388783 次
  • 性别: Icon_minigender_1
  • 来自: 陕西.西安
社区版块
存档分类
最新评论

JPEG Rotation and EXIF Orientation

阅读更多

http://blog.csdn.net/daisyhd/archive/2010/11/10/6000962.aspx

 

JPEG Rotation and EXIF Orientation

Digital Cameras with orientation sensors allow auto-rotation of portrait images. Unfortunately, support for this feature is not widespread or consistently applied.

Digital Cameras with Orientation Sensors

Many newer digital cameras (both dSLR and Point & Shoot digicams) have a built-in orientation sensor. Virtually all Canon and Nikon digital cameras have an orientation sensor. The output of this sensor is used to set the EXIF orientation flag in the image file's metatdata to reflect the positioning of the camera with respect to the ground. Canon calls their sensor the "Intelligent Orientation" sensor. It is presumably a 2-axis tilt sensor, allowing 4 possible orientations to be detected (shown in the left side of the diagram below). 
EXIF Orientation Flag Values


 

Note that one would only expect the four orientation settings shown on the left to be possible with a digital camera. The other four settings would imply that the resulting image was flipped horizontally before recording. Unless the camera were to encode the image right-to-left or know that you were taking a photo in a mirror, I don't see how these values will ever be used.

The values 1-8 represent the following descriptions (as shown by utilities that support EXIF field decode): EXIF Orientation Value Row #0 is: Column #0 is:
1 Top Left side
2 Top Right side
3 Bottom Right side
4 Bottom Left side
5 Left side Top
6 Right side Top
7 Right side Bottom
8 Left side Bottom


Auto-rotation in Digital Cameras

While your digital camera may include an option to "auto-rotate images" due to the camera's orientation, this is almost always just a "virtual rotation". A flag is set to indicate to the viewing software / LCD preview which way to rotate the image before display, rather than rotating the image content itself.

As lossless image rotation is a fairly compute-intensive operation, digital cameras are not likely to include true lossless rotation after capturing the photo. The CCD/CMOS sensor hardware is designed to stream raw data in a particular direction (e.g. rows then columns), and so it may be hard to incorporate true auto-rotation in-camera without a performance impact to continuous shooting (frames per second).

Software Support for Orientation

While there are countless software programs available today that display JPEG images, only a subset of them actually interpret the EXIF Orientation flag. Just like color management, many programs simply display the JPEG image as it is stored, and completely ignore any extra details stored in the file's metadata. The most important of these additional details is the Orientation flag, stored in the JPEG APP1 marker under EXIF IFD0. Application Orientation Supported?
Windows Picture and Fax Viewer No
IrfanView Yes (need to enable) 
Photoshop  Yes


IrfanView Auto-rotation

In IrfanView, auto-rotation is not enabled by default. To ensure that images are auto-rotated, you will find the option located under Options->Properties in the JPG/PCD/GIF tab.

Windows Picture and Fax Viewer

Surprisingly, the Windows Picture and Fax Viewer (built into Windows XP) does not support the EXIF orientation flag. This is surprising, as the makers have obviously thought enough to support lossless rotation functions. So, what you will see shown by the viewer is the real image data (assuming landscape orientation), without respecting any indication from the camera as to the real orientation of the image.

Beware of Rotating Photos in Windows Picture and Fax Viewer!

Another surprising detail is that if you decide to perform lossless image rotation (by using the Rotate Clockwise or Rotate CounterClockwise buttons), the EXIF Orientation flag is removed! As the flag is removed, if you do a double-rotation on a portrait photo (rotate, then rotate in the opposite direction), the resulting orientation observed by other viewers such as Photoshop will be wrong!

In fact, when you use the rotate functions of this utility, most of the image metadata (camera information, shot details, makernotes, etc.) are deleted. Therefore, I strongly recommend against using this program to rotate any of your digital photos.

I have also noticed that some images which were rotated that don't conform to 16x16 pixel multiples, the quantization tables don't appear to be rotated properly.

Because many new digital photographers may not be aware of this, Nikon even went so far as to issue a press release to warn of the potential dangers.

NOTE: The damage is done as soon as you press one of the rotate buttons . The disk icon  is just for copying the file and should not be thought of as a Save button!
The following table details some of the metadata corrupted / modified by Windows Picture and Fax Viewer: Removed Added Modified
IFD0-Orientation IFD0-x1001
IFD0-x1002

IFD0-xA401

IFD0-xA402

IFD0-xA403
  
SubIFD-ExifInteroperabilityOffset
SubIFD-CustomRendered

SubIFD-ExposureMode

SubIFD-WhiteBalance

SubIFD-SceneCaptureType
   SubIFD-MakerNote
SubIFD-UserComment
 
MakerNotes: Nearly all fields zeroed
out except: SerialNumber, ImageNumber
    


 

Auto-Rotation Utilities

There are several tools that allow the image content to be rotated losslessly in software, based on the information stored in the EXIF orientation flag. By far the best time to perform this is during image import (e.g. from memory card). Most import applications (such as DownloaderPro) can do this during the copy operation (from memory card to hard drive). Doing so ensure that all programs can see the image properly rotated, without having to rely on the EXIF Orientation flag. This means that even programs such as Microsoft's Windows Picture and Fax Viewer will also show correct orientation for portrait / vertical images.

Most programs will rotate the image content and then update the Orientation flag to reflect the new orientation (usually a value of 1), while still leaving other metadata intact.

 

读取图片文件的扩展信息(EXIF)
using System;
using System.Collections.Generic;
using System.Text;

namespace ExifWorks
{
//
// Utility class for working with EXIF data in images. Provides abstraction
// for most common data and generic utilities for work with all other.
//
//
// Copyright (c) Michal A. Valášek - Altair Communications, 2003-2005
// Copmany: http://software.altaircom.net, E-mail: support@altaircom.net
// Private: http://www.rider.cz, E-mail: rider@rider.cz
// This is free software licensed under GNU Lesser General Public License
//
//
// [altair] 10.09.2003 Created
// [altair] 12.06.2004 Added capability to write EXIF data
// [altair] 11.07.2004 Added option to change encoding
// [altair] 04.09.2005 Changed source of Width and Height properties from EXIF to image
// [altair] 05.09.2005 Code clean-up and minor changes
// [marco.ridoni@virgilio.it] 02-11-2006 C# translation
//
public class ExifManager : IDisposable
{

private System.Drawing.Bitmap _Image;
private System.Text.Encoding _Encoding = System.Text.Encoding.UTF8;


#region Type declarations

//
// Contains possible values of EXIF tag names (ID)
//
// See GdiPlusImaging.h
//
// [altair] 10.09.2003 Created
//

public enum TagNames : int
{
ExifIFD = 0x8769,
GpsIFD = 0x8825,
NewSubfileType = 0xFE,
SubfileType = 0xFF,
ImageWidth = 0x100,
ImageHeight = 0x101,
BitsPerSample = 0x102,
Compression = 0x103,
PhotometricInterp = 0x106,
ThreshHolding = 0x107,
CellWidth = 0x108,
CellHeight = 0x109,
FillOrder = 0x10A,
DocumentName = 0x10D,
ImageDescription = 0x10E,
EquipMake = 0x10F,
EquipModel = 0x110,
StripOffsets = 0x111,
orientation = 0x112,
SamplesPerPixel = 0x115,
RowsPerStrip = 0x116,
StripBytesCount = 0x117,
MinSampleValue = 0x118,
MaxSampleValue = 0x119,
XResolution = 0x11A,
YResolution = 0x11B,
PlanarConfig = 0x11C,
PageName = 0x11D,
XPosition = 0x11E,
YPosition = 0x11F,
FreeOffset = 0x120,
FreeByteCounts = 0x121,
GrayResponseUnit = 0x122,
GrayResponseCurve = 0x123,
T4Option = 0x124,
T6Option = 0x125,
ResolutionUnit = 0x128,
PageNumber = 0x129,
TransferFuncition = 0x12D,
SoftwareUsed = 0x131,
DateTime = 0x132,
Artist = 0x13B,
HostComputer = 0x13C,
Predictor = 0x13D,
WhitePoint = 0x13E,
PrimaryChromaticities = 0x13F,
ColorMap = 0x140,
HalftoneHints = 0x141,
TileWidth = 0x142,
TileLength = 0x143,
TileOffset = 0x144,
TileByteCounts = 0x145,
InkSet = 0x14C,
InkNames = 0x14D,
NumberOfInks = 0x14E,
DotRange = 0x150,
TargetPrinter = 0x151,
ExtraSamples = 0x152,
SampleFormat = 0x153,
SMinSampleValue = 0x154,
SMaxSampleValue = 0x155,
TransferRange = 0x156,
JPEGProc = 0x200,
JPEGInterFormat = 0x201,
JPEGInterLength = 0x202,
JPEGRestartInterval = 0x203,
JPEGLosslessPredictors = 0x205,
JPEGPointTransforms = 0x206,
JPEGQTables = 0x207,
JPEGDCTables = 0x208,
JPEGACTables = 0x209,
YCbCrCoefficients = 0x211,
YCbCrSubsampling = 0x212,
YCbCrPositioning = 0x213,
REFBlackWhite = 0x214,
ICCProfile = 0x8773,
Gamma = 0x301,
ICCProfileDescriptor = 0x302,
SRGBRenderingIntent = 0x303,
ImageTitle = 0x320,
Copyright = 0x8298,
ResolutionXUnit = 0x5001,
ResolutionYUnit = 0x5002,
ResolutionXLengthUnit = 0x5003,
ResolutionYLengthUnit = 0x5004,
PrintFlags = 0x5005,
PrintFlagsVersion = 0x5006,
PrintFlagsCrop = 0x5007,
PrintFlagsBleedWidth = 0x5008,
PrintFlagsBleedWidthScale = 0x5009,
HalftoneLPI = 0x500A,
HalftoneLPIUnit = 0x500B,
HalftoneDegree = 0x500C,
HalftoneShape = 0x500D,
HalftoneMisc = 0x500E,
HalftoneScreen = 0x500F,
JPEGQuality = 0x5010,
GridSize = 0x5011,
ThumbnailFormat = 0x5012,
ThumbnailWidth = 0x5013,
ThumbnailHeight = 0x5014,
ThumbnailColorDepth = 0x5015,
ThumbnailPlanes = 0x5016,
ThumbnailRawBytes = 0x5017,
ThumbnailSize = 0x5018,
ThumbnailCompressedSize = 0x5019,
ColorTransferFunction = 0x501A,
ThumbnailData = 0x501B,
ThumbnailImageWidth = 0x5020,
ThumbnailImageHeight = 0x502,
ThumbnailBitsPerSample = 0x5022,
ThumbnailCompression = 0x5023,
ThumbnailPhotometricInterp = 0x5024,
ThumbnailImageDescription = 0x5025,
ThumbnailEquipMake = 0x5026,
ThumbnailEquipModel = 0x5027,
ThumbnailStripOffsets = 0x5028,
ThumbnailOrientation = 0x5029,
ThumbnailSamplesPerPixel = 0x502A,
ThumbnailRowsPerStrip = 0x502B,
ThumbnailStripBytesCount = 0x502C,
ThumbnailResolutionX = 0x502D,
ThumbnailResolutionY = 0x502E,
ThumbnailPlanarConfig = 0x502F,
ThumbnailResolutionUnit = 0x5030,
ThumbnailTransferFunction = 0x5031,
ThumbnailSoftwareUsed = 0x5032,
ThumbnailDateTime = 0x5033,
ThumbnailArtist = 0x5034,
ThumbnailWhitePoint = 0x5035,
ThumbnailPrimaryChromaticities = 0x5036,
ThumbnailYCbCrCoefficients = 0x5037,
ThumbnailYCbCrSubsampling = 0x5038,
ThumbnailYCbCrPositioning = 0x5039,
ThumbnailRefBlackWhite = 0x503A,
ThumbnailCopyRight = 0x503B,
LuminanceTable = 0x5090,
ChrominanceTable = 0x5091,
FrameDelay = 0x5100,
LoopCount = 0x5101,
PixelUnit = 0x5110,
PixelPerUnitX = 0x5111,
PixelPerUnitY = 0x5112,
PaletteHistogram = 0x5113,
ExifExposureTime = 0x829A,
ExifFNumber = 0x829D,
ExifExposureProg = 0x8822,
ExifSpectralSense = 0x8824,
ExifISOSpeed = 0x8827,
ExifOECF = 0x8828,
ExifVer = 0x9000,
ExifDTOrig = 0x9003,
ExifDTDigitized = 0x9004,
ExifCompConfig = 0x9101,
ExifCompBPP = 0x9102,
ExifShutterSpeed = 0x9201,
ExifAperture = 0x9202,
ExifBrightness = 0x9203,
ExifExposureBias = 0x9204,
ExifMaxAperture = 0x9205,
ExifSubjectDist = 0x9206,
ExifMeteringMode = 0x9207,
ExifLightSource = 0x9208,
ExifFlash = 0x9209,
ExifFocalLength = 0x920A,
ExifMakerNote = 0x927C,
ExifUserComment = 0x9286,
ExifDTSubsec = 0x9290,
ExifDTOrigSS = 0x9291,
ExifDTDigSS = 0x9292,
ExifFPXVer = 0xA000,
ExifColorSpace = 0xA001,
ExifPixXDim = 0xA002,
ExifPixYDim = 0xA003,
ExifRelatedWav = 0xA004,
ExifInterop = 0xA005,
ExifFlashEnergy = 0xA20B,
ExifSpatialFR = 0xA20C,
ExifFocalXRes = 0xA20E,
ExifFocalYRes = 0xA20F,
ExifFocalResUnit = 0xA210,
ExifSubjectLoc = 0xA214,
ExifExposureIndex = 0xA215,
ExifSensingMethod = 0xA217,
ExifFileSource = 0xA300,
ExifSceneType = 0xA301,
ExifCfaPattern = 0xA302,
GpsVer = 0x0,
GpsLatitudeRef = 0x1,
GpsLatitude = 0x2,
GpsLongitudeRef = 0x3,
GpsLongitude = 0x4,
GpsAltitudeRef = 0x5,
GpsAltitude = 0x6,
GpsGpsTime = 0x7,
GpsGpsSatellites = 0x8,
GpsGpsStatus = 0x9,
GpsGpsMeasureMode = 0xA,
GpsGpsDop = 0xB,
GpsSpeedRef = 0xC,
GpsSpeed = 0xD,
GpsTrackRef = 0xE,
GpsTrack = 0xF,
GpsImgDirRef = 0x10,
GpsImgDir = 0x11,
GpsMapDatum = 0x12,
GpsDestLatRef = 0x13,
GpsDestLat = 0x14,
GpsDestLongRef = 0x15,
GpsDestLong = 0x16,
GpsDestBearRef = 0x17,
GpsDestBear = 0x18,
GpsDestDistRef = 0x19,
GpsDestDist = 0x1A
}


//
// Real position of 0th row and column of picture
//
//
//
// [altair] 10.09.2003 Created
//

public enum orientations
{
TopLeft = 1,
TopRight = 2,
BottomRight = 3,
BottomLeft = 4,
LeftTop = 5,
RightTop = 6,
RightBottom = 7,
LftBottom = 8
}


//
// Exposure programs
//
//
//
// [altair] 10.09.2003 Created
//

public enum ExposurePrograms
{
Manual = 1,
Normal = 2,
AperturePriority = 3,
ShutterPriority = 4,
Creative = 5,
Action = 6,
Portrait = 7,
Landscape = 8,
}


//
// Exposure metering modes
//
//
//
// [altair] 10.09.2003 Created
//

public enum ExposureMeteringModes
{
Unknown = 0,
Average = 1,
CenterWeightedAverage = 2,
Spot = 3,
MultiSpot = 4,
MultiSegment = 5,
Partial = 6,
Other = 255
}


//
// Flash activity modes
//
//
//
// [altair] 10.09.2003 Created
//

public enum FlashModes
{
NotFired = 0,
Fired = 1,
FiredButNoStrobeReturned = 5,
FiredAndStrobeReturned = 7,
}


//
// Possible light sources (white balance)
//
//
//
// [altair] 10.09.2003 Created
//

public enum LightSources
{
Unknown = 0,
Daylight = 1,
Fluorescent = 2,
Tungsten = 3,
Flash = 10,
StandardLightA = 17,
StandardLightB = 18,
StandardLightC = 19,
D55 = 20,
D65 = 21,
D75 = 22,
Other = 255
}


//
// EXIF data types
//
//
//
// [altair] 12.6.2004 Created
//
public enum ExifDataTypes : short
{
UnsignedByte = 1,
AsciiString = 2,
UnsignedShort = 3,
UnsignedLong = 4,
UnsignedRational = 5,
SignedByte = 6,
Undefined = 7,
SignedShort = 8,
SignedLong = 9,
SignedRational = 10,
SingleFloat = 11,
DoubleFloat = 12
}


//
// Represents rational which is type of some Exif properties
//
//
//
// [altair] 10.09.2003 Created
//
public struct Rational
{
public Int32 Numerator;
public Int32 Denominator;


//
// Converts rational to string representation
//
// Optional, default "/". String to be used as delimiter of components.
// String representation of the rational.
//
//
// [altair] 10.09.2003 Created
//

public override string ToString()
{
return ToString("/");
}

public string ToString(string Delimiter)
{
return Numerator + "/" + Denominator;
}

//
// Converts rational to double precision real number
//
// The rational as double precision real number.
//
//
// [altair] 10.09.2003 Created
//

public double ToDouble()
{
return (double)Numerator / Denominator;
}
}

#endregion

//
// Initializes new instance of this class.
//
// Bitmap to read exif information from
//
//
// [altair] 10.09.2003 Created
//
public ExifManager(System.Drawing.Bitmap Bitmap)
{
if (Bitmap == null)
throw new ArgumentNullException("Bitmap");
this._Image = Bitmap;
}

//
// Initializes new instance of this class.
//
// Name of file to be loaded
//
//
// [altair] 13.06.2004 Created
//
public ExifManager(string FileName)
{
this._Image = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromFile(FileName);
}

//
// Get or set encoding used for string metadata
//
// Encoding used for string metadata
// Default encoding is UTF-8
//
// [altair] 11.07.2004 Created
// [altair] 05.09.2005 Changed from shared to instance member
//
public System.Text.Encoding Encoding
{
get
{
return this._Encoding;
}
set
{
if (value == null)
throw new ArgumentNullException();
this._Encoding = value;
}
}

//
// Returns copy of bitmap this instance is working on
//
//
//
//
// [altair] 13.06.2004 Created
//
public System.Drawing.Bitmap GetBitmap()
{
return (System.Drawing.Bitmap)this._Image.Clone();
}

//
// Returns all available data in formatted string form
//
//
//
//
// [altair] 10.09.2003 Created
//
public override string ToString()
{
System.Text.StringBuilder SB = new StringBuilder();

SB.Append("Image:");
SB.Append("\n\tDimensions: " + this.Width + " x " + this.Height + " px");
SB.Append("\n\tResolution: " + this.ResolutionX + " x " + this.ResolutionY + " dpi");
SB.Append("\n\tOrientation: " + Enum.GetName(typeof(Orientations), this.Orientation));
SB.Append("\n\tTitle: " + this.Title);
SB.Append("\n\tDescription: " + this.Description);
SB.Append("\n\tCopyright: " + this.Copyright);
SB.Append("\nEquipment:");
SB.Append("\n\tMaker: " + this.EquipmentMaker);
SB.Append("\n\tModel: " + this.EquipmentModel);
SB.Append("\n\tSoftware: " + this.Software);
SB.Append("\nDate and time:");
SB.Append("\n\tGeneral: " + this.DateTimeLastModified.ToString());
SB.Append("\n\tOriginal: " + this.DateTimeOriginal.ToString());
SB.Append("\n\tDigitized: " + this.DateTimeDigitized.ToString());
SB.Append("\nShooting conditions:");
SB.Append("\n\tExposure time: " + this.ExposureTime.ToString("N4") + " s");
SB.Append("\n\tExposure program: " + Enum.GetName(typeof(ExposurePrograms), this.ExposureProgram));
SB.Append("\n\tExposure mode: " + Enum.GetName(typeof(ExposureMeteringModes), this.ExposureMeteringMode));
SB.Append("\n\tAperture: F" + this.Aperture.ToString("N2"));
SB.Append("\n\tISO sensitivity: " + this.ISO);
SB.Append("\n\tSubject distance: " + this.SubjectDistance.ToString("N2") + " m");
SB.Append("\n\tFocal length: " + this.FocalLength);
SB.Append("\n\tFlash: " + Enum.GetName(typeof(FlashModes), this.FlashMode));
SB.Append("\n\tLight source (WB): " + Enum.GetName(typeof(LightSources), this.LightSource));
//SB.Replace("\n", vbCrLf);
//SB.Replace("\t", vbTab);
return SB.ToString();
}

#region Nicely formatted well-known properties

//
// Brand of equipment (EXIF EquipMake)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string EquipmentMaker
{
get
{
return this.GetPropertyString((int)TagNames.EquipMake);
}
}

//
// Model of equipment (EXIF EquipModel)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string EquipmentModel
{
get
{
return this.GetPropertyString((int)TagNames.EquipModel);
}
}

//
// Software used for processing (EXIF Software)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Software
{
get
{
return this.GetPropertyString((int)TagNames.SoftwareUsed);
}
}

//
// orientation of image (position of row 0, column 0) (EXIF orientation)
//
//
//
//
// [altair] 10.09.2003 Created
//
public orientations orientation
{
get
{
Int32 X = this.GetPropertyInt16((int)TagNames.Orientation);

if (!Enum.IsDefined(typeof(Orientations), X))
return orientations.TopLeft;
else
return (Orientations)Enum.Parse(typeof(Orientations), Enum.GetName(typeof(Orientations), X));
}
}

//
// Time when image was last modified (EXIF DateTime).
//
//
//
//
// [altair] 10.09.2003 Created
//
public DateTime DateTimeLastModified
{
get
{
try
{
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.DateTime), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
this.SetPropertyString((int)TagNames.DateTime, value.ToString(@"yyyy\:MM\:dd HH\:mm\:ss"));
}
catch
{ }
}
}

//
// Time when image was taken (EXIF DateTimeOriginal).
//
//
//
//
// [altair] 10.09.2003 Created
//
public DateTime DateTimeOriginal
{
get
{
try
{
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTOrig), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
this.SetPropertyString((int)TagNames.ExifDTOrig, value.ToString(@"yyyy\:MM\:dd HH\:mm\:ss"));
}
catch
{ }
}
}

//
// Time when image was digitized (EXIF DateTimeDigitized).
//
//
//
//
// [altair] 10.09.2003 Created
//
public DateTime DateTimeDigitized
{
get
{
try
{
return DateTime.ParseExact(this.GetPropertyString((int)TagNames.ExifDTDigitized), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
this.SetPropertyString((int)TagNames.ExifDTDigitized, value.ToString(@"yyyy\:MM\:dd HH\:mm\:ss"));
}
catch
{ }
}
}

//
// Image width
//
//
//
//
// [altair] 10.09.2003 Created
// [altair] 04.09.2005 Changed output to Int32, load from image instead of EXIF
//
public Int32 Width
{
get { return this._Image.Width; }
}

//
// Image height
//
//
//
//
// [altair] 10.09.2003 Created
// [altair] 04.09.2005 Changed output to Int32, load from image instead of EXIF
//
public Int32 Height
{
get { return this._Image.Height; }
}

//
// X resolution in dpi (EXIF XResolution/ResolutionUnit)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double ResolutionX
{
get
{
double R = this.GetPropertyRational((int)TagNames.XResolution).ToDouble();

if (this.GetPropertyInt16((int)TagNames.ResolutionUnit) == 3)
{
// -- resolution is in points/cm
return R * 2.54;
}
else
{
// -- resolution is in points/inch
return R;
}
}
}

//
// Y resolution in dpi (EXIF YResolution/ResolutionUnit)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double ResolutionY
{
get
{
double R = this.GetPropertyRational((int)TagNames.YResolution).ToDouble();

if (this.GetPropertyInt16((int)TagNames.ResolutionUnit) == 3)
{
// -- resolution is in points/cm
return R * 2.54;
}
else
{
// -- resolution is in points/inch
return R;
}
}
}

//
// Image title (EXIF ImageTitle)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Title
{
get
{
return this.GetPropertyString((int)TagNames.ImageTitle);
}
set
{
try
{
this.SetPropertyString((int)TagNames.ImageTitle, value);
}
catch { }
}
}

//
// User comment (EXIF UserComment)
//
//
//
//
// [altair] 13.06.2004 Created
//
public string UserComment
{
get
{
return this.GetPropertyString((int)TagNames.ExifUserComment);
}
set
{
try
{
this.SetPropertyString((int)TagNames.ExifUserComment, value);
}
catch { }
}
}

//
// Artist name (EXIF Artist)
//
//
//
//
// [altair] 13.06.2004 Created
//
public string Artist
{
get
{
return this.GetPropertyString((int)TagNames.Artist);
}
set
{
try
{
this.SetPropertyString((int)TagNames.Artist, value);
}
catch { }
}
}

//
// Image description (EXIF ImageDescription)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Description
{
get
{
return this.GetPropertyString((int)TagNames.ImageDescription);
}
set
{
try
{
this.SetPropertyString((int)TagNames.ImageDescription, value);
}
catch { }
}
}

//
// Image copyright (EXIF Copyright)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Copyright
{
get
{
return this.GetPropertyString((int)TagNames.Copyright);
}
set
{
try
{
this.SetPropertyString((int)TagNames.Copyright, value);
}
catch { }
}
}


//
// Exposure time in seconds (EXIF ExifExposureTime/ExifShutterSpeed)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double ExposureTimeAbs
{
get
{
if (this.IsPropertyDefined((int)TagNames.ExifExposureTime))
// -- Exposure time is explicitly specified
return this.GetPropertyRational((int)TagNames.ExifExposureTime).ToDouble();
else
if (this.IsPropertyDefined((int)TagNames.ExifShutterSpeed))
//'-- Compute exposure time from shutter spee
return (1 / Math.Pow(2, this.GetPropertyRational((int)TagNames.ExifShutterSpeed).ToDouble()));
else
// -- Can't figure out
return 0;
}
}

public Rational ExposureTime
{
get
{
if (this.IsPropertyDefined((int)TagNames.ExifExposureTime))
// -- Exposure time is explicitly specified
return this.GetPropertyRational((int)TagNames.ExifExposureTime);
else
return new Rational();
}
}

//
// Aperture value as F number (EXIF ExifFNumber/ExifApertureValue)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double Aperture
{
get
{
if (this.IsPropertyDefined((int)TagNames.ExifFNumber))
return this.GetPropertyRational((int)TagNames.ExifFNumber).ToDouble();
else
if (this.IsPropertyDefined((int)TagNames.ExifAperture))
return Math.Pow(System.Math.Sqrt(2), this.GetPropertyRational((int)TagNames.ExifAperture).ToDouble());
else
return 0;
}
}

//
// Exposure program used (EXIF ExifExposureProg)
//
//
// If not specified, returns Normal (2)
//
// [altair] 10.09.2003 Created
//
public ExposurePrograms ExposureProgram
{
get
{
Int32 X = this.GetPropertyInt16((int)TagNames.ExifExposureProg);

if (Enum.IsDefined(typeof(ExposurePrograms), X))
return (ExposurePrograms)Enum.Parse(typeof(ExposurePrograms), Enum.GetName(typeof(ExposurePrograms), X));
else
return ExposurePrograms.Normal;
}
}

//
// ISO sensitivity
//
//
//
//
// [altair] 10.09.2003 Created
//
public Int16 ISO
{
get { return this.GetPropertyInt16((int)TagNames.ExifISOSpeed); }
}

//
// Subject distance in meters (EXIF SubjectDistance)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double SubjectDistance
{
get { return this.GetPropertyRational((int)TagNames.ExifSubjectDist).ToDouble(); }
}

//
// Exposure method metering mode used (EXIF MeteringMode)
//
//
// If not specified, returns Unknown (0)
//
// [altair] 10.09.2003 Created
//
public ExposureMeteringModes ExposureMeteringMode
{
get
{
Int32 X = this.GetPropertyInt16((int)TagNames.ExifMeteringMode);

if (Enum.IsDefined(typeof(ExposureMeteringModes), X))
return (ExposureMeteringModes)Enum.Parse(typeof(ExposureMeteringModes), Enum.GetName(typeof(ExposureMeteringModes), X));
else
return ExposureMeteringModes.Unknown;
}
}

//
// Focal length of lenses in mm (EXIF FocalLength)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double FocalLength
{
get { return this.GetPropertyRational((int)TagNames.ExifFocalLength).ToDouble(); }
}

//
// Flash mode (EXIF Flash)
//
//
// If not present, value NotFired (0) is returned
//
// [altair] 10.09.2003 Created
//
public FlashModes FlashMode
{
get
{
Int32 X = this.GetPropertyInt16((int)TagNames.ExifFlash);

if (Enum.IsDefined(typeof(FlashModes), X))
return (FlashModes)Enum.Parse(typeof(FlashModes), Enum.GetName(typeof(FlashModes), X));
else
return FlashModes.NotFired;
}
}

//
// Light source / white balance (EXIF LightSource)
//
//
// If not specified, returns Unknown (0).
//
// [altair] 10.09.2003 Created
//
public LightSources LightSource
{
get
{
Int32 X = this.GetPropertyInt16((int)TagNames.ExifLightSource);

if (Enum.IsDefined(typeof(LightSources), X))
return (LightSources)Enum.Parse(typeof(LightSources), Enum.GetName(typeof(LightSources), X));
else
return LightSources.Unknown;
}
}

#endregion

#region Support methods for working with EXIF properties

//
// Checks if current image has specified certain property
//
//
// True if image has specified property, False otherwise.
//
//
// [altair] 10.09.2003 Created
//
public bool IsPropertyDefined(Int32 PID)
{
return (Array.IndexOf(this._Image.PropertyIdList, PID) > -1);
}

//
// Gets specified Int32 property
//
// Property ID
// Optional, default 0. Default value returned if property is not present.
// Value of property or DefaultValue if property is not present.
//
//
// [altair] 10.09.2003 Created
//
public Int32 GetPropertyInt32(Int32 PID)
{
return GetPropertyInt32(PID, 0);
}

public Int32 GetPropertyInt32(Int32 PID, Int32 DefaultValue)
{
if (IsPropertyDefined(PID))
return GetInt32(this._Image.GetPropertyItem(PID).Value);
else
return DefaultValue;
}

//
// Gets specified Int16 property
//
// Property ID
// Optional, default 0. Default value returned if property is not present.
// Value of property or DefaultValue if property is not present.
//
//
// [altair] 10.09.2003 Created
//
public Int16 GetPropertyInt16(Int32 PID)
{
return GetPropertyInt16(PID, 0);
}

public Int16 GetPropertyInt16(Int32 PID, Int16 DefaultValue)
{
if (IsPropertyDefined(PID))
return GetInt16(this._Image.GetPropertyItem(PID).Value);
else
return DefaultValue;
}

//
// Gets specified string property
//
// Property ID
// Optional, default String.Empty. Default value returned if property is not present.
//
// Value of property or DefaultValue if property is not present.
//
// [altair] 10.09.2003 Created
//
public string GetPropertyString(Int32 PID)
{
return GetPropertyString(PID, "");
}

public string GetPropertyString(Int32 PID, string DefaultValue)
{
if (IsPropertyDefined(PID))
return GetString(this._Image.GetPropertyItem(PID).Value);
else
return DefaultValue;
}

//
// Gets specified property in raw form
//
// Property ID
// Optional, default Nothing. Default value returned if property is not present.
//
// Is recommended to use typed methods (like etc.) instead, when possible.
//
// [altair] 05.09.2005 Created
//
public byte[] GetProperty(Int32 PID, byte[] DefaultValue)
{
if (IsPropertyDefined(PID))
return this._Image.GetPropertyItem(PID).Value;
else
return DefaultValue;
}

public byte[] GetProperty(Int32 PID)
{
return GetProperty(PID, null);
}

//
// Gets specified rational property
//
// Property ID
//
// Value of property or 0/1 if not present.
//
// [altair] 10.09.2003 Created
//
public Rational GetPropertyRational(Int32 PID)
{
if (IsPropertyDefined(PID))
return GetRational(this._Image.GetPropertyItem(PID).Value);
else
{
Rational R;
R.Numerator = 0;
R.Denominator = 1;
return R;
}
}

//
// Sets specified string property
//
// Property ID
// Value to be set
//
//
// [altair] 12.6.2004 Created
//
public void SetPropertyString(Int32 PID, string Value)
{
byte[] Data = this._Encoding.GetBytes(Value + '\0');
SetProperty(PID, Data, ExifDataTypes.AsciiString);
}

//
// Sets specified Int16 property
//
// Property ID
// Value to be set
//
//
// [altair] 12.6.2004 Created
//
public void SetPropertyInt16(Int32 PID, Int16 Value)
{
byte[] Data = new byte[2];
Data[0] = (byte)(Value & 0xFF);
Data[1] = (byte)((Value & 0xFF00) >> 8);
SetProperty(PID, Data, ExifDataTypes.SignedShort);
}

//
// Sets specified Int32 property
//
// Property ID
// Value to be set
//
//
// [altair] 13.06.2004 Created
//
public void SetPropertyInt32(Int32 PID, Int32 Value)
{
byte[] Data = new byte[4];
for (int I = 0; I < 4; I++)
{
Data[I] = (byte)(Value & 0xFF);
Value >>= 8;
}
SetProperty(PID, Data, ExifDataTypes.SignedLong);
}

//
// Sets specified property in raw form
//
// Property ID
// Raw data
// EXIF data type
// Is recommended to use typed methods (like etc.) instead, when possible.
//
// [altair] 12.6.2004 Created
//
public void SetProperty(Int32 PID, byte[] Data, ExifDataTypes Type)
{
System.Drawing.Imaging.PropertyItem P = this._Image.PropertyItems[0];
P.Id = PID;
P.Value = Data;
P.Type = (Int16)Type;
P.Len = Data.Length;
this._Image.SetPropertyItem(P);
}

//
// Reads Int32 from EXIF bytearray.
//
// EXIF bytearray to process
//
//
//
// [altair] 10.09.2003 Created
// [altair] 05.09.2005 Changed from public shared to private instance method
//
private Int32 GetInt32(byte[] B)
{
if (B.Length < 4)
throw new ArgumentException("Data too short (4 bytes expected)", "B");

return B[3] << 24 | B[2] << 16 | B[1] << 8 | B[0];
}

//
// Reads Int16 from EXIF bytearray.
//
// EXIF bytearray to process
//
//
//
// [altair] 10.09.2003 Created
// [altair] 05.09.2005 Changed from public shared to private instance method
//
private Int16 GetInt16(byte[] B)
{
if (B.Length < 2)
throw new ArgumentException("Data too short (2 bytes expected)", "B");

return (short)(B[1] << 8 | B[0]);
}

//
// Reads string from EXIF bytearray.
//
// EXIF bytearray to process
//
//
//
// [altair] 10.09.2003 Created
// [altair] 05.09.2005 Changed from public shared to private instance method
//
private string GetString(byte[] B)
{
string R = this._Encoding.GetString(B);
if (R.EndsWith("\0"))
R = R.Substring(0, R.Length - 1);
return R;
}

//
// Reads rational from EXIF bytearray.
//
// EXIF bytearray to process
//
//
//
// [altair] 10.09.2003 Created
// [altair] 05.09.2005 Changed from public shared to private instance method
//
private Rational GetRational(byte[] B)
{
Rational R = new Rational();
byte[] N = new byte[4];
byte[] D = new byte[4];
Array.Copy(B, 0, N, 0, 4);
Array.Copy(B, 4, D, 0, 4);
R.Denominator = this.GetInt32(D);
R.Numerator = this.GetInt32(N);
return R;
}

#endregion

#region " IDisposable implementation "

//
// Disposes unmanaged resources of this class
//
//
//
// [altair] 10.09.2003 Created
//
public void Dispose()
{
this._Image.Dispose();
}

#endregion

}

}


调用方法:
        ExifWorks.ExifManager exif = new ExifWorks.ExifManager(@"d:\2.jpg");
        System.Reflection.PropertyInfo[] ps = exif.GetType().GetProperties();
        StringBuilder sb = new StringBuilder();
        sb.Append("{");
        foreach (System.Reflection.PropertyInfo pi in ps)
        {
            try
            {
                object value = pi.GetValue(exif, null);
                sb.AppendFormat("\"{0}\":\"{1}\",", pi.Name, value.ToString()).Append("</br>");
            }
            catch (Exception)
            {

            }
        }
        sb.Append("}");
        Response.Write(sb.ToString());

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/daisyhd/archive/2010/11/10/6000962.aspx

分享到:
评论

相关推荐

    jpeg-autorotate:节点模块根据EXIF方向旋转JPEG图像

    在Orientation EXIF标记中写入1 (这是默认方向) 更新PixelXDimension和PixelYDimension EXIF值 不会更改其他EXIF标签 如果满足以下条件,它可能会很有用: 您需要使用去除EXIF数据而不旋转像素的工具来压缩图像...

    WPF 通过 EXIF 设置和读取图片的旋转信息.rar

    在EXIF数据中,有专门的标记如Orientation Tag(0th IFD, Tag 274),用于指示图像应该以何种方式显示。它提供了8种可能的旋转状态,例如“顶部正常”(1)、“逆时针90度”(3)、“180度旋转”(6)等。 在WPF中...

    java 图片压缩 iphone拍照上传旋转问题处理压缩工具类

    `getRotationAngle`方法需要实现从元数据中提取旋转角度的逻辑,这通常涉及到解析Exif中的`Orientation`字段。`rotateImage`方法则负责实际的图像旋转操作,可以使用Java AWT的`AffineTransformOp`。 `...

    数分1.11Tableau安装及使用教程

    数分1.11Tableau安装及使用教程

    软考信息系统运行管理员:涵盖信息系统运维、安全、架构及技术标准的多维考核

    内容概要:本文主要围绕着计算机信息系统运行管理员考试展开讨论,详细介绍了有关信息系统在运维中的各种问题及其应对方案。具体而言,文中不仅列举出了不同类型的信息系统对其本身的要求,而且还深入探讨了运维管理中面临的挑战和技术手段。另外,文章特别提及了一些特定类型的系统(例如政府系统和财务管理等),并指明在面对它们时需要考虑的安全级别、稳定性等关键要素;同时也强调了良好的文档管理和合理的设施运维对象划分,以及软硬件的选择与维护。同时文章还讲解了多种工具的作用(比如Nagios),以及硬件如计算机机房和UPS的具体规格和要求;并且讲述了关于变更管理和发布管理等的概念与实际应用场景。此外,在最后一部分内容里也谈到了云架构及其各个构成部分。 适用人群:本文适合即将参加软考信息运行管理员认证的专业人士,也适用于希望深入了解信息系统运作、管理和维护的技术从业者和相关领域的管理人员。 使用场景及目标:本资料旨在辅助考生掌握信息系统的高效、稳健地构建与运营所需的知识和技术,帮助他们顺利通过软考的同时提升实战经验;同时也为企业信息化建设提供了宝贵的理论基础和实践指南。 其他说明:虽然本文聚焦于特定职业资格证书

    伪知识图谱:元路径引导检索与图内文本技术,助力RAG增强型LLM

    大型语言模型(LLMs)的出现彻底改变了自然语言处理。然而,这些模型在从大量数据集中检索精确信息时面临挑战。检索增强生成(RAG)旨在通过结合外部信息检索系统来增强LLMs,从而提高响应的准确性和上下文性。尽管有所改进,RAG在高容量、低信息密度数据库中的全面检索仍然存在困难,并且缺乏关系意识,导致答案碎片化。 为了解决这一问题,本文介绍了伪知识图谱(PKG)框架,该框架通过集成元路径检索、图内文本和向量检索到LLMs中,旨在克服这些限制。通过保留自然语言文本并利用各种检索技术,PKG提供了更丰富的知识表示并提高了信息检索的准确性。使用Open Compass和MultiHop-RAG基准进行的广泛评估表明,该框架在管理和处理大量数据及复杂关系方面具有有效性。

    zedr_clean-code-python_1741402803.zip

    python学习教程

    kibana-7.10.2 docker镜像压缩包,百度网盘

    请到网盘中自取压缩包,此包为kibana-7.10.2 镜像压缩包,是通过现有镜像导出来的,主要是为了解决有些机器无法连接外网,导致无法下载镜像 加载镜像: docker load -i kibana-7.10.2.tar 查看镜像: docker images 备注:elk此镜像配套资源,相同版本的elasticsearch和logstash,请在我的资源中搜索其他镜像

    UniApp开发一个简单的记事本应用文字教程

    UniApp开发一个简单的记事本应用文字教程

    基于Andorid的音乐播放器项目设计(QQ音乐).zip

    基于Andorid的音乐播放器项目设计(QQ音乐)实现源码,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。

    编程语言_Python_Cookbook_管理工具_1741398354.zip

    python学习资源

    React Developer Tools在谷歌拓展的应用商城下载不了任何解决

    React Developer Tools在谷歌拓展的应用商城下载不了任何解决

    【毕业设计-java】springboot-vue健身房管理系统源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计-java】springboot-vue健身房管理系统源码(完整前后端+mysql+说明文档+LunW).zip

    网络通信_批量IP管理_远程命令执行_工具_1741401998.zip

    python学习资源

    在Anaconda中创建和配置PyTorch环境的详细步骤

    本文提供了一套完整的指南,帮助用户在Anaconda中配置PyTorch环境,便于深度学习开发。首先,用户需要确保安装Anaconda,并通过Anaconda Prompt创建一个新的虚拟环境,以隔离项目依赖。创建好环境后,用户可以根据所用操作系统以及CUDA版本,选择适合的安装命令。对于Windows和Linux用户,提供了安装PyTorch、TorchVision和TorchAudio的具体命令,包括CUDA Toolkit的版本选择。macOS用户则可以安装仅支持CPU的版本。安装完成后,通过简单的Python代码验证PyTorch是否成功安装以及GPU的可用性。文中还列出了常见问题及解决方法,帮助用户快速排查安装过程中可能遇到的障碍。通过遵循这些步骤,用户可以顺利搭建起一个专属的PyTorch开发环境,提升深度学习的工作效率和体验。

    药品同步线程池模式_自动超时退出机制_1741403804.zip

    python学习教程

    数据结构学习指南:从资源到实战全方位提升编程技能

    内容概要:本文汇总了学习数据结构的相关资源,旨在帮助读者系统化地理解和掌握这一计算机科学的基础概念。文中首先列举了一系列权威在线学习资源,包括知名教授的主页、在线编程平台LeetCode和技术博客,这些资源不仅理论丰富,还提供大量的实例和练习机会。接着推荐了几本经典的书籍,如《算法导论》、《大话数据结构》,适合不同程度的学习者深入理解算法和数据结构的细节。此外,还特别提及了几门高质量的网络课程,能够为初学者提供清晰的学习路径。最后强调通过动手实践,如动态数组的C语言实现以及算法题目的刷题练习,是提高编程技能的有效途径。 适合人群:对于想要系统学习并掌握数据结构的程序员及爱好者。 使用场景及目标:适用于个人自学或者课堂教学,目的是通过综合使用理论学习、实践操作来达到对数据结构和算法有全面深刻的认识。 其他说明:本文提供了丰富的链接,让读者可以直接访问各个优质教育资源进行深度探究,鼓励大家积极参与讨论,相互分享心得体验,形成良好的互动交流氛围。

    QMI8658 Datasheet

    QMI8658 Datasheet

    【毕业设计】java-springboot-vue火车订票管理系统源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计】java-springboot-vue火车订票管理系统源码(完整前后端+mysql+说明文档+LunW).zip

Global site tag (gtag.js) - Google Analytics