private static void PersistColorAndTransparency(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // if the color is non-default (e.g. not black), then store it // the v1 encoder throws away the default color (Black) so it isn't valuable // to save. if (da.ContainsPropertyData(KnownIds.Color)) { Color daColor = da.Color; System.Diagnostics.Debug.Assert(da.Color != (Color)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.Color), "Color was put in the EPC for the default value!"); //Note: we don't store the alpha value of the color (we don't use it) uint r = (uint)daColor.R, g = (uint)daColor.G, b = (uint)(daColor.B); uint colorVal = r + (g << Native.BitsPerByte) + (b << (Native.BitsPerByte * 2)); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Color, true)); cbData += SerializationHelper.Encode(stream, colorVal); } //set transparency if Color.A is set byte alphaChannel = da.Color.A; if (alphaChannel != 255) { //note: Color.A is set to 255 by default, which means fully opaque //transparency is just the opposite - 0 means fully opaque so //we need to flip the values int transparency = MathHelper.AbsNoThrow(((int)alphaChannel) - 255); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Transparency, true)); cbData += SerializationHelper.Encode(stream, Convert.ToUInt32(transparency)); } }
/// <Summary> /// Encodes the StylusTip in the ISF stream. /// </Summary> #else /// <Summary> /// Encodes the StylusTip in the ISF stream. /// </Summary> #endif private static void PersistStylusTip(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // // persist the StylusTip // if (da.ContainsPropertyData(KnownIds.StylusTip)) { System.Diagnostics.Debug.Assert(da.StylusTip != StylusTip.Ellipse, "StylusTip was put in the EPC for the default value!"); // // persist PenTip.Rectangle for V1 ISF // Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.PenTip, true)); cbData += SerializationHelper.Encode(stream, (uint)PenTip.Rectangle); using (MemoryStream localStream = new MemoryStream(6)) //reasonable default { Int32 stylusTip = Convert.ToInt32(da.StylusTip, System.Globalization.CultureInfo.InvariantCulture); System.Runtime.InteropServices.VarEnum type = SerializationHelper.ConvertToVarEnum(PersistenceTypes.StylusTip, true); ExtendedPropertySerializer.EncodeAttribute(KnownIds.StylusTip, stylusTip, type, localStream); cbData += ExtendedPropertySerializer.EncodeAsISF(KnownIds.StylusTip, localStream.ToArray(), stream, guidList, 0, true); } } }
private static void PersistDrawingFlags(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // // always serialize DrawingFlags, even when it is the default of AntiAliased. V1 loaders // expect it. // Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.DrawingFlags, true)); cbData += SerializationHelper.Encode(stream, (uint)(int)da.DrawingFlags); if (da.ContainsPropertyData(KnownIds.CurveFittingError)) { Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.CurveFittingError, true)); cbData += SerializationHelper.Encode(stream, (uint)(int)da.GetPropertyData(KnownIds.CurveFittingError)); } }
private static void PersistRasterOperation(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // write any non-default RasterOp value that we might have picked up from // V1 interop or by setting IsHighlighter. if (da.RasterOperation != DrawingAttributeSerializer.RasterOperationDefaultV1) { uint ropSize = GuidList.GetDataSizeIfKnownGuid(KnownIds.RasterOperation); if (ropSize == 0) { throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data size was not found")); } Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.RasterOperation, true)); long currentPosition = stream.Position; bw.Write(da.RasterOperation); if ((uint)(stream.Position - currentPosition) != ropSize) { throw new InvalidOperationException(StrokeCollectionSerializer.ISFDebugMessage("ROP data was incorrectly serialized")); } cbData += ropSize; } }
/// <summary> /// Builds the Stroke Descriptor for this stroke based on Packet Layout and Extended Properties /// For details on how this is strored please refer to the spec. /// </summary> internal static void BuildStrokeDescriptor( Stroke stroke, GuidList guidList, StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry, out StrokeDescriptor strokeDescriptor, out MetricBlock metricBlock) { // Initialize the metric block for this stroke metricBlock = new MetricBlock(); // Clear any existing template strokeDescriptor = new StrokeDescriptor(); // Uninitialized variable passed in AddMetricEntry MetricEntryType metricEntryType; StylusPointDescription stylusPointDescription = stroke.StylusPoints.Description; KnownTagCache.KnownTagIndex tag = guidList.FindTag(KnownIds.X, true); metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.X), tag); tag = guidList.FindTag(KnownIds.Y, true); metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.Y), tag); ReadOnlyCollection <StylusPointPropertyInfo> propertyInfos = stylusPointDescription.GetStylusPointProperties(); int i = 0; //i is defined out of the for loop so we can use it later for buttons for (i = 2 /*past x,y*/; i < propertyInfos.Count; i++) { if (i == /*StylusPointDescription.RequiredPressureIndex //修复构建的代码 */ 2 && !strokeLookupEntry.StorePressure) { // // don't store pressure information // continue; } StylusPointPropertyInfo propertyInfo = propertyInfos[i]; if (propertyInfo.IsButton) { //we don't serialize buttons break; } tag = guidList.FindTag(propertyInfo.Id, true); strokeDescriptor.Template.Add(tag); strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); // Create the MetricEntry for this property if necessary metricEntryType = metricBlock.AddMetricEntry(propertyInfo, tag); } /* * we drop button data on the floor. * int buttonCount = stylusPointDescription.ButtonCount; * // Now write the button tags in the Template * if (buttonCount > 0) * { * // First write the TAG_BUTTONS * strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.Buttons); * strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.Buttons); * * // Next write the i of buttons * strokeDescriptor.Template.Add((KnownTagCache.KnownTagIndex)buttonCount); * strokeDescriptor.Size += SerializationHelper.VarSize((uint)buttonCount); * * //we broke above on i when it was a button, it still * //points to the first button * for (; i < propertyInfos.Count; i++) * { * StylusPointPropertyInfo propertyInfo = propertyInfos[i]; * tag = guidList.FindTag(propertyInfo.Id, false); * * strokeDescriptor.Template.Add(tag); * strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); * } * } */ // Now write the extended properties in the template if (stroke.ExtendedProperties.Count > 0) { strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.StrokePropertyList); strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.StrokePropertyList); // Now write the tags corresponding to each extended properties of the stroke for (int x = 0; x < stroke.ExtendedProperties.Count; x++) { tag = guidList.FindTag(stroke.ExtendedProperties[(int)x].Id, false); strokeDescriptor.Template.Add(tag); strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); } } }
/// <summary> /// Encodes a custom attribute to the ISF stream /// </summary> #endif internal static uint EncodeAsISF(Guid id, byte[] data, Stream strm, GuidList guidList, byte compressionAlgorithm, bool fTag) { uint cbWrite = 0; uint cbSize = GuidList.GetDataSizeIfKnownGuid(id); Debug.Assert(strm != null); if (fTag) { uint uTag = (uint)guidList.FindTag(id, true); cbWrite += SerializationHelper.Encode(strm, uTag); } // If cbSize is 0, it is either a custom property or a known property with 0 // size. In either case, we need to write the size of the individual object if (0 == cbSize) { // Now we need to write the actual data for the property cbSize = (uint)data.Length; byte[] compresseddata = Compressor.CompressPropertyData(data, compressionAlgorithm); #if OLD_ISF byte nAlgo = compressionAlgorithm; uint cbOut = 0; Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, null); // Allocate a buffer big enough to hold the compressed data byte[] compresseddata2 = new byte[cbOut]; // NativeCompressor the data Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, compresseddata2); if (compresseddata.Length != compresseddata2.Length) { throw new InvalidOperationException("MAGIC EXCEPTION: Property bytes length when compressed didn't match with new compression"); } for (int i = 0; i < compresseddata.Length; i++) { if (compresseddata[i] != compresseddata2[i]) { throw new InvalidOperationException("MAGIC EXCEPTION: Property data didn't match with new property compression at index " + i.ToString()); } } #endif // write the encoded compressed size minus the algo byte cbWrite += SerializationHelper.Encode(strm, (uint)(compresseddata.Length - 1)); // Write the raw data strm.Write(compresseddata, 0, (int)compresseddata.Length); cbWrite += (uint)compresseddata.Length; } else { // // note that we used to write the nocompression byte, but that // was incorrect. We must not write it because loaders do not // expect it for known guids // // write the algo byte //strm.WriteByte(Compressor.NoCompression); //cbWrite++; // write the raw data without compression strm.Write(data, 0, (int)data.Length); cbWrite += (uint)data.Length; } return cbWrite; }
private static void PersistWidthHeight(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { //persist the height and width // For v1 loaders we persist height and width in StylusHeight and StylusWidth double stylusWidth = da.Width; double stylusHeight = da.Height; // Save the pen tip's width and height. for (int i = 0; i < 2; i++) { Guid guid = (i == 0) ? KnownIds.StylusWidth : KnownIds.StylusHeight; double size = (0 == i) ? stylusWidth : stylusHeight; // // the size is now in Avalon units, we need to convert to HIMETRIC // size *= StrokeCollectionSerializer.AvalonToHimetricMultiplier; double sizeWhenMissing = (0 == i) ? V1PenWidthWhenWidthIsMissing : V1PenHeightWhenHeightIsMissing; // // only persist height / width if they are equal to the height / width // when missing in the isf stream OR for compatibility with V1 // bool skipPersisting = DoubleUtil.AreClose(size, sizeWhenMissing); if ( stylusWidth == stylusHeight && da.StylusTip == StylusTip.Ellipse && guid == KnownIds.StylusHeight && da.HeightChangedForCompatabity) { //we need to put height in the ISF stream for compat skipPersisting = true; } if (!skipPersisting) { uint uIntegral = (uint)(size + 0.5f); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(guid, true)); cbData += SerializationHelper.Encode(stream, uIntegral); short sFraction = (size > uIntegral) ? (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) + 0.5f) : (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) - 0.5); // If the fractional values is non zero, we store this value along with TAG_MANTISSA and size with a precisson of 1000 if (0 != sFraction) { uint cb = Native.SizeOfUShort; // For header NO_COMPRESS Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Mantissa); cbData += SerializationHelper.Encode(stream, cb); bw.Write((byte)0x00); bw.Write((short)sFraction); cbData += cb + 1; // include size of encoded 0 and encoded fraction value } } } }
/// <Summary> /// Encodes the StylusTip in the ISF stream. /// </Summary> #endif private static void PersistStylusTip(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // // persist the StylusTip // if (da.ContainsPropertyData(KnownIds.StylusTip)) { System.Diagnostics.Debug.Assert(da.StylusTip != StylusTip.Ellipse, "StylusTip was put in the EPC for the default value!"); // // persist PenTip.Rectangle for V1 ISF // Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.PenTip, true)); cbData += SerializationHelper.Encode(stream, (uint)PenTip.Rectangle); using (MemoryStream localStream = new MemoryStream(6)) //reasonable default { Int32 stylusTip = Convert.ToInt32(da.StylusTip, System.Globalization.CultureInfo.InvariantCulture); System.Runtime.InteropServices.VarEnum type = SerializationHelper.ConvertToVarEnum(PersistenceTypes.StylusTip, true); ExtendedPropertySerializer.EncodeAttribute(KnownIds.StylusTip, stylusTip, type, localStream); cbData += ExtendedPropertySerializer.EncodeAsISF(KnownIds.StylusTip, localStream.ToArray(), stream, guidList, 0, true); } } }
private static void PersistColorAndTransparency(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { // if the color is non-default (e.g. not black), then store it // the v1 encoder throws away the default color (Black) so it isn't valuable // to save. if (da.ContainsPropertyData(KnownIds.Color)) { Color daColor = da.Color; System.Diagnostics.Debug.Assert(da.Color != (Color)DrawingAttributes.GetDefaultDrawingAttributeValue(KnownIds.Color), "Color was put in the EPC for the default value!"); //Note: we don't store the alpha value of the color (we don't use it) uint r = (uint)daColor.R, g = (uint)daColor.G, b = (uint)(daColor.B); uint colorVal = r + (g << Native.BitsPerByte) + (b << (Native.BitsPerByte * 2)); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Color, true)); cbData += SerializationHelper.Encode(stream, colorVal); } //set transparency if Color.A is set byte alphaChannel = da.Color.A; if (alphaChannel != 255) { //note: Color.A is set to 255 by default, which means fully opaque //transparency is just the opposite - 0 means fully opaque so //we need to flip the values int transparency = MathHelper.AbsNoThrow(( (int)alphaChannel ) - 255); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(KnownIds.Transparency, true)); cbData += SerializationHelper.Encode(stream, Convert.ToUInt32(transparency)); } }
private static void PersistWidthHeight(DrawingAttributes da, Stream stream, GuidList guidList, ref uint cbData, ref BinaryWriter bw) { //persist the height and width // For v1 loaders we persist height and width in StylusHeight and StylusWidth double stylusWidth = da.Width; double stylusHeight = da.Height; // Save the pen tip's width and height. for (int i = 0; i < 2; i++) { Guid guid = (i == 0) ? KnownIds.StylusWidth : KnownIds.StylusHeight; double size = (0 == i) ? stylusWidth : stylusHeight; // // the size is now in Avalon units, we need to convert to HIMETRIC // size *= StrokeCollectionSerializer.AvalonToHimetricMultiplier; double sizeWhenMissing = (0 == i) ? V1PenWidthWhenWidthIsMissing : V1PenHeightWhenHeightIsMissing; // // only persist height / width if they are equal to the height / width // when missing in the isf stream OR for compatibility with V1 // bool skipPersisting = DoubleUtil.AreClose(size, sizeWhenMissing); if (stylusWidth == stylusHeight && da.StylusTip == StylusTip.Ellipse && guid == KnownIds.StylusHeight && da.HeightChangedForCompatabity) { //we need to put height in the ISF stream for compat skipPersisting = true; } if (!skipPersisting) { uint uIntegral = (uint)(size + 0.5f); Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)guidList.FindTag(guid, true)); cbData += SerializationHelper.Encode(stream, uIntegral); short sFraction = (size > uIntegral) ? (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) + 0.5f) : (short)(DrawingAttributes.StylusPrecision * (size - uIntegral) - 0.5); // If the fractional values is non zero, we store this value along with TAG_MANTISSA and size with a precisson of 1000 if (0 != sFraction) { uint cb = Native.SizeOfUShort; // For header NO_COMPRESS Debug.Assert(bw != null); cbData += SerializationHelper.Encode(stream, (uint)MS.Internal.Ink.InkSerializedFormat.KnownTagCache.KnownTagIndex.Mantissa); cbData += SerializationHelper.Encode(stream, cb); bw.Write((byte)0x00); bw.Write((short)sFraction); cbData += cb + 1; // include size of encoded 0 and encoded fraction value } } } }
/// <summary> /// Builds the Stroke Descriptor for this stroke based on Packet Layout and Extended Properties /// For details on how this is strored please refer to the spec. /// </summary> internal static void BuildStrokeDescriptor( Stroke stroke, GuidList guidList, StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry, out StrokeDescriptor strokeDescriptor, out MetricBlock metricBlock) { // Initialize the metric block for this stroke metricBlock = new MetricBlock(); // Clear any existing template strokeDescriptor = new StrokeDescriptor(); // Uninitialized variable passed in AddMetricEntry MetricEntryType metricEntryType; StylusPointDescription stylusPointDescription = stroke.StylusPoints.Description; KnownTagCache.KnownTagIndex tag = guidList.FindTag(KnownIds.X, true); metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.X), tag); tag = guidList.FindTag(KnownIds.Y, true); metricEntryType = metricBlock.AddMetricEntry(stylusPointDescription.GetPropertyInfo(StylusPointProperties.Y), tag); ReadOnlyCollection<StylusPointPropertyInfo> propertyInfos = stylusPointDescription.GetStylusPointProperties(); int i = 0; //i is defined out of the for loop so we can use it later for buttons for (i = 2/*past x,y*/; i < propertyInfos.Count; i++) { if (i == StylusPointDescription.RequiredPressureIndex/*2*/ && !strokeLookupEntry.StorePressure) { // // don't store pressure information // continue; } StylusPointPropertyInfo propertyInfo = propertyInfos[i]; if (propertyInfo.IsButton) { //we don't serialize buttons break; } tag = guidList.FindTag(propertyInfo.Id, true); strokeDescriptor.Template.Add(tag); strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); // Create the MetricEntry for this property if necessary metricEntryType = metricBlock.AddMetricEntry(propertyInfo, tag); } /* we drop button data on the floor. See Windows OS Bugs 1413460 for details int buttonCount = stylusPointDescription.ButtonCount; // Now write the button tags in the Template if (buttonCount > 0) { // First write the TAG_BUTTONS strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.Buttons); strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.Buttons); // Next write the i of buttons strokeDescriptor.Template.Add((KnownTagCache.KnownTagIndex)buttonCount); strokeDescriptor.Size += SerializationHelper.VarSize((uint)buttonCount); //we broke above on i when it was a button, it still //points to the first button for (; i < propertyInfos.Count; i++) { StylusPointPropertyInfo propertyInfo = propertyInfos[i]; tag = guidList.FindTag(propertyInfo.Id, false); strokeDescriptor.Template.Add(tag); strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); } } */ // Now write the extended properties in the template if (stroke.ExtendedProperties.Count > 0) { strokeDescriptor.Template.Add(KnownTagCache.KnownTagIndex.StrokePropertyList); strokeDescriptor.Size += SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.StrokePropertyList); // Now write the tags corresponding to each extended properties of the stroke for (int x = 0; x < stroke.ExtendedProperties.Count; x++) { tag = guidList.FindTag(stroke.ExtendedProperties[(int)x].Id, false); strokeDescriptor.Template.Add(tag); strokeDescriptor.Size += SerializationHelper.VarSize((uint)tag); } } }
/// <summary> /// Encodes a custom attribute to the ISF stream /// </summary> #endif internal static uint EncodeAsISF(Guid id, byte[] data, Stream strm, GuidList guidList, byte compressionAlgorithm, bool fTag) { uint cbWrite = 0; uint cbSize = GuidList.GetDataSizeIfKnownGuid(id); Debug.Assert(strm != null); if (fTag) { uint uTag = (uint)guidList.FindTag(id, true); cbWrite += SerializationHelper.Encode(strm, uTag); } // If cbSize is 0, it is either a custom property or a known property with 0 // size. In either case, we need to write the size of the individual object if (0 == cbSize) { // Now we need to write the actual data for the property cbSize = (uint)data.Length; byte[] compresseddata = Compressor.CompressPropertyData(data, compressionAlgorithm); #if OLD_ISF byte nAlgo = compressionAlgorithm; uint cbOut = 0; Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, null); // Allocate a buffer big enough to hold the compressed data byte[] compresseddata2 = new byte[cbOut]; // NativeCompressor the data Compressor.CompressPropertyData(data, ref nAlgo, ref cbOut, compresseddata2); if (compresseddata.Length != compresseddata2.Length) { throw new InvalidOperationException("MAGIC EXCEPTION: Property bytes length when compressed didn't match with new compression"); } for (int i = 0; i < compresseddata.Length; i++) { if (compresseddata[i] != compresseddata2[i]) { throw new InvalidOperationException("MAGIC EXCEPTION: Property data didn't match with new property compression at index " + i.ToString()); } } #endif // write the encoded compressed size minus the algo byte cbWrite += SerializationHelper.Encode(strm, (uint)(compresseddata.Length - 1)); // Write the raw data strm.Write(compresseddata, 0, (int)compresseddata.Length); cbWrite += (uint)compresseddata.Length; } else { // // note that we used to write the nocompression byte, but that // was incorrect. We must not write it because loaders do not // expect it for known guids // // write the algo byte //strm.WriteByte(Compressor.NoCompression); //cbWrite++; // write the raw data without compression strm.Write(data, 0, (int)data.Length); cbWrite += (uint)data.Length; } return(cbWrite); }