/** * <summary>Executes scanning on this operation.</summary> * <param name="state">Graphics state context.</param> * <param name="textScanner">Scanner to be notified about text contents. * In case it's null, the operation is applied to the graphics state context.</param> */ public void Scan( ContentScanner.GraphicsState state, IScanner textScanner ) { /* * TODO: I really dislike this solution -- it's a temporary hack until the event-driven * parsing mechanism is implemented... */ /* * TODO: support to vertical writing mode. */ double contextHeight = state.Scanner.ContextSize.Height; // PK - 2017-09-15 - state.Font can be null, which throws an exception below, so fall back on standard Courier Font font = state.Font ?? new StandardType1Font(((Page)state.Scanner.RootLevel.ContentContext).Document, StandardType1Font.FamilyEnum.Courier, false, false); double fontSize = state.FontSize; double scaledFactor = Font.GetScalingFactor(fontSize) * state.Scale; bool wordSpaceSupported = !(font is CompositeFont); double wordSpace = wordSpaceSupported ? state.WordSpace * state.Scale : 0; double charSpace = state.CharSpace * state.Scale; Matrix ctm = state.Ctm.Clone(); Matrix tm = state.Tm; if (this is ShowTextToNextLine) { ShowTextToNextLine showTextToNextLine = (ShowTextToNextLine)this; double? newWordSpace = showTextToNextLine.WordSpace; if (newWordSpace != null) { if (textScanner == null) { state.WordSpace = newWordSpace.Value; } if (wordSpaceSupported) { wordSpace = newWordSpace.Value * state.Scale; } } double?newCharSpace = showTextToNextLine.CharSpace; if (newCharSpace != null) { if (textScanner == null) { state.CharSpace = newCharSpace.Value; } charSpace = newCharSpace.Value * state.Scale; } tm = state.Tlm.Clone(); tm.Multiply(new Matrix(1, 0, 0, 1, 0, (float)-state.Lead)); } else { tm = state.Tm.Clone(); } foreach (object textElement in Value) { if (textElement is byte[]) // Text string. { string textString = font.Decode((byte[])textElement); foreach (char textChar in textString) { double charWidth = font.GetWidth(textChar) * scaledFactor; if (textScanner != null) { /* * NOTE: The text rendering matrix is recomputed before each glyph is painted * during a text-showing operation. */ Matrix trm = ctm.Clone(); trm.Multiply(tm); double charHeight = font.GetHeight(textChar, fontSize); drawing::RectangleF charBox = new drawing::RectangleF( trm.Elements[4], (float)(contextHeight - trm.Elements[5] - font.GetAscent(fontSize) * trm.Elements[3]), (float)charWidth * trm.Elements[0], (float)charHeight * trm.Elements[3] ); textScanner.ScanChar(textChar, charBox); } /* * NOTE: After the glyph is painted, the text matrix is updated * according to the glyph displacement and any applicable spacing parameter. */ tm.Translate((float)(charWidth + charSpace + (textChar == ' ' ? wordSpace : 0)), 0); } } else // Text position adjustment. { tm.Translate((float)(-Convert.ToSingle(textElement) * scaledFactor), 0); } } if (textScanner == null) { state.Tm = tm; if (this is ShowTextToNextLine) { state.Tlm = tm.Clone(); } } }
/** * <summary>Executes scanning on this operation.</summary> * <param name="state">Graphics state context.</param> * <param name="textScanner">Scanner to be notified about text contents. * In case it's null, the operation is applied to the graphics state context.</param> */ public void Scan( ContentScanner.GraphicsState state, IScanner textScanner ) { /* * TODO: I really dislike this solution -- it's a temporary hack until the event-driven * parsing mechanism is implemented... */ /* * TODO: support to vertical writing mode. */ IContentContext context = state.Scanner.ContentContext; float contextHeight = context.Box.Height; Font font = state.Font; float fontSize = state.FontSize; float scale = state.Scale / 100; float scaledFactor = Font.GetScalingFactor(fontSize) * scale; float wordSpace = state.WordSpace * scale; float charSpace = state.CharSpace * scale; Matrix ctm = state.Ctm.Clone(); Matrix tm = state.Tm; if (this is ShowTextToNextLine) { ShowTextToNextLine showTextToNextLine = (ShowTextToNextLine)this; float?newWordSpace = showTextToNextLine.WordSpace; if (newWordSpace != null) { if (textScanner == null) { state.WordSpace = newWordSpace.Value; } wordSpace = newWordSpace.Value * scale; } float?newCharSpace = showTextToNextLine.CharSpace; if (newCharSpace != null) { if (textScanner == null) { state.CharSpace = newCharSpace.Value; } charSpace = newCharSpace.Value * scale; } tm = state.Tlm.Clone(); tm.Translate(0, state.Lead); } else { tm = state.Tm.Clone(); } foreach (object textElement in Value) { if (textElement is byte[]) // Text string. { string textString = font.Decode((byte[])textElement); foreach (char textChar in textString) { float charWidth = font.GetWidth(textChar) * scaledFactor; if (textScanner != null) { /* * NOTE: The text rendering matrix is recomputed before each glyph is painted * during a text-showing operation. */ Matrix trm = ctm.Clone(); trm.Multiply(tm); float charHeight = font.GetHeight(textChar, fontSize); drawing::RectangleF charBox = new drawing::RectangleF( trm.Elements[4], contextHeight - trm.Elements[5] - font.GetAscent(fontSize) * tm.Elements[3], charWidth * tm.Elements[0], charHeight * tm.Elements[3] ); textScanner.ScanChar(textChar, charBox); } /* * NOTE: After the glyph is painted, the text matrix is updated * according to the glyph displacement and any applicable spacing parameter. */ tm.Translate(charWidth + charSpace + (textChar == ' ' ? wordSpace : 0), 0); } } else // Text position adjustment. { tm.Translate(-Convert.ToSingle(textElement) * scaledFactor, 0); } } if (textScanner == null) { state.Tm = tm; if (this is ShowTextToNextLine) { state.Tlm = tm.Clone(); } } }