@@ -259,6 +259,10 @@ private static void makeFullImage(Photo.Metadata metadata, BitmapImage img) {
259
259
img . Freeze ( ) ;
260
260
}
261
261
262
+ private class ImageLoadException : Exception {
263
+ public ImageLoadException ( string message ) : base ( message ) { }
264
+ }
265
+
262
266
/// <summary>
263
267
/// Saves the given <see cref="Photo"/> to the disk.
264
268
/// </summary>
@@ -268,61 +272,19 @@ private static void makeFullImage(Photo.Metadata metadata, BitmapImage img) {
268
272
/// </param>
269
273
/// <returns></returns>
270
274
public static async Task Commit ( Photo photo , string destination = null ) {
271
- var tempFile = photo . FileName + DateTime . Now . Ticks . ToString ( ) + ".tmp" ;
272
- if ( destination != null ) {
273
- tempFile = destination ;
274
- }
275
+ var tempFile = destination ?? photo . FileName + DateTime . Now . Ticks . ToString ( ) + ".tmp" ;
275
276
Photo . Metadata newSource ;
276
- using ( var mmap = MemoryMappedFile . OpenExisting (
277
- mmapName ( photo . FileName ) ,
278
- MemoryMappedFileRights . Read ) ) {
279
- using ( var stream = new UnsafeMemoryMapStream (
280
- mmap . CreateViewAccessor ( 0 , 0 , MemoryMappedFileAccess . Read ) ,
281
- FileAccess . Read ) ) {
282
- BitmapFrame sourceFrame ;
283
- Guid format ;
284
- int width , height ;
285
- {
286
- var decoder = BitmapDecoder . Create ( stream . Stream ,
287
- BitmapCreateOptions . PreservePixelFormat ,
288
- BitmapCacheOption . None ) ;
289
- var frames = decoder . Frames ;
290
- if ( frames . Count < 1 ) {
291
- await photo . Dispatcher . InvokeAsync ( ( ) => {
292
- MessageBox . Show ( "Invalid image data" ,
293
- string . Format ( "Image {0} did not contain any frames." ,
294
- photo . FileName ) ,
295
- MessageBoxButton . OK ,
296
- MessageBoxImage . Error ) ;
297
- } ) ;
298
- return ;
299
- }
300
- sourceFrame = frames [ 0 ] ;
301
- format = decoder . CodecInfo . ContainerFormat ;
302
- width = sourceFrame . PixelWidth ;
303
- height = sourceFrame . PixelHeight ;
304
- }
305
- var md = sourceFrame . Metadata . Clone ( ) as BitmapMetadata ;
306
- newSource = await Exif . SetMetadata ( photo , md ) ;
307
- newSource . Width = width ;
308
- newSource . Height = height ;
309
- BitmapEncoder encoder ;
310
- if ( destination != null ) {
311
- encoder = new JpegBitmapEncoder ( ) ;
312
- } else {
313
- encoder = BitmapEncoder . Create ( format ) ;
314
- }
315
- encoder . Frames . Add (
316
- BitmapFrame . Create (
317
- sourceFrame . Clone ( ) as BitmapFrame ,
318
- sourceFrame . Thumbnail ,
319
- md ,
320
- sourceFrame . ColorContexts ) ) ;
321
- sourceFrame = null ;
322
- using ( var outFile = new FileStream ( tempFile , FileMode . CreateNew ) ) {
323
- encoder . Save ( outFile ) ;
324
- }
325
- }
277
+ try {
278
+ newSource = await reloadAndSave ( photo , destination != null , tempFile ) ;
279
+ } catch ( ImageLoadException ex ) {
280
+ await photo . Dispatcher . InvokeAsync ( ( ) => {
281
+ MessageBox . Show ( "Invalid image data" ,
282
+ string . Format ( $ "Image { photo . FileName } { ex . Message } .",
283
+ photo . FileName ) ,
284
+ MessageBoxButton . OK ,
285
+ MessageBoxImage . Error ) ;
286
+ } ) ;
287
+ return ;
326
288
}
327
289
if ( destination == null ) {
328
290
var oldFile = tempFile + "2" ;
@@ -354,6 +316,51 @@ await photo.Dispatcher.InvokeAsync(() => {
354
316
}
355
317
}
356
318
319
+ private static async Task < Photo . Metadata > reloadAndSave (
320
+ Photo photo , bool forceJpeg , string destFile ) {
321
+ using ( var mmap = MemoryMappedFile . OpenExisting (
322
+ mmapName ( photo . FileName ) ,
323
+ MemoryMappedFileRights . Read ) ) {
324
+ using ( var stream = new UnsafeMemoryMapStream (
325
+ mmap . CreateViewAccessor ( 0 , 0 , MemoryMappedFileAccess . Read ) ,
326
+ FileAccess . Read ) ) {
327
+ BitmapFrame sourceFrame ;
328
+ Guid format ;
329
+ ( sourceFrame , format ) = loadFrame ( stream . Stream ) ;
330
+ var md = sourceFrame . Metadata . Clone ( ) as BitmapMetadata ;
331
+ Photo . Metadata newMetadata = await Exif . SetMetadata ( photo , md ) ;
332
+ newMetadata . Width = sourceFrame . PixelWidth ;
333
+ newMetadata . Height = sourceFrame . PixelHeight ;
334
+ BitmapEncoder encoder = forceJpeg ?
335
+ new JpegBitmapEncoder ( ) :
336
+ BitmapEncoder . Create ( format ) ;
337
+ encoder . Frames . Add (
338
+ BitmapFrame . Create (
339
+ sourceFrame . Clone ( ) as BitmapFrame ,
340
+ sourceFrame . Thumbnail ,
341
+ md ,
342
+ sourceFrame . ColorContexts ) ) ;
343
+ sourceFrame = null ;
344
+ using ( var outFile = new FileStream ( destFile , FileMode . CreateNew ) ) {
345
+ encoder . Save ( outFile ) ;
346
+ }
347
+ return newMetadata ;
348
+ }
349
+ }
350
+ }
351
+
352
+ private static ValueTuple < BitmapFrame , Guid > loadFrame ( Stream stream ) {
353
+ var decoder = BitmapDecoder . Create ( stream ,
354
+ BitmapCreateOptions . PreservePixelFormat ,
355
+ BitmapCacheOption . None ) ;
356
+ var frames = decoder . Frames ;
357
+ if ( frames . Count < 1 ) {
358
+ throw new ImageLoadException ( "did not contain any frames" ) ;
359
+ }
360
+ var sourceFrame = frames [ 0 ] ;
361
+ return ( sourceFrame , decoder . CodecInfo . ContainerFormat ) ;
362
+ }
363
+
357
364
/// <summary>
358
365
/// Remove <paramref name="oldFile"/> after closing any handles
359
366
/// <paramref name="photo"/> might have open for it and replacing them
0 commit comments