private void StretchForDifferentDpi(IntPtr hwnd, int width, int height, Image masterImage) { Size offset = new Size(masterImage.Width - width, masterImage.Height - height); //The original application of this method assumes that a master image was captured on a machine //set to 96dpi and scales the window size appropriately. However, if a master was actually captured on a //machine that is set to a dpi other than 96, we want to provide the option not to automatically scale the Window. if (_resizeWindowForDpi) { IMasterDimension currentDpi = MasterMetadata.GetDimension("DpiDimension"); int standardDpi = 96; if (currentDpi.GetCurrentValue() != standardDpi.ToString()) { int dpi = int.Parse(currentDpi.GetCurrentValue()); float ratio = (float)dpi / standardDpi; offset.Width = (int)(masterImage.Width * ratio - width + .5); offset.Height = (int)(masterImage.Height * ratio - height + .5); } } if (offset.IsEmpty) { return; } ResizeWindow(hwnd, offset.Width, offset.Height, true); }
private void SetMetadataToImage(Image image) { MasterMetadata metadata = ImageMetadata.MetadataFromImage(image); metadata._criteria.Clear(); metadata._criteria.AddRange(_masterIndex.GetCurrentCriteriaValue().Keys); ImageMetadata.SetMetadataToImage(metadata, image); }
private AsyncData CommonCompare(IntPtr hwnd, System.Drawing.Rectangle rect, ManualResetEvent resetEvent) { _counter++; Bitmap masterImage = _masterIndex.Resolve(); string masterName = string.Empty; if (masterImage != null) { masterName = _masterIndex.ResolvedMasterName; Microsoft.Test.Logging.GlobalLog.LogStatus("Picking master '" + masterName + "'"); } else { Microsoft.Test.Logging.GlobalLog.LogStatus("No Matching master found !"); } if (_stabilizeWindowBeforeCapture) { StabilizeWindow(hwnd, masterImage); } Bitmap actualImage; if (rect != System.Drawing.Rectangle.Empty) { actualImage = SnapshotRect(rect); } else { actualImage = SnapshotWindow(hwnd); } if (masterImage == null) { Microsoft.Test.Logging.GlobalLog.LogStatus("Encoding information in new master"); MasterMetadata metadata = ImageMetadata.MetadataFromImage(actualImage); metadata._criteria.Clear(); metadata._criteria.AddRange(_masterIndex.GetCurrentCriteriaValue().Keys); ImageMetadata.SetMetadataToImage(metadata, actualImage); // Save rendered as actual string actualName = ".\\Actual_" + _counter + IMAGE_EXTENSION; actualImage.Save(actualName, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(actualName); // Save render with new name already set actualName = _masterIndex.GetNewMasterName(); Microsoft.Test.Logging.GlobalLog.LogStatus("Saving master as '" + System.IO.Path.GetFileName(actualName) + "'"); actualImage.Save(actualName, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(actualName); } return(new AsyncData(masterImage, masterName, actualImage, resetEvent, _toleranceSettings, _counter)); }
/// <summary> /// Set the metadata OSinfo into an image /// </summary> /// <param name="metadata"></param> /// <param name="image"></param> public static void SetMetadataToImage(MasterMetadata metadata, Image image) { // Serialize Description and Criteria into an Xml node and put into image metadata using (System.IO.MemoryStream metadataStream = new System.IO.MemoryStream()) { XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.Encoding = System.Text.ASCIIEncoding.UTF8; using (XmlWriter writer = XmlWriter.Create(metadataStream, writerSettings)) { writer.WriteStartElement("MasterMetadata"); foreach (KeyValuePair <IMasterDimension, string> keyValue in metadata.Description) { writer.WriteStartElement("Description"); writer.WriteStartElement("Dim"); writer.WriteAttributeString("name", keyValue.Key.GetType().Name); writer.WriteAttributeString("value", keyValue.Value); writer.WriteEndElement(); // </Dim> writer.WriteEndElement(); // </Description> } foreach (KeyValuePair <IMasterDimension, string> keyValue in metadata.Criteria) { writer.WriteStartElement("Criteria"); writer.WriteStartElement("Index"); writer.WriteAttributeString("name", keyValue.Key.GetType().Name); writer.WriteEndElement(); // </Index> writer.WriteEndElement(); // </Criteria> } writer.WriteEndElement(); // </MasterMetadata>; } // Workaround Win7 Bug 687567: GDI+ : 1.1 expects NULL terminated string when // the PropertyItem type is PropertyTagTypeASCII in SetPropertyItem, while 1.0 always append NULL terminator UTF8Encoding utf8Encoding = new UTF8Encoding(); byte[] nullTerminator = utf8Encoding.GetBytes(new char[] { '\0' }); metadataStream.WriteByte(nullTerminator[0]); metadataStream.Position = 0; // Build PropertyItem and save serialized info into it. PropertyItem pi = CreatePropertyItem(); pi.Id = EXIF_IMAGEINFO; pi.Value = metadataStream.GetBuffer(); pi.Len = pi.Value.Length; pi.Type = 2; image.SetPropertyItem(pi); } // Encode XP Keyword & description into image image.SetPropertyItem(BuildUserFriendlyTag(EXIF_XP_KEYWORD, metadata.Criteria)); image.SetPropertyItem(BuildUserFriendlyTag(EXIF_XP_DESCRIPTION, metadata.Description)); // Add Vista Comments and Tag (Description and Keyword counterpart to XP) image.SetPropertyItem(AddVistaInfo(metadata)); }
/// <summary> /// Retrieve the OSinfo stored in the image /// </summary> /// <param name="image">The image to parse</param> /// <returns>returne a MasterMetadata object containing the description and criteria</returns> public static MasterMetadata MetadataFromImage(Image image) { MasterMetadata retVal = new MasterMetadata(); // Check if the image contains criteria & description List <int> idList = new List <int>(); idList.AddRange(image.PropertyIdList); if (idList.Contains(EXIF_IMAGEINFO)) { // Deserialize Description and Criteria from the image metadata (saved as xmlNode) PropertyItem pi = image.GetPropertyItem(EXIF_IMAGEINFO); // Remove trailing '\0' since it messes up deserialization string serializedInfo = System.Text.UTF8Encoding.UTF8.GetString(pi.Value); System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(serializedInfo.Trim('\0'))); XmlReaderSettings readerSettings = new XmlReaderSettings(); memoryStream.Position = 0; XmlReader reader = XmlReader.Create(memoryStream, readerSettings); while (reader.Read()) { string dim = string.Empty; string val = string.Empty; string index = string.Empty; if (reader.Name == "Dim") { dim = reader["name"]; val = reader["value"]; retVal.Description[MasterMetadata.GetDimension(dim)] = val; } if (reader.Name == "Index") { index = reader["name"]; retVal._criteria.Add(MasterMetadata.GetDimension(index)); } } } return(retVal); }
private static PropertyItem AddVistaInfo(MasterMetadata metadata) { PropertyItem retVal = CreatePropertyItem(); retVal.Id = EXIF_VISTA_INFO; retVal.Type = 1; List <string> keywords = new List <string>(); if (metadata.Criteria != null) { foreach (KeyValuePair <IMasterDimension, string> criteriaKeyPair in metadata.Criteria) { string keywordTag = KEYWORD_TAG.Replace(KEYWORD, criteriaKeyPair.Key.GetType().Name + "=" + criteriaKeyPair.Value); keywords.Add(keywordTag); } } string descriptions = string.Empty; if (metadata.Description != null) { foreach (KeyValuePair <IMasterDimension, string> descKeyPair in metadata.Description) { descriptions += descKeyPair.Key.GetType().Name + "=" + descKeyPair.Value + " / "; } } string xmpString = XMP_STRING; xmpString = xmpString.Replace(KEYWORD_TAGS, string.Join("", keywords.ToArray())); xmpString = xmpString.Replace(DESCRIPTIONS, descriptions); retVal.Value = System.Text.UTF8Encoding.UTF8.GetBytes(xmpString); retVal.Len = retVal.Value.Length; return(retVal); }
internal Bitmap Resolve() { _resolvedMasterName = string.Empty; if (System.IO.Directory.Exists(_path) == false) { return(null); } // Get the current Dimensions (and its the values) for what the user cares about Dictionary <IMasterDimension, string> expectedDimensions = GetCurrentCriteriaValue(); // Get all masters with for this testcase string[] files = System.IO.Directory.GetFiles(_path, FileName); // Loop thru all potential masters int[] matchingScores = new int[files.Length]; for (int fileIndex = 0; fileIndex < files.Length; fileIndex++) { matchingScores[fileIndex] = 0; MasterMetadata masterMetadata = null; using (Image img = new Bitmap(files[fileIndex])) { // Retrieve Image metadata (Description and Criteria) for each master masterMetadata = ImageMetadata.MetadataFromImage(img); } // Check that every master dimensions are required by the user foreach (KeyValuePair <IMasterDimension, string> masterDim in masterMetadata.Criteria) { if (expectedDimensions.ContainsKey(masterDim.Key) == false) { // User did not specfy this Dimension matchingScores[fileIndex] = -1; break; } if (expectedDimensions[masterDim.Key].ToLowerInvariant() != masterDim.Value.ToLowerInvariant()) { // Dimension specified by user but this machine is not the right value. matchingScores[fileIndex] = -1; break; } matchingScores[fileIndex] += _weightedCriteria[masterDim.Key]; } } // Find the best master int bestMatchIndex = -1; int bestScore = -1; for (int t = 0; t < matchingScores.Length; t++) { if (matchingScores[t] > bestScore) { bestScore = matchingScores[t]; bestMatchIndex = t; } } if (bestMatchIndex == -1) { return(null); } _resolvedMasterName = files[bestMatchIndex]; return(new Bitmap(files[bestMatchIndex])); }
private void DoVscanCompare(object asyncData) { AsyncData data = asyncData as AsyncData; if (data == null) { throw new ArgumentException("Parameter passed in to the Method not of type AsyncData (or null)", "asyncData"); } ImageComparator ic = new ImageComparator(); ic.Curve.CurveTolerance.LoadTolerance(data.ToleranceSettings.XmlNodeTolerance); IImageAdapter masterAdapter = new ImageAdapter(data.MasterImage); IImageAdapter capturedAdapter = new ImageAdapter(data.CapturedImage); // compare Master to the Capture image using the Compare overload that will scale the images size accounting for the DPI data.Result.Succeeded = ic.Compare(masterAdapter, MetadataInfoHelper.GetDpi(masterAdapter), capturedAdapter, MetadataInfoHelper.GetDpi(capturedAdapter), false); if (data.Result.Succeeded == false) { Microsoft.Test.Logging.GlobalLog.LogStatus("Regular comparison failed"); } // On filaure, check if user whats to filter the image ( IgnoreAntiAliasing will do ) IImageAdapter masterFiltered = null; IImageAdapter captureFiltered = null; if (data.Result.Succeeded == false && data.ToleranceSettings.Filter != null) { // first save error diff image string errorDiffName = ".\\ErrorDiff_" + data.Index + IMAGE_EXTENSION; ImageUtility.ToImageFile(ic.GetErrorDifference(ErrorDifferenceType.IgnoreAlpha), errorDiffName); Microsoft.Test.Logging.GlobalLog.LogFile(errorDiffName); // Compare failed, filter the images and retry Microsoft.Test.Logging.GlobalLog.LogStatus("Filtering and recompare"); masterFiltered = data.ToleranceSettings.Filter.Process(masterAdapter); captureFiltered = data.ToleranceSettings.Filter.Process(capturedAdapter); data.Result.Succeeded = ic.Compare(masterFiltered, captureFiltered, false); if (data.Result.Succeeded == false) { Microsoft.Test.Logging.GlobalLog.LogStatus("==> Filtered comparison failed as well"); } } if (data.Result.Succeeded) { Microsoft.Test.Logging.GlobalLog.LogStatus("Comparison SUCCEEDED."); } else { // Save Masters * filtered master for easy analysis string masterName = ".\\Master_" + data.Index + IMAGE_EXTENSION; data.MasterImage.Save(masterName, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(masterName); if (masterFiltered != null) { string filteredMasterName = ".\\MasterFiltered_" + data.Index + IMAGE_EXTENSION; using (Bitmap filteredMaster = ImageUtility.ToBitmap(masterFiltered)) { SetMetadataToImage(filteredMaster); filteredMaster.Save(filteredMasterName, System.Drawing.Imaging.ImageFormat.Tiff); } Microsoft.Test.Logging.GlobalLog.LogFile(filteredMasterName); } // Save rendered image (as "Actual_n") for easy analysis string capturedName = ".\\Actual_" + data.Index + IMAGE_EXTENSION; data.CapturedImage.Save(capturedName, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(capturedName); // Save actual filtered for easy analysis if (captureFiltered != null) { string filteredRenderedName = ".\\ActualFiltered_" + data.Index + IMAGE_EXTENSION; using (Bitmap filteredRendered = ImageUtility.ToBitmap(captureFiltered)) { SetMetadataToImage(filteredRendered); filteredRendered.Save(filteredRenderedName, System.Drawing.Imaging.ImageFormat.Tiff); } Microsoft.Test.Logging.GlobalLog.LogFile(filteredRenderedName); } // Master might need to be updated, save with correct name and metadata // // In this image, encode full criteria string name = System.IO.Path.GetFileName(data.MasterName); string originalName = name.Replace(IMAGE_EXTENSION, "_FullCtriteria" + IMAGE_EXTENSION); Microsoft.Test.Logging.GlobalLog.LogStatus("Saving master with all criteria (new master) as '" + originalName + "'"); SetMetadataToImage(data.CapturedImage); data.CapturedImage.Save(originalName, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(originalName); // // In this image, encode only criteria that match the master string originalNameFull = name.Replace(IMAGE_EXTENSION, "_MatchingCriteria" + IMAGE_EXTENSION); Microsoft.Test.Logging.GlobalLog.LogStatus("Saving master with matching criteria encoded (to replace previous master) as '" + originalNameFull + "'"); MasterMetadata metadata = ImageMetadata.MetadataFromImage(data.MasterImage); // Keep master Criteria but update its Description. IMasterDimension[] keys = new IMasterDimension[metadata.Description.Count]; metadata.Description.Keys.CopyTo(keys, 0); for (int t = 0; t < keys.Length; t++) { metadata.Description[keys[t]] = keys[t].GetCurrentValue(); } ImageMetadata.SetMetadataToImage(metadata, data.CapturedImage); data.CapturedImage.Save(originalNameFull, System.Drawing.Imaging.ImageFormat.Tiff); Microsoft.Test.Logging.GlobalLog.LogFile(originalNameFull); // first save error diff image string errorDiffFilterName = ".\\ErrorDiffFiltered_" + data.Index + IMAGE_EXTENSION; if (data.ToleranceSettings.Filter == null) { // Not filter were applied, change name (so it's not confusing) errorDiffFilterName = ".\\ErrorDiff_" + data.Index + IMAGE_EXTENSION; } ImageUtility.ToImageFile(ic.GetErrorDifference(ErrorDifferenceType.IgnoreAlpha), errorDiffFilterName); Microsoft.Test.Logging.GlobalLog.LogFile(errorDiffFilterName); } data.Result.IsCompleted = true; if (data.SynchronizationObject != null) { data.SynchronizationObject.Set(); } }