55using System . Linq ;
66using System . Text ;
77using System . Threading . Tasks ;
8+ using System . Windows . Media ;
89using System . Windows . Media . Imaging ;
910
1011namespace PhotoTagger . Imaging {
@@ -35,7 +36,8 @@ private static string fromUniversalNewline(string from) {
3536 const string XmpDescriptionQuery = "/xmp/dc:description" ;
3637 const string DateTakenQuery = "/app1/ifd/exif/{ushort=36867}" ;
3738 const string DateTakenSubsecQuery = "/app1/ifd/exif/{ushort=37521}" ;
38- const string OrientationQuery = "/app1/ifd/{ushort=274}" ;
39+ const string JpegOrientationQuery = "/app1/ifd/{ushort=274}" ;
40+ const string RawOrientationQuery = "/ifd/{ushort=274}" ;
3941
4042 const string LatitudeRefQuery = "/app1/ifd/gps/subifd:{ulong=1}" ;
4143 const string LatitudeQuery = "/app1/ifd/gps/subifd:{ulong=2}" ;
@@ -45,6 +47,32 @@ private static string fromUniversalNewline(string from) {
4547 const string PaddingQuery = "/app1/ifd/PaddingSchema:Padding" ;
4648 const string ExifPaddingQuery = "/app1/ifd/exif/PaddingSchema:Padding" ;
4749 const string XmpPaddingQuery = "/xmp/PaddingSchema:Padding" ;
50+ const string ColorSpaceQuery = "/app1/{ushort=0}/{ushort=34665}/{ushort=40961}" ;
51+
52+ // From the System.Title Photo Metadata Policy
53+ readonly static string [ ] TitleReadQueries = {
54+ WinTitleQuery ,
55+ "/xmp/<xmpalt>dc:title" ,
56+ XmpTitleQuery ,
57+ "/app1/ifd/exif/{ushort=37510}" ,
58+ TitleQuery ,
59+ "/app13/irb/8bimiptc/iptc/caption" ,
60+ "/xmp/<xmpalt>dc:description" ,
61+ XmpDescriptionQuery ,
62+ "/app13/irb/8bimiptc/iptc/caption" ,
63+ "/xmp/<xmpalt>exif:UserComment" ,
64+ } ;
65+
66+ // From the System.Title Photo Metadata Policy
67+ readonly static string [ ] TitleRemoveQueries = {
68+ WinTitleQuery ,
69+ XmpTitleQuery ,
70+ "/app1/ifd/exif/{ushort=37510}" ,
71+ "/xmp/<xmpalt>exif:UserComment" ,
72+ TitleQuery ,
73+ "/app13/irb/8bimiptc/iptc/caption" ,
74+ XmpDescriptionQuery ,
75+ } ;
4876
4977 #endregion
5078
@@ -82,22 +110,14 @@ private static string readString(BitmapMetadata metadata, string key) {
82110 }
83111
84112 private static string readTitle ( BitmapMetadata metadata ) {
85- var xmpTitle = readString ( metadata , XmpDescriptionQuery ) as string ??
86- readString ( metadata , XmpTitleQuery ) as string ;
87- if ( ! string . IsNullOrWhiteSpace ( xmpTitle ) ) {
88- return fromUniversalNewline ( xmpTitle ) . Trim ( ) ;
89- }
90- var exifTitle = readString ( metadata , TitleQuery ) ;
91- if ( ! string . IsNullOrWhiteSpace ( exifTitle ) ) {
92- return fromUniversalNewline ( exifTitle ) . Trim ( ) ;
93- }
94- xmpTitle = readString ( metadata , WinTitleQuery ) ;
95- if ( ! string . IsNullOrWhiteSpace ( xmpTitle ) ) {
96- // Remove trailing null.
97- return fromUniversalNewline ( xmpTitle
98- . Substring ( 0 , xmpTitle . Length - 1 ) ) . Trim ( ) ;
99- }
100- return xmpTitle ;
113+ foreach ( var query in TitleReadQueries ) {
114+ var v = readString ( metadata , query ) ;
115+ if ( ! string . IsNullOrWhiteSpace ( v ) ) {
116+ return fromUniversalNewline ( v )
117+ . TrimEnd ( '\0 ' ) . Trim ( ) ;
118+ }
119+ }
120+ return string . Empty ;
101121 }
102122
103123 private static string readAuthor ( BitmapMetadata metadata ) {
@@ -159,7 +179,14 @@ public static Rotation OrienationToRotation(short orienation) {
159179
160180 private static short getOrientation ( BitmapMetadata metadata ) {
161181 try {
162- var orientationProp = metadata . GetQuery ( OrientationQuery ) as ushort ? ;
182+ ushort ? orientationProp ;
183+ if ( metadata . ContainsQuery ( JpegOrientationQuery ) ) {
184+ orientationProp = metadata . GetQuery ( JpegOrientationQuery ) as ushort ? ;
185+ } else if ( metadata . ContainsQuery ( RawOrientationQuery ) ) {
186+ orientationProp = metadata . GetQuery ( RawOrientationQuery ) as ushort ? ;
187+ } else {
188+ return 1 ;
189+ }
163190 if ( orientationProp . HasValue ) {
164191 return ( short ) orientationProp . Value ;
165192 }
@@ -180,39 +207,41 @@ await photo.Dispatcher.InvokeAsync(() => {
180207 source . Author = photo . Photographer ;
181208 source . DateTaken = photo . DateTaken ;
182209 source . Location = photo . Location ;
210+ source . Orientation = 1 ;
183211 } ) ;
184- int pad = 0 ;
185- if ( source . Title != null ) {
212+ if ( ! string . IsNullOrWhiteSpace ( source . Title ) ) {
186213 var title = toUniversalNewline ( source . Title . Trim ( ) ) ;
187214 var bytes = Encoding . UTF8 . GetBytes ( title ) ;
188215 dest . SetQuery ( TitleQuery , Encoding . Default . GetString ( bytes ) ) ;
189216 var utf16bytes = Encoding . Unicode . GetBytes ( title + '\0 ' ) ;
190217 dest . SetQuery ( WinTitleQuery , utf16bytes ) ;
191218 dest . Title = title ;
192- pad += bytes . Length * 4 + utf16bytes . Length + 16 ;
219+ } else {
220+ dest . Title = string . Empty ;
221+ foreach ( var query in TitleRemoveQueries ) {
222+ dest . RemoveQuery ( query ) ;
223+ }
193224 }
194- if ( source . Author != null ) {
225+ if ( ! string . IsNullOrWhiteSpace ( source . Author ) ) {
195226 var bytes = Encoding . UTF8 . GetBytes ( source . Author ) ;
196227 dest . Author = new ReadOnlyCollection < string > ( new string [ ] {
197228 Encoding . Default . GetString ( bytes )
198229 } ) ;
199- pad += bytes . Length + 16 ;
230+ } else {
231+ dest . Author = null ;
200232 }
201233 if ( source . DateTaken . HasValue ) {
202234 var bytes = Encoding . ASCII . GetBytes (
203235 source . DateTaken . Value . ToString ( ExifDateFormat , CultureInfo . InvariantCulture ) ) ;
204236 dest . SetQuery ( DateTakenQuery , Encoding . Default . GetString ( bytes ) ) ;
205- pad += bytes . Length + 16 ;
237+ } else {
238+ dest . RemoveQuery ( DateTakenQuery ) ;
239+ dest . RemoveQuery ( DateTakenSubsecQuery ) ;
206240 }
207241 if ( source . Location != null ) {
208242 setLocation ( dest , source . Location ) ;
209- pad += 404 ;
210- }
211- if ( pad != 0 ) {
212- uint padding = ( uint ) pad + 256u ;
213- dest . SetQuery ( PaddingQuery , padding ) ;
214- dest . SetQuery ( ExifPaddingQuery , padding ) ;
215- dest . SetQuery ( XmpPaddingQuery , padding ) ;
243+ } else {
244+ clearLocation ( dest ) ;
216245 }
217246 return source ;
218247 }
@@ -230,6 +259,21 @@ private static void setLocation(BitmapMetadata dest, GpsLocation loc) {
230259 dest . SetQuery ( LongitudeQuery , bytesToLongs ( loc . LonBytes ) . ToArray ( ) ) ;
231260 }
232261
262+ private static void clearLocation ( BitmapMetadata dest ) {
263+ dest . RemoveQuery ( LatitudeRefQuery ) ;
264+ dest . RemoveQuery ( LatitudeQuery ) ;
265+ dest . RemoveQuery ( LongitudeRefQuery ) ;
266+ dest . RemoveQuery ( LongitudeQuery ) ;
267+ }
268+
269+ internal static Rotation SaveRotation ( BitmapMetadata md ) {
270+ var rotation = OrienationToRotation ( getOrientation ( md ) ) ;
271+ if ( rotation != Rotation . Rotate0 ) {
272+ md . SetQuery ( JpegOrientationQuery , ( short ) 1 ) ;
273+ }
274+ return rotation ;
275+ }
276+
233277 #endregion
234278 }
235279}
0 commit comments