/// <summary> /// Receive stroke for Presenter 1. /// </summary> /// <param name="bc"></param> private void ReceiveStroke(BufferChunk bc) { BinaryFormatter formatter = new BinaryFormatter(); MemoryStream memoryStream = new MemoryStream(bc.Buffer, 1, bc.Length - 1); int slideIndex = (int)formatter.Deserialize(memoryStream); if (this.SlideDeck != null && slideIndex >= 0) { InkScribble s = (InkScribble)this.SlideDeck.GetOverlay(slideIndex).Scribble; // Restore the bytes to ink. byte[] bytes = new byte[memoryStream.Length - memoryStream.Position]; memoryStream.Read(bytes, 0, bytes.Length); Ink.Ink ink = new Ink.Ink(); ink.Load(bytes); // Delete the previous version of this stroke if necessary. foreach (Ink.Stroke stroke in ink.Strokes) { if (stroke.ExtendedProperties.DoesPropertyExist(GUID_TAG)) { Ink.Stroke foundStroke; bool found = FastFindStrokeFromGuid(s, new Guid((string)stroke.ExtendedProperties[GUID_TAG].Data), out foundStroke, GUID_TAG); if (found) { s.Ink.DeleteStroke(foundStroke); } } } lock (this) { Rectangle r = ink.Strokes.GetBoundingBox(); r.X = (int)(r.X * XinkScaleFactor); r.Y = (int)(r.Y * YinkScaleFactor); r.Width = (int)(r.Width * XinkScaleFactor); r.Height = (int)(r.Height * YinkScaleFactor); s.Ink.AddStrokesAtRectangle(ink.Strokes, r); // Make note of the ink's strokes in the guidtable. // ASSUME that these strokes went on the end. int sCount = s.Ink.Strokes.Count; int newCount = ink.Strokes.Count; for (int i = sCount - newCount; i < sCount; i++) { Ink.Stroke stroke = s.Ink.Strokes[i]; if (stroke.ExtendedProperties.Contains(GUID_TAG)) { Guid guid = new Guid((string)stroke.ExtendedProperties[GUID_TAG].Data); this.myGuidTable[new ScribbleIntPair(s, stroke.Id)] = guid; this.myGuidReverseTable[guid] = new ScribbleIntPair(s, stroke.Id); } } } } }
public override void SerializePoints(Stream stream, int numPoints) { IFormatter formatter = new BinaryFormatter(); // Calculate the number of strokes to serialize int index = this.myInk.Strokes.Count; int countLeft = numPoints; while (countLeft > 0 && index > 0) { index--; countLeft -= this.myInk.Strokes[index].GetPoints().Length; } // Index is now -1 or the first stroke to send. if (index < 0) { index = 0; } if (countLeft < 0) { countLeft += this.myInk.Strokes[index].GetPoints().Length; } // If there is a partial stroke, serialize it specially if (countLeft > 0) { formatter.Serialize(stream, true); // Flag that there is a partial stroke. } else { formatter.Serialize(stream, false); // Flag that there is no partial stroke. } // Serialize just a zero (length) for an empty scribble. if (this.myInk.Strokes.Count - index == 0) { formatter.Serialize(stream, 0); } else { // Serialize all remaining strokes completely Ink.Ink ink = new Ink.Ink(); int[] ids = new int[this.myInk.Strokes.Count - index]; for (int i = index; i < this.myInk.Strokes.Count; i++) { ids[i - index] = this.myInk.Strokes[i].Id; } // Note: AddStrokesAtRectangle is used since the documentation for AddStrokes // states that the strokes must *already* be in the ink object (so, it's only // used for updating custom strokes collections??). Ink.Strokes strokes = this.myInk.CreateStrokes(ids); ink.AddStrokesAtRectangle(strokes, strokes.GetBoundingBox()); byte[] inkBytes = ink.Save(); formatter.Serialize(stream, inkBytes.Length); stream.Write(inkBytes, 0, inkBytes.Length); } }
/// <summary> /// Find Stroke from Guid /// </summary> /// The original version was much too slow for the archive replay scenario. /// <param name="scribble"></param> /// <param name="guid"></param> /// <param name="stroke"></param> /// <param name="guidTag"></param> /// <returns></returns> private bool FastFindStrokeFromGuid(InkScribble scribble, Guid guid, out Ink.Stroke stroke, Guid guidTag) { Ink.Ink ink = scribble.Ink; if (this.myGuidReverseTable.Contains(guid)) { if (((ScribbleIntPair)this.myGuidReverseTable[guid]).scribble == scribble) { ScribbleIntPair pair = (ScribbleIntPair)this.myGuidReverseTable[guid]; /// The count can be zero right after a clear slide or clear deck operation /// if count is zero, CreateStrokes will except. if (pair.scribble.Count == 0) { stroke = null; return(false); } Ink.Strokes targetStrokes = null; try { targetStrokes = ink.CreateStrokes(new int[] { pair.id }); } catch (Exception e) { //not clear when this would happen? stroke = null; Trace.WriteLine("FastFindStrokeFromGuid: Exception during CreateStrokes: " + e.ToString()); return(false); } if (targetStrokes.Count < 1) //not clear when this would happen? { stroke = null; Trace.WriteLine("FastFindStrokeFromGuid: Found target with zero stroke count."); return(false); } // Found it. stroke = targetStrokes[0]; return(true); } else { //This happens when we revisit slides we've been on previously this.myGuidReverseTable.Remove(guid); stroke = null; return(false); } } else { stroke = null; return(false); } }
/// <summary> /// Receive Presenter2 stroke /// </summary> /// <param name="drawStroke"></param> public void ReceiveStroke(ArchiveRTNav.RTDrawStroke drawStroke) { int slideIndex; slideIndex = slideMap.GetMapping(drawStroke.SlideIndex, drawStroke.DeckGuid); InkScribble s = (InkScribble)this.SlideDeck.GetOverlay(slideIndex).Scribble; Ink.Stroke foundStroke; bool found = FastFindStrokeFromGuid(s, drawStroke.Guid, out foundStroke, NEW_GUID_TAG); if (found) { s.Ink.DeleteStroke(foundStroke); } Ink.Ink ink = drawStroke.Ink; lock (this) { Rectangle r = ink.Strokes.GetBoundingBox(); r.X = (int)(r.X * XinkScaleFactor); r.Y = (int)(r.Y * YinkScaleFactor); r.Width = (int)(r.Width * XinkScaleFactor); r.Height = (int)(r.Height * YinkScaleFactor); s.Ink.AddStrokesAtRectangle(ink.Strokes, r); // Make note of the ink's strokes in the guidtable. // ASSUME that these strokes went on the end. int sCount = s.Ink.Strokes.Count; int newCount = ink.Strokes.Count; for (int i = sCount - newCount; i < sCount; i++) { Ink.Stroke stroke = s.Ink.Strokes[i]; if (stroke.ExtendedProperties.Contains(NEW_GUID_TAG)) { Guid guid = Guid.Empty; try { //Saw this except once. Couldn't repro. Suspect corrupted data. guid = new Guid((string)stroke.ExtendedProperties[NEW_GUID_TAG].Data); } catch { continue; } this.myGuidTable[new ScribbleIntPair(s, stroke.Id)] = guid; this.myGuidReverseTable[guid] = new ScribbleIntPair(s, stroke.Id); } } } }
public override void DeserializePoints(Stream stream) { // Check if there was a partial stroke; if so, delete the current last stroke. IFormatter formatter = new BinaryFormatter(); bool partial = (bool)formatter.Deserialize(stream); if (partial) { if (this.myInk.Strokes.Count == 0) { System.Diagnostics.Debug.WriteLine("no partial stroke to delete", "WARNING"); } else { this.myInk.DeleteStroke(this.myInk.Strokes[this.myInk.Strokes.Count - 1]); } } // Deserialize all remaining strokes. int length = (int)formatter.Deserialize(stream); if (length > 0) { byte[] inkBytes = new byte[length]; stream.Read(inkBytes, 0, length); Ink.Ink ink = new Ink.Ink(); ink.Load(inkBytes); // Note: AddStrokesAtRectangle is used since the documentation for AddStrokes // states that the strokes must *already* be in the ink object (so, it's only // used for updating custom strokes collections??). if (ink.Strokes.Count > 0) { this.myInk.AddStrokesAtRectangle(ink.Strokes, ink.Strokes.GetBoundingBox()); } } foreach (Ink.Stroke stroke in this.myInk.Strokes) { this.OnStroke(new NumericEventArgs(stroke.Id)); } }
public InkScribble() { myInk = new Ink.Ink(); Initialize(); }
private bool FindStrokeFromGuid(InkScribble scribble, Guid guid, out Ink.Stroke stroke, Guid guidTag) { Ink.Ink ink = scribble.Ink; // Check if the guid tables are out of date. This might be indicated by either: // * The guid is not in the reverse table. // * The reverse table entry's scribble does not match the given scribble. // If the tables are out of date, update the entries for this scribble object. if (!this.myGuidReverseTable.Contains(guid) || ((ScribbleIntPair)this.myGuidReverseTable[guid]).scribble != scribble) { // Ensure that, at the least, the stale entry is removed. this.myGuidReverseTable.Remove(guid); // Refresh entries for all strokes in this scribble. foreach (Ink.Stroke s in ink.Strokes) { try { if (s.ExtendedProperties.DoesPropertyExist(guidTag)) { Guid strokeGuid = new Guid((string)s.ExtendedProperties[guidTag].Data); this.myGuidReverseTable[strokeGuid] = new ScribbleIntPair(scribble, s.Id); this.myGuidTable[new ScribbleIntPair(scribble, s.Id)] = strokeGuid; } } catch { //this try/catch because I once saw an exception thrown here. Not sure if it was a bug // in the data, the TPC SDK, or in my code.. Anyway it seemed safe to ignore. } } } // If the guid is still not in the table, it is not found. if (!this.myGuidReverseTable.Contains(guid)) { stroke = null; return(false); } // Can we find the specific id sought? ScribbleIntPair pair = (ScribbleIntPair)this.myGuidReverseTable[guid]; //This try/catch is a hack to deal with multiple-play (archive) scenario. //I believe the real fix is to catch WMP stop and postion change events and //to rebuild guid tables and InkScribble appropriately for the new media position. Ink.Strokes targetStrokes = null; try { targetStrokes = ink.CreateStrokes(new int[] { pair.id }); } catch { stroke = null; return(false); } if (targetStrokes.Count < 1) { stroke = null; return(false); } // Found it. stroke = targetStrokes[0]; return(true); }