Creating measure dictionary for distance annotation - dictionary

Creating a measure distanced annotation does not display the correct measurement unit, nor gives the correct calculation. Any idea which part I am doing wrong? or if there is some lacking data.
I am currently creating a measure distance annotation. Using pixel, it works just fine. but since now i am taking into account actual measurement and unit, i am not sure which part of code i am having problem with or if i am lacking something.
Please see image. That is some application i use to create a distance annotation and i calibrate it that that distance is 14.5cm so by dividing it by pixel, the calibration value per pixel would be 0.0519548.
Now, when I apply it to iText code, i am confused why the display is always still in inches? Even if i set my code to be inches and not cm, the calculation is incorrect.
I am not entirely sure what the problem is.
public class Test {
public static void main(String[] args) throws Exception {
PdfReader reader = new PdfReader("src.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("result.pdf"));
Rectangle location = new Rectangle(55.78125f, 493.875f, 253.59375f, 562.3125f);
PdfDictionary dict = new PdfDictionary();
PdfArray lineEndings = new PdfArray();
lineEndings.add(new PdfName("OpenArrow"));
lineEndings.add(new PdfName("OpenArrow"));
PdfAnnotation stamp = PdfAnnotation.createLine(stamper.getWriter(), location, "test measurement", 55.78125f, 562.3125f, 253.59375f, 493.875f);
stamp.put(new PdfName("LE"), lineEndings);
stamp.put(PdfName.ROTATE, new PdfNumber(0));
stamp.put(PdfName.MEASURE, createMeasureDictionary());
stamp.put(new PdfName("IT"), new PdfName("LineDimension"));
stamp.put(new PdfName("Cap"), new PdfBoolean(true));
stamp.put(PdfName.F, new PdfNumber(516));
stamp.setColor(PdfGraphics2D.prepareColor(Color.RED));
stamper.addAnnotation(stamp, 1);
stamper.close();
reader.close();
}
private static PdfDictionary createMeasureDictionary() {
PdfDictionary measureDictionary = new PdfDictionary(PdfName.MEASURE);
measureDictionary.put(PdfName.R, new PdfString("1 cm = 1 cm"));
PdfDictionary xDictionary = new PdfDictionary(PdfName.NUMBERFORMAT);
xDictionary.put(PdfName.U, new PdfString("cm"));
xDictionary.put(PdfName.C, new PdfNumber(0.0519548f));
measureDictionary.put(PdfName.X, new PdfArray(xDictionary));
PdfDictionary dDictionary = new PdfDictionary(PdfName.NUMBERFORMAT);
dDictionary.put(PdfName.U, new PdfString("cm"));
dDictionary.put(PdfName.C, new PdfNumber(1.0f));
measureDictionary.put(PdfName.D, new PdfArray(dDictionary));
PdfDictionary aDictionary = new PdfDictionary(PdfName.NUMBERFORMAT);
aDictionary.put(PdfName.U, new PdfString("cm"));
aDictionary.put(PdfName.C, new PdfNumber(1.0f));
measureDictionary.put(PdfName.A, new PdfArray(aDictionary));
return measureDictionary;
}
}
#mkl im tagging you in case you have free time to check and guide. thank you.

I do not fully follow your math.
Your line has a length of ca. 209.3 user space units. If you want that line to represent 14.5 cm, the X Conversion factor should be about 0.069273 and not your 0.0519548.
Setting
xDictionary.put(PdfName.C, new PdfNumber(0.069273f));
I get a PDF which upon opening shows
and after a slightest move (after which Adobe Reader rebuilds the appearance)
so no inches...

Related

Using GraphView Library for functions to display multiple graphs

I'm currently developing an android app for reading out multiple sensor values via Bluetooth and display them in a graph. When I stumbled upon jjoe64's GraphViewLibrary, I knew this would fit my purposes perfectly. But now I'm kind of stuck. Basically, I wrote a little function that would generate and display the values of three sensors in 3 different graphs one under the other. This works just fine when the activity is started first, all three graphs a nicely rendered and displayed. But when I want to update the graphs with different values using the resetData()-method to render the new values in each graph, only the last of the three graphs is updated. Obviously, because it's the last graph generated using this rather simple function. My question is: Is there any other elegant way to use a function like mine for generating and updating all three graphs one after the other? I already tried to set the GraphView variable back to null and different combinations of removing and adding the view. Passing the function a individual GraphView-variable like graphView1, graphView2... does also not work.
Here is the function:
private GraphView graphView;
private GraphViewSeries graphViewSerie;
private Boolean graphExisting = false;
...
public void makeGraphs (float[] valueArray, String heading, int graphId) {
String graphNumber = "graph"+graphId;
int resId = getResources().getIdentifier(graphNumber,"id", getPackageName());
LinearLayout layout = (LinearLayout) findViewById(resId);
int numElements = valueArray.length;
GraphViewData[] data = new GraphViewData[numElements];
for (int c = 0; c<numElements; c++) {
data[c] = new GraphViewData(c+1, valueArray[c]);
Log.i(tag, "GraphView Graph"+graphId+": ["+(c+1)+"] ["+valueArray[c]+"].");
}
if (!graphExisting) {
// init temperature series data
graphView = new LineGraphView(
this // context
, heading // heading
);
graphViewSerie = new GraphViewSeries(data);
graphView.addSeries(graphViewSerie);
((LineGraphView) graphView).setDrawBackground(true);
graphView.getGraphViewStyle().setNumHorizontalLabels(numElements);
graphView.getGraphViewStyle().setNumVerticalLabels(5);
graphView.getGraphViewStyle().setTextSize(10);
layout.addView(graphView);
}
else {
//graphViewSerie = new GraphViewSeries(data);
//graphViewSerie.resetData(data);
graphViewSerie.resetData(new GraphViewData[] {
new GraphViewData(1, 1.2f)
, new GraphViewData(2, 1.4f)
, new GraphViewData(2.5, 1.5f) // another frequency
, new GraphViewData(3, 1.7f)
, new GraphViewData(4, 1.3f)
, new GraphViewData(5, 1.0f)
});
}
And this is the function-call depending on an previously generated array (which is being monitored to be filled with the right values):
makeGraphs(graphData[0], "TempHistory", 1);
makeGraphs(graphData[1], "AirHistory", 2);
makeGraphs(graphData[2], "SensHistory", 3);
graphExisting = true;
Any help and / or any feedback in general is greatly appreciated! Lots of thanks in advance!
EDIT / UPDATE:
Thanks to jjoe64's answer I was able to modify the function to work properly. I was clearly having a mistake in my thinking, since I thought I'd also be changing a GraphViewSeries-object I would handle my function as additional parameter (which I tried before). Of course this does not work. However, with this minor Improvements I managed to make this work using a Graphviewseries Array. To give people struggling with a similar problem an idea of what I had to change, here the quick-and-dirty draft of the solution.
I just changed
private GraphViewSeries graphViewSerie;
to
private GraphViewSeries graphViewSerie[] = new GraphViewSeries[3];
and access the right Series using the already given parameter graphId within the function (if-clause) like this:
int graphIndex = graphId - 1;
graphViewSerie[graphIndex] = new GraphViewSeries(data);
In the else-clause I'm updating the series likewise by calling
graphViewSerie[graphIndex].resetData(data);
So, once again many thanks for your support, jjoe64. I'm sorry I wasn't able to update the question earlier, but I did not find time for it.
of course it is not working correct, because you save always the latest graphseries-object in the member graphViewSerie.
First you have to store the 3 different graphviewseries (maybe via array or map) and then you have to access the correct graphviewseries-object in the else clause.

Using scanner and multi variable arrays

So, I have this tiny problem. I'm prompting the user to input 3 variables (Str, Str, Int) that need to be stored in a multi variable array and I can't get it to work. Any help will be appreciated.
LibraryBook[] book = new LibraryBook[5];
//inputing a new book
Scanner input = new Scanner(System.in);
LibraryBook[] myBook = new LibraryBook[0];
System.out.println("Enter book name: ");
String title = input.nextLine().trim();
System.out.println("Enter author name: ");
String author = input.nextLine().trim();
System.out.println("Enter # pages: ");
int pages = input.nextInt();
myBook[0] =new LibraryBook(title,author,pages);
I get this error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at LibraryBookSort.main(LibraryBookSort.java:36)
----jGRASP wedge2: exit code for process is 1.
delete this line
LibraryBook[] myBook = new LibraryBook[0];
and replace last line
myBook[0] =new LibraryBook(title,author,pages);
by this
book[0] =new LibraryBook(title,author,pages);
You're initializing your array with zero size, so you basically don't have any space to store a variable (a class in your case). Here's the correction:
LibraryBook[] myBook = new LibraryBook[10];
I'm assuming you will need no more than 10 locations in your program.
Edit: I just noticed you have two LibraryBook arrays declared, but you're only using one. Is there a necessity for the unused one?

How to update a PDF file?

I am required to replace a word with a new word, selected from a drop-down list by user, in a PDF document in ASP.NET. I am using iTextSharp , but the new PDF that is created is all distorted as I am not able to extract the formatting/styling info of the PDF while extracting. Also, IS There a way to read a pdf line-by-line? Please help..
protected void Page_Load(object sender, EventArgs e)
{
String s = DropDownList1.SelectedValue;
Response.Write(s);
ListFieldNames(s);
}
private void CreatePDF(string text)
{
string outFileName = #"z:\TEMP\PDF\Test_abc.pdf";
Document doc = new Document();
doc.SetMargins(30f, 30f, 30f, 30f);
PdfWriter.GetInstance(doc, new FileStream(outFileName, FileMode.Create));
doc.Open();
BaseFont bfTimes = BaseFont.CreateFont(BaseFont.COURIER, BaseFont.CP1252, false);
Font times = new Font(bfTimes, 12, Font.BOLDITALIC);
//Chunk ch = new Chunk(text,times);
Paragraph para = new Paragraph(text,times);
//para.SpacingAfter = 9f;
para.Alignment = Element.ALIGN_CENTER;
//para.IndentationLeft = 100;
doc.Add(para);
//doc.Add(new Paragraph(text,times));
doc.Close();
Response.Redirect(#"z:\TEMP\PDF\Test_abc.pdf",false);
}
private void ListFieldNames(string s)
{
ArrayList arrCheck = new ArrayList();
try
{
string pdfTemplate = #"z:\TEMP\PDF\abc.pdf";
//string dest = #"z:\TEMP\PDF\Test_abc.pdf";
PdfReader pdfReader = new PdfReader(pdfTemplate);
string pdfText = string.Empty;
string extracttext = "";
for (int page = 1; page <= pdfReader.NumberOfPages; page++)
{
ITextExtractionStrategy its = new iTextSharp.text.pdf.parser.SimpleTextExtractionStrategy();
PdfReader reader = new PdfReader((string)pdfTemplate);
extracttext = PdfTextExtractor.GetTextFromPage(reader, page, its);
extracttext = Encoding.Unicode.GetString(ASCIIEncoding.Convert(Encoding.Default, Encoding.Unicode, Encoding.Default.GetBytes(extracttext)));
pdfText = pdfText + extracttext;
pdfText = pdfText.Replace("[xyz]", s);
pdfReader.Close();
}
CreatePDF(pdfText);
}
catch (Exception ex)
{
}
finally
{
}
}
You are making one wrong assumption after the other.
You assume that the concept of "lines" exists in PDF. This is wrong. In Text State, different snippets of text are drawn on the page at absolute positions. For every "show text" operator, iText will return a TextRenderInfo object with the portion of text that was drawn and its coordinates. One line can consist of multiple text snippets. A text snippet may contain whitespace or may even be empty.
You assume that all text in a PDF keeps its natural reading order. This should be true for PDF/UA (UA stands for Universal Accessibility), but it's certainly not true for most PDFs you can find in the wild. That's why iText provides location-based text extraction (see p521 of iText in Action, Second Edition). As explained on p516, the text "Hello World" can be stored in the PDF as "ld", "Wor", "llo", "He". The LocationTextExtractionStrategy will order all the text snippets, reconstructing words if necessary. For instance: it will concatenate "He" and "llo" to "Hello", because there's not sufficient space between the "He" snippet and the "llo" snippet. However, for reasons unknown (probably ignorance), you're using the SimpleTextExtractionStrategy which doesn't order the text based on its location.
You are completely ignoring all the Graphics State operators, as well as the Text State operators that define the font, etc...
You assume that PDF is a Word processing format. This is wrong on many levels, as is your code. Please read the intro of chapter 6 of my book.
All these wrong assumptions almost make me want to vote down your question. At the risk of being voted down myself for this answer, I must tell you that you shouldn't try to "do the same". You're asking something that is very complex, and in many cases even impossible!

Increment multidimensional array in Java

I have a file to put in a multidimensional array. I have to put to [0] a date (long) and one of the dimensions must be incremented depending on the value of the second token.
Here's the code :
BufferedReader bufStatsFile = new BufferedReader(new FileReader(statsFile));
String line = null;
List<Long[]> stats = new ArrayList<Long[]>();
stats.add(new Long[11]);
int i = 0; // will be in a loop later
while((line = bufStatsFile.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line,";");
while(st.hasMoreTokens()) {
stats.get(i)[0] = Long.parseLong(st.nextToken());
stats.get(i)[Integer.parseInt(st.nextToken())]++; // Here is the problematic line.
}
}
bufStatsFile.close();
But the incrementation doesn't work. Maybe it is because of my array which is probably not correct, but I didn't found another proper way to do that.
Ok. I have found and it was, of course, stupid.
The problem was in my array declaration. I did it like that :
List<Long[]> stats = new ArrayList<Long[]>();
stats.add(new Long[11]);
And then, I tried to increment an Object and not a long number.
So now, I just do it like this :
List<long[]> stats = new ArrayList<>();
stats.add(new long[11]);
And it's perfectly working.
Check that the elements in your file are numbers from 0 to 10. Why are you having a List if you are only manipulating the row 0?
Which exception are your code throwing away?

How can I pass controls as reference in Bada?

In the big picture I want to create a frame based application in Bada that has a single UI control - a label. So far so good, but I want it to display a number of my choosing and decrement it repeatedly every X seconds. The threading is fine (I think), but I can't pass the label pointer as a class variable.
//MyTask.h
//...
result Construct(Label* pLabel, int seconds);
//...
Label* pLabel;
//MyTask.cpp
//...
result
MyTask::Construct(Label* pLabel, int seconds) {
result r = E_SUCCESS;
r = Thread::Construct(THREAD_TYPE_EVENT_DRIVEN);
AppLog("I'm in da constructor");
this->pLabel = pLabel;
this->seconds = seconds;
return r;
}
//...
bool
Threading::OnAppInitializing(AppRegistry& appRegistry)
{
// ...
Label* pLabel = new Label();
pLabel = static_cast<Label*>(pForm->GetControl(L"IDC_LABEL1"));
MyTask* task = new MyTask();
task->Construct(&pLabel); // HERE IS THE ERROR no matching for Label**
task->Start();
// ...
}
The problem is that I have tried every possible combination of *, &, and just plain pLabel, known in Combinatorics...
It is not extremely important that I get this (it is just for training) but I am dying to understand how to solve the problem.
Have you tried:
task->Construct(pLabel, 0);
And by that I want to point out that you are missing the second parameter for MyTask::Construct.
No, I haven't. I don't know of a second parameter. But this problem is solved. If I declare a variable Object* __pVar, then the constructor should be Init(Object* pVar), and if I want to initialize an instance variable I should write
Object* pVar = new Object();
MyClass* mClass = new MyClass();
mClass->Construct(pVar);

Resources