Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / AlphaFlattener / Optimizer.cs / 1 / Optimizer.cs
//------------------------------------------------------------------------------ // Microsoft Printing // Copyright (c) Microsoft Corporation, 2005 // // File: Optimizer.cs // // History: // [....]: 06/24/2005 Created //----------------------------------------------------------------------------- using System; using System.Diagnostics; using System.Collections; // for ArrayList using System.Windows; // for Rect WindowsBase.dll using System.Windows.Media; // for Geometry, Brush, ImageData. PresentationCore.dll using System.Windows.Media.Imaging; using System.Collections.Generic; using System.Windows.Xps.Serialization; namespace Microsoft.Internal.AlphaFlattener { internal class Cluster { #region Private Fields private Listm_primitives; private Rect m_bounds; #if DEBUG private bool m_debugRasterize; #endif private int m_lowestPrimitive; // lowest index in m_primitives #endregion #region Constructors public Cluster() { m_primitives = new List (); m_bounds = Rect.Empty; m_lowestPrimitive = int.MaxValue; } #endregion #region Public Methods public void Render(List commands, IProxyDrawingContext dc) { Toolbox.StartEvent(Toolbox.DRXRASTERGUID); int width = (int)Math.Round(m_bounds.Width * Configuration.RasterizationDPI / 96); int height = (int)Math.Round(m_bounds.Height * Configuration.RasterizationDPI / 96); if ((width >= 1) && (height >= 1)) // Skip shape which is too small { Matrix mat = Utility.CreateMappingTransform(m_bounds, width, height); RenderTargetBitmap brushImage = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); DrawingVisual visual = new DrawingVisual(); // clip image to the primitives it contains Geometry clip = null; using (DrawingContext ctx = visual.RenderOpen()) { ctx.PushTransform(new MatrixTransform(mat)); m_primitives.Sort(); foreach (int i in m_primitives) { Primitive primitive = commands[i].primitive; // Fix bug 1396393: Can't use AddToCluster without fixing that bug. // We need to clip cluster to primitives in case primitives have clipping. Debug.Assert(GetPrimitiveIntersectAction() == PrimitiveIntersectAction.ClipToCluster); bool empty; Geometry geometry = Utility.Intersect(primitive.GetShapeGeometry(), primitive.Clip, Matrix.Identity, out empty); if (!empty) { primitive.OnRender(ctx); // clip cluster to this clipped primitive. we must have geometry information, // otherwise the primitive will be clipped away. Debug.Assert(geometry != null, "No geometry available for primitive"); if (clip == null) { clip = geometry; } else { CombinedGeometry cg = new CombinedGeometry(); // Opt-out of inheritance through the new Freezable. cg.CanBeInheritanceContext = false; cg.GeometryCombineMode = GeometryCombineMode.Union; cg.Geometry1 = clip; cg.Geometry2 = geometry; clip = cg; } } commands[i] = null; // Command can be deleted after cluster is rendered } ctx.Pop(); } brushImage.Render(visual); Toolbox.EndEvent(Toolbox.DRXRASTERGUID); dc.DrawImage(new ImageProxy(brushImage), m_bounds, clip, Matrix.Identity); } } #endregion #region Public Static Methods public static void CheckForRasterization(List clusters, List commands) { foreach (Cluster c in clusters) { if (c.BetterRasterize(commands)) { #if DEBUG c.m_debugRasterize = true; #endif foreach (int i in c.m_primitives) { commands[i].m_cluster = c; } } } } public static List CalculateCluster(List commands, int count, bool disjoint, List [] oldUnderlay) { List transparentCluster = new List (); // indicates which primitives have been added to any cluster bool[] addedPrimitives = new bool[commands.Count]; // calculate clusters until cluster bounds stabilize while (true) { bool clusterBoundsChanged = CalculateClusterCore( commands, count, disjoint, oldUnderlay, transparentCluster, addedPrimitives ); if (!clusterBoundsChanged || GetPrimitiveIntersectAction() != PrimitiveIntersectAction.AddToCluster) break; // // Cluster bounds have changed somewhere, need to examine all primitives that haven't // been added to a cluster and test for intersection with cluster. We add primitives // that intersect and rendered before the cluster. // // Note that here we check even opaque primitives, since they might get covered // by a transparent cluster, and thus need to be rasterized with a cluster if intersection // exists. // for (int primIndex = 0; primIndex < addedPrimitives.Length; primIndex++) { if (!addedPrimitives[primIndex] && commands[primIndex] != null) { PrimitiveInfo primitive = commands[primIndex]; for (int clusterIndex = 0; clusterIndex < transparentCluster.Count; clusterIndex++) { Cluster cluster = transparentCluster[clusterIndex]; if (primitive.GetClippedBounds().IntersectsWith(cluster.m_bounds) && primIndex < cluster.m_lowestPrimitive) { // primitive intersects this cluster, add to cluster cluster.Add( primIndex, oldUnderlay, commands, addedPrimitives ); } } } } } return transparentCluster; } #endregion #region Private Methods /// /// What action to take to handle cases where primitives intersect a cluster's bounding box, /// but does not touch any of the cluster's primitives. /// private enum PrimitiveIntersectAction { ////// Don't do anything, behavior corresponds to /// bug 1267200: MGC - ToolBarTray element does not print in some cases. /// None, ////// Adds the primitive to the cluster for rasterization. /// AddToCluster, ////// Clips the cluster rasterized image to the primitives it contains. /// ClipToCluster, } private static PrimitiveIntersectAction GetPrimitiveIntersectAction() { // // Fix bug 1396393: Printing: Background pictures are only partially printed for an xCal calendar // // The bug involves printing a calendar. What happens is the January ImagePrimitive is clipped // to the rectangle for January, but it's rasterized as part of a cluster with a color fill of // that same rectangle. Cluster rasterization loses the clipping on the picture, which effectively // makes the cluster grow to overlap April below January. This causes April to appear clipped. // // Fixing involves clipping clusters to its clipped primitives. As such, AddToCluster cannot // be used without further fixes. // return PrimitiveIntersectAction.ClipToCluster; } ////// Adds primitive to this cluster. /// /// primitive index /// underlay information /// list of primitives /// indicates which primitives have been added to any cluster private void Add( int i, List[] underlay, List commands, bool[] addedPrimitives ) { // clip bounds to avoid generating excessively large cluster Rect bounds = commands[i].GetClippedBounds(); m_bounds.Union(bounds); m_primitives.Add(i); addedPrimitives[i] = true; if (i < m_lowestPrimitive) { m_lowestPrimitive = i; } // Add all primitives covered by i recursively if ((underlay != null) && (underlay[i] != null)) { foreach (int j in underlay[i]) { if ((commands[j] != null) && m_primitives.IndexOf(j) < 0) { Add(j, underlay, commands, addedPrimitives); } } } } private void MergeWith(Cluster c) { m_bounds.Union(c.m_bounds); for (int i = 0; i < c.m_primitives.Count; i++) { if (m_primitives.IndexOf(c.m_primitives[i]) < 0) { m_primitives.Add(c.m_primitives[i]); } } } /// /// Check if the whole cluster is complex enough such that rasterizing the whole thing is better than flattening it /// /// ///private bool BetterRasterize(List commands) { double clustersize = m_bounds.Width * m_bounds.Height; double diff = - Configuration.RasterizationCost(m_bounds.Width, m_bounds.Height); // Estimate cost of geometry operations (intersecting) double pathComplexity = 1; foreach (int i in m_primitives) { PrimitiveInfo pi = commands[i]; Primitive p = pi.primitive; GeometryPrimitive gp = p as GeometryPrimitive; Rect bounds = pi.GetClippedBounds(); bool rasterize = true; if (gp != null) { double complexity = 1; Geometry geo = gp.Geometry; if (geo != null) { complexity = Utility.GetGeometryPointCount(geo); // weight down the complexity of small region complexity *= bounds.Width * bounds.Height / clustersize; } BrushProxy bp = gp.Brush; if (bp == null) { bp = gp.Pen.StrokeBrush; // Widen path would at least double the points complexity *= 3; } if (complexity > 1) { pathComplexity *= complexity; if (pathComplexity > 100000) // 333 x 333 { return true; } } if (bp != null) { Brush b = bp.Brush; if ((b != null) && ((b is SolidColorBrush) || (b is LinearGradientBrush))) { // SolidColorBrush does not need full rasterization // Vertical/Horizontal linear gradient brush does not need full rasterization rasterize = false; } } } if (rasterize) { diff += Configuration.RasterizationCost(bounds.Width, bounds.Height); if (diff > 0) { break; } } } return diff > 0; } /// /// Calculates list of transparent clusters, returning true if clusters added or bounding rectangles changed. /// private static bool CalculateClusterCore( Listcommands, int count, bool disjoint, List [] oldUnderlay, List transparentCluster, bool[] addedPrimitives // primitives added to clusters ) { bool clusterBoundsChanged = false; // Build clusters of transparent primitives for (int i = 0; i < count; i++) { PrimitiveInfo pi = commands[i]; // When disjoint is true (flattening a subtree), add all primitives to a single cluster if ((pi != null) && (disjoint || !pi.primitive.IsOpaque) && !addedPrimitives[i]) { Rect bounds = pi.GetClippedBounds(); Cluster home = null; for (int j = 0; j < transparentCluster.Count; j++) { Cluster c = transparentCluster[j]; if (disjoint || bounds.IntersectsWith(c.m_bounds)) { home = c; break; } } if (home == null) { home = new Cluster(); transparentCluster.Add(home); } Rect oldClusterBounds = home.m_bounds; home.Add(i, oldUnderlay, commands, addedPrimitives); if (!clusterBoundsChanged && oldClusterBounds != home.m_bounds) { // cluster bounds have changed clusterBoundsChanged = true; } } } // Merges clusters which touch each other bool changed; do { changed = false; for (int i = 0; i < transparentCluster.Count; i++) for (int j = i + 1; j < transparentCluster.Count; j++) { if (transparentCluster[i].m_bounds.IntersectsWith(transparentCluster[j].m_bounds)) { transparentCluster[i].MergeWith(transparentCluster[j]); // cluster bounds have changed since merging two clusters clusterBoundsChanged = true; transparentCluster.RemoveAt(j); changed = true; break; } } } while (changed); return clusterBoundsChanged; } #endregion #if DEBUG internal List DebugPrimitives { get { return m_primitives; } } internal Rect DebugBounds { get { return m_bounds; } } internal bool DebugRasterize { get { return m_debugRasterize; } } #endif } } // end of namespace // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HighlightVisual.cs
- MembershipAdapter.cs
- CodeNamespaceImportCollection.cs
- ConfigUtil.cs
- IdentityValidationException.cs
- FontInfo.cs
- TreeNodeBindingCollection.cs
- HyperLinkStyle.cs
- EntityViewGenerator.cs
- ZipIOEndOfCentralDirectoryBlock.cs
- ParserExtension.cs
- FixedSOMGroup.cs
- ConfigurationManagerInternalFactory.cs
- Vector3DCollectionConverter.cs
- TypeConverterHelper.cs
- WebCategoryAttribute.cs
- ReceiveMessageRecord.cs
- X509Certificate.cs
- ColorComboBox.cs
- OrderToken.cs
- DependencyObjectPropertyDescriptor.cs
- CopyOfAction.cs
- MonikerProxyAttribute.cs
- CollectionExtensions.cs
- RecommendedAsConfigurableAttribute.cs
- SvcMapFileLoader.cs
- PaperSource.cs
- EntityContainerEntitySet.cs
- AxisAngleRotation3D.cs
- _Events.cs
- HostingEnvironmentSection.cs
- TreeIterators.cs
- DrawingCollection.cs
- HtmlInputFile.cs
- EntityDataSourceColumn.cs
- XmlWrappingWriter.cs
- PlaceHolder.cs
- TimeStampChecker.cs
- Size3D.cs
- ReachDocumentReferenceCollectionSerializer.cs
- StyleSelector.cs
- DeferredSelectedIndexReference.cs
- DataSourceHelper.cs
- QueryableDataSourceHelper.cs
- SQLDateTimeStorage.cs
- MobileTemplatedControlDesigner.cs
- ArithmeticException.cs
- TableProvider.cs
- CurrencyWrapper.cs
- ColumnResult.cs
- RuntimeConfigurationRecord.cs
- NotificationContext.cs
- DocumentEventArgs.cs
- FocusChangedEventArgs.cs
- InfiniteTimeSpanConverter.cs
- SecurityContext.cs
- ImportContext.cs
- MinimizableAttributeTypeConverter.cs
- ObjectTag.cs
- DispatcherSynchronizationContext.cs
- RuleSetBrowserDialog.cs
- HyperLinkColumn.cs
- CollaborationHelperFunctions.cs
- RelatedEnd.cs
- CommonObjectSecurity.cs
- NullRuntimeConfig.cs
- controlskin.cs
- NamespaceQuery.cs
- SourceItem.cs
- ProviderException.cs
- ZipIORawDataFileBlock.cs
- ToolStripDropDownButton.cs
- StaticFileHandler.cs
- QueryConverter.cs
- PartialTrustHelpers.cs
- ToolStripManager.cs
- QueueProcessor.cs
- UrlMappingsModule.cs
- DragCompletedEventArgs.cs
- InputLanguageEventArgs.cs
- PropertyGeneratedEventArgs.cs
- MessageBox.cs
- CodeExpressionCollection.cs
- RegexTree.cs
- MouseButton.cs
- WebControl.cs
- NativeMethods.cs
- Matrix.cs
- StringFormat.cs
- PersonalizableAttribute.cs
- ExpressionEditorSheet.cs
- X509SubjectKeyIdentifierClause.cs
- RootBuilder.cs
- SelectedDatesCollection.cs
- ObjectTag.cs
- ObjectFactoryCodeDomTreeGenerator.cs
- PropertyTabAttribute.cs
- Misc.cs
- TraceContextRecord.cs
- ChineseLunisolarCalendar.cs