iTextSharp GetFieldPositions to SetSimpleColumn - c#

I'm using the latest version of iTextSharp found here: http://sourceforge.net/projects/itextsharp/
I am trying to use ColumnText.SetSimpleColumn after getting the position of some AcroFields using GetFieldPositions( fieldName ).
All the examples I can find show GetFieldPositions returning a float[] however this doesn't appear to be the case anymore. It now appears to be returning IList which doesn't (according to Visual Studio) implicitly convert to a float[].
Inside the return value at the 0 index is a position member that is a Rectangle, but since the examples I've seen perform math operations on the returned float[] I'm not sure what values from the return value in GetFieldPostions to use when using SetSimpleColumn. Here's one article that I'm referencing: http://blog.dmbcllc.com/2009/07/08/itextsharp-html-to-pdf-positioning-text/
Simplest accepted answer will be how to translate the value from GetFieldPositions to SetSimpleColumn.
Thanks!

I think this was done for two reasons. 1), GetFieldPositions() could actually return multiple items because you can technically have more than one field with the same name and 2), the original array method required knowing "magic array numbers" to find what was what. All of the code that you saw pretty much assumed that GetFieldPositions() only returned a single item, which is true 99% of the time. Instead of working with indexes you can now work with normal properties.
So the code from the link that you posted:
float[] fieldPosition = null;
fieldPosition = fields.GetFieldPositions("fieldNameInThePDF");
left = fieldPosition[1];
right = fieldPosition[3];
top = fieldPosition[4];
bottom = fieldPosition[2];
if (rotation == 90)
{
left = fieldPosition[2];
right = fieldPosition[4];
top = pageSize.Right - fieldPosition[1];
bottom = pageSize.Right - fieldPosition[3];
}
Should be converted to:
IList<AcroFields.FieldPosition> fieldPositions = fields.GetFieldPositions("fieldNameInThePDF");
if (fieldPositions == null || fieldPositions.Count <= 0) throw new ApplicationException("Error locating field");
AcroFields.FieldPosition fieldPosition = fieldPositions[0];
left = fieldPosition.position.Left;
right = fieldPosition.position.Right;
top = fieldPosition.position.Top;
bottom = fieldPosition.position.Bottom;
if (rotation == 90)
{
left = fieldPosition.position.Bottom;
right = fieldPosition.position.Top;
top = pageSize.Right - fieldPosition.position.Left;
bottom = pageSize.Right - fieldPosition.position.Right;
}

Related

Calculate new ScrollPercent - after ViewSize changed

First of all, basically I believe I just need help in figuring out how to calculate it, math isnt really my strong side.
FYI, the MS-Word is most likely not relevant to solve my problem, I basically just mention it so you know the context I am in, but I believe it should be solvable also for people who have no knowledge about MS-Word.
I have the problem that Word has the property VerticalPercentScrolled which is an integer.
Which isnt as accurate as I need it to be, consider a Word Document with 300 pages and the scrollbar can only have a integer between 0 - 100 (percent), so for example 25 percent of a 300 page document is a rather big range.
I have now gone and read the correct value, with the help of UI Automation library - TestStack.White - and can successfully set it to its old value, if some un-desired scrolling happens.
Like this:
var hWnd = (IntPtr)WordUtils.GetHwnd();
var processId = Process.GetCurrentProcess().Id;
var uiApp = TestStack.White.Application.Attach((int)processId);
var uiWindow = uiApp.GetWindow(WindowHandling.GetWindowText(hWnd), InitializeOption.NoCache);
var wf = (IUIItemContainer)uiWindow.Get(SearchCriteria.ByClassName("_WwF"));
var wbs= wf.GetMultiple(SearchCriteria.ByClassName("_WwB"));
if (wbs.Length != 1)
return;
var wb= (IUIItemContainer)wbs.First();
var wgs = wb.GetMultiple(SearchCriteria.ByClassName("_WwG"));
if (wgs.Length != 1)
return;
var wg = wgs.First();
var element = wg.AutomationElement;
var oldVerticalPercent = (double)element.GetCurrentPropertyValue(ScrollPattern.VerticalScrollPercentProperty);
with this code I get a percent value of lets say 9.442248572683356 instead of 9.
To reset the value I use the following code:
object scrollPattern;
if (element.TryGetCurrentPattern(ScrollPattern.Pattern, out scrollPattern))
((ScrollPattern)scrollPattern).SetScrollPercent(ScrollPattern.NoScroll, oldVerticalPercent);
This works like a charm.
Now my problem is what if my document gets larger/smaller during the time I stored the oldValue and want to reapply it, my oldValue needs to be adjusted.
I can read the following values (at least those I found so far):
ScrollPattern.VerticalScrollPercentProperty
ScrollPattern.VerticalViewSizeProperty
I can also go and look for the scrollbar it self and read the following values:
RangeValuePattern.LargeChangeProperty
RangeValuePattern.MaximumProperty
RangeValuePattern.MinimumProperty
RangeValuePattern.SmallChangeProperty
RangeValuePattern.ValueProperty
To look for the scrollbar, I use the following code:
var hWnd = (IntPtr)WordUtils.GetHwnd();
var processId = Process.GetCurrentProcess().Id;
var uiApp = Ts.Application.Attach((int)processId);
var uiWindow = uiApp.GetWindow(WindowHandling.GetWindowText(hWnd), InitializeOption.NoCache);
var wf = (IUIItemContainer)uiWindow.Get(SearchCriteria.ByClassName("_WwF"));
var wbs = wf.GetMultiple(SearchCriteria.ByClassName("_WwB"));
if (wbs.Length != 1)
return;
var wb = (IUIItemContainer)wbs.First();
var wgs= wb.GetMultiple(SearchCriteria.ByClassName("_WwG"));
if (wgs.Length != 1)
return;
var nUiScrollBars = wgs.GetMultiple(SearchCriteria.ByClassName("NUIScrollbar"));
if (scrollBar.Length != 1)
return;
var nUiScrollBar = (IUIItemContainer)nUiScrollBars.First();
var nUiHwndElements = nUiScrollBar.GetMultiple(SearchCriteria.ByClassName("NetUIHWNDElement"));
if (nUiHwndElements.Length != 1)
return;
var nUiHwndElement = (IUIItemContainer)nUiHwndElements.First();
var netUiScrollBar = nUiHwndElement.GetElement(SearchCriteria.ByClassName("NetUIScrollBar"));
var scrollBarValue = (double)netUiScrollBar.GetCurrentPropertyValue(RangeValuePattern.ValueProperty);
You may ask yourself, why I dont set the RangeValuePattern.ValueProperty when I am able to access it, the problem there is that Word doesnt update the document when I change this property, the scroll thumb does move but the document doesnt move an inch.
I have to set the ScrollPattern.VerticalScrollPercentProperty for it to work.
So my question, is how do I calculate the new ScrollPattern.VerticalScrollPercentProperty based on the oldValue, where the document could shrink or grow in size in between?
Edit:
Here is a testscenario:
scrollPercent 64.86486486486487
scrollViewSize 74.394463667820062
scrollBarLargeChange 37197
scrollBarMaximum 12803
scrollBarMinimum 0
scrollBarSmallChange 1
scrollBarValue 8304
After inserting 5 new pages
scrollPercent 87.890366182251867 <-- undesired scrolling occured (see desired values below)
scrollViewSize 9.442248572683356
scrollBarLargeChange 4721
scrollBarMaximum 45279
scrollBarMinimum 0
scrollBarSmallChange 1
scrollBarValue 39795 <-- undesired scrolling occured (see desired values below)
And as said, I need to adjust the scrollPercent - after inserting those pages - so that it is again on the old position.
I can tell you that in this testscenario, I would need the new value to be
scrollPercent 2.3278413357480452
after changing it to the desired percentValue the scrollBarValue is the only value getting updated and it is than at
scrollBarValue 1054
So, it looks like your scrollPercent is calculated like this:
scrollPercent = 100.0 * scrollBarValue / (scrollBarMaximum - 1);
So the math should work out like this (assuming floating-point division):
scrollPercentOld = 100.0 * scrollBarValueOld / (scrollBarMaximumOld - 1)
scrollPercentNew = 100.0 * scrollBarValueOld / (scrollBarMaximumNew - 1)
From that, you have:
scrollBarValueOld = scrollPercentOld * (scrollBarMaximumOld - 1) / 100.0
scrollBarValueOld = scrollPercentNew * (scrollBarMaximumNew - 1) / 100.0
When you equate the two, you get:
scrollPercentOld * (scrollBarMaximumOld - 1) = scrollPercentNew * (scrollBarMaximumNew - 1)
And then finally:
scrollPercentNew = scrollPercentOld * (scrollBarMaximumOld - 1) / (scrollBarMaximumNew - 1)

Pdf form fields position retrieval with Itext

With iTextSharp, I can retrieve all the form fields that are present in a PDF form.I'm using Adobe acrobat reader to edit the PDF, where I see, every field have a position attribute which denotes where the PDF field will reside in a form.
So my question is, can I read that value ?
For example if I have a form field Name in a PDF form, can I get the position value of this field, like left 0.5 inches, right 2.5 inches, top 2 inches, bottom 2 inches ?
Right now I'm retrieving the form fields with the below code :
string pdfTemplate = #"D:\abc.pdf";
PdfReader reader = new PdfReader(pdfTemplate);
var fields = reader.AcroFields;
int ffRadio = 1 << 15; //Per spec, 16th bit is radio button
int ffPushbutton = 1 << 16; //17th bit is push button
int ff;
//Loop through each field
foreach (var f in fields.Fields)
{
String type = "";
String name = f.Key.ToString();
String value = fields.GetField(f.Key);
//Get the widgets for the field (note, this could return more than 1, this should be checked)
PdfDictionary w = f.Value.GetWidget(0);
//See if it is a button-like object (/Ft == /Btn)
if (!w.Contains(PdfName.FT) || !w.Get(PdfName.FT).Equals(PdfName.BTN))
{
type = "T";
}
else
{
//Get the optional field flags, if they don't exist then just use zero
ff = (w.Contains(PdfName.FF) ? w.GetAsNumber(PdfName.FF).IntValue : 0);
if ((ff & ffRadio) == ffRadio)
{
//Is Radio
type = "R";
}
else if (((ff & ffRadio) != ffRadio) && ((ff & ffPushbutton) != ffPushbutton))
{
//Is Checkbox
type = "C";
}
else
{
//Regular button
type = "B";
}
}
//MessageBox.Show(type + "=>" + name + "=>" + value);
FormFields fld = new FormFields(name, type, value, "inputfield" +form_fields.Count);
form_fields.Add(fld);
if (type.Equals("T"))
addContent(form_fields.Count);
}
I was about to close this question as a duplicate of Find field absolute position and dimension by acrokey but that's a Java answer, and although most developers have no problem converting the Java to C#, it may be helpful for some developers to get the C# answer.
Fields in a PDF are visualized using widget annotations. One field can correspond with different of those annotations. For instance, you could have a field named name that is visualized on every page. In this case, the value of this field would be shown on every page.
There's a GetFieldPositions() method that returns a list of multiple positions, one for every widget annotations.
This is some code I copied from the answer to the question iTextSharp GetFieldPositions to SetSimpleColumn
IList<AcroFields.FieldPosition> fieldPositions = fields.GetFieldPositions("fieldNameInThePDF");
if (fieldPositions == null || fieldPositions.Count <= 0) throw new ApplicationException("Error locating field");
AcroFields.FieldPosition fieldPosition = fieldPositions[0];
left = fieldPosition.position.Left;
right = fieldPosition.position.Right;
top = fieldPosition.position.Top;
bottom = fieldPosition.position.Bottom;
If one field corresponds with one widget annotation, then left, right, top, and bottom will give you the left, right, top and bottom coordinate of the field. The width of the field can be calculated like this: right - left; the height like this: top - bottom. These values are expressed in user units. By default there are 72 user units in one inch.
If your document contains more than one page, then fieldPosition.page will give you the page number where you'll find the field.
All of this is documented on http://developers.itextpdf.com/

passing a result(double type variable) from a method as an element of an array

Background -
I am new to programming in C# and am trying to code a custom indicator. On a trading platform that uses C#. A histogram with
positive Y axis = reqAskArraySum
negative Y axis = reqBidArraySum
The inbuilt compiler shows no errors. However the desired results do not seem to show up.
I know/it is possible there are some platform specific initialization problems i.e. code that I have not entered yet correctly.
Question -
The question here is with regards to the code posted below , which is a part of the whole code.
I would like to know whether the posted code satisfies the below objectives.
The objective here is to get a 'number' using a method.
Then only accept selected 'numbers' into an array. The selection/filtration is done by an 'If' statement
Any help and pointers would be highly appreciated.
int i=0;
double iAskSize = GetLevel2Size(ASK,0); //GetLevel2Size(ASK,0) is the method that helps me to retrieve the ASK side 'numbers'//
double iBidSize = GetLevel2Size(BID,0); //GetLevel2Size(BID,0) is the method that helps me to retrieve the BID side 'numbers' //
if(iAskSize>=AskTH_value) //the number should be >= user defined AskTH_value, this is the filtration of the Ask Side 'numbers'//
I am trying to get the filtered iAskSize 'numbers' into the array
reqAskSize, I believe there is a problem here. However I am not sure
{
double[] reqAskSize = new double[1000];
double reqAskArraySum = 0;
for(i=0;i<reqAskSize.Length;i++)
{
reqAskArraySum = reqAskArraySum + reqAskSize[i];
}
SetValue(0,reqAskArraySum);
}
if(iBidSize>=BidTH_value) **//the number should be >= user defined BidTH_value,this is the filtration of the Bid Side 'numbers'//**
I am trying to get the filtered iBidSize 'numbers' into the array
reqBidSize, I believe there is a problem here. However I am not sure
{
double[] reqBidSize = new double[1000];
double reqBidArraySum = 0;
for(i=0;i<reqBidSize.Length;i++)
{
reqBidArraySum = reqBidArraySum + reqBidSize[i];
}
SetValue(1,-reqBidArraySum);
}
If you are trying to add selected numbers into an array, once a number has been selected (through a conditional like if/else), the number should be set in the array.
For example
int[] array = new int[6];
for(int val = 0; val < 6; val++)
{
if(array[val] > 0)
array[val] = 6;
}
Also to obtain a numeral, a return statement makes clear if anything is got.
You should try and see where a return statement may belong within your code.

c# ms word get visible text

I'm trying to obtain the text shown in a MS Word window in C# using Microsoft.Office.Interop.Word.
Please note it's not the whole document or even the page; just the same content the user sees.
The following code seems to work with simple documents:
Application word = new Application();
word.Visible = true;
object fileName = #"example.docx";
word.Documents.Add(ref fileName, Type.Missing, Type.Missing, true);
Rect rect = AutomationElement.FocusedElement.Current.BoundingRectangle;
Range r1 = word.ActiveWindow.RangeFromPoint((int)rect.Left, (int)rect.Top);
Range r2 = word.ActiveWindow.RangeFromPoint((int)rect.Left + (int)rect.Width, (int)rect.Top + (int)rect.Height);
r1.End = r2.Start;
Console.WriteLine(r1.Text.Replace("\r", "\r\n"));
However, when the document includes other structures such as headers, only parts of the text are returned.
So, what's the correct way to achieve this?
Thanks a lot!
Updated Code
Rect rect = AutomationElement.FocusedElement.Current.BoundingRectangle;
foreach (Range r in word.ActiveDocument.StoryRanges) {
int left = 0, top = 0, width = 0, height = 0;
try {
try {
word.ActiveWindow.GetPoint(out left, out top, out width, out height, r);
} catch {
left = (int)rect.Left;
top = (int)rect.Top;
width = (int)rect.Width;
height = (int)rect.Height;
}
Rect newRect = new Rect(left, top, width, height);
Rect inter;
if ((inter = Rect.Intersect(rect, newRect)) != Rect.Empty) {
Range r1 = word.ActiveWindow.RangeFromPoint((int)inter.Left, (int)inter.Top);
Range r2 = word.ActiveWindow.RangeFromPoint((int)inter.Right, (int)inter.Bottom);
r.SetRange(r1.Start, r2.Start);
Console.WriteLine(r.Text.Replace("\r", "\r\n"));
}
} catch { }
}
There may be some problems with this:
Its not reliable. Are you truly able to get consistent results each
time? For example, on a simple "=rand()" document, run the program 5
times in a row without changing the state of Word. When I do this, I
get a different range printed to the console each time. I would first start here: there seems to be something wrong with your logic for getting the ranges. For example, rect.Left keeps returning different numbers every time I execute it against the same document left alone on screen
It gets tricky with other stories. Perhaps RangeFromPoint cannot
extend across multiple story boundaries. However, lets assume it does. You would still need to enumerate each story e.g.
enumerator = r1.StoryRanges.GetEnumerator();
{
while (enumerator.MoveNext()
{
Range current = (Range) enumerator.Current;
}
}
Have you tried to look at How to programmatically extract the text of the currently viewed page of an Office.Interop.Word.Document object ?
You are probably seeing the side effects of range selecting across page elements.
In most cases, if you move your cursor to the top left of the screen, down to the bottom right of the screen it will only select the main body text (no headers or footers). Also, if the document has columns, and those columns start or end off screen, then when you select from the fist column the text through to the last column will be selected, even if it is off the screen.
To my knowledge there is no easy way to achieve your goal unless you are willing to ignore the inconsistencies, or want to deal with all the use cases specifically (images, columns, tables, etc.).
If you can tell us what you are trying to do then we can offer alternatives, otherwise please mark an answer as correct.
The above discussion is very specific to the Office versions.
I think my code will work in all cases.
IntPtr h = (IntPtr)Globals.ThisAddIn.Application.ActiveWindow.Hwnd;
String strText = NativeInvoker.GetWindowText(h);
if (strText != null && strText.StartsWith(Globals.ThisAddIn.Application.ActiveWindow.Caption))
{
h = NativeInvoker.FindWindowEx(h, IntPtr.Zero, "_WwF", "");
h = NativeInvoker.FindWindowEx(h, IntPtr.Zero, "_WwB", null);
h = NativeInvoker.FindWindowEx(h, IntPtr.Zero, "_WwG", null);
Rect t;
if (NativeInvoker.GetWindowRect(h, out t))
{
Range r1 = (Range)Globals.ThisAddIn.Application.ActiveWindow.RangeFromPoint((int)t.Left, (int)t.Top);
Range r2 = (Range)Globals.ThisAddIn.Application.ActiveWindow.RangeFromPoint((int)t.Right, (int)t.Bottom);
Range r = Globals.ThisAddIn.Application.ActiveDocument.Range(r1.Start, r2.Start);
....
You can refer to the NativeInvoker class contents from anyware.
I hope my code will help your work.
Phon.
I have similar requirement in my Word add ins.
Try bellow code, it works for me.
IntPtr h = Process.GetCurrentProcess().MainWindowHandle;
h = NativeMethodsActiveScreen.FindWindowExW(h, new IntPtr(0), "_WwF", "");
h = NativeMethodsActiveScreen.FindWindowExW(h, new IntPtr(0), "_WwB", null);
h = NativeMethodsActiveScreen.FindWindowExW(h, new IntPtr(0), "_WwG", null);
NativeMethodsActiveScreen.tagRECT t = new NativeMethodsActiveScreen.tagRECT();
NativeMethodsActiveScreen.GetWindowRect(h, out t);
var Aw = RibbonHelper.SharedApplicationInstance.ActiveWindow;
Range fullDocRange = RibbonHelper.SharedApplicationInstance.ActiveDocument.Range();
Range r1 = RibbonHelper.SharedApplicationInstance.ActiveWindow.RangeFromPoint(t.left, t.top);
Range r2 = RibbonHelper.SharedApplicationInstance.ActiveWindow.RangeFromPoint(t.right, t.bottom);
Range r = RibbonHelper.SharedApplicationInstance.ActiveDocument.Range(r1.Start, r2.Start);
if it helps please mark answer as helpful.
Thanks

How do I translate the below javascript to C#?

I don't understand how 's' is being used in '(+s[i])'. What is the '+' for? Also I do not understand the use of the || symbol in this way, what is it doing?
var draw = function(s){
...
if (+s[i]) a = (a+90)%360||360; // Right
else a = (a-90||360); // Left
In the code below I do not understand what 'while (n--)' does?
var getS = function(n){
var s = '';
while (n--) s += getNext(0);
return s;
};
If you want to look at this code in context go to http://fractal.qfox.nl/ and press F12 to get the developer tools up and look for dragon.js in the scripts. Please feel entirely free to post a complete translation to C# as well if you fancy the challenge.
Putting + in front of an expression coerces it into a number, e.g. from a string.
The || operator has the value of its left side if that can convert to true, otherwise the value of its right side. And so a||b would mean "use a if it's not null, false, zero or an empty string, otherwise use b".
And n-- will have boolean value false when n reaches zero.
if (+s[i]) is checking if s[i] exists and is a number != 0. In C# it would be the same as
int n;
if (int.TryParse(s[i], out n) && n != 0) { }
a = (a-90||360); is basically saying if leftside of || is null, undefined, false or zero, then take rightside. In C# it would look something like
a = (a-90 > 0)? a-90 : 360;
but a would have to be declared prior to that line.
while (n--){ } keeps repeating itself until n is 0. n must be declared prior to running that code though such as var n = 10;. In C# it would be
int n = 10;
while (n >= 0)
{
n--;
}

Categories