Code:
/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / AlphaFlattener / ImageProxy.cs / 1 / ImageProxy.cs
//------------------------------------------------------------------------------ // Microsoft Printing // Copyright (c) Microsoft Corporation, 2004 // // File: ImageProxy.cs // // History: // [....]: 04/20/2004 Created //----------------------------------------------------------------------------- using System; using System.Collections; // for ArrayList using System.Collections.Generic; using System.Diagnostics; using System.Windows; // for Rect WindowsBase.dll using System.Windows.Media; // for Geometry, Brush, ImageSource. PresentationCore.dll using System.Windows.Media.Imaging; using System.Windows.Controls; // for Image using System.Windows.Shapes; // for Glyphs using System.Security; using System.Security.Permissions; //using System.Drawing.Printing; namespace Microsoft.Internal.AlphaFlattener { ////// Decode ImageSource into PARGB32 format, keep in managed memory to allow multiple blending, /// finally generate ImageSource when needed to interface with Avalon. /// Avalon ImageSource converts data to unmanaged memory. /// internal class ImageProxy { ////// Maximum ratio between pixel count of requested clip rectangle and actual image rectangle /// for clipping of image data to be performed. /// ////// The flattening process draws primitive intersection regions by blending brushes together, /// then clipping to that region. The problem is when blending image primitive with something: /// the entire image is drawn regardless of the intersection region size. This can significantly /// increase spool file size. /// /// The solution is to detect such cases and clip image data down prior to blending and drawing /// the intersection. This ratio controls when this clipping occurs. /// private const double MaximumClipRatio = 0.9; ////// Minimum ratio between this image's size and brush size when blending before we magnify /// this image. Without magnification, the brush will lose detail due to being scaled down /// to image's size. /// private const double MinimumBlendRatio = 0.5; ////// Maximum size to use when magnify image if scale is less than MinimumBlendRatio, to avoid /// huge image /// private const int MaximumOpacityMaskViewport = 1024; protected int _pixelWidth; protected int _pixelHeight; protected BitmapSource _image; ////// Critical: Data is from CriticalCopyPixels /// [SecurityCritical] protected Byte[] _pixels; public ImageProxy(BitmapSource image) { Debug.Assert(image != null); _pixelWidth = image.PixelWidth; _pixelHeight = image.PixelHeight; _image = image; // _pixels = null; } public BitmapSource Image { get { return _image; } } ////// Critical: _pixels is SecurityCritical /// public Byte[] Buffer { [SecurityCritical] get { return _pixels; } } public int PixelWidth { get { return _pixelWidth; } } public int PixelHeight { get { return _pixelHeight; } } ////// Scales the image. /// /// /// ////// Critical : This code touches _pixels /// TreatAsSafe: _pixels is reset to null, not leaked /// [SecurityCritical, SecurityTreatAsSafe] public void Scale(double scaleX, double scaleY) { _image = new TransformedBitmap( _image, new MatrixTransform(Matrix.CreateScaling(scaleX, scaleY)) ); _pixelWidth = _image.PixelWidth; _pixelHeight = _image.PixelHeight; _pixels = null; } ////// Critical : This code calls an internal PresentationCore function CriticalCopyPixels /// TreatAsSafe: Pixel is copied to _pixels array, which is marked as SecurityCritical /// [SecurityCritical, SecurityTreatAsSafe] private void Decode() { if (_pixels == null) { _pixels = GetDecodedPixels(new Int32Rect(0, 0, _pixelWidth, _pixelHeight)); } } ////// Critical : This code calls an internal PresentationCore function CriticalCopyPixels, returns critical data /// ////// Decodes a subimage, returning the decoded pixels. /// /// Bounds of subimage to decode ///Returns critical pixels [SecurityCritical] private byte[] GetDecodedPixels(Int32Rect bounds) { Debug.Assert( (bounds.X >= 0) && (bounds.Y >= 0) && ((bounds.X + bounds.Width) <= _pixelWidth) && ((bounds.Y + bounds.Height) <= _pixelHeight) ); int stride = bounds.Width * 4; byte[] pixels = new Byte[stride * bounds.Height]; FormatConvertedBitmap converter = new FormatConvertedBitmap(); converter.BeginInit(); converter.Source = _image; converter.DestinationFormat = PixelFormats.Pbgra32; converter.EndInit(); converter.CriticalCopyPixels(bounds, pixels, stride, 0); return pixels; } ////// Critical : It touches critical data in _pixels /// TreatAsSafe: _pixels is just modified in place, not leaked /// /// /// /// Image destination rectangle /// Transformation from image to final destination [SecurityCritical, SecurityTreatAsSafe] public void PushOpacity(double opacity, BrushProxy opacityMask, Rect rect, Matrix trans) { if (opacityMask != null) { rect.Transform(trans); // // Blend this image on top of opacity mask. // // Calculate scaling factor from opacity mask to this image. TileBrush opacityBrush = opacityMask.Brush as TileBrush; Rect viewport; if (opacityBrush != null) { Debug.Assert(opacityBrush.ViewportUnits == BrushMappingMode.Absolute, "TileBrush must have absolute viewport by this point"); viewport = opacityBrush.Viewport; } else { // viewport covers entire image viewport = rect; } // Fix for 1689025: double scaleX = _pixelWidth / rect.Width; double scaleY = _pixelHeight / rect.Height; // If current image is too small, magnify it to match opacity mask's size, // otherwise we lose the detail in opacity mask. if ((scaleX < MinimumBlendRatio || scaleY < MinimumBlendRatio) && (rect.Width <= MaximumOpacityMaskViewport) && (rect.Height <= MaximumOpacityMaskViewport)) // Avoiding generate huge bitmap { Scale(rect.Width / _pixelWidth, rect.Height / _pixelHeight); scaleX = 1.0; scaleY = 1.0; } // Transform brush to image space. Matrix transform = new Matrix(); transform.Translate(-rect.Left, -rect.Top); transform.Scale(scaleX, scaleY); // Blend opacity mask into image. BlendUnderBrush(false, opacityMask, transform); } int op = Utility.OpacityToByte(opacity); if (op <= 0) { _image = null; _pixels = null; return; } else if (op >= 255) { return; } Decode(); Byte[] map = new Byte[256]; for (int i = 0; i < 256; i ++) { map[i] = (Byte)(i * op / 255); } int count = _pixelWidth * _pixelHeight * 4; for (int i = 0; i < count; i++) { _pixels[i] = map[_pixels[i]]; } } ////// Critical : It touches critical data in _pixels /// TreatAsSafe: _pixels is just modified in place, not leaked /// [SecurityCritical, SecurityTreatAsSafe] public void BlendUnderColor(Color color, double opacity, bool opacityOnly) { Decode(); Utility.BlendUnderColor(_pixels, _pixelWidth * _pixelHeight, color, opacity, opacityOnly); } ////// Critical : It touches critical data in _pixels /// TreatAsSafe: _pixels is just modified in place, not leaked /// [SecurityCritical, SecurityTreatAsSafe] public void BlendOverColor(Color color, double opacity, bool opacityOnly) { if (opacityOnly || !Utility.IsOpaque(opacity) || !IsOpaque()) { // Always blend if image is opacity mask, so that a proper opacity mask image // is formed, otherwise the original image pixels will be used. Decode(); Utility.BlendOverColor(_pixels, _pixelWidth * _pixelHeight, color, opacity, opacityOnly); } } ////// Render a brush on top of current image /// /// /// /// ////// Critical: It calls into SecurityCritical function RasterizeBrush /// TreatAsSafe: Output will be in _pixels, which is marked as SecurityCritical /// [SecurityCritical, SecurityTreatAsSafe] public void BlendUnderBrush(bool opacityOnly, BrushProxy brush, Matrix trans) { if (brush.Brush is SolidColorBrush) { SolidColorBrush sb = brush.Brush as SolidColorBrush; BlendUnderColor(Utility.Scale(sb.Color, brush.Opacity), 1, opacityOnly); } else { Byte[] brushPixels = RasterizeBrush(brush, trans); Decode(); Utility.BlendPixels(_pixels, opacityOnly, brushPixels, brush.OpacityOnly, _pixelWidth * _pixelHeight, _pixels); } } ////// Rasterize a brush into a bitmap /// /// Brush to rasterize /// ///Pbgra32 pixel byte array ////// Critical: CreateBrushImage is SecurityCritical because it calls internal PresentationCore function CriticalCopyPixels /// [SecurityCritical] private Byte[] RasterizeBrush(BrushProxy brush, Matrix trans) { return brush.CreateBrushImage(trans, _pixelWidth, _pixelHeight); } ////// Render a brush under current image /// /// /// /// ////// Critical: It calls into SecurityCritical function RasterizeBrush /// TreatAsSafe: Output will be in _pixels, which is marked as SecurityCritical /// [SecurityCritical, SecurityTreatAsSafe] public void BlendOverBrush(bool opacityOnly, BrushProxy brush, Matrix trans) { if (IsOpaque()) { Debug.Assert(!opacityOnly, "Opaque image OpacityMask should not be blended with brush"); return; } if (brush.Brush is SolidColorBrush) { SolidColorBrush sb = brush.Brush as SolidColorBrush; BlendOverColor(Utility.Scale(sb.Color, brush.Opacity), 1.0, opacityOnly); } else { Byte[] brushPixels = RasterizeBrush(brush, trans); Decode(); Utility.BlendPixels(brushPixels, brush.OpacityOnly, _pixels, opacityOnly, _pixelWidth * _pixelHeight, _pixels); } } internal static int HasAlpha(BitmapSource bitmap) { if (bitmap.Format.HasAlpha) { return 1; } if (bitmap.Format.Palettized) { BitmapPalette palette = bitmap.Palette; if (palette != null) { IListpalColor = palette.Colors; if (palColor != null) { foreach (Color c in palColor) { if (! Utility.IsOpaque(c.ScA)) { return 2; } } } } } return 0; } /// /// Critical : It touches critical data in _pixels /// TreatAsSafe: _pixels is read to return a Boolean value /// [SecurityCritical, SecurityTreatAsSafe] public bool IsOpaque() { if (_image == null) { return false; } if (_pixels == null) // Not decoded yet { int hasAlpha = HasAlpha(_image); if (hasAlpha == 2) { return false; } if (hasAlpha == 0) { return true; } } Decode(); int count = _pixelWidth * _pixelHeight; for (int i = 0; i < count; i++) { if (_pixels[i * 4 + 3] != 255) { return false; } } return true; } ////// Check if an image is totally transparent /// ////// /// Critical : It touches critical data in _pixels /// TreatAsSafe: _pixels is exam to return a Boolean flag /// [SecurityCritical, SecurityTreatAsSafe] public bool IsTransparent() { if (_image == null) { return true; } Decode(); int count = _pixelWidth * _pixelHeight * 4; // _pixels is in PBGRA format, check all channels for (int i = 0; i < count; i++) { if (_pixels[i] != 0) { return false; } } return true; } ////// Critical : Critical information in _pixels is exposed /// TreatAsSafe: Image is wrapped in a BitmapSource, which needs CopyPixels or CriticalCopyPixels to get out /// [SecurityCritical, SecurityTreatAsSafe] public BitmapSource GetImage() { if (_pixels == null) { return _image; } else if (_image != null) { return BitmapSource.Create(_pixelWidth, _pixelHeight, _image.DpiX, _image.DpiY, PixelFormats.Pbgra32, null, _pixels, _pixelWidth * 4); } else { return null; } } ////// Critical : Critical information in _pixels is exposed /// TreatAsSafe: Image is wrapped in a BitmapSource, which needs CopyPixels or CriticalCopyPixels to get out /// ////// Creates a BitmapSource that has image clipped to the specified bounds. /// /// Desired clipping bounds in image DPI /// Receives actual bounds to which image was clipped ////// clipBounds may be one of following: /// - Empty: Entire image was clipped. /// - Equal to original image size: No image clipping performed. /// - Other: Some clipping performed. /// /// Clipping is not always performed; see MaximumClipRatio. /// [SecurityCritical, SecurityTreatAsSafe] public BitmapSource GetClippedImage(Rect bounds, out Rect clipBounds) { BitmapSource result = null; // default to entire image clipped away clipBounds = Rect.Empty; // scale bounds according to image DPI double dpiScaleX = _image.DpiX / 96.0; double dpiScaleY = _image.DpiY / 96.0; if (Utility.IsZero(dpiScaleX)) dpiScaleX = 1; if (Utility.IsZero(dpiScaleY)) dpiScaleY = 1; bounds.Scale(dpiScaleX, dpiScaleY); bounds.Intersect(new Rect(0, 0, _pixelWidth, _pixelHeight)); double currentPixelCount = _pixelWidth * _pixelHeight; double clipPixelCount = bounds.Width * bounds.Height; if (currentPixelCount > 0) { if ((clipPixelCount / currentPixelCount) > MaximumClipRatio) { // Desired clip bounds not small enough to necessitate clipping image data. result = GetImage(); clipBounds = new Rect(0, 0, _pixelWidth, _pixelHeight); } else { // // Clipped rectangle significantly smaller than image size. Manually // clip image down to bounds. // // Fix bug 1494512: Round so that we try to get at least a pixel, otherwise // bounds < 1 pixel (which'll display a solid color) may get clipped away. // int x0 = (int)Math.Max(Math.Floor(bounds.Left), 0); int y0 = (int)Math.Max(Math.Floor(bounds.Top), 0); int x1 = (int)Math.Ceiling(bounds.Right); int y1 = (int)Math.Ceiling(bounds.Bottom); int width = x1 - x0; int height = y1 - y0; if (width > 0 && height > 0) { byte[] pixels; if (_pixels == null) { // not decoded yet, we perform clipping while decoding pixels = GetDecodedPixels(new Int32Rect(x0, y0, width, height)); } else { // clip previously decoded pixels pixels = Utility.ClipPixels(_pixels, _pixelWidth, _pixelHeight, x0, y0, width, height); } result = BitmapSource.Create( width, height, _image.DpiX, _image.DpiY, PixelFormats.Pbgra32, null, pixels, width * 4 ); clipBounds = bounds; } } } // unscale according to image DPI if (!clipBounds.IsEmpty) { clipBounds.Scale(1.0 / dpiScaleX, 1.0 / dpiScaleY); } return result; } public ImageProxy Clone() { return new ImageProxy(GetImage()); } } // end of ImageProxy class } // 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
- CodeIndexerExpression.cs
- DataGridViewImageColumn.cs
- Int64.cs
- DictionaryEntry.cs
- NavigateEvent.cs
- ReversePositionQuery.cs
- UnicastIPAddressInformationCollection.cs
- SimpleApplicationHost.cs
- ProgressBar.cs
- DataControlFieldCollection.cs
- StackSpiller.Bindings.cs
- XpsSerializerWriter.cs
- GenericXmlSecurityToken.cs
- webproxy.cs
- HelpProvider.cs
- SafeFileHandle.cs
- ChameleonKey.cs
- PipelineModuleStepContainer.cs
- SmiMetaData.cs
- PublisherIdentityPermission.cs
- CacheRequest.cs
- PrintEvent.cs
- SimpleLine.cs
- Rect3DValueSerializer.cs
- CodeDirectiveCollection.cs
- MimeParameterWriter.cs
- UserMapPath.cs
- DuplicateWaitObjectException.cs
- TemplatePropertyEntry.cs
- Registry.cs
- TreeNodeStyle.cs
- IpcClientManager.cs
- DefaultBinder.cs
- WebBaseEventKeyComparer.cs
- XmlElement.cs
- CqlLexerHelpers.cs
- ValueOfAction.cs
- TextRangeSerialization.cs
- ISFTagAndGuidCache.cs
- IntegerFacetDescriptionElement.cs
- RootDesignerSerializerAttribute.cs
- QuaternionAnimation.cs
- CookieProtection.cs
- MatrixKeyFrameCollection.cs
- Int32CAMarshaler.cs
- LifetimeServices.cs
- LayoutEditorPart.cs
- DocumentSchemaValidator.cs
- EmbeddedMailObjectsCollection.cs
- CssTextWriter.cs
- Effect.cs
- NativeWindow.cs
- UnionExpr.cs
- COM2Properties.cs
- WebPartCancelEventArgs.cs
- CSharpCodeProvider.cs
- TextEndOfParagraph.cs
- COAUTHIDENTITY.cs
- ApplicationGesture.cs
- ScrollContentPresenter.cs
- TrustLevelCollection.cs
- ResetableIterator.cs
- TextTreeTextNode.cs
- SiteMapDataSourceView.cs
- StylusPointProperties.cs
- TextRangeEditTables.cs
- LongAverageAggregationOperator.cs
- CollectionViewGroup.cs
- Dump.cs
- WinEventWrap.cs
- TreeSet.cs
- LocatorGroup.cs
- SelectionPattern.cs
- FileUtil.cs
- DateTimeUtil.cs
- MetaModel.cs
- ValidatorCollection.cs
- ComponentResourceManager.cs
- querybuilder.cs
- DataViewSetting.cs
- WindowsRebar.cs
- EndpointInfo.cs
- PermissionToken.cs
- WmlLabelAdapter.cs
- WorkflowDurableInstance.cs
- SecurityPolicySection.cs
- XmlHierarchicalEnumerable.cs
- ResourceDescriptionAttribute.cs
- ToolTipService.cs
- embossbitmapeffect.cs
- __Filters.cs
- Vector3DAnimation.cs
- TableCell.cs
- SocketInformation.cs
- UnsafePeerToPeerMethods.cs
- NameValueSectionHandler.cs
- ThemeDictionaryExtension.cs
- SmiEventStream.cs
- SessionStateItemCollection.cs
- RequestCacheValidator.cs