2 using System.Drawing;
\r
3 using System.Diagnostics;
\r
7 using System.Reflection;
\r
8 using System.Xml.Serialization;
\r
9 using System.Collections;
\r
10 using System.Security.Cryptography;
\r
13 using awt = java.awt;
\r
14 using javax.imageio;
\r
16 using java.security;
\r
17 using java.awt.image;
\r
19 using System.Windows.Forms;
\r
20 using System.Drawing.Imaging;
\r
21 using System.Runtime.InteropServices;
\r
24 using NUnit.Framework;
\r
26 namespace DrawingTestHelper
\r
28 #region Results serialization classes
\r
29 public sealed class ExpectedResult {
\r
30 public ExpectedResult(){}
\r
31 public ExpectedResult(string testName, double norm) {
\r
32 TestName = testName;
\r
35 public string TestName;
\r
39 public sealed class ExpectedResults {
\r
40 [XmlArrayItem(typeof(ExpectedResult))]
\r
41 public ArrayList Tests = new ArrayList();
\r
44 public sealed class ExpectedResultsHash {
\r
46 ExpectedResults _suite;
\r
48 public ExpectedResultsHash () {
\r
50 using (StreamReader s = new StreamReader (FileName)) {
\r
51 _suite = (ExpectedResults)TestSuiteSerializer.Deserialize(s);
\r
55 _suite = new ExpectedResults ();
\r
57 _hash = new Hashtable(_suite.Tests.Count);
\r
58 foreach (ExpectedResult res in _suite.Tests)
\r
59 _hash[res.TestName] = res.Norm;
\r
62 public const string FileName = "ExpectedResults.xml";
\r
63 public readonly static XmlSerializer TestSuiteSerializer = new XmlSerializer(typeof(ExpectedResults));
\r
65 public double GetNorm(string testName) {
\r
66 object res = _hash[testName];
\r
72 public void WriteNorm (string testName, double myNorm) {
\r
73 if (_hash.Contains (testName)) {
\r
74 for (int i = 0; i < _suite.Tests.Count; i++) {
\r
75 ExpectedResult cur = (ExpectedResult) _suite.Tests[i];
\r
76 if (cur.TestName == testName) {
\r
83 _suite.Tests.Add(new ExpectedResult(testName, myNorm));
\r
85 _hash[testName] = myNorm;
\r
86 using(StreamWriter w = new StreamWriter(FileName))
\r
87 TestSuiteSerializer.Serialize(w, _suite);
\r
91 public sealed class CachedResult {
\r
92 public CachedResult (){}
\r
93 public CachedResult (string testName, string sha1, double norm) {
\r
94 TestName = testName;
\r
97 DateTime = DateTime.Now;
\r
100 public string TestName;
\r
101 public string SHA1;
\r
102 public double Norm;
\r
103 public DateTime DateTime;
\r
106 public sealed class CachedResults {
\r
107 [XmlArrayItem(typeof(CachedResult))]
\r
108 public ArrayList Tests = new ArrayList();
\r
111 public class Cache {
\r
113 CachedResults _results;
\r
116 public const string FileName = "CachedResults.xml";
\r
117 public const string NewFileName = "NewCachedResults.xml";
\r
119 public const string FileName = "dotnet.CachedResults.xml";
\r
120 public const string NewFileName = "dotnet.NewCachedResults.xml";
\r
122 public readonly static XmlSerializer TestSuiteSerializer =
\r
123 new XmlSerializer(typeof(CachedResults));
\r
127 using (StreamReader r = new StreamReader(FileName))
\r
128 _results = (CachedResults)TestSuiteSerializer.Deserialize(r);
\r
131 _results = new CachedResults ();
\r
134 _hash = new Hashtable(_results.Tests.Count);
\r
135 foreach (CachedResult res in _results.Tests)
\r
136 _hash[res.SHA1] = res.Norm;
\r
139 public double GetNorm (string sha1) {
\r
140 if (_hash.ContainsKey (sha1))
\r
141 return (double)_hash[sha1];
\r
146 public void Add (string testName, string sha1, double norm) {
\r
147 if (_hash.ContainsKey (sha1))
\r
148 throw new ArgumentException ("This SHA1 is already in the cache", "sha1");
\r
150 _results.Tests.Add (new CachedResult(testName, sha1, norm));
\r
151 _hash.Add (sha1, norm);
\r
153 using(StreamWriter w = new StreamWriter(NewFileName))
\r
154 TestSuiteSerializer.Serialize(w, _results);
\r
160 /// Summary description for DrawingTest.
\r
162 public abstract class DrawingTest : IDisposable {
\r
164 public const float DEFAULT_FLOAT_TOLERANCE = 1e-5f;
\r
165 public const int DEFAULT_IMAGE_TOLERANCE = 2;
\r
167 Graphics _graphics;
\r
168 protected Bitmap _bitmap;
\r
169 static string _callingFunction;
\r
170 //static int _counter;
\r
171 static Hashtable _mpFuncCount = new Hashtable();
\r
172 static bool _showForms = false;
\r
173 static bool _createResults = true;
\r
174 protected string _ownerClass = "";
\r
175 protected Hashtable _specialTolerance = null;
\r
177 protected readonly static ExpectedResultsHash ExpectedResults = new ExpectedResultsHash ();
\r
178 protected readonly static Cache cache = new Cache ();
\r
180 public Graphics Graphics {get {return _graphics;}}
\r
181 public Bitmap Bitmap {get { return _bitmap; }}
\r
183 public Hashtable SpecialTolerance
\r
185 get {return _specialTolerance;}
\r
186 set {_specialTolerance = value;}
\r
189 public string OwnerClass
\r
191 get {return _ownerClass;}
\r
192 set {_ownerClass = value;}
\r
195 public static bool ShowForms
\r
197 get {return _showForms;}
\r
198 set {_showForms = value;}
\r
201 public static bool CreateResults {
\r
202 get {return _createResults;}
\r
203 set {_createResults = value;}
\r
206 protected DrawingTest() {}
\r
208 private void Init (int width, int height) {
\r
209 Init (new Bitmap (width, height));
\r
212 private void Init (Bitmap bitmap) {
\r
214 _graphics = Graphics.FromImage (_bitmap);
\r
217 protected abstract string DetermineCallingFunction ();
\r
219 protected interface IMyForm {
\r
223 protected abstract IMyForm CreateForm (string title);
\r
225 public void Show () {
\r
229 IMyForm form = CreateForm(_callingFunction + _mpFuncCount[_callingFunction]);
\r
233 static protected string TestName {
\r
235 return _callingFunction + ":" + _mpFuncCount[_callingFunction]/* + ".dat"*/;
\r
239 #region GetImageFFTArray
\r
240 private static ComplexF[] GetImageFFTArray(Bitmap bitmap) {
\r
241 float scale = 1F / (float) System.Math.Sqrt(bitmap.Width * bitmap.Height);
\r
242 ComplexF[] data = new ComplexF [bitmap.Width * bitmap.Height * 4];
\r
245 for( int y = 0; y < bitmap.Height; y ++ )
\r
246 for( int x = 0; x < bitmap.Width; x ++ ) {
\r
247 Color c = bitmap.GetPixel (x, y);
\r
249 if( (( x + y ) & 0x1 ) != 0 ) {
\r
253 data [offset++] = new ComplexF( c.A * s / 256F, 0);
\r
254 data [offset++] = new ComplexF( c.R * s / -256F, 0);
\r
255 data [offset++] = new ComplexF( c.G * s / 256F, 0);
\r
256 data [offset++] = new ComplexF( c.B * s / -256F, 0);
\r
260 Fourier.FFT3( data, 4, bitmap.Width, bitmap.Height, FourierDirection.Forward );
\r
262 for( int i = 0; i < data.Length; i ++ ) {
\r
270 abstract public string CalculateSHA1 ();
\r
272 public static double CalculateNorm (Bitmap bitmap) {
\r
273 ComplexF[] matrix = GetImageFFTArray(bitmap);
\r
276 int size_x = 4; //ARGB values
\r
277 int size_y = bitmap.Width;
\r
278 int size_z = bitmap.Height;
\r
279 for (int x=1; x<=size_x; x++) {
\r
281 for (int y=1; y<=size_y; y++) {
\r
283 for (int z=1; z<=size_z; z++) {
\r
284 ComplexF cur = matrix[(size_x-x)+size_x*(size_y-y)+size_x*size_y*(size_z-z)];
\r
285 norm_z += cur.GetModulusSquared ();// * z;
\r
287 norm_y += norm_z;// * y;
\r
289 norm += norm_y;// * x;
\r
294 public double GetNorm () {
\r
295 string sha1 = CalculateSHA1 ();
\r
297 double norm = cache.GetNorm (sha1);
\r
298 if (double.IsNaN (norm)) {
\r
299 norm = CalculateNorm (_bitmap);
\r
300 cache.Add (TestName, sha1, norm);
\r
301 //_bitmap.Save(TestName.Replace(":", "_"));
\r
306 protected abstract double GetExpectedNorm (double myNorm);
\r
308 private void CheckCounter () {
\r
309 string callFunc = DetermineCallingFunction ();
\r
310 _callingFunction = callFunc;
\r
311 if (!_mpFuncCount.Contains(_callingFunction)) {
\r
313 _mpFuncCount[_callingFunction] = 1;
\r
316 int counter = (int)_mpFuncCount[_callingFunction];
\r
318 _mpFuncCount[_callingFunction] = counter;
\r
322 public static void AssertAlmostEqual (float expected, float actual)
\r
324 AssertAlmostEqual (expected, actual, DEFAULT_FLOAT_TOLERANCE);
\r
327 public static void AssertAlmostEqual (float expected, float actual, float tolerance)
\r
329 string msg = String.Format("\nExpected : {0} \nActual : {1}",expected.ToString(),actual.ToString());
\r
330 AssertAlmostEqual (expected, actual, tolerance, msg);
\r
333 private static void AssertAlmostEqual (float expected, float actual, float tolerance, string message)
\r
335 float error = System.Math.Abs ((expected - actual) / (expected + actual + float.Epsilon));
\r
336 Assert.IsTrue (error < tolerance, message);
\r
339 public static void AssertAlmostEqual (PointF expected, PointF actual)
\r
341 string msg = String.Format("\nExpected : {0} \n Actual : {1}",expected.ToString(),actual.ToString());
\r
342 AssertAlmostEqual (expected.X, actual.X, DEFAULT_FLOAT_TOLERANCE, msg);
\r
343 AssertAlmostEqual (expected.Y, actual.Y, DEFAULT_FLOAT_TOLERANCE, msg);
\r
347 /// Checks that the given bitmap norm is similar to expected
\r
349 /// <param name="tolerance">tolerance in percents (0..100)</param>
\r
350 /// <returns></returns>
\r
352 public bool Compare (double tolerance) {
\r
355 double error = CompareToExpectedInternal()*100;
\r
357 if (SpecialTolerance != null)
\r
358 return error <= GetSpecialTolerance(TestName);
\r
360 return error <= tolerance;
\r
363 public bool PDCompare (double tolerance) {
\r
364 Bitmap ri = GetReferenceImage(TestName);
\r
368 double error = PDComparer.Compare(ri, _bitmap);
\r
369 return error <= tolerance;
\r
372 public bool Compare () {
\r
375 double error = CompareToExpectedInternal()*100;
\r
377 if (SpecialTolerance != null)
\r
378 return error <= GetSpecialTolerance(TestName);
\r
380 return error <= DEFAULT_IMAGE_TOLERANCE;
\r
383 public bool PDCompare () {
\r
384 Bitmap ri = GetReferenceImage(TestName);
\r
388 double error = PDComparer.Compare(ri, _bitmap);
\r
389 return error <= DEFAULT_IMAGE_TOLERANCE;
\r
392 protected abstract Bitmap GetReferenceImage(string testName);
\r
394 protected double GetSpecialTolerance(string testName) {
\r
396 string shortTestName = testName.Substring( testName.LastIndexOf(".") + 1 );
\r
397 object o = SpecialTolerance[shortTestName];
\r
399 return DEFAULT_IMAGE_TOLERANCE;
\r
401 return Convert.ToDouble(o);
\r
403 catch (System.Exception) {
\r
404 return DEFAULT_IMAGE_TOLERANCE;
\r
408 public void AssertCompare () {
\r
410 Assert.IsTrue ((CompareToExpectedInternal () * 100) < DEFAULT_IMAGE_TOLERANCE);
\r
413 public void AssertCompare (double tolerance) {
\r
415 Assert.IsTrue ((CompareToExpectedInternal () * 100) < tolerance);
\r
418 public double CompareToExpected () {
\r
420 return CompareToExpectedInternal ();
\r
423 double CompareToExpectedInternal () {
\r
427 double norm = GetNorm ();
\r
428 double expNorm = GetExpectedNorm (norm);
\r
429 return System.Math.Abs (norm-expNorm)/(norm+expNorm+double.Epsilon);
\r
432 public static DrawingTest Create (int width, int height) {
\r
433 return Create(width, height, "GraphicsFixture");
\r
435 public static DrawingTest Create (int width, int height, string ownerClass) {
\r
438 test = new JavaDrawingTest ();
\r
440 test = new NetDrawingTest ();
\r
442 test.Init (width, height);
\r
443 test.OwnerClass = ownerClass;
\r
446 #region IDisposable Members
\r
448 public void Dispose()
\r
450 // TODO: Add DrawingTest.Dispose implementation
\r
451 if (_graphics != null) {
\r
452 _graphics.Dispose();
\r
461 internal class JavaDrawingTest:DrawingTest {
\r
462 java.awt.image.BufferedImage _image;
\r
463 java.awt.image.BufferedImage Image {
\r
465 if (_image != null)
\r
467 Type imageType = typeof (Bitmap);
\r
468 PropertyInfo [] props = imageType.GetProperties (
\r
469 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
\r
471 PropertyInfo prop = null;
\r
472 foreach (PropertyInfo p in props) {
\r
473 if (p.Name == "NativeObject")
\r
474 if (p.PropertyType == typeof(java.awt.image.BufferedImage))
\r
478 MethodInfo method = prop.GetGetMethod (true);
\r
479 _image = (java.awt.image.BufferedImage) method.Invoke (_bitmap, new object [0]);
\r
484 public JavaDrawingTest () {}
\r
486 protected override double GetExpectedNorm (double myNorm) {
\r
487 return ExpectedResults.GetNorm(TestName);
\r
490 protected override Bitmap GetReferenceImage(string testName) {
\r
492 string dotNetResultsFolder = @"";
\r
493 string fileName = dotNetResultsFolder + testName.Replace(":", "_") + ".png";
\r
494 return new Bitmap(fileName);
\r
496 catch(System.Exception e) {
\r
497 throw new System.Exception("Error creating .Net reference image");
\r
501 private class JavaForm:java.awt.Dialog,IMyForm {
\r
502 class EventListener : java.awt.@event.WindowListener {
\r
503 #region WindowListener Members
\r
505 public void windowOpened(java.awt.@event.WindowEvent arg_0) {
\r
506 // TODO: Add ttt.windowOpened implementation
\r
509 public void windowActivated(java.awt.@event.WindowEvent arg_0) {
\r
510 // TODO: Add ttt.windowActivated implementation
\r
513 public void windowClosed(java.awt.@event.WindowEvent arg_0) {
\r
514 // TODO: Add ttt.windowClosed implementation
\r
517 public void windowDeiconified(java.awt.@event.WindowEvent arg_0) {
\r
518 // TODO: Add ttt.windowDeiconified implementation
\r
521 public void windowIconified(java.awt.@event.WindowEvent arg_0) {
\r
522 // TODO: Add ttt.windowIconified implementation
\r
525 public void windowClosing(java.awt.@event.WindowEvent arg_0) {
\r
526 // TODO: Add ttt.windowClosing implementation
\r
527 java.awt.Window w = arg_0.getWindow();
\r
528 java.awt.Window par = w.getOwner ();
\r
533 public void windowDeactivated(java.awt.@event.WindowEvent arg_0) {
\r
534 // TODO: Add ttt.windowDeactivated implementation
\r
540 java.awt.Image _image;
\r
543 public JavaForm (string title, java.awt.Image anImage, Size s)
\r
544 : base(new java.awt.Frame(), title, true) {
\r
548 addWindowListener(new EventListener());
\r
550 public override void paint (java.awt.Graphics g) {
\r
552 awt.Insets insets = this.getInsets ();
\r
553 g.drawImage (_image, insets.left, insets.top, null);
\r
555 void IMyForm.Show () {
\r
556 awt.Insets insets = this.getInsets ();
\r
557 base.setSize (_s.Width + insets.left + insets.right,
\r
558 _s.Width + insets.top + insets.bottom);
\r
561 //ImageIO.write((java.awt.image.RenderedImage)_image, "png", new java.io.File("test.java.png"));
\r
565 protected override IMyForm CreateForm(string title) {
\r
566 return new JavaForm (title, Image, _bitmap.Size);
\r
569 protected override string DetermineCallingFunction() {
\r
570 System.Exception e = new System.Exception ();
\r
571 java.lang.Class c = vmw.common.TypeUtils.ToClass (e);
\r
572 java.lang.reflect.Method m = c.getMethod ("getStackTrace",
\r
573 new java.lang.Class [0]);
\r
574 java.lang.StackTraceElement [] els = (java.lang.StackTraceElement [])
\r
575 m.invoke (e, new object [0]);
\r
576 java.lang.StackTraceElement el = els [4];
\r
577 return el.getClassName () + "." + _ownerClass + "." + el.getMethodName ();
\r
580 public override string CalculateSHA1() {
\r
581 MessageDigest md = MessageDigest.getInstance ("SHA");
\r
582 DataBufferInt dbi = (DataBufferInt) Image.getRaster ().getDataBuffer ();
\r
583 for (int i=0; i<dbi.getNumBanks (); i++) {
\r
584 int [] curBank = dbi.getData (i);
\r
585 for (int j=0; j<curBank.Length; j++) {
\r
586 int x = curBank[j];
\r
587 md.update ((sbyte) (x & 0xFF));
\r
588 md.update ((sbyte) ((x>>8) & 0xFF));
\r
589 md.update ((sbyte) ((x>>16) & 0xFF));
\r
590 md.update ((sbyte) ((x>>24) & 0xFF));
\r
593 byte [] resdata = (byte[])vmw.common.TypeUtils.ToByteArray(md.digest());
\r
594 return Convert.ToBase64String (resdata);
\r
598 internal class NetDrawingTest:DrawingTest {
\r
599 public NetDrawingTest () {}
\r
601 protected override double GetExpectedNorm (double myNorm) {
\r
603 ExpectedResults.WriteNorm (TestName, myNorm);
\r
608 protected override Bitmap GetReferenceImage(string testName) {
\r
610 string fileName = testName.Replace(":", "_") + ".png";
\r
611 _bitmap.Save( fileName );
\r
615 catch(System.Exception e) {
\r
616 throw new System.Exception("Error creating .Net reference image");
\r
620 private class NetForm:Form,IMyForm {
\r
622 public NetForm(string title, Image anImage):base() {
\r
626 protected override void OnPaint(PaintEventArgs e) {
\r
627 e.Graphics.DrawImageUnscaled (image, 0, 0);
\r
629 void IMyForm.Show () {
\r
630 this.Size = image.Size;
\r
631 this.ShowDialog ();
\r
632 this.image.Save("test.net.png");
\r
635 protected override IMyForm CreateForm(string title) {
\r
636 return new NetForm (title, _bitmap);
\r
639 protected override string DetermineCallingFunction() {
\r
640 StackFrame sf = new StackFrame (3, true);
\r
641 MethodBase mb = sf.GetMethod ();
\r
643 string name = mb.DeclaringType.FullName + "." + _ownerClass + "." + mb.Name;
\r
647 public override string CalculateSHA1() {
\r
648 Rectangle r = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);
\r
650 BitmapData data = _bitmap.LockBits (r, ImageLockMode.ReadOnly,
\r
651 _bitmap.PixelFormat);
\r
652 int dataSize = data.Stride * data.Height;
\r
653 byte [] bdata = new byte [dataSize];
\r
654 Marshal.Copy (data.Scan0, bdata, 0, dataSize);
\r
655 _bitmap.UnlockBits (data);
\r
657 SHA1 sha1 = new SHA1CryptoServiceProvider ();
\r
658 byte [] resdata = sha1.ComputeHash (bdata);
\r
659 return Convert.ToBase64String (resdata);
\r