/// <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> /// 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, see Windows OS Bugs 1413460 for details //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, see Windows OS Bugs 1413460 for details // 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; }
/// <summary> /// Returns an array of bytes of the saved stroke /// </summary> /// <param name="stroke">Stroke to save</param> /// <param name="stream">null to calculate only the size</param> /// <param name="compressionAlgorithm"></param> /// <param name="guidList"></param> /// <param name="strokeLookupEntry"></param> #endif internal static uint EncodeStroke( Stroke stroke, Stream stream, #if OLD_ISF Compressor compressor, #endif byte compressionAlgorithm, GuidList guidList, StrokeCollectionSerializer.StrokeLookupEntry strokeLookupEntry) { uint cbWrite = SavePackets( stroke, stream, #if OLD_ISF compressor, #endif strokeLookupEntry); if (stroke.ExtendedProperties.Count > 0) cbWrite += ExtendedPropertySerializer.EncodeAsISF(stroke.ExtendedProperties, stream, guidList, compressionAlgorithm, false); return cbWrite; }