Reading Metadata property of GifBitmapDecoder...why is it null? - wpf

How can I read the delay, left and top offset data for each frame of a gif? I've gotten this far.
Load the Gif
var myGif = new GifBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
Get a frame
var frame = myGif.Frames[i];
From MSDN: Native Image Format Metadata Queries read (ushort)Metadata.GetQuery("/grctlext/Delay"), (ushort)Metadata.GetQuery("/imgdesc/Left"), (ushort)Metadata.GetQuery("/imgdesc/Top")
But two things don't work. First the Metadata property of both the gif and the frame are always null, even if I try different animated gif files. Second, the Metadata property of the frame doesn't seem to have a GetQuery method.
How do I run these queries, what did I miss?
Edit:
Here is sample code that gives me null metadata. Using a fresh install of VS2010 Premium, on a fresh WPF application. The image file is the one in the comments.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var uri = new Uri(#"c:\b-414328-animated_gif_.gif");
var myGif = new GifBitmapDecoder(uri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
var frame = myGif.Frames[0];
Title = "";
Title += "Global Metadata is null: " + (myGif.Metadata == null).ToString();
Title += "; Frame Metadata is null: " + (frame.Metadata == null).ToString();
// Crash due to null metadata
//var frameData = (BitmapMetadata)frame.Metadata;
//var rate = (ushort)frameData.GetQuery("/grctlext/Delay");
}
}
}

First, you need to Freeze the Frame you want to obtain the metadata from:
var frame = myGif.Frames[0];
frame.Freeze();
Second, the frame.Metadata returns an ImageMetadata which does not have a GetQuery method, but in fact the object returned is of type BitmapMetadata which has a GetQuery method, so you just need to cast frame.Metadata to BitmapMetadata as you do in the last commented lines of your code.

Related

Localization in winforms

Resource files are not getting created for the newly added forms when the localized property is set to true in VS 2012.
When I add a new form to the project, set the Localizable property to true and build the application, .resx files are not getting created.
Carefully follow this walkthrough. The experiment I did below in VS 2012 is working fine.
Step1.
Put a Label onto Form1
Set Form1.Localizable = true
Set Form1.Language = Default
Set label's text = "Hello world!"
Step2.
Set Form1.Language = Russian
Set label's text = "Привет мир!"
After these steps resource files become visible in Solution Explorer
Now add following code into Form1's constructor
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
switch (MessageBox.Show(
"Press 'Yes' for default language, 'No' for Russian.",
"Language Option", MessageBoxButtons.YesNo))
{
case System.Windows.Forms.DialogResult.Yes:
System.Threading.Thread.CurrentThread.CurrentUICulture =
System.Globalization.CultureInfo.CreateSpecificCulture("");
break;
case System.Windows.Forms.DialogResult.No:
System.Threading.Thread.CurrentThread.CurrentUICulture =
System.Globalization.CultureInfo.CreateSpecificCulture("ru");
break;
}
InitializeComponent();
}
}
}
Run the application and see the result.
The main purpose of the code is to show that CurrentUICulture must be set before the method InitializeComponent is called. In real applications, however, setting CurrentUICulture property, usually, takes place on program startup. So the code must be moved to where the program starts.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
switch (MessageBox.Show(
"Press 'Yes' for default language, 'No' for Russian.",
"Language Option", MessageBoxButtons.YesNo))
{
case System.Windows.Forms.DialogResult.Yes:
System.Threading.Thread.CurrentThread.CurrentUICulture =
System.Globalization.CultureInfo.CreateSpecificCulture("");
break;
case System.Windows.Forms.DialogResult.No:
System.Threading.Thread.CurrentThread.CurrentUICulture =
System.Globalization.CultureInfo.CreateSpecificCulture("ru");
break;
}
Application.Run(new Form1());
}
}
}
If you define UI language setting for your application then you can use the value of the setting here and set UI language. It will affect all forms you have defined in your application.

Issues with tutorial - Serializing data from/to disk

So I'm trying to work through the Catel 'getting started' examples here:
https://catelproject.atlassian.net/wiki/display/CTL/Getting+started+with+WPF
But I'm getting some errors in visual studio on step 3 (Serializing data from/to disk) - https://catelproject.atlassian.net/wiki/pages/viewpage.action?pageId=15630363
I create a 'top container' model called 'Settings' and a 'child class' of this called 'Global' (pretty much exactly the same as the tutorial except for less properties and different model names).
I create an interface based on the example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using App.Models;
namespace App.Services.Interfaces
{
public interface IGlobalService
{
IEnumerable<Global> LoadGlobals();
void SaveGlobals(IEnumerable<Global> globals);
}
}
Then I create the service implementation:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using Catel.Collections;
using Catel.Data;
using App.Models;
using App.Services.Interfaces;
namespace App.Services
{
public class GlobalService : IGlobalService
{
private readonly string _path;
public GlobalService()
{
string directory = Catel.IO.Path.GetApplicationDataDirectory("CatenaLogic", "WPF.GettingStarted");
_path = Path.Combine(directory, "global.xml");
}
public IEnumerable<Global> LoadGlobals()
{
if (!File.Exists(_path))
{
return new Global[] { };
}
using (var fileStream = File.Open(_path, FileMode.Open))
{
var settings = Settings.Load(fileStream, SerializationMode.Xml);
return settings.Globals;
}
}
public void SaveGlobals(IEnumerable<Global> globals)
{
var settings = new Settings();
settings.Globals.ReplaceRange(globals);
settings.Save(_path, SerializationMode.Xml);
}
}
}
Visual studio then throws 2 errors and a warning:
Error CS0619 'SavableModelBase.Load(Stream,
SerializationMode)' is obsolete: 'Please use Load(Stream,
SerializationMode, ISerializationConfiguration) instead. Will be
removed in version
5.0.0.'
Error CS0619 'SavableModelBase.Save(string,
SerializationMode)' is obsolete: 'Please use Save(string,
SerializationMode, ISerializationConfiguration) instead. Will be
removed in version 5.0.0.'
Warning CS0618 'CollectionExtensions.ReplaceRange(ObservableCollection,
IEnumerable)' is obsolete: 'Please use ReplaceRange(this
ICollection<T>, IEnumerable<T>) instead. Will be treated as an error
from version 5.0.0. Will be removed in version 5.0.0.'
So far all research I have done on this has come up blank. What is 'ISerializationConfiguration' and how do I implement it? Am I missing something obvious?
Setup is:
Visual Studio 2015 Community (14.0.25425.01 Update 3)
Project targeting .NET 4.5.2
Project initialized using New > Online > WPF application using Catel
NuGet:
Catel.Core 4.5.3
Catel.Extensions.Controls 4.5.3
Catel.MVVM 4.5.3
Catel.Fody 2.14.0
Any help would be much appreciated.
Use the overload as specified by the error / warning:
Load(stream, null);
Save(stream, null);

Using Settings.settings in a windows WPF app (vs2010)

This is an offline app And I am simply trying to write back to to the Settings.settings file.
In my project under Properties in the file named Settings.settings I add
Name: User, Type: string, Scope:User, Value:Default
After that in my App.xaml.cs file I attempt to read from and write to that value. I have no issue reading from that value, but it seems that it is not even an option to write back.
Here is my code:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
namespace StrainTracker
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
string userName= StrainTracker.Properties.Settings.Default.User;
StrainTracker.Properties.Settings.Default.User = "SomethingSilly"; //line 16
StrainTracker.Properties.Settings.Default.Save(); //line 17
}
}
Here are the errors generated by visual studio.
Error 1 Invalid token '=' in class, struct, or interface member declaration ..\Projects\StrainTracker\StrainTracker\App.xaml.cs 16 63 StrainTracker
Error 2 Invalid token '(' in class, struct, or interface member declaration ..\Projects\StrainTracker\StrainTracker\App.xaml.cs 17 55 StrainTracker
Error 3 'StrainTracker.Properties.Settings.Default' is a 'property' but is used like a 'type' ..\Projects\StrainTracker\StrainTracker\App.xaml.cs 16 43 StrainTracker
Error 4 'StrainTracker.Properties.Settings.Default' is a 'property' but is used like a 'type' ..\Projects\StrainTracker\StrainTracker\App.xaml.cs 17 43 StrainTracker
I can not for the life of me figure out what the issue is. Any thoughts?
Consider placing the code inside a constructor or some method:
public partial class App : Application
{
public App()
{
string userName= StrainTracker.Properties.Settings.Default.User;
StrainTracker.Properties.Settings.Default.User = "SomethingSilly";
StrainTracker.Properties.Settings.Default.Save();
}
}

PageBreak in flow documents at runtime

I AM able to get a text file on a flow document but now I have to divide the contents in proper pagebreaks at runtime i.e if contents are huge they shud get itself in number of pages that too at runtime.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace TextOnFlowDoc
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
Paragraph paragraph = new Paragraph();
paragraph.Inlines.Add(System.IO.File.ReadAllText(#"C:\Lis.txt"));
paragraph.FontFamily = new FontFamily("CourierNew");
FlowDocument document = new FlowDocument(paragraph);
// FlowDocumentReader rdr = new FlowDocumentReader();
FlowDocScl.Document = document;
}
}
}
Now this "FlowDocScl" is now a flow document and needs to be breaked into pages AT RUNTIME.
I am not sure why you want custom page-breaks, if you display it in a FlowDocumentPageViewer for example you get automatic breaks if the content is too large for the viewer.
If you must insert breaks on demand you need to split the document in Blocks, those have a property called BreakPageBefore which when set to true inserts a page break before that block obviously.
Something like this (untested):
private void BreakAndAddText(string text)
{
var pages = text.Split(new string[] { "\\f" }, StringSplitOptions.None);
foreach (var page in pages)
{
document.Blocks.Add(new Paragraph(new Run(page)) { BreakPageBefore = true });
}
}

Load Dicom image and display it - using ClearCanvas library

This is a very narrow and specific question, but I know there are someone else out there using this, so I'll keep my fingers crossed and hope anyone of you pics this question up.
I'm working on a WPF application where one part of it is a Dicom viewer. We'd like to use a 3rd party component to handle the Dicom stuff, and ClearCanvas is the one we've got the best impression of this far. We're able to load a Dicom file and fetch the attributes, but we're having problems putting the image data on the Source property of an Image control to show it. Anyone with hints on how to make this happen?
Here's the code I use for extracting the image data:
var file = new DicomFile(dicomFilePath);
var patientName = file.DataSet.GetAttribute(DicomTags.PatientsName);
var imageData = file.DataSet.GetAttribute(DicomTags.PixelData);
Have also tried using the ImageViewer library, but it is still the same data..
var localSopDataSource = new LocalSopDataSource(new DicomFile(dicomFilePath));
var patientName = localSopDataSource.File.DataSet.GetAttribute(DicomTags.PatientsName);
var imageData = localSopDataSource.File.DataSet.GetAttribute(DicomTags.PixelData);
Okay, I figured it out.. There might be some more ways of achieving this, but this is what I did. Now I have a Wpf Image bound to a property which provides the bitmap data. The following is the property used to provide the Bitmap data.
public BitmapSource CurrentFrameData
{
get
{
LocalSopDataSource _dicomDataSource =
new LocalSopDataSource(_dicomFilePath);
var imageSop = new ImageSop(_dicomDataSource);
IPresentationImage presentationImage =
PresentationImageFactory.Create(imageSop.Frames[CurrentFrame]);
int width = imageSop.Frames[CurrentFrame].Columns;
int height = imageSop.Frames[CurrentFrame].Rows;
Bitmap bmp = presentationImage.DrawToBitmap(width, height);
BitmapSource output = Imaging.CreateBitmapSourceFromHBitmap(
bmp.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromWidthAndHeight(width, height));
return output;
}
}
Note that this is a very straight forward solution. One might e.g. want to do stuff like preloading the pictures etc to avoid heavy load when scrolling multiframe images. But for the "howto display the image" question - this should answer it..
Ok, I've managed to show a DICOM image in a Picturebox using this code:
Here are the assemblies I used:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ClearCanvas.Common;
using ClearCanvas.Dicom;
using System.Windows.Media.Imaging;
using ClearCanvas.ImageViewer;
using ClearCanvas.ImageViewer.StudyManagement;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows;
using System.IO;
I also had to copy these dll into bin/debug:
BilinearInterpolation.dll (this one I could'nt reference it as assemblie so I just copied it into the bin/degug folder)
WindowsBase.dll (This one I was able to reference it as an assemblie)
Code (There's a button in my project that lets you select the dcm file and then show it in a picturebox)
Private void button2_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "DICOM Files(*.*)|*.*";
if (ofd.ShowDialog() == DialogResult.OK)
{
if (ofd.FileName.Length > 0)
{
var imagen = new DicomFile(ofd.FileName);
LocalSopDataSource DatosImagen = new LocalSopDataSource(ofd.FileName);
ImageSop imageSop = new ImageSop(DatosImagen);
IPresentationImage imagen_a_mostrar = PresentationImageFactory.Create(imageSop.Frames[1]);
int width = imageSop.Frames[1].Columns;
int height = imageSop.Frames[1].Rows;
Bitmap bmp = imagen_a_mostrar.DrawToBitmap(width, height);
PictureBox1.Image = bmp;
imageOpened = true;
}
ofd.Dispose();
}
}

Resources