/// <summary> /// return a list of rtDrawStroke messages if ink has been cached for this slide, else null. /// The expectation is that the toc entry for slideId does exist before this is called. /// </summary> /// <param name="slideId"></param> private List <object> getCachedStrokes(Guid slideId) { List <object> outputMessages = null; TableOfContents.TocEntry tocEntry = toc.LookupBySlideId(slideId); if (tocEntry == null) { Debug.WriteLine("Warning: getCachedStrokes failed to find TOC entry."); return(null); } if (this.pendingInk.ContainsKey(slideId)) { foreach (Ink ink in pendingInk[slideId]) { if (ink.Strokes.Count <= 0) { continue; } Guid strokeId = Guid.NewGuid(); //Pull out the identifier which is used if we need to delete the stroke later: if (ink.Strokes[0].ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) { strokeId = new Guid((string)ink.Strokes[0].ExtendedProperties[StrokeIdExtendedProperty].Data); } else { Debug.WriteLine("Warning: Failed to find stroke Id."); } //WebViewer looks for the CP2 extended property, so add it too. ink.Strokes[0].ExtendedProperties.Add(CP2StrokeIdExtendedProperty, (object)strokeId.ToString()); //WebViewer wants ink to be scaled to 500x500 ink.Strokes.Scale(500f / getCurrentSlideWidth(), 500f / getCurrentSlideHeight()); RTDrawStroke rtds = new RTDrawStroke(ink, strokeId, true, tocEntry.DeckId, tocEntry.SlideIndex); //Add the stroke to our list to optimize deletes if (!strokeCountsBySlideId.ContainsKey(slideId)) { strokeCountsBySlideId.Add(slideId, 1); } else { strokeCountsBySlideId[slideId]++; } if (outputMessages == null) { outputMessages = new List <object>(); } outputMessages.Add(rtds); Debug.WriteLine("***** getCachedStrokes:Adding Stroke ID=" + strokeId.ToString()); } pendingInk.Remove(slideId); } return(outputMessages); }
/// <summary> /// Translate real-time ink packets to a stroke and return RTStrokeAdded. /// </summary> /// <param name="rtispm"></param> /// <returns></returns> internal object AddRealTimeInkSheetPackets(UW.ClassroomPresenter.Network.Messages.Presentation.RealTimeInkSheetPacketsMessage rtispm) { //Resolve the sheetId to a slideId, and use it to look up a TOC entry. if (!sheetToSlideLookup.ContainsKey(rtispm.TargetId)) { if (this.currentSlideId.Equals(Guid.Empty)) { warning += "Warning: found real-time ink on an unknown sheet. Ignoring the ink. "; return(null); } //Can we assume current slide?? Probably.. sheetToSlideLookup.Add(rtispm.TargetId, currentSlideId); } TableOfContents.TocEntry tocEntry = toc.LookupBySlideId((Guid)sheetToSlideLookup[rtispm.TargetId]); if (tocEntry == null) { warning += "Warning: Failed to find a TOC entry for a slide when applying real-time ink. Ignoring the ink. "; return(null); } //Tablet Properties should have been received in a StylusDown message. if (previousTabletProperties == null) { warning += "Warning: Received real-time ink without tablet properties. Ignoring the ink. "; return(null); } //Debug.WriteLine("***** Realtime Ink packets StrokeID=" + rtispm.StrokeId.ToString() + "; stylusId=" + rtispm.StylusId.ToString()); // Verify that the stroke we're about to render matches the StrokeId // from the most recent StylusDown event. (If not, then something // probably got lost over the network.) if (this.previousRealTimeStroke != rtispm.StrokeId) { previousRealTimeStroke = rtispm.StrokeId; previousRealTimePackets = new int[] { }; } // Get the DrawingAttributes which were in effect on StylusDown. We should have received this in a // RealTimeInkSheetInformationMessage previously. if (!this.sheetToDrawingAttributesLookup.ContainsKey(rtispm.TargetId)) { //Note: this seems to happen all the time, but I don't notice any ill effects. Ignore the ink but leave out the warning. //this.warning += "Warning: Real-time ink was found that lacks DrawingAttributes. The ink will be ignored. "; return(null); } DrawingAttributes atts = (DrawingAttributes)this.sheetToDrawingAttributesLookup[rtispm.TargetId]; // Ink packets for this stroke so far. Initial packets should have been received in the Stylus Down message. if (this.previousRealTimePackets == null) { this.warning += "Warning: Failed to find previous real-time ink packets. The ink will be ignored. "; return(null); } // Assemble the completed information we'll need to create the mini-stroke. int[] combinedPackets = new int[this.previousRealTimePackets.Length + rtispm.Packets.Length]; this.previousRealTimePackets.CopyTo(combinedPackets, 0); rtispm.Packets.CopyTo(combinedPackets, this.previousRealTimePackets.Length); // Store the new data. this.previousRealTimePackets = combinedPackets; // Now that we have the data, we're ready to create the temporary stroke. Ink ink = new Ink(); Stroke stroke = ink.CreateStroke(combinedPackets, previousTabletProperties); stroke.DrawingAttributes = atts; //Look up the data for this stroke, or assign a new Guid if needed. RTStrokeData rtsData; if (!realTimeStrokesPending.TryGetValue(rtispm.StrokeId, out rtsData)) { rtsData = new RTStrokeData(Guid.NewGuid(), tocEntry.DeckId, tocEntry.SlideIndex); realTimeStrokesPending.Add(rtispm.StrokeId, rtsData); } Guid strokeId = rtsData.StrokeId; //WebViewer requires the CP2 extended property to allow deletion of the stroke ink.Strokes[0].ExtendedProperties.Add(CP2StrokeIdExtendedProperty, (object)strokeId.ToString()); //WebViewer wants ink to be scaled to 500x500 ink.Strokes.Scale(500f / getCurrentSlideWidth(), 500f / getCurrentSlideHeight()); Debug.WriteLine("***** Adding Real-time Stroke ID=" + strokeId.ToString()); RTDrawStroke rtds = new RTDrawStroke(ink, strokeId, false, tocEntry.DeckId, tocEntry.SlideIndex); return(rtds); }
/// <summary> /// This is the message received when there is a completed stroke. Translate to RTDrawStroke. /// </summary> /// <param name="issam"></param> /// <returns></returns> internal RTDrawStroke AddInkSheetStrokesAdded(CP3Msgs.InkSheetStrokesAddedMessage issam) { //Notice that we tend to get a fair number of these messages that have nothing in the SavedInks property.. presenter bug? byte[][] saved = issam.SavedInks; if (saved.Length == 0) { return(null); } if (saved[0].Length == 0) { return(null); } if (saved.Length > 1) { //This does not seem to occur in practice. If it ever does, we need to generate multiple RTDrawStroke messages: warning += "Warning: Valid ink may be ignored because we only support one byte[] per ink message. "; } Ink ink = new Ink(); ink.Load(saved[0]); if (ink.Strokes.Count <= 0) { return(null); } //This message has a targetID identifying a Sheet which we use to look up a toc entry. Debug.WriteLine("***** InkSheetStrokesAdded targetid=" + issam.TargetId.ToString()); if (!sheetToSlideLookup.ContainsKey(issam.TargetId)) { if (issam.SlideId.Equals(Guid.Empty)) { //Don't think this should ever happen. warning += "Warning: InkSheetStrokesAdded does not match a known sheet. Ignoring ink. "; return(null); } sheetToSlideLookup.Add(issam.TargetId, issam.SlideId); } Guid slideId = (Guid)sheetToSlideLookup[issam.TargetId]; //Get DeckID and Slide index from toc. Return RTDrawStroke. TableOfContents.TocEntry tocEntry = toc.LookupBySlideId(slideId); if (tocEntry == null) { //In some cases ink arrives before the TOC entry. // Save the ink to send later when the TOC entry is available. if (!pendingInk.ContainsKey(slideId)) { pendingInk.Add(slideId, new List <Ink>()); } pendingInk[slideId].Add(ink); Debug.WriteLine("InkSheetStrokesAdded does not have a Toc entry. Caching for later."); return(null); } Guid strokeId = Guid.NewGuid(); //Pull out the identifier which is used if we need to delete the stroke later: if (ink.Strokes[0].ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) { strokeId = new Guid((string)ink.Strokes[0].ExtendedProperties[StrokeIdExtendedProperty].Data); } else { warning += "Warning: Failed to find stroke Id. "; } //WebViewer looks for the CP2 extended property, so add it too. ink.Strokes[0].ExtendedProperties.Add(CP2StrokeIdExtendedProperty, (object)strokeId.ToString()); //WebViewer wants ink to be scaled to 500x500 ink.Strokes.Scale(500f / getCurrentSlideWidth(), 500f / getCurrentSlideHeight()); //Debug.WriteLine("***** Adding Stroke ID=" + strokeId.ToString()); RTDrawStroke rtds = new RTDrawStroke(ink, strokeId, true, tocEntry.DeckId, tocEntry.SlideIndex); //Add the stroke to our list to optimize deletes if (!strokeCountsBySlideId.ContainsKey(slideId)) { strokeCountsBySlideId.Add(slideId, 1); } else { strokeCountsBySlideId[slideId]++; } return(rtds); }