PDFlib - place wrapping text using "textflow" in top-left corner instead of bottom-left - pdflib

Given: a) a long paragraph of text that can only be 10cm wide. Height is unlimited, paragraph text should wrap when it hits the right margin; b) a page with topdown=true.
I'm trying to use combination of add_textflow() and fit_textflow() to do it. but PDFlib places paragraph in the lower-left corner, while known coordinates for that paragraph are for the top-left corner.
My code:
$p->begin_page_ext($width, $height);
$p->set_option("usercoordinates=true");
$p->set_option("topdown=true");
...
$tf = 0;
$tf = $p->add_textflow($tf, 'My loooong wrapping paragraph, 'fontname=Helvetica fontsize=10 encoding=unicode charref');
$result = $p->fit_textflow($tf, $lowerLeftX, $lowerLeftY, $upperRightX, $upperRightY, 'fitmethod=nofit');
$p->delete_textflow($tf);
Question:
What can I do to supply coordinates as:
$p->fit_textflow($tf, $topLeftX, $topLeftY, $lowerRightX, $lowerRightY)?
I tried adding position={left top} to fit_textflow() options, but PDFlib is throwing error.

first of all, your code missed the non optional parameter $option in the begin_page_ext() call. In your case you might use
$p->begin_page_ext($width, $height, "topdown=true");
so you get rid of the additional set_option() call.
Textflow output starts always at the top of the fitbox (the area where the text will be placed) no line will be written behind the right border. So your requirement is the default.
You might start using with starter_textflow.php sample to get a first impression how you can use it (especially for long text, which do not fit to the given fitbox). As well many further samples within the PDFlib cookbook show further (more complex) aspects: https://www.pdflib.com/pdflib-cookbook/textflow/
In your case, you might simple work with:
$lowerLeftX = 0;
$lowerLeftY = $height; // this is the page height
$upperRightX = 10 * 72 / 2.54; // this is 10 cm in the default coordinate system
$upperRightY = 0; // this is the top border of the page
$result = $p->fit_textflow($tf, $lowerLeftX, $lowerLeftY, $upperRightX, $upperRightY, 'fitmethod=nofit');
Please see PDFlib 9.2 Tutorial, chapter 3.2.1 "Coordinate Systems" for details on the coordinate system.

Related

Docs Inserted Image always before all text

Making a simple app script that puts images and Text into a Google Doc separated by 2 Columns, for whatever reason, no matter the way I try it the images are always above the text (Inline) in the Doc, even though they should be layered (Inline),
//Replace QR Code
let qrText = editLocalBody.findText("{{qrCode}}");
let setImagePlace = qrText.getElement().asText().replaceText("{{qrCode}}", "");
let qrCodeImage = setImagePlace.getParent().asParagraph().insertInlineImage(0, qrCodeBlob);
From what I've seen this should insert an image wherever the text was previously located, but when it runs this it's always in the wrong spot, somehow above the text it was suppost to be in!
//Edit - To Show The Progression Of What Is Suppose To Happen And What Actually Happens:
I'm making QR Code badges for a propriety system that runs integrated tightly with Google, so I'm using appscript to get an entry from a google form containing an amount of badges (With relevent data) and autofill a Google Doc Accordingly.
// Loop Start
I fill my template with a text line that has key words in it I can select and replace later, with a keyword it can use to insert another this (This Part Works)
I first edit (findText("{{qrCode}}");) the QR Code, replacing (.replaceText) the keyword for it to nothing ("")
I then get the parent of the piece of code I ran above, which is a block of text (I think all the text in the Doc, I think this is where the issue lies, it puts it above the text because it's just one 'paragraph' or not multiple 'bodies' of text, if I could separate this I think it would work!) As a paragraph, and insert An Inline Image at Child Index (0, of the image ,qrCodeBlob)
I've debugged this script quite a bit, so I know It's that final line that inserting images fails, it sees all the text as 'one'.
// I want this (In Descending Order, each it's own full line):
Image
Text
Image
Text
//What It Gives Me (In Descending Order, each it's own full line):
Image
Image
Text
Text
let qrCodeImage = setImagePlace.getParent().asParagraph().insertInlineImage(0, qrCodeBlob);

Is there an attribute 'fit-to-page' in add_picture() using python docx

I have added a picture in a doc by using python docx. It looks good as long as it's small. But the picture goes next page or it's displayed half of it if the size is too big. How to make my picture 'fit-to-page'. I dont want to give any constants like Inches-5.5 or something.
p1 = doc.add_paragraph(' ')
pic = doc.add_picture(os.path.join(base_path, fi),
width=Inches(5.0))
para = doc.paragraphs[-1]
It's possible to get the text width, which is the page width minus the left and right margins, and pass this value to the width argument of add_picture().
An example of a function to get the text width is:
def get_text_width(document):
"""
Returns the text width in mm.
"""
section = document.sections[0]
return (section.page_width - section.left_margin - section.right_margin) / 36000
You can then call the function when adding a new picture:
r.add_picture(image, width=Mm(get_text_width(doc)))
If you need to add pictures in different sections of a document, it's necessary to improve the function to address this.
References:
How to change page size to A4 in python-docx
https://www.trichview.com/help/units_of_measurement.html#:~:text=English%20metric%20unit%20(EMU)%20is,%2C%201%20mm%20%3D%2036000%20EMU

Aligning chart title with left side of numbers on the y axis

I am trying to make an Altair theme that conforms with our internal guidelines. I found this excellent article that solved most of my issues. However, neither the article nor a search of the documentation has solved the problem of aligning the chart title with the left side of the numbers on the y axis.
See the dotted line in Urban institute's theme for visual explanation.
The problem is that I do not know the width of the longest number on the y axis. The solutions I have found just hard code an offset for the expected width of the number. However, I have to make a theme that automatically conforms to the standard in all cases.
Hints to possible solutions are welcome. I will try them out and post results.
The available title alignment settings for Altair/Vega-Lite are listed here: https://vega.github.io/vega-lite/docs/title.html#params
The closest thing to what you desire is to set anchor='start' in the title config:
import altair as alt
from vega_datasets import data
cars = data.cars()
alt.Chart(cars).mark_bar().encode(
x=alt.X('Miles_per_Gallon', bin=True),
y='count()',
).properties(
title='A bar chart'
).configure_title(
anchor='start'
)
Unfortunately, there is no way in the Vega-Lite schema to control the alignment more finely than that. If this is important to your use of Altair/Vega-Lite, I would suggest opening a Vega-Lite feature request.
I'm not sure if this exactly what you're looking for since you mentioned wanting to create a theme, but you can recreate the look of the UI theme by adding text to your chart via mark_text().
Here's an example:
df = pd.DataFrame({'col1':[0,1,2,3,4,5], 'col2':[0,1,2,3,4,5]})
text_df = pd.DataFrame({'col1':[0], 'col2':[0], 'col3':['title']})
line = alt.Chart(df).mark_line().encode(x='col1', y='col2')
text = alt.Chart(text_df.query('col1 == 0')).mark_text(dx=-60, dy=-400, fontSize=24, font='Lato').encode(x='col1', y='col2', text='col3')
line + text
This is the resulting chart:

Access VBA Create Word header with text and position picture

Having trouble getting access vba to set a word document's header properly. I've got this.
oDoc.PageSetup.DifferentFirstPageHeaderFooter = True
oDoc.Sections(1).Headers(wdHeaderFooterFirstPage).Range.InlineShapes.AddPicture "C:\Users\mr.helpless\Pictures\doody.jpg"
oDoc.Sections(1).Headers(wdHeaderFooterFirstPage).Range.Text = "hello there"
oDoc.Sections(1).Headers(wdHeaderFooterPrimary).Range.Text = "whooo hooo!"
What happens right now is the text will replace the picture for the first page (subsequent pages are fine).
I need to have the picture and text - and I need to offset the picture to the left about half an inch while text is centered with normal margins.
Any idea how to go about it? Basically I need to set a document letterhead with a logo.
Update
Dim myText As String
myText = "hello there"
With oDoc.Sections(1).Headers(wdHeaderFooterFirstPage)
.Shapes.AddPicture Filename:="C:\Users\mr.helpless\Pictures\doody.jpg", LinkToFile:=False, SaveWithDocument:=True
.Range.Collapse
.Range.InsertAfter (myText)
.Range.Font.Name = "Helvetica"
.Range.Font.Size = 8
.Range.Font.Bold = True
.Range.Paragraphs.Alignment = wdAlignParagraphCenter
End With
I've got half of it done, now I just need to position the image to -.5 to margin.
Completed Solution
Just add "Left:=-35" to the picture like such (or whatever value works)
.Shapes.AddPicture Filename:="C:\Users\mr.helpless\Pictures\doody.jpg", LinkToFile:=False, SaveWithDocument:=True, Left:=-35
Have you tried recording a macro in Word that does the rough reposition - then bring the code over to Access and edit it for the correct object and size?
All of it is updated in the original thread. it took using the .Range Collapse to add in text along with the image and it took putting Left:=(value) to move it where I needed it.

(AS3) Getting an HTML-specific character index in a textfield after word wrap

I didn't know how to phrase the title, so sorry about that. If you have a better title suggestion, let me know and I'll change it.
I've got a chunk of text that is displayed as HTML in a TextField. An example of this text is this:
1
<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font>
</br>
2
<i>99 percent of lawyers give the rest a bad name.</i>
<b>Artificial intelligence is no match for natural stupidity.</b>
<u>The last thing I want to do is insult you. But it IS on the list.</u>
</br>
3<showimage=Images/image1.jpg>
I don't have a solution, but I do admire the problem.
The only substitute for good manners is fast reflexes.
Support bacteria - they're the only culture some people have.
</br>
4
Letting the cat out of the bag is a whole lot easier than putting it back in.
Well, here I am! What are your other two wishes?
Most of the tags are basic, meant to display what I can do formatting wise. However, since Adobe Air has a sandbox that prevents inline images (via the <img src='foo.png'> tag), I've had to come up with another way to display images.
Basically, I intend on having an image displayed somewhere on the screen, and as the user scrolls the image will change based on where in the text they have scrolled to. The image can be a background image, a slideshow on the right, anything really.
In the snippet above, look for my custom tag <showimage=Images/image1.jpg>. I want to get the local y position of that tag once the TextField is rendered as HTML and word wrapped. The trouble is, when I query the y position of the tag (using getCharBoundaries), I can only either search for the tag when I render the text as a .text instead of a .htmlText. If I search for the tag in the TextField after rendering it as .htmlText, it doesn't get found because the tags are hidden and replaced with formatting.
The trouble with the y value I get before rendering the HTML is that the y value will be different due to font sizes, tags being hidden and word wrap changing the line and y value that the tag is located at.
How do I get the correct y value of an HTML tag once the HTML has been rendered?
I've considered using a different style tag, maybe something like &&&&&showImage=Images/image1.jpg&&&&, but that seems like a cop-out and I'd still run into problems if multiple of those tags were in a block of text and the tags were removed, followed by word wrap that shifts lines in a pretty unpredictable way.
myTextField.textHeight tells you the height of the text in pixels. So you can split the string on whatever you're looking for, put the text before your target in the textField and get the textHeight, then put the rest of the text in.
Here's some example code - tMain is the name of the textField:
var iTextHeight: int = 0;
var sText: String = '<font size="30" color="#FF0000">When your only tool is a hammer, all problems start looking like nails.</font></br><i>99 percent of lawyers give the rest a bad name.</i><b>Artificial intelligence is no match for natural stupidity.</b><u>The last thing I want to do is insult you. But it IS on the list.</u></br><showimage=Images/image1.jpg> I don\'t have a solution, but I do admire the problem. The only substitute for good manners is fast reflexes. Support bacteria - they\'re the only culture some people have. </br>Letting the cat out of the bag is a whole lot easier than putting it back in. Well, here I am! What are your other two wishes?';
var aStringParts: Array = sText.split("<showimage=Images/image1.jpg>");
for (var i = 0; i < aStringParts.length; i++) {
if (i == 0) {
tMain.htmlText = aStringParts[i];
trace("height of text: " + tMain.textHeight);
} else {
tMain.appendText(aStringParts[i]);
}
}
sText gets split on the tag you're looking for (removes the text you're looking for and breaks remaining text into an array). The text leading up to the tag is put in the textField and the textHeight is traced. Then the rest of the text is put in the textField. This gives you the y pixel number you need to arrange things.
Let me know of any questions you have.
Instead of going through the trouble of parsing your image tag, have you tried playing with HTMLLoader and using the loadString method? This should load everything in its proper place including the image using the img tag.
private var htmlLoader:HTMLLoader;
private function loadHtml(content:String):void
{
htmlLoader = new HTMLLoader(); //Constructor
htmlLoader.addEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Handle complete
htmlLoader.loadString(content); //Load html from string
}
private function handleHtmlLoadComplete(e:Event):void
{
htmlLoader.removeEventListener(Event.COMPLETE, handleHtmlLoadComplete); //Always remove event listeners!
htmlLoader.width = htmlLoader.contentWidth; //Set width and height container
htmlLoader.height = htmlLoader.contentHeight;
addChild(htmlLoader); //Add to stage
}
Another approach is to search your html string for <showImage ..> tags and replace these with shortcodes e.g [showImage ..] , before inserting the htmlString in a textField. Then this is NOT xml but text and you can retrieve the y value (that is if i understand correctly your issue).
Then the rest of your code can take it from there.
(ps using HtmlLoader seems nice alternative though)