/// <summary> /// Handle the reception of a RTStroke object. /// </summary> /// <param name="rtStroke">Stroke received</param> private void RTStrokeReceived(RTStroke rtStroke) { Page pg = rtDoc.Resources.Pages[rtStroke.PageIdentifier]; if (pg == null) // if the page is missing, ignore the stroke :( { return; } SizeF imageSize = GetSlideSize(pg.Image); // Resize the received stroke float xRatio = (imageSize.Width / constWidthPageSend) * inkSpaceToPixel; float yRatio = (imageSize.Height / constHeightPageSend) * inkSpaceToPixel; Rectangle bounds = rtStroke.Stroke.GetBoundingBox(); RectangleF newBounds = new RectangleF(bounds.X * xRatio, bounds.Y * yRatio, bounds.Width * xRatio, bounds.Height * yRatio); // Add the stroke to the page StringBuilder importData = new StringBuilder(2000); XmlTextWriter xml = CreateInitdXml(importData); xml.WriteStartElement("PlaceObjects"); xml.WriteAttributeString("pagePath", crntONFile); xml.WriteAttributeString("pageGuid", rtStroke.PageIdentifier.ToString("B")); xml.WriteStartElement("Object"); xml.WriteAttributeString("guid", rtStroke.StrokeIdentifier.ToString("B")); xml.WriteStartElement("Position"); xml.WriteAttributeString("x", newBounds.X.ToString()); xml.WriteAttributeString("y", newBounds.Y.ToString()); xml.WriteEndElement(); // end Position xml.WriteStartElement("Ink"); xml.WriteAttributeString("width", newBounds.Width.ToString()); xml.WriteAttributeString("height", newBounds.Height.ToString()); Ink ink = new Ink(); ink.AddStrokesAtRectangle(rtStroke.Strokes, rtStroke.Strokes.GetBoundingBox()); byte[] base64ISF_bytes = ink.Save(PersistenceFormat.Base64InkSerializedFormat); xml.WriteStartElement("Data"); xml.WriteBase64(base64ISF_bytes, 0, base64ISF_bytes.Length); xml.WriteEndElement(); // end Data xml.WriteEndDocument(); string finalData = importData.ToString(); LogAsLastCommand(finalData); importer.Import(finalData); // prevents ink & objects from getting inserted too quickly after a page System.Threading.Thread.Sleep(50); // Store the stroke ID in strokesPerPage ((ArrayList)strokesPerPage[rtStroke.PageIdentifier]).Add(rtStroke.StrokeIdentifier); }
/// <summary> /// Handle frames from a native RTDocument generator such as the CXP presentation tool /// </summary> /// <param name="rtobj"></param> private void acceptRTDocFrame(object rtobj) { ///Notes about RTDocuments: /// /// RTDocuments have Resources and Organizations. Resources contain Pages/Images etc while Organizations /// contain the TOC/titles, etc. The TOC Nodes contain references to the resources and resource IDs. /// The navigation message RTNodeChanged just tells us the organization node ID, while /// Page and ink messages only contain the Resource ID. RTDocument messages contain the TOC which maps pages and org nodes. /// PageAdds will not have an existing TocNode in the RTDocument map, but they carry their own TocNode property. /// /// For this application, we only care about having one unique page identifier. We take the strategy of storing /// SlideImages under the resource Identifier, and maintaining a lookup table of Organization identifier to /// resource identifier. We use this table to resolve Organization identifiers when navigation messages are received. if (rtobj is RTDocument) { RTDocument rtd = (RTDocument)rtobj; //Keep the mapping of TocNode.Identifier to TocNode.ResourceIdentifier foreach (TOCNode tn in rtd.Organization.TableOfContents) { if (!orgToResource.ContainsKey(tn.Identifier)) { orgToResource.Add(tn.Identifier, tn.ResourceIdentifier); } else { orgToResource[tn.Identifier] = tn.ResourceIdentifier; } } //There is an implicit navigation to the first slide here. this.currentSlide.SetRTDocReference(rtd.Organization.TableOfContents[0].ResourceIdentifier); } else if (rtobj is Page) { //These are slide deck pages //p.Identifier is a Resource Identifier. Store the image under that Identifier. Page p = (Page)rtobj; if (!slideImages.ContainsKey(p.Identifier.ToString())) { slideImages.Add(p.Identifier.ToString(), new SlideImage()); } ((SlideImage)slideImages[p.Identifier.ToString()]).SetImage(p.Image, false); } else if (rtobj is RTPageAdd) { //These are dynamically added pages such as WB and screenshots RTPageAdd rtpa = (RTPageAdd)rtobj; //RTPageAdd comes with a TocNode. Store the mapping of resource ID to TocNode.Identifier if (!orgToResource.ContainsKey(rtpa.TOCNode.Identifier)) { orgToResource.Add(rtpa.TOCNode.Identifier, rtpa.Page.Identifier); } else { orgToResource[rtpa.TOCNode.Identifier] = rtpa.Page.Identifier; } //Store the page Image under the resource ID. if (!slideImages.ContainsKey(rtpa.Page.Identifier.ToString())) { slideImages.Add(rtpa.Page.Identifier.ToString(), new SlideImage()); } ((SlideImage)slideImages[rtpa.Page.Identifier.ToString()]).SetImage(rtpa.Page.Image, false); } else if (rtobj is RTNodeChanged) { RTNodeChanged rtnc = (RTNodeChanged)rtobj; //Look up the resource ID and update curent page. if (orgToResource.ContainsKey(rtnc.OrganizationNodeIdentifier)) { currentSlide.SetRTDocReference(((Guid)orgToResource[rtnc.OrganizationNodeIdentifier])); } else { //Indicate slide missing by setting currentSlide reference to Guid.Empty currentSlide.SetRTDocReference(Guid.Empty); } } else if (rtobj is RTStroke) { RTStroke rts = (RTStroke)rtobj; //apply the ink to the given Page Identifier. Create a new SlideImage if necessary. if (!slideImages.ContainsKey(rts.PageIdentifier.ToString())) { slideImages.Add(rts.PageIdentifier.ToString(), new SlideImage()); } Microsoft.Ink.Ink ink = rts.Stroke.Ink.Clone(); for (int i = 0; i < ink.Strokes.Count; i++) { ink.Strokes[i].Scale(500f / 960f, 500f / 720f); } ((SlideImage)slideImages[rts.PageIdentifier.ToString()]).AddInk(ink, rts.StrokeIdentifier); //There appears to be an implicit navigation here. currentSlide.SetRTDocReference(rts.PageIdentifier); } else if (rtobj is RTStrokeRemove) { RTStrokeRemove rtsr = (RTStrokeRemove)rtobj; //Use the PageIdentifer to identify the page from which to remove the stroke. if (slideImages.ContainsKey(rtsr.PageIdentifier.ToString())) { ((SlideImage)slideImages[rtsr.PageIdentifier.ToString()]).RemoveInk(rtsr.StrokeIdentifier); } } else if (rtobj is RTFrame) { RTFrame rtf = (RTFrame)rtobj; if (rtf.ObjectTypeIdentifier == Constants.RTDocEraseAllGuid) { //Erase all ink on the current slide. if ((currentSlide.IsSet) && (slideImages.ContainsKey(currentSlide.GetStringHashCode()))) { ((SlideImage)slideImages[currentSlide.GetStringHashCode()]).RemoveAllInk(); } } else { Debug.WriteLine("Unhandled RTFrame type."); } } else { Debug.WriteLine("Unhandled RT obj:" + rtobj.ToString()); } }