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)
{
IList palColor = 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
- EventListener.cs
- SqlRecordBuffer.cs
- NativeMethods.cs
- BitmapEffectDrawingContextWalker.cs
- Query.cs
- DefaultValueAttribute.cs
- WebResponse.cs
- CredentialCache.cs
- DefaultAutoFieldGenerator.cs
- TripleDES.cs
- CriticalHandle.cs
- RefType.cs
- ThemeableAttribute.cs
- EditorZoneBase.cs
- _NegoStream.cs
- Parser.cs
- XmlQueryTypeFactory.cs
- SharedStatics.cs
- WindowsRichEditRange.cs
- CompareValidator.cs
- StateMachineWorkflowInstance.cs
- FloaterParaClient.cs
- XmlCharType.cs
- PersistChildrenAttribute.cs
- TrustLevel.cs
- InputManager.cs
- MetaForeignKeyColumn.cs
- Config.cs
- HtmlInputButton.cs
- PipelineModuleStepContainer.cs
- Parameter.cs
- DesignerRegionMouseEventArgs.cs
- StylusTip.cs
- HttpBrowserCapabilitiesWrapper.cs
- BaseTemplateBuildProvider.cs
- DetailsViewRowCollection.cs
- BorderSidesEditor.cs
- WindowsAuthenticationModule.cs
- GroupStyle.cs
- KeyFrames.cs
- SimpleMailWebEventProvider.cs
- StringConverter.cs
- TextControl.cs
- InternalRelationshipCollection.cs
- UdpRetransmissionSettings.cs
- GridViewRowCollection.cs
- SmtpDigestAuthenticationModule.cs
- webproxy.cs
- ZipIOCentralDirectoryFileHeader.cs
- CatalogZoneBase.cs
- CallTemplateAction.cs
- DataGridViewColumnEventArgs.cs
- ProfileService.cs
- SplitterEvent.cs
- DropShadowBitmapEffect.cs
- ImageFormatConverter.cs
- ChangeInterceptorAttribute.cs
- MenuAutoFormat.cs
- TypefaceMetricsCache.cs
- CacheManager.cs
- CancellableEnumerable.cs
- SQLInt64Storage.cs
- BuildProviderAppliesToAttribute.cs
- ConfigurationProperty.cs
- MenuAutoFormat.cs
- TaskFileService.cs
- Filter.cs
- HealthMonitoringSectionHelper.cs
- Brush.cs
- PropertyCollection.cs
- XPathNavigatorReader.cs
- TemplateBuilder.cs
- DataGridViewLinkColumn.cs
- TypeConverter.cs
- CodeGen.cs
- SplitterEvent.cs
- Ref.cs
- ToolTipService.cs
- PanelStyle.cs
- TraceContext.cs
- SqlConnectionManager.cs
- PeerTransportCredentialType.cs
- UpDownBaseDesigner.cs
- UIElementPropertyUndoUnit.cs
- Converter.cs
- PrintPreviewControl.cs
- LicenseProviderAttribute.cs
- ProjectedSlot.cs
- StylusCaptureWithinProperty.cs
- FilterableData.cs
- SiteMapNodeItem.cs
- PasswordTextContainer.cs
- WebPartDescriptionCollection.cs
- ModelPropertyCollectionImpl.cs
- MenuAutoFormat.cs
- SecurityTokenValidationException.cs
- LinkedResourceCollection.cs
- ResourcePermissionBase.cs
- ObjectListComponentEditor.cs
- Page.cs