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
11 using System.Runtime.InteropServices;
\r
12 using System.Drawing.Imaging;
\r
17 using awt = java.awt;
\r
18 using javax.imageio;
\r
20 using java.security;
\r
21 using java.awt.image;
\r
23 using System.Windows.Forms;
\r
27 using NUnit.Framework;
\r
29 namespace DrawingTestHelper
\r
31 #region Results serialization classes
\r
32 public sealed class ExpectedResult {
\r
33 public ExpectedResult(){}
\r
34 public ExpectedResult(string testName, double norm) {
\r
35 TestName = testName;
\r
38 public string TestName;
\r
42 public sealed class ExpectedResults {
\r
43 [XmlArrayItem(typeof(ExpectedResult))]
\r
44 public ArrayList Tests = new ArrayList();
\r
47 public sealed class ExpectedResultsHash {
\r
49 ExpectedResults _suite;
\r
51 public ExpectedResultsHash () {
\r
53 using (StreamReader s = new StreamReader (FileName)) {
\r
54 _suite = (ExpectedResults)TestSuiteSerializer.Deserialize(s);
\r
58 _suite = new ExpectedResults ();
\r
60 _hash = new Hashtable(_suite.Tests.Count);
\r
61 foreach (ExpectedResult res in _suite.Tests)
\r
62 _hash[res.TestName] = res.Norm;
\r
65 public const string FileName = "ExpectedResults.xml";
\r
66 public readonly static XmlSerializer TestSuiteSerializer = new XmlSerializer(typeof(ExpectedResults));
\r
68 public double GetNorm(string testName) {
\r
69 object res = _hash[testName];
\r
75 public void WriteNorm (string testName, double myNorm) {
\r
76 if (_hash.Contains (testName)) {
\r
77 for (int i = 0; i < _suite.Tests.Count; i++) {
\r
78 ExpectedResult cur = (ExpectedResult) _suite.Tests[i];
\r
79 if (cur.TestName == testName) {
\r
86 _suite.Tests.Add(new ExpectedResult(testName, myNorm));
\r
88 _hash[testName] = myNorm;
\r
89 using(StreamWriter w = new StreamWriter(FileName))
\r
90 TestSuiteSerializer.Serialize(w, _suite);
\r
94 public sealed class CachedResult {
\r
95 public CachedResult (){}
\r
96 public CachedResult (string testName, string sha1, double norm) {
\r
97 TestName = testName;
\r
100 DateTime = DateTime.Now;
\r
103 public string TestName;
\r
104 public string SHA1;
\r
105 public double Norm;
\r
106 public DateTime DateTime;
\r
109 public sealed class CachedResults {
\r
110 [XmlArrayItem(typeof(CachedResult))]
\r
111 public ArrayList Tests = new ArrayList();
\r
114 public class Cache {
\r
116 CachedResults _results;
\r
119 public const string FileName = "CachedResults.xml";
\r
120 public const string NewFileName = "NewCachedResults.xml";
\r
122 public const string FileName = "dotnet.CachedResults.xml";
\r
123 public const string NewFileName = "dotnet.NewCachedResults.xml";
\r
125 public readonly static XmlSerializer TestSuiteSerializer =
\r
126 new XmlSerializer(typeof(CachedResults));
\r
130 using (StreamReader r = new StreamReader(FileName))
\r
131 _results = (CachedResults)TestSuiteSerializer.Deserialize(r);
\r
134 _results = new CachedResults ();
\r
137 _hash = new Hashtable(_results.Tests.Count);
\r
138 foreach (CachedResult res in _results.Tests)
\r
139 _hash[res.SHA1] = res.Norm;
\r
142 public double GetNorm (string sha1) {
\r
143 if (_hash.ContainsKey (sha1))
\r
144 return (double)_hash[sha1];
\r
149 public void Add (string testName, string sha1, double norm) {
\r
150 if (_hash.ContainsKey (sha1))
\r
151 throw new ArgumentException ("This SHA1 is already in the cache", "sha1");
\r
153 _results.Tests.Add (new CachedResult(testName, sha1, norm));
\r
154 _hash.Add (sha1, norm);
\r
156 using(StreamWriter w = new StreamWriter(NewFileName))
\r
157 TestSuiteSerializer.Serialize(w, _results);
\r
163 /// Summary description for DrawingTest.
\r
165 public abstract class DrawingTest : IDisposable {
\r
167 public const float DEFAULT_FLOAT_TOLERANCE = 1e-5f;
\r
168 public const int DEFAULT_IMAGE_TOLERANCE = 2;
\r
170 Graphics _graphics;
\r
171 protected Bitmap _bitmap;
\r
172 static string _callingFunction;
\r
173 //static int _counter;
\r
174 static Hashtable _mpFuncCount = new Hashtable();
\r
175 static bool _showForms = false;
\r
176 static bool _createResults = true;
\r
177 protected string _ownerClass = "";
\r
178 protected Hashtable _specialTolerance = null;
\r
180 protected readonly static ExpectedResultsHash ExpectedResults = new ExpectedResultsHash ();
\r
181 protected readonly static Cache cache = new Cache ();
\r
183 public Graphics Graphics {get {return _graphics;}}
\r
184 public Bitmap Bitmap {get { return _bitmap; }}
\r
186 public Hashtable SpecialTolerance
\r
188 get {return _specialTolerance;}
\r
189 set {_specialTolerance = value;}
\r
192 public string OwnerClass
\r
194 get {return _ownerClass;}
\r
195 set {_ownerClass = value;}
\r
198 public static bool ShowForms
\r
200 get {return _showForms;}
\r
201 set {_showForms = value;}
\r
204 public static bool CreateResults {
\r
205 get {return _createResults;}
\r
206 set {_createResults = value;}
\r
209 protected DrawingTest() {}
\r
211 private void Init (int width, int height) {
\r
212 Init (new Bitmap (width, height));
\r
215 private void Init (Bitmap bitmap) {
\r
217 _graphics = Graphics.FromImage (_bitmap);
\r
220 protected abstract string DetermineCallingFunction ();
\r
222 protected interface IMyForm {
\r
226 protected abstract IMyForm CreateForm (string title);
\r
228 public void Show () {
\r
232 IMyForm form = CreateForm(_callingFunction + _mpFuncCount[_callingFunction]);
\r
236 static protected string TestName {
\r
238 return _callingFunction + ":" + _mpFuncCount[_callingFunction]/* + ".dat"*/;
\r
242 #region GetImageFFTArray
\r
243 private static ComplexF[] GetImageFFTArray(Bitmap bitmap) {
\r
244 float scale = 1F / (float) System.Math.Sqrt(bitmap.Width * bitmap.Height);
\r
245 ComplexF[] data = new ComplexF [bitmap.Width * bitmap.Height * 4];
\r
248 for( int y = 0; y < bitmap.Height; y ++ )
\r
249 for( int x = 0; x < bitmap.Width; x ++ ) {
\r
250 Color c = bitmap.GetPixel (x, y);
\r
252 if( (( x + y ) & 0x1 ) != 0 ) {
\r
256 data [offset++] = new ComplexF( c.A * s / 256F, 0);
\r
257 data [offset++] = new ComplexF( c.R * s / -256F, 0);
\r
258 data [offset++] = new ComplexF( c.G * s / 256F, 0);
\r
259 data [offset++] = new ComplexF( c.B * s / -256F, 0);
\r
263 Fourier.FFT3( data, 4, bitmap.Width, bitmap.Height, FourierDirection.Forward );
\r
265 for( int i = 0; i < data.Length; i ++ ) {
\r
273 abstract public string CalculateSHA1 ();
\r
275 public static double CalculateNorm (Bitmap bitmap) {
\r
276 ComplexF[] matrix = GetImageFFTArray(bitmap);
\r
279 int size_x = 4; //ARGB values
\r
280 int size_y = bitmap.Width;
\r
281 int size_z = bitmap.Height;
\r
282 for (int x=1; x<=size_x; x++) {
\r
284 for (int y=1; y<=size_y; y++) {
\r
286 for (int z=1; z<=size_z; z++) {
\r
287 ComplexF cur = matrix[(size_x-x)+size_x*(size_y-y)+size_x*size_y*(size_z-z)];
\r
288 norm_z += cur.GetModulusSquared ();// * z;
\r
290 norm_y += norm_z;// * y;
\r
292 norm += norm_y;// * x;
\r
297 public double GetNorm () {
\r
298 string sha1 = CalculateSHA1 ();
\r
300 double norm = cache.GetNorm (sha1);
\r
301 if (double.IsNaN (norm)) {
\r
302 norm = CalculateNorm (_bitmap);
\r
303 cache.Add (TestName, sha1, norm);
\r
304 //_bitmap.Save(TestName.Replace(":", "_"));
\r
309 protected abstract double GetExpectedNorm (double myNorm);
\r
311 private void CheckCounter () {
\r
312 string callFunc = DetermineCallingFunction ();
\r
313 _callingFunction = callFunc;
\r
314 if (!_mpFuncCount.Contains(_callingFunction)) {
\r
316 _mpFuncCount[_callingFunction] = 1;
\r
319 int counter = (int)_mpFuncCount[_callingFunction];
\r
321 _mpFuncCount[_callingFunction] = counter;
\r
325 public static void AssertAlmostEqual (float expected, float actual)
\r
327 AssertAlmostEqual (expected, actual, DEFAULT_FLOAT_TOLERANCE);
\r
330 public static void AssertAlmostEqual (float expected, float actual, float tolerance)
\r
332 string msg = String.Format("\nExpected : {0} \nActual : {1}",expected.ToString(),actual.ToString());
\r
333 AssertAlmostEqual (expected, actual, tolerance, msg);
\r
336 private static void AssertAlmostEqual (float expected, float actual, float tolerance, string message)
\r
338 float error = System.Math.Abs ((expected - actual) / (expected + actual + float.Epsilon));
\r
339 Assert.That (error < tolerance, Is.True, message);
\r
342 public static void AssertAlmostEqual (PointF expected, PointF actual)
\r
344 string msg = String.Format("\nExpected : {0} \n Actual : {1}",expected.ToString(),actual.ToString());
\r
345 AssertAlmostEqual (expected.X, actual.X, DEFAULT_FLOAT_TOLERANCE, msg);
\r
346 AssertAlmostEqual (expected.Y, actual.Y, DEFAULT_FLOAT_TOLERANCE, msg);
\r
350 /// Checks that the given bitmap norm is similar to expected
\r
352 /// <param name="tolerance">tolerance in percents (0..100)</param>
\r
353 /// <returns></returns>
\r
355 public bool Compare (double tolerance) {
\r
358 double error = CompareToExpectedInternal()*100;
\r
360 if (SpecialTolerance != null)
\r
361 return error <= GetSpecialTolerance(TestName);
\r
363 return error <= tolerance;
\r
366 public bool PDCompare (double tolerance) {
\r
367 Bitmap ri = GetReferenceImage(TestName);
\r
371 double error = PDComparer.Compare(ri, _bitmap);
\r
372 return error <= tolerance;
\r
375 public bool Compare () {
\r
378 double error = CompareToExpectedInternal()*100;
\r
380 if (SpecialTolerance != null)
\r
381 return error <= GetSpecialTolerance(TestName);
\r
383 return error <= DEFAULT_IMAGE_TOLERANCE;
\r
386 public bool PDCompare () {
\r
387 Bitmap ri = GetReferenceImage(TestName);
\r
391 double error = PDComparer.Compare(ri, _bitmap);
\r
392 return error <= DEFAULT_IMAGE_TOLERANCE;
\r
395 protected abstract Bitmap GetReferenceImage(string testName);
\r
397 protected double GetSpecialTolerance(string testName) {
\r
399 string shortTestName = testName.Substring( testName.LastIndexOf(".") + 1 );
\r
400 object o = SpecialTolerance[shortTestName];
\r
402 return DEFAULT_IMAGE_TOLERANCE;
\r
404 return Convert.ToDouble(o);
\r
406 catch (System.Exception) {
\r
407 return DEFAULT_IMAGE_TOLERANCE;
\r
411 public void AssertCompare () {
\r
413 Assert.That ((CompareToExpectedInternal () * 100) < DEFAULT_IMAGE_TOLERANCE, Is.True);
\r
416 public void AssertCompare (double tolerance) {
\r
418 Assert.That ((CompareToExpectedInternal () * 100) < tolerance, Is.True);
\r
421 public double CompareToExpected () {
\r
423 return CompareToExpectedInternal ();
\r
426 double CompareToExpectedInternal () {
\r
430 double norm = GetNorm ();
\r
431 double expNorm = GetExpectedNorm (norm);
\r
432 return System.Math.Abs (norm-expNorm)/(norm+expNorm+double.Epsilon);
\r
435 public static DrawingTest Create (int width, int height) {
\r
436 return Create(width, height, "GraphicsFixture");
\r
438 public static DrawingTest Create (int width, int height, string ownerClass) {
\r
441 test = new JavaDrawingTest ();
\r
443 test = new NetDrawingTest ();
\r
445 test.Init (width, height);
\r
446 test.OwnerClass = ownerClass;
\r
449 #region IDisposable Members
\r
451 public void Dispose()
\r
453 // TODO: Add DrawingTest.Dispose implementation
\r
454 if (_graphics != null) {
\r
455 _graphics.Dispose();
\r
464 internal class JavaDrawingTest:DrawingTest {
\r
465 java.awt.image.BufferedImage _image;
\r
466 java.awt.image.BufferedImage Image {
\r
468 if (_image != null)
\r
470 Type imageType = typeof (Bitmap);
\r
471 PropertyInfo [] props = imageType.GetProperties (
\r
472 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
\r
474 PropertyInfo prop = null;
\r
475 foreach (PropertyInfo p in props) {
\r
476 if (p.Name == "NativeObject")
\r
477 if (p.PropertyType == typeof(java.awt.image.BufferedImage))
\r
481 MethodInfo method = prop.GetGetMethod (true);
\r
482 _image = (java.awt.image.BufferedImage) method.Invoke (_bitmap, new object [0]);
\r
487 public JavaDrawingTest () {}
\r
489 protected override double GetExpectedNorm (double myNorm) {
\r
490 return ExpectedResults.GetNorm(TestName);
\r
493 protected override Bitmap GetReferenceImage(string testName) {
\r
495 string dotNetResultsFolder = @"";
\r
496 string fileName = dotNetResultsFolder + testName.Replace(":", "_") + ".png";
\r
497 return new Bitmap(fileName);
\r
499 catch(System.Exception e) {
\r
500 throw new System.Exception("Error creating .Net reference image");
\r
504 private class JavaForm:java.awt.Dialog,IMyForm {
\r
505 class EventListener : java.awt.@event.WindowListener {
\r
506 #region WindowListener Members
\r
508 public void windowOpened(java.awt.@event.WindowEvent arg_0) {
\r
509 // TODO: Add ttt.windowOpened implementation
\r
512 public void windowActivated(java.awt.@event.WindowEvent arg_0) {
\r
513 // TODO: Add ttt.windowActivated implementation
\r
516 public void windowClosed(java.awt.@event.WindowEvent arg_0) {
\r
517 // TODO: Add ttt.windowClosed implementation
\r
520 public void windowDeiconified(java.awt.@event.WindowEvent arg_0) {
\r
521 // TODO: Add ttt.windowDeiconified implementation
\r
524 public void windowIconified(java.awt.@event.WindowEvent arg_0) {
\r
525 // TODO: Add ttt.windowIconified implementation
\r
528 public void windowClosing(java.awt.@event.WindowEvent arg_0) {
\r
529 // TODO: Add ttt.windowClosing implementation
\r
530 java.awt.Window w = arg_0.getWindow();
\r
531 java.awt.Window par = w.getOwner ();
\r
536 public void windowDeactivated(java.awt.@event.WindowEvent arg_0) {
\r
537 // TODO: Add ttt.windowDeactivated implementation
\r
543 java.awt.Image _image;
\r
546 public JavaForm (string title, java.awt.Image anImage, Size s)
\r
547 : base(new java.awt.Frame(), title, true) {
\r
551 addWindowListener(new EventListener());
\r
553 public override void paint (java.awt.Graphics g) {
\r
555 awt.Insets insets = this.getInsets ();
\r
556 g.drawImage (_image, insets.left, insets.top, null);
\r
558 void IMyForm.Show () {
\r
559 awt.Insets insets = this.getInsets ();
\r
560 base.setSize (_s.Width + insets.left + insets.right,
\r
561 _s.Width + insets.top + insets.bottom);
\r
564 //ImageIO.write((java.awt.image.RenderedImage)_image, "png", new java.io.File("test.java.png"));
\r
568 protected override IMyForm CreateForm(string title) {
\r
569 return new JavaForm (title, Image, _bitmap.Size);
\r
572 protected override string DetermineCallingFunction() {
\r
573 System.Exception e = new System.Exception ();
\r
574 java.lang.Class c = vmw.common.TypeUtils.ToClass (e);
\r
575 java.lang.reflect.Method m = c.getMethod ("getStackTrace",
\r
576 new java.lang.Class [0]);
\r
577 java.lang.StackTraceElement [] els = (java.lang.StackTraceElement [])
\r
578 m.invoke (e, new object [0]);
\r
579 java.lang.StackTraceElement el = els [4];
\r
580 return el.getClassName () + "." + _ownerClass + "." + el.getMethodName ();
\r
583 public override string CalculateSHA1() {
\r
584 MessageDigest md = MessageDigest.getInstance ("SHA");
\r
585 DataBufferInt dbi = (DataBufferInt) Image.getRaster ().getDataBuffer ();
\r
586 for (int i=0; i<dbi.getNumBanks (); i++) {
\r
587 int [] curBank = dbi.getData (i);
\r
588 for (int j=0; j<curBank.Length; j++) {
\r
589 int x = curBank[j];
\r
590 md.update ((sbyte) (x & 0xFF));
\r
591 md.update ((sbyte) ((x>>8) & 0xFF));
\r
592 md.update ((sbyte) ((x>>16) & 0xFF));
\r
593 md.update ((sbyte) ((x>>24) & 0xFF));
\r
596 byte [] resdata = (byte[])vmw.common.TypeUtils.ToByteArray(md.digest());
\r
597 return Convert.ToBase64String (resdata);
\r
601 internal class NetDrawingTest:DrawingTest {
\r
602 public NetDrawingTest () {}
\r
604 protected override double GetExpectedNorm (double myNorm) {
\r
606 ExpectedResults.WriteNorm (TestName, myNorm);
\r
611 protected override Bitmap GetReferenceImage(string testName) {
\r
612 string fileName = testName.Replace(":", "_") + ".png";
\r
615 return new Bitmap("/Developer/MonoTouch/Source/mono/mcs/class/System.Drawing/Test/DrawingTest/Test/PNGs/" + fileName);
\r
617 _bitmap.Save( fileName );
\r
622 catch(System.Exception e) {
\r
623 throw new System.Exception("Error loading .Net reference image: " + fileName);
\r
628 private class NetForm:MonoTouch.UIKit.UIViewController,IMyForm {
\r
630 public NetForm(string title, Image anImage):base() {
\r
631 //base.Text = title;
\r
634 void IMyForm.Show () {
\r
635 this.image.Save("test.net.png");
\r
639 private class NetForm:Form,IMyForm {
\r
641 public NetForm(string title, Image anImage):base() {
\r
645 protected override void OnPaint(PaintEventArgs e) {
\r
646 e.Graphics.DrawImageUnscaled (image, 0, 0);
\r
648 void IMyForm.Show () {
\r
649 this.Size = image.Size;
\r
650 this.ShowDialog ();
\r
651 this.image.Save("test.net.png");
\r
655 protected override IMyForm CreateForm(string title) {
\r
656 return new NetForm (title, _bitmap);
\r
659 protected override string DetermineCallingFunction() {
\r
660 StackFrame sf = new StackFrame (3, true);
\r
661 MethodBase mb = sf.GetMethod ();
\r
663 string name = mb.DeclaringType.FullName + "." + _ownerClass + "." + mb.Name;
\r
667 public override string CalculateSHA1() {
\r
668 Rectangle r = new Rectangle(0, 0, _bitmap.Width, _bitmap.Height);
\r
670 BitmapData data = _bitmap.LockBits (r, ImageLockMode.ReadOnly,
\r
671 _bitmap.PixelFormat);
\r
672 int dataSize = data.Stride * data.Height;
\r
673 byte [] bdata = new byte [dataSize];
\r
674 Marshal.Copy (data.Scan0, bdata, 0, dataSize);
\r
675 _bitmap.UnlockBits (data);
\r
677 SHA1 sha1 = new SHA1CryptoServiceProvider ();
\r
678 byte [] resdata = sha1.ComputeHash (bdata);
\r
679 return Convert.ToBase64String (resdata);
\r