/// <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 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 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)); } }
/// <summary> /// Initializes a MetricEntry based on StylusPointPropertyInfo and default StylusPointPropertyInfo for the property /// </summary> /// <param name="originalInfo"></param> /// <param name="defaultInfo"></param> /// <returns></returns> public void Initialize(StylusPointPropertyInfo originalInfo, StylusPointPropertyInfo defaultInfo) { _size = 0; using (MemoryStream strm = new MemoryStream(_data)) { if (!DoubleUtil.AreClose(originalInfo.Resolution, defaultInfo.Resolution)) { // First min value _size += SerializationHelper.SignEncode(strm, originalInfo.Minimum); // Max value _size += SerializationHelper.SignEncode(strm, originalInfo.Maximum); // Units _size += SerializationHelper.Encode(strm, (uint)originalInfo.Unit); // resolution using (BinaryWriter bw = new BinaryWriter(strm)) { bw.Write(originalInfo.Resolution); _size += 4; // sizeof(float) } } else if (originalInfo.Unit != defaultInfo.Unit) { // First min value _size += SerializationHelper.SignEncode(strm, originalInfo.Minimum); // Max value _size += SerializationHelper.SignEncode(strm, originalInfo.Maximum); // Units _size += SerializationHelper.Encode(strm, (uint)originalInfo.Unit); } else if (originalInfo.Maximum != defaultInfo.Maximum) { // First min value _size += SerializationHelper.SignEncode(strm, originalInfo.Minimum); // Max value _size += SerializationHelper.SignEncode(strm, originalInfo.Maximum); } else if (originalInfo.Minimum != defaultInfo.Minimum) { _size += SerializationHelper.SignEncode(strm, originalInfo.Minimum); } } }
/// <summary> /// This function Packs the data in the buffer provided. The /// function is being called during the save loop and caller /// must call GetSize for the block before calling this function. /// The buffer must be preallocated and buffer size must be at /// least the size of the block. /// On return cbBuffer contains the size of the data written. /// Called only by BuildMetricTable funtion /// </summary> /// <param name="strm"></param> /// <returns></returns> public uint Pack(Stream strm) { // Write the size of the Block at the begining of the buffer. // But first check the validity of the buffer & its size uint cbWrite = 0; // First write the size of the block cbWrite = SerializationHelper.Encode(strm, _size); // Now write each entry for the block MetricEntry entry = _Entry; while (null != entry) { cbWrite += SerializationHelper.Encode(strm, (uint)entry.Tag); cbWrite += SerializationHelper.Encode(strm, entry.Size); strm.Write(entry.Data, 0, (int)entry.Size); cbWrite += entry.Size; entry = entry.Next; } return(cbWrite); }
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> /// Serializes the GuidList in the memory stream and returns the size /// </summary> /// <param name="stream">If null, calculates the size only</param> /// <returns></returns> public uint Save(Stream stream) { // calculate the number of custom guids to persist // custom guids are those which are not reserved in ISF via 'tags' uint ul = (uint)(_CustomGuids.Count * Native.SizeOfGuid); // if there are no custom guids, then the guid list can be persisted // without any cost ('tags' are freely storeable) if (ul == 0) { return(0); } // if only the size was requested, return it if (null == stream) { return((uint)(ul + SerializationHelper.VarSize(ul) + SerializationHelper.VarSize((uint)KnownTagCache.KnownTagIndex.GuidTable))); } // encode the guid table tag in the output stream uint cbWrote = SerializationHelper.Encode(stream, (uint)KnownTagCache.KnownTagIndex.GuidTable); // encode the size of the guid table cbWrote += SerializationHelper.Encode(stream, ul); // encode each guid in the table for (int i = 0; i < _CustomGuids.Count; i++) { Guid guid = (Guid)_CustomGuids[i]; stream.Write(guid.ToByteArray(), 0, (int)Native.SizeOfGuid); } cbWrote += ul; return(cbWrote); }
/// <summary> /// Saves the packets into a stream of bytes /// </summary> /// <param name="stroke">Stroke to save</param> /// <param name="stream">null to calculate size only</param> /// <param name="compressor"></param> /// <param name="strokeLookupEntry"></param> /// <returns></returns> #else /// <summary> /// Saves the packets into a stream of bytes /// </summary> /// <param name="stroke">Stroke to save</param> /// <param name="stream">null to calculate size only</param> /// <param name="strokeLookupEntry"></param> #endif static uint SavePackets( Stroke stroke, Stream stream, #if OLD_ISF Compressor compressor, #endif StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry) { // First write or calculate how many points are there uint pointCount = (uint)stroke.StylusPoints.Count; uint localBytesWritten = (stream != null) ? SerializationHelper.Encode(stream, pointCount) : SerializationHelper.VarSize(pointCount); byte compressionAlgorithm; int[][] outputArrays = strokeLookupEntry.ISFReadyStrokeData; //We don't serialize button data //int valuesPerPoint = stroke.StylusPoints.Description.GetOutputArrayLengthPerPoint(); //int buttonCount = stroke.StylusPoints.Description.ButtonCount; ReadOnlyCollection <StylusPointPropertyInfo> propertyInfos = stroke.StylusPoints.Description.GetStylusPointProperties(); int i = 0; for (; i < propertyInfos.Count; i++) { StylusPointPropertyInfo propertyInfo = propertyInfos[i]; if (i == 2 && !strokeLookupEntry.StorePressure) { // // only store pressure if we need to // continue; } if (propertyInfo.IsButton) { // // we're at the buttons, handle this below // break; } compressionAlgorithm = strokeLookupEntry.CompressionData; localBytesWritten += SavePacketPropertyData(outputArrays[i], stream, #if OLD_ISF compressor, #endif propertyInfo.Id, ref compressionAlgorithm); } /* * We don't serialize button data * // Now write all button data. Button data is stored as if it is another packet property * // with size (cbuttoncount + 7)/8 bytes and corresponding guids are stored in the packet * // description. Button data is only stored if buttons are present in the description and there * // are packets in the stroke * if (buttonCount > 0 && pointCount > 0) * { * Debug.Assert(i == valuesPerPoint - 1); * BitStreamWriter bitWriter = new BitStreamWriter(); * // * // Get the array of button data (i is still pointing at it) * // * int[] buttonData = outputArrays[i]; * * for (int x = 0; x < pointCount; x++) * { * // * // each int in the button data array contains buttonCount number * // of bits that need to be written to the BitStreamWriter * // the BitStreamWriter takes bytes at a time. We always write the most * // signifigant bits first * // * int uncompactedButtonDataForPoint = buttonData[x]; * * // calculate the number of full bytes used for buttons per packet * // Example: 10 buttons would require 1 full byte * // but 8 would require * int fullBytesForButtonsPerPacket = buttonCount / Native.BitsPerByte; * * // calculate the number of bits that spill beyond the full byte boundary * // Example: 10 buttons would require 2 extra bits (8 fit in a full byte) * int bitsToWrite = buttonCount % Native.BitsPerByte; * * for (; fullBytesForButtonsPerPacket >= 0; fullBytesForButtonsPerPacket--) * { * byte byteOfButtonData = * Convert.ToByte(uncompactedButtonDataForPoint >> (fullBytesForButtonsPerPacket * Native.BitsPerByte)); * // * // write 8 or less bytes to the bitwriter * // checking for 0 handles the case where we're writing 8, 16 or 24 bytes * // and bitsToWrite is initialize to zero * // * if (bitsToWrite > 0) * { * bitWriter.Write(byteOfButtonData, bitsToWrite); * } * if (fullBytesForButtonsPerPacket > 0) * { * bitsToWrite = Native.BitsPerByte; * } * } * } * * // retrieve the button bytes * byte[] packedButtonData = bitWriter.ToBytes(); * * if (packedButtonData.Length != * ((buttonCount * pointCount + 7) / Native.BitsPerByte)) * { * throw new ArgumentException(StrokeCollectionSerializer.ISFDebugMessage("Packed button length not equal to expected length")); * } * * // write out the packed button data to the output stream * stream.Write(packedButtonData, 0, packedButtonData.Length); * localBytesWritten += (uint)packedButtonData.Length; * } */ return(localBytesWritten); }
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 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); }