|
see Saving Edits thread
also - i changed the SetProperties code in ExifWorks to
Dim P = (From e In _Image.PropertyItems() Where e.Id = PID).FirstOrDefault (this is under vs 2008 3.5 Framework)
P.Value = Data
P.Len = Data.Length
since we are not updateing the ID no need to set and there is also no reason to update the Type because we should not be changing the type either. You shouldnt be adding to the property list but updating them with new data.
|
|
|
|
|
Was looking at efixworks for some jpg manipulation for a slide show app.I would like to let the user tag photos when they are on screen. Is there any way to add tags like in vista pic viewer? like tag photos with italy or names of people in photos like loori or rod. this would be used to let user set slide show a tag group like show all Italy pics.
Thanks in advance!
|
|
|
|
|
Hi I just tried this code as well as some VB6 source, in both case it seems that the ISO speed info cannot be saved where I can change aperture and shutter speed. Any ides?
Thanks
Phil
|
|
|
|
|
Below is the code for extracting the Thumbnail image from the Exif data.
Public ReadOnly Property HasThumbnail() As Boolean
Get
Return IsPropertyDefined(TagNames.ThumbnailData)
End Get
End Property
Private mThumb As Image
Public ReadOnly Property Thumbnail() As Image
Get
If mThumb Is Nothing Then
' Let's try to load the thumbnail from the raw bytes!
Dim thumbData() As Byte = Me.GetProperty(TagNames.ThumbnailData)
If thumbData IsNot Nothing Then
Dim thumbStream As New IO.MemoryStream(thumbData)
Try
mThumb = Drawing.Image.FromStream(thumbStream)
Catch ex As Exception
'Couldn't load the thumbnail :( Reason? Unknown.
End Try
End If
End If
Return mThumb
End Get
End Property
Also, when the image is loaded from a file, it normally has to load the entire full image, which takes a long time. If we tell the image not to load, it performs way better. This is especially useful if we're just trying to extract a thumbnail. So, below, I modified the constructor to skip loading the whole image.
Private shouldDisposeImage As Boolean
''' <summary>
''' Reads EXIF data from a file.
''' </summary>
''' <param name="FileName">Name of file to be loaded</param>
''' <param name="loadEntireImage">IF False, then ONLY the EXIF data is loaded, and not the entire image! This saves a TON of time. If True, then the entire image is loaded.</param>
''' <remarks></remarks>
''' <history>
''' [altair] 13.06.2004 Created
''' </history>
Public Sub New(ByVal FileName As String, Optional ByVal loadEntireImage As Boolean = False)
'Me._Image = System.Drawing.Bitmap.FromFile(FileName)
Dim fileStream As New System.IO.FileStream(FileName, IO.FileMode.Open, IO.FileAccess.Read)
Me._Image = System.Drawing.Image.FromStream(fileStream, True, loadEntireImage)
Me.shouldDisposeImage = True 'since we created the bitmap, we are responsible for destroying it
End Sub
''' <summary>
''' Disposes unmanaged resources of this class
''' </summary>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' </history>
Public Sub Dispose() Implements System.IDisposable.Dispose
If shouldDisposeImage Then Me._Image.Dispose()
End Sub
modified on Tuesday, June 23, 2009 1:05 PM
|
|
|
|
|
Works well. Have you tried to SET the thumbnail after editing the base image. I wrote up my own display form and made rotate functions. The base jpg image rotates but when the form redisplays, it is grabbing the thmbnail image coded within the jpeg fiel which doesnt have the rotation. I know many software viewing program auto rotate (if the camera has that function) but when uploading to a website (facebook, WIndows Live) the image has to be corrected because their displaying software doesnt auto-rotate.
Wondered if you had any luck writing back to the thumbnail image before I take a stab at it.
|
|
|
|
|
No, I haven't done that.
It might be really easy, basically you just reverse the decoding code that I wrote. Create a new thumbnail, save it to a memory stream, and put those bytes back into the PropertyItems.
However, it's up to the GDI classes to save it properly to the JPG format. Let me know how things turn out!
|
|
|
|
|
ok. Have written where a new thumbnail is generated based on the newly edit picture (rotated 90 degrees). I save the thumb as a file, loading into filestream and convert it to byte(). Return Byte() to calling function and then set exifworks newly created set function to created Byte()
Edited your get Thumbnail as
Public Property Thumbnail() As Image
Get
If mThumb Is Nothing Then ' Let's try to load the thumbnail from the raw bytes!
Dim thumbData() As Byte = Me.GetProperty(TagNames.ThumbnailData)
If thumbData IsNot Nothing Then
Dim thumbStream As New IO.MemoryStream(thumbData)
Try
mThumb = Drawing.Image.FromStream(thumbStream)
Catch ex As Exception 'Couldn't load the thumbnail Reason? Unknown.
End Try
End If
End If
Return mThumb
End Get
Set(ByVal value As Image)
'data is not saved as actual image but as a byte() within the jpeg exif metadata
Dim valueByte As Byte() = ConvertImageFiletoBytes(NewThmubImage)
Try
Me.SetProperty(TagNames.ThumbnailData, valueByte, ExifDataTypes.SignedByte)
Catch ex As Exception
End Try
End Set
End Property
Nothing seems to save. I tried to change the Orientation tag just to see if it was the byte() not being made correctly but even a simple update of this didnt work either - even hard coded the value in the set
Public Property Orientation() As Orientations
Get
Dim X As Int32 = Me.GetPropertyInt16(TagNames.Orientation)
If Not [Enum].IsDefined(GetType(Orientations), X) Then
Return Orientations.TopLeft
Else
Return CType([Enum].Parse(GetType(Orientations), [Enum].GetName(GetType(Orientations), X)), Orientations)
End If
End Get
Set(ByVal value As Orientations)
value = Orientations.TopLeft
Me.SetPropertyInt16(TagNames.Orientation, value)
End Set
End Property
Any ideas?????
|
|
|
|
|
Alright, I battled over whether or not I wanted to fire up Visual Studio to take a stab at this, and eventually my curiosity won me over.
Your code was *really* close to correct but obviously "ConvertImageFileToBytes" was just high-hopes, so here's some totally untested code for you to try:
Set(ByVal value As Image)
If value IsNot Nothing Then
' Create a memory stream to write to:
Dim thumbStream As New IO.MemoryStream()
' Save the image to the memory stream:
value.Save(thumbStream, ImageFormat.Jpeg)
' Convert the memory stream to an array of bytes:
Dim thumbData() As Byte = thumbStream.ToArray
' Save the bytes back to the PropertyItems: (a byte array is an undefined type)
Me.SetProperty(TagNames.ThumbnailData, thumbData, ExifDataTypes.Undefined)
' Update our cached thumbnail:
Me.mThumb = value
End If
End Set
The use of MemoryStream is necessary because the Save method of an image requires any Stream to write to. Also, the ExifDataType is Undefined because we have to write raw data.
The Orientation is just metadata, and has nothing to do with the actual thumbnail. However, if you are rotating the image, then it would be wise of you to also correct the Orientation tag.
|
|
|
|
|
MADE IT WORK!!!!!
Yeah!
I was sending the rotated image in memory to teh exifworks, trying to update the properties there. That wasnt wroking. So I saved the image rotated, then loaded the file into exifworks and tested for thumbnail. IF thmb was there then i created a new thumb from the rotated version and turned it into bytes (thanks) and then changed the SetProperty routine to loop through all the properties until the thmb ID was found and changed that. Then dim a new image as the exifworkd update image, saved it to a new temp file name (because exif still has control of the image). Once the new updated image is saved to disc then dispose of exifworks; delete original, copy temp to original name; then delete temp. This should jsut be easier.
I am going to take the looping out and should be able to just insert the PID in the propertyitem line and save processing time looping through all 47 properties!
Thanks for all your help.
|
|
|
|
|
By the way... dont have good wisdom on io.memstream stuff. Can you load a picture directly into a memorystream object?? Do you have to have the windows handle of the item??? any help on this one would be good.
|
|
|
|
|
using System;
using System.Text;
using System.Drawing;
using System.IO;
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 FileStream _Stream;
private Bitmap _Image;
private Encoding _Encoding = Encoding.UTF8;
#region Type declarations
//
// Contains possible values of EXIF tag names (ID)
//
// See GdiPlusImaging.h
//
// [altair] 10.09.2003 Created
//
public enum TagNames
{
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(Bitmap Bitmap)
{
if (Bitmap == null)
throw new ArgumentNullException("Bitmap");
_Image = Bitmap;
}
//
// Initializes new instance of this class.
//
// Name of file to be loaded
//
//
// [altair] 13.06.2004 Created
//
public ExifManager(string FileName)
{
if (FileName == null)
throw new ArgumentNullException("FileName");
_Stream = new FileStream(FileName, FileMode.Open, FileAccess.Read);
_Image = (Bitmap)Image.FromStream(_Stream, true, /*avoid loading here!*/ false);
// _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 Encoding Encoding
{
get
{
return _Encoding;
}
set
{
if (value == null)
throw new ArgumentNullException();
_Encoding = value;
}
}
//
// Returns copy of bitmap this instance is working on
//
//
//
//
// [altair] 13.06.2004 Created
//
public Bitmap GetBitmap()
{
return (Bitmap)_Image.Clone();
}
//
// Returns all available data in formatted string form
//
//
//
//
// [altair] 10.09.2003 Created
//
public override string ToString()
{
StringBuilder SB = new StringBuilder();
SB.Append("Image:");
SB.Append("\n\tDimensions: " + Width + " x " + Height + " px");
SB.Append("\n\tResolution: " + ResolutionX + " x " + ResolutionY + " dpi");
SB.Append("\n\tOrientation: " + Enum.GetName(typeof(Orientations), Orientation));
SB.Append("\n\tTitle: " + Title);
SB.Append("\n\tDescription: " + Description);
SB.Append("\n\tCopyright: " + Copyright);
SB.Append("\nEquipment:");
SB.Append("\n\tMaker: " + EquipmentMaker);
SB.Append("\n\tModel: " + EquipmentModel);
SB.Append("\n\tSoftware: " + Software);
SB.Append("\nDate and time:");
SB.Append("\n\tGeneral: " + DateTimeLastModified.ToString());
SB.Append("\n\tOriginal: " + DateTimeOriginal.ToString());
SB.Append("\n\tDigitized: " + DateTimeDigitized.ToString());
SB.Append("\nShooting conditions:");
SB.Append("\n\tExposure time: " + ExposureTime.ToString("N4") + " s");
SB.Append("\n\tExposure program: " + Enum.GetName(typeof(ExposurePrograms), ExposureProgram));
SB.Append("\n\tExposure mode: " + Enum.GetName(typeof(ExposureMeteringModes), ExposureMeteringMode));
SB.Append("\n\tAperture: F" + Aperture.ToString("N2"));
SB.Append("\n\tISO sensitivity: " + ISO);
SB.Append("\n\tSubject distance: " + SubjectDistance.ToString("N2") + " m");
SB.Append("\n\tFocal length: " + FocalLength);
SB.Append("\n\tFlash: " + Enum.GetName(typeof(FlashModes), FlashMode));
SB.Append("\n\tLight source (WB): " + Enum.GetName(typeof(LightSources), 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 GetPropertyString(TagNames.EquipMake);
}
}
//
// Model of equipment (EXIF EquipModel)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string EquipmentModel
{
get
{
return GetPropertyString(TagNames.EquipModel);
}
}
//
// Software used for processing (EXIF Software)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Software
{
get
{
return GetPropertyString(TagNames.SoftwareUsed);
}
}
//
// Orientation of image (position of row 0, column 0) (EXIF Orientation)
//
//
//
//
// [altair] 10.09.2003 Created
//
public Orientations Orientation
{
get
{
Int32 X = GetPropertyInt16(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(GetPropertyString(TagNames.DateTime), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
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(GetPropertyString(TagNames.ExifDTOrig), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
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(GetPropertyString(TagNames.ExifDTDigitized), @"yyyy\:MM\:dd HH\:mm\:ss", null);
}
catch
{
return DateTime.MinValue;
}
}
set
{
try
{
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 _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 _Image.Height; }
}
//
// X resolution in dpi (EXIF XResolution/ResolutionUnit)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double ResolutionX
{
get
{
double R = GetPropertyRational(TagNames.XResolution).ToDouble();
if (GetPropertyInt16(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 = GetPropertyRational(TagNames.YResolution).ToDouble();
if (GetPropertyInt16(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 GetPropertyString(TagNames.ImageTitle);
}
set
{
try
{
SetPropertyString((int)TagNames.ImageTitle, value);
}
catch { }
}
}
//
// User comment (EXIF UserComment)
//
//
//
//
// [altair] 13.06.2004 Created
//
public string UserComment
{
get
{
return GetPropertyString(TagNames.ExifUserComment);
}
set
{
try
{
SetPropertyString((int)TagNames.ExifUserComment, value);
}
catch { }
}
}
//
// Artist name (EXIF Artist)
//
//
//
//
// [altair] 13.06.2004 Created
//
public string Artist
{
get
{
return GetPropertyString(TagNames.Artist);
}
set
{
try
{
SetPropertyString((int)TagNames.Artist, value);
}
catch { }
}
}
//
// Image description (EXIF ImageDescription)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Description
{
get
{
return GetPropertyString(TagNames.ImageDescription);
}
set
{
try
{
SetPropertyString((int)TagNames.ImageDescription, value);
}
catch { }
}
}
//
// Image copyright (EXIF Copyright)
//
//
//
//
// [altair] 10.09.2003 Created
//
public string Copyright
{
get
{
return GetPropertyString(TagNames.Copyright);
}
set
{
try
{
SetPropertyString((int)TagNames.Copyright, value);
}
catch { }
}
}
//
// Exposure time in seconds (EXIF ExifExposureTime/ExifShutterSpeed)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double ExposureTimeAbs
{
get
{
if (IsPropertyDefined(TagNames.ExifExposureTime))
// -- Exposure time is explicitly specified
return GetPropertyRational(TagNames.ExifExposureTime).ToDouble();
else
if (IsPropertyDefined(TagNames.ExifShutterSpeed))
//'-- Compute exposure time from shutter spee
return (1 / Math.Pow(2, GetPropertyRational(TagNames.ExifShutterSpeed).ToDouble()));
else
// -- Can't figure out
return 0;
}
}
public Rational ExposureTime
{
get
{
if (IsPropertyDefined(TagNames.ExifExposureTime))
// -- Exposure time is explicitly specified
return GetPropertyRational(TagNames.ExifExposureTime);
else
return new Rational();
}
}
//
// Aperture value as F number (EXIF ExifFNumber/ExifApertureValue)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double Aperture
{
get
{
if (IsPropertyDefined(TagNames.ExifFNumber))
return GetPropertyRational(TagNames.ExifFNumber).ToDouble();
else
if (IsPropertyDefined(TagNames.ExifAperture))
return Math.Pow(System.Math.Sqrt(2), GetPropertyRational(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 = GetPropertyInt16(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 GetPropertyInt16(TagNames.ExifISOSpeed); }
}
//
// Subject distance in meters (EXIF SubjectDistance)
//
//
//
//
// [altair] 10.09.2003 Created
//
public double SubjectDistance
{
get { return GetPropertyRational(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 = GetPropertyInt16(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 GetPropertyRational(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 = GetPropertyInt16(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 = GetPropertyInt16(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(TagNames PID)
{
return (Array.IndexOf(_Image.PropertyIdList, (int)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(TagNames PID)
{
return GetPropertyInt32(PID, 0);
}
public Int32 GetPropertyInt32(TagNames PID, Int32 DefaultValue)
{
if (IsPropertyDefined(PID))
return GetInt32(_Image.GetPropertyItem((int)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(TagNames PID)
{
return GetPropertyInt16(PID, 0);
}
public Int16 GetPropertyInt16(TagNames PID, Int16 DefaultValue)
{
if (IsPropertyDefined(PID))
return GetInt16(_Image.GetPropertyItem((int)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(TagNames PID)
{
return GetPropertyString(PID, "");
}
public string GetPropertyString(TagNames PID, string DefaultValue)
{
if (IsPropertyDefined(PID))
return GetString(_Image.GetPropertyItem((int)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(TagNames PID, byte[] DefaultValue)
{
if (IsPropertyDefined(PID))
return _Image.GetPropertyItem((int)PID).Value;
else
return DefaultValue;
}
public byte[] GetProperty(TagNames 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(TagNames PID)
{
if (IsPropertyDefined(PID))
return GetRational(_Image.GetPropertyItem((int)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 = _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 = _Image.PropertyItems[0];
P.Id = PID;
P.Value = Data;
P.Type = (Int16)Type;
P.Len = Data.Length;
_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 static 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 static 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 = _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 static 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 = GetInt32(D);
R.Numerator = GetInt32(N);
return R;
}
//
// Gets specified rational property
//
// Property ID
//
// Value of property or 0/1 if not present.
//
// [altair] 10.09.2003 Created
//
public Rational GetPropertyRational(TagNames PID, int rank)
{
if (IsPropertyDefined(PID))
{
byte[] N = new byte[8];
Array.Copy(_Image.GetPropertyItem((int)PID).Value, rank * 8, N, 0, 8);
return GetRational(N);
}
else
{
Rational R = new Rational { Numerator = 0, Denominator = 1 };
return R;
}
}
static double DMStoDD(double vDeg, double vMin, double vSec)
{
return vDeg + (vMin / 60) + (vSec / 3600);
}
public double Latitude
{
get
{
if (IsPropertyDefined(TagNames.GpsLatitude))
{
Rational deg = GetPropertyRational(TagNames.GpsLatitude, 0);
Rational min = GetPropertyRational(TagNames.GpsLatitude, 1);
Rational sec = GetPropertyRational(TagNames.GpsLatitude, 2);
Double res = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble());
String Ref = GetPropertyString(TagNames.GpsLatitudeRef);
if (Ref != "N")
res = -res;
return res;
}
else
return Double.NaN;
}
}
public double Longitude
{
get
{
if (IsPropertyDefined(TagNames.GpsLongitude))
{
Rational deg = GetPropertyRational(TagNames.GpsLongitude, 0);
Rational min = GetPropertyRational(TagNames.GpsLongitude, 1);
Rational sec = GetPropertyRational(TagNames.GpsLongitude, 2);
Double res = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble());
String Ref = GetPropertyString(TagNames.GpsLongitudeRef);
if (Ref != "E")
res = -res;
return res;
}
else
return Double.NaN;
}
}
#endregion
#region " IDisposable implementation "
//
// Disposes unmanaged resources of this class
//
//
//
// [altair] 10.09.2003 Created
//
public void Dispose()
{
_Image.Dispose();
_Stream.Dispose();
}
#endregion
}
}
|
|
|
|
|
I want to open an image, change some properties and then save it again as the same file. How to do it?
Currently I try to create a temp file of the source file, delete the original, open the temp file with ExifWorks and save it with the original filename. All this works OK, but I then want to delete the temp file. Even though I use .Dispose on the ExifWorks object I get an error message saying that the file is opened by another process.
Is this the smoothest way to do this? Or are there an other, smoother way?
|
|
|
|
|
I used the EXIFWorks class and followed the style of extacting EXIF data to pull back latitude & longitude. However, I can only seem to pull back the first degrees part eg. 51 instead of 51, 27.86
Here is how I've done it:
'In ExifWorks Class
Public ReadOnly Property GPSLatitude() As Integer
Get
Return Me.GetPropertyInt32(TagNames.GpsLatitude)
End Get
End Property
'In my project
Dim GPSLat As Long = EW.GPSLatitude()
labelLat.Text = GPSLat
Am I not using the correct data type (Integer/PropertyInt32)?
|
|
|
|
|
I've stumbled upon the same problem. There must be something wrong with the data type. The data type "Integer" only supports real integers. Did you get any answer to this question or did you manage to solve it yourself? I'm curious since I can't solve it...
|
|
|
|
|
I just published the answer below.
|
|
|
|
|
The posting you did above is the converted version of vb.net, right? As I converted it back to vb.net (I am programming in that language) I noted that there were no references at all to any GPS-information. I'm back to square one. Could you please show me how to write the coding that gets that information out of the exif?
// Kristofer
|
|
|
|
|
Latitude and Longitude are new properties near the end of the C# version above.
I have converted them back to VB.Net and included the fixed Get* routines below:
''' <summary>
''' Read Int32 from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetInt32(ByVal B As Byte()) As Int32
If B.Length < 4 Then
Throw New ArgumentException("Data too short (4 bytes expected)", "B")
End If
Return System.BitConverter.ToInt32(B, 0)
End Function
''' <summary>
''' Read Int16 from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetInt16(ByVal B As Byte()) As Int16
If B.Length < 2 Then
Throw New ArgumentException("Data too short (2 bytes expected)", "B")
End If
Return System.BitConverter.ToInt16(B, 0)
End Function
''' <summary>
''' Read string from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Function GetString(ByVal B As Byte()) As String
Dim R As String = _Encoding.GetString(B)
If R.EndsWith(vbNullChar) Then
R = R.Substring(0, R.Length - 1)
End If
Return R
End Function
''' <summary>
''' Read rational from EXIF bytearray.
''' </summary>
''' <param name="B">EXIF bytearray to process</param>
''' <returns></returns>
''' <remarks></remarks>
''' <history>
''' [altair] 10.09.2003 Created
''' [altair] 05.09.2005 Changed from public shared to private instance method
''' </history>
Private Shared Function GetRational(ByVal B As Byte()) As Rational
Dim R As New Rational
R.Denominator = System.BitConverter.ToInt32(B, 4)
R.Numerator = System.BitConverter.ToInt32(B, 0)
Return R
End Function
''' <summary>
''' Get specified rational property
''' </summary>
''' <param name="PID">Property ID</param>
''' <param name="rank"></param>
''' <returns>Value of property or 0/1 if not present</returns>
''' <history>
''' [altair] 10.09.2003 Created
''' </history>
Public Function GetPropertyRational(ByVal PID As TagNames, ByVal rank As Integer) As Rational
If IsPropertyDefined(PID) Then
Dim N As Byte() = New Byte(7) {}
Array.Copy(_Image.GetPropertyItem(PID).Value, rank * 8, N, 0, 8)
Return GetRational(N)
Else
Dim R As New Rational()
Return R
End If
End Function
''' <summary>
''' Degrees, Minutes, Seconds to Decimal Degrees
''' </summary>
''' <param name="Deg">Degrees</param>
''' <param name="Min">Minutes</param>
''' <param name="Sec">Seconds</param>
''' <returns>Decimal Degrees</returns>
''' <remarks>in EXIF, Deg is always positive, but added case for negative degrees in case this routine is reused</remarks>
Private Shared Function DMStoDD(ByVal Deg As Double, ByVal Min As Double, ByVal Sec As Double) As Double
Dim lFraction As Double = (Min / 60) + (Sec / 3600)
If Deg > 0 Then
Return Deg + lFraction
Else
Return Deg - lFraction
End If
End Function
''' <summary>
''' GPS Latitude
''' </summary>
''' <returns>Decimal degrees of latitude</returns>
Public ReadOnly Property Latitude() As Double
Get
If IsPropertyDefined(TagNames.GpsLatitude) Then
Dim deg As Rational = GetPropertyRational(TagNames.GpsLatitude, 0)
Dim min As Rational = GetPropertyRational(TagNames.GpsLatitude, 1)
Dim sec As Rational = GetPropertyRational(TagNames.GpsLatitude, 2)
Dim res As [Double] = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble())
Dim Ref As [String] = GetPropertyString(TagNames.GpsLatitudeRef)
If Ref <> "N" Then
res = -res
End If
Return res
Else
Return [Double].NaN
End If
End Get
End Property
''' <summary>
''' GPS Longitude
''' </summary>
''' <returns>Decimal degrees of longitude</returns>
Public ReadOnly Property Longitude() As Double
Get
If IsPropertyDefined(TagNames.GpsLongitude) Then
Dim deg As Rational = GetPropertyRational(TagNames.GpsLongitude, 0)
Dim min As Rational = GetPropertyRational(TagNames.GpsLongitude, 1)
Dim sec As Rational = GetPropertyRational(TagNames.GpsLongitude, 2)
Dim res As [Double] = DMStoDD(deg.ToDouble(), min.ToDouble(), sec.ToDouble())
Dim Ref As [String] = GetPropertyString(TagNames.GpsLongitudeRef)
If Ref <> "E" Then
res = -res
End If
Return res
Else
Return [Double].NaN
End If
End Get
End Property
|
|
|
|
|
You are only reading the 1st value in GpsLatitude, there are 3, Degrees, Minutes and Seconds so you need to write code to obtain all three. Happily someone has already done this
http://www.vbforums.com/showthread.php?t=647226
|
|
|
|
|
Hi,
There may be other bugs other than what i found but at first sight, it gives wrong info about Flash Mode. Though other programs say "Flash is Fired" and i'm sure i fired the Flash (my own photo), your class returns NotFired value from FlashModes enum.
Some further optimizations might be needed for the issues like that one.
Thanks.
|
|
|
|
|
Flash info is returned wrong. Any others having it?
|
|
|
|
|
Any code will he helpful.
Pendin Approval
|
|
|
|
|
I have written a test program to update and save the Title and User Comments tags with limited success...meaning that I can re-read the saved image and I can see the changes that I made to the Title and User Comments ...if I read the image using EXIFWorks....however if I use any of the Windows picture viewing products (either Vista Windows Photo Gallery or Microsoft Office 2007 Picture Manager) the updated Title or User Comments are NOT visible when the picture properties is displayed.
Any idea why ?
|
|
|
|
|
Hello,
just a remark: your ExifWorks class implements the IDisposable interface which cleans up the image passed on to it. This is bad, as that image (of class Bitmap) is a MANAGED resource which will be cleared automatically by the CLR during garbage collection if appropriate. As it stands now code like that below will fail further down the line because:
Public Shared Sub AddCalibratedMetadata(ByVal img As bitmap)
Dim exif As New CIPF.ExifWorks(img)
exif.Description = "Calibrated"
exif.Dispose()
End Sub
From here on the img reference is invalid ...
So there is no need for the IDIsposable interface, this is for cleaning up stuff like COM objects.
Keep up the good work
Yves
|
|
|
|
|
Hi,
thankyou for your work.
I found this problem in your Class.
In this routine:
<br />
Public Sub New(ByVal FileName As String)<br />
Me._Image = DirectCast(System.Drawing.Bitmap.FromFile(FileName), System.Drawing.Bitmap)<br />
Me._Image.Tag = FileName 'safe path and filename for later use<br />
End Sub<br />
when image was loaded, the file will be locked and this lock never be released.
I tryed this code:
<br />
Private _reader As System.IO.StreamReader<br />
<br />
Public Sub New(ByVal FileName As String)<br />
If FileName = "" Then Throw New ArgumentNullException("File Name")<br />
<br />
Me._reader = New System.IO.StreamReader(FileName)<br />
Me._Image = DirectCast(System.Drawing.Bitmap.FromStream(_reader.BaseStream), System.Drawing.Bitmap)<br />
Me._reader.Close()<br />
Me._Image.Tag = FileName 'safe path and filename for later use<br />
<br />
End Sub<br />
in this case the file will be unlocked, but when i'll try to read any property I'll get an error.
Can you help me?
Many Thanks
Marco
|
|
|
|
|
Hi,
seem i found a solution.
I need to modify all Get Property like this:
<br />
Public Function GetPropertyString(ByVal PID As Int32, Optional ByVal DefaultValue As String = "") As String<br />
If Me.IsPropertyDefined(PID) Then<br />
Dim a As String = GetString(Me._Image.GetPropertyItem(PID).Value)<br />
Me._Image.Dispose()<br />
Return a<br />
Else<br />
Me._Image.Dispose()<br />
Return DefaultValue<br />
End If<br />
End Function<br />
Seem it works fine.
|
|
|
|
|