RinohType sphinx customize the styles in PDF - python-sphinx

I am using RinohType for generating my RST files to PDF.
I am trying to understand how to provide custom styles in the PDF for my logo and other elements.
I somehow felt the explanation in the Default matcher doesn't provide examples on how to do this.
conf.py
rinoh_documents = [dict(doc='index', # top-level file (index.rst)
target='manual',
template='rinohtype.rtt',
logo='_static/rr-logo-vertical2022-1100px-transp.png')]
rhinotype.rtt
[TEMPLATE_CONFIGURATION]
name = my article configuration
template = article
stylesheet = my_stylesheet.rts
parts =
title
;front_matter
contents
language = fr
abstract_location = title
[SectionTitles]
contents = 'Contents'
[AdmonitionTitles]
caution = 'Careful!'
warning = 'Please be warned'
[VARIABLES]
paper_size = A5
[title]
page_number_format = lowercase roman
end_at_page = left
[contents]
page_number_format = number
[title_page]
top_margin = 2cm
my_stylesheet.rts
Here I am trying to change the width of my logo in the PDF.
What is the correct way to give the css properties here.
width: 100px

The default matcher defines the title page logo style. To adjust the style of this element, you can create a style sheet that builds upon the default sphinx style sheet and tweak the title page logo style:
[STYLESHEET]
name=My Style Sheet
description=My tweaks to the Sphinx style sheet
base=sphinx
[title page logo]
width = 4cm
This style accepts the FlowableStyle style attributes. In the linked documentation, you can see the width attribute supports a bunch of units but not px.
Please stay tuned for better documentation. Something is actually happening in that area!
P.S. If you want to make more changes to the styling of your document, the style log can be very useful to find out which style name corresponds to a particular document element.

Related

HexaPDF add font when importing other document's page

I have app that adding texts for original pdf and generate new pdf.
All is good until I have page that contain different font, then target pdf have no glyphs(boxes instead of characters), when source_doc saved, it displays font properly.
Perhaps something to do with how .import method work but i did not found way :/
Here is part of code:
target_doc = HexaPDF::Document.new
source_doc = HexaPDF::Document.open("source.pdf")
page = source_doc.pages[0]
canvas = page.canvas(type: :overlay)
# ... some code filling the doc with the text
font_file = "new_font.ttf"
source_doc.fonts.add(font_file)
canvas.font font_file
canvas.text(text, at: [x, y])
# back to default font
canvas.font(FONT_FAMILY, size: FONT_SIZE)
source_doc.pages.each { |page| target_doc.pages << target_doc.import(page) }
target_doc.write(output_file)
I have tried to .add font to target_doc but it did not added(tried before and after import)
In the target_doc.fonts I can see font loaded in loaded_fonts_cache and in glyphs.
Anyone has any clue how can I import pages including font used in it ?
Document used: https://hexapdf.gettalong.org/examples/merging.html
In order to import page with missing information(like new fonts), need to call this method before importing pages to a new pdf, after source_doc.fonts.add(font_file) because this info available only after all glyps are known to the source document.
source_doc.dispatch_message(:complete_objects)
Thanks to Thomas, author of HexaPDF <3
https://github.com/gettalong/hexapdf/issues/214

rinohtype export to PDF - document header with chapter name and title

I'd like to define and style header as shown on the picture - the light part contains chapter name, document title is in the dark one.
Now I can only have the light grey section with text aligned to the right.
How can I define header style to achieve this? Also how can I insert those squares into the layout?
Thanks
I'd like to define and style header as shown on the picture - the light part contains chapter name, document title is in the dark one.
Unfortunately, this functionality is not yet documented well. Here are the steps necessary to obtain this:
Set a custom template configuration in conf.py if you haven't done so yet
rinoh_documents = [dict(doc='index', target='manual', template='my_template.rtt')]
Define the page header content in the template configuration (my_template.rtt)
[TEMPLATE_CONFIGURATION]
name = My Template
template = article
stylesheet = my_stylesheet.rts
[contents_page]
header_text = '\t' '{SECTION_TITLE(1)}' (header section title)
'\t' '{DOCUMENT_TITLE}' (header document title)
Style the header text and adjust the tab stop positions and alignment in the style sheet (my_stylesheet.rts)
[STYLESHEET]
name = My Style Sheet
base = sphinx_article
[header]
tab_stops=12cm RIGHT, 100% RIGHT
[header section title : StyledText('header section title')]
base = default
font_weight = bold
[header document title : StyledText('header document title')]
base = header section title
font_slant = italic
Also how can I insert those squares (in front of the text) into the layout?
For black squares, you can insert a unicode character, for example the aptly named BLACK SQUARE character using python-style escape sequences or simply pasting the character into the template configuration:
[contents_page]
header_text = '\t' '\N{BLACK SQUARE} {SECTION_TITLE(1)}' (header section title)
'\t' '■' (header square) ' {DOCUMENT_TITLE}' (header document title)
As you can see, you an style the square differently (e.g. larger font).
You can also use inline images, if unicode (or the font) doesn't cover your needs:
[contents_page]
header_text = '\t' IMAGE('img/square.png', scale=0.3) ' {SECTION_TITLE(1)}' (header section title)
'\t' IMAGE('img/circle.png', scale=0.3) '{DOCUMENT_TITLE}' (header document title)
Also how can I insert those squares into the layout? Adding a background for the page headers
You can set a background image on the page template in your template configuration. You can draw this in a vector drawing application such as Inkscape and export it to PDF.
[contents_page]
background='img/contents_background.pdf' scale=fill
You can adjust the placement of the header text by adjusting the margins and header_footer_distance in the page template configuration and .

PDFClown Copy annotations and then manipulate them

I have the need to copy annotations from one PDF File to another. I have used the excellent PDFClown library but unable to manipulate things like color,rotation etc. Is this possible? I can see the baseobject information but also unsure how to manipulate that directly.
I can copy the appearance via cloning appearance but can't "edit" it.
Thanks in advance.
Alex
P.S If Stephano the author is listeing ,is project dead?
On annotations in general and Callout annotations in particular
I looked into it a bit, and I'm afraid there is not much you can deterministically manipulate for arbitrary inputs using high level methods. The reason is that there are numerous alternative ways to set the appearance of a Callout annotation and PDF Clown only supports the less prioritized ways with explicit high level methods. From high priority downwards
An explicit appearance in an AP stream. If it is given, it is used, ignoring whether this appearance looks like a Callout annotation at all, let alone like one defined by the other Callout properties.
PDF Clown does not create an appearance for callout annotations from the other values yet, let alone update existing appearances to follow up to some specific attribute (e.g. Color) change. For ISO 32000-2 support, PDF Clown here will have to improve as appearance streams have become mandatory.
If it exists, you can retrieve the appearance using getAppearance() but you only get a FormXObject with its low level drawing instructions, nothing Callout specific.
One thing you can manipulate quite easily given a FormXObject, though, you can rotate or skew the appearance quite easily by setting its Matrix accordingly, e.g.
annotation.getAppearance().getNormal().get(null).setMatrix(AffineTransform.getRotateInstance(100, 10));
A rich text string in the RC string or stream. Unless an appearance is given, the text in the Callout text box is generated from this rich text datum (rich text here uses a XHTML 1.0 subset for formatting).
PDF Clown does not create a rich text representation of the Callout text yet, let alone update existing ones to follow up to some specific attribute (e.g. Color) change..
If it exists, you can retrieve the rich text by low level access using getBaseDataObject().get(PdfName.RC), change this string or stream, and set it again using getBaseDataObject().put(PdfName.RC, ...). Similarly you can retrieve, manipulate, and set the rich text default style string using its name PdfName.DS instead.
A number of different settings for separate aspects used to build the Callout from in the absence of appearance stream and (as far as the text content is concerned) rich text string.
PDF Clown supports (many of) these attributes, in particular if you cast the cloned annotation to StaticNote, e.g. the opacity CA using get/set/withAlpha, the border Border / BS using get/set/withBorder, the background color C using get/set/withColor, ...
It by the way has an error in its line ending style LE support: Apparently the code for the Line annotation LE property was copied without checking; unfortunately that attribute there follows a different syntax...
Your tasks
Concerning the attributes you stated you want to change, therefore,
Rotation: There is no rotation attribute in the Callout annotation per se (other than the flag whether or not to follow the page rotation). Thus, you cannot set a rotation as a simple annotation attribute. If the source annotation does have an appearance stream, though, you can manipulate its Matrix to rotate it inside the annotation rectangle, see above.
Border color and font: If your Callout has an appearance stream, you can try and parse its content using a ContentScanner and manipulate color and font setting operations. Otherwise, if rich text information is set, for the font you can try and parse the rich text using some XML parser and manipulate font style attributes. Otherwise, you can parse the default appearance DA string and manipulate its font and color setting instructions.
Some example code
I created a file with an example Callout annotation using Adobe Acrobat: Callout-Yellow.pdf. It contains an appearance stream, rich text, and simple attributes, so one can use this file for example manipulations at different levels.
The I applied this code to it with different values for keepAppearanceStream and keepRichText (you didn't mention whether you used PDF Clown for Java or .Net; so I chose Java; a port to .Net should be trivial, though...):
boolean keepAppearanceStream = ...;
boolean keepRichText = ...;
try ( InputStream sourceResource = GET_STREAM_FOR("Callout-Yellow.pdf");
InputStream targetResource = GET_STREAM_FOR("test123.pdf");
org.pdfclown.files.File sourceFile = new org.pdfclown.files.File(sourceResource);
org.pdfclown.files.File targetFile = new org.pdfclown.files.File(targetResource); ) {
Document sourceDoc = sourceFile.getDocument();
Page sourcePage = sourceDoc.getPages().get(0);
Annotation<?> sourceAnnotation = sourcePage.getAnnotations().get(0);
Document targetDoc = targetFile.getDocument();
Page targetPage = targetDoc.getPages().get(0);
StaticNote targetAnnotation = (StaticNote) sourceAnnotation.clone(targetDoc);
if (keepAppearanceStream) {
// changing properties of an appearance
// rotating the appearance in the appearance rectangle
targetAnnotation.getAppearance().getNormal().get(null).setMatrix(AffineTransform.getRotateInstance(100, 10));
} else {
// removing the appearance to allow lower level properties changes
targetAnnotation.setAppearance(null);
}
// changing text background color
targetAnnotation.setColor(new DeviceRGBColor(0, 0, 1));
if (keepRichText) {
// changing rich text properties
PdfString richText = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.RC);
String richTextString = richText.getStringValue();
// replacing the font family
richTextString = richTextString.replaceAll("font-family:Helvetica", "font-family:Courier");
richText = new PdfString(richTextString);
targetAnnotation.getBaseDataObject().put(PdfName.RC, richText);
} else {
targetAnnotation.getBaseDataObject().remove(PdfName.RC);
targetAnnotation.getBaseDataObject().remove(PdfName.DS);
}
// changing default appearance properties
PdfString defaultAppearance = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.DA);
String defaultAppearanceString = defaultAppearance.getStringValue();
// replacing the font
defaultAppearanceString = defaultAppearanceString.replaceFirst("Helv", "HeBo");
// replacing the text and line color
defaultAppearanceString = defaultAppearanceString.replaceFirst(". . . rg", ".5 g");
defaultAppearance = new PdfString(defaultAppearanceString);
targetAnnotation.getBaseDataObject().put(PdfName.DA, defaultAppearance);
// changing the text value
PdfString contents = (PdfString) targetAnnotation.getBaseDataObject().get(PdfName.Contents);
String contentsString = contents.getStringValue();
contentsString = contentsString.replaceFirst("text", "text line");
contents = new PdfString(contentsString);
targetAnnotation.getBaseDataObject().put(PdfName.Contents, contents);
// change the line width and style
targetAnnotation.setBorder(new Border(0, new LineDash(new double[] {3, 2})));
targetPage.getAnnotations().add(targetAnnotation);
targetFile.save(new File(RESULT_FOLDER, "test123-withCalloutCopy.pdf"), SerializationModeEnum.Standard);
}
(CopyCallOut test testCopyCallout)
Beware, the code only has proof-of-concept quality: For arbitrary PDFs you cannot simply expect a string replace of "font-family:Helvetica" by "font-family:Courier" or "Helv" by "HeBo" or ". . . rg" by ".5 g" to do the job: fonts can be given using different style attributes or names, and different coloring instructions may be used.
Screenshots in Adobe
The original file:
keepAppearanceStream = true:
keepAppearanceStream = false and keepRichText = true:
keepAppearanceStream = false and keepRichText = false:
As a post commment Mkl
Your great advice is really helpful for when creating new annotations. I did apply the following as a method of "copying" an existing annotation where note is the "cloned" annotation ad baseAnnotation the source
foreach (PdfName t in baseAnnotation.BaseDataObject.Keys)
{
if (t.Equals(PdfName.DA) || t.Equals(PdfName.DS) || t.Equals(PdfName.RC) || t.Equals(PdfName.Rotate))
{
note.BaseDataObject[t] = baseAnnotation.BaseDataObject[t];
}
}
Thanks again

jQuery UI Multiselect Widget With Images (Eric Hynds Version)

The excellent dropdown jQuery UI Multiselect widget that supports styling via jQuery UI Themeroller still doesn't have support for including images within the drop down rows.
I didn't see any answers to this problem within Stackoverflow yet it seems to be asked regularly in various areas of the internet, so I am giving the answer to this question below..
(ALSO See my FIDDLE Example to see this in action,)
The following is based on an initial idea by 'pdlove' for introducing the use of images within this excellent UI Multiselect for jQuery.
Adding Image support for line items in check box text area is achieved by setting out the selector option rows html like this:
<option value="somevalue" image="yourimage.jpg" class="multSelktrImg">
normal visible text
</option>
I would also add a class control to your style sheet css file to set the image size being rendered in the option line items of the drop down, along with a couple of position settings for the image, label and span text.
In this example I use the class name 'multSelktrImg', so within the css file it would look something like this:
.multSelktrImg span{position: relative;top: 10px;vertical-align: middle;
display: inline-flex;}
.multSelktrImg input {vertical-align: -2px;}
.multSelktrImg img {position: relative;height: 30px;margin: 2px 6px;top: -10px;}
Now for the change in the src/jquery.multiselect.js file
Search for the following matching code around line 130 (depending on what version id of the script you are using):
// build items
el.find('option').each(function( i ){
var $this = $(this),
parent = this.parentNode,
title = this.innerHTML,
description = this.title,
....
ADD the following line above "title = this.innerHTML,":
image = this.getAttribute("image");
so that it looks like this:
// build items
el.find('option').each(function( i ){
var $this = $(this),
parent = this.parentNode,
image = this.getAttribute("image");
title = this.innerHTML,
description = this.title,
Now Search for the following matching code around line 180:
// add the title and close everything off
html += ' /><span>' + title + '</span></label></li>';
....
Replace the code line with the following to allow for rendering of your images:
// add the title and close everything off
html += ' /><span>';
if (image != null) {
html += '<img src="'+image+'" class="multSelktrImg">';
}
html += title + '</span></label></li>';
save the new version of the script src/jquery.multiselect.js file and now the images will appear in the multiselect drop down. Use the 'multSelktrImg' class value to control the size of the image displayed by altering the pixel size for the class in your css file.
In the FIDDLE version, I have altered the minimized version of the jQuery script, and created an initialisation of the Select object.

Arabic font in Web UI and itextsharp

I'm not able to find a reason why my MVC 3 web site shows arabic font correctly and my pdf not.
I use a bliss font in my web site;
#font-face {
font-family: 'blissregular';
src: url('/Fonts/blissregular-webfont.eot');
src: url('/Fonts/blissregular-webfont.eot?#iefix') format('embedded-opentype'),
url('/Fonts/blissregular-webfont.ttf') format('truetype');
font-weight: normal;
font-style: normal;}
All working fine.
After that I want to create the pdf of the output but arabic fonts does not appears.
I've googled and understand that the font must have the arabic character to show up correctly. I've changed to arial font (that contains arabic character) and... pdf worked.
So... How is possible that with bliss font (that does NOT have arabic characters) I see arabic font in web site?
I'm really confused....
thanks a lot to everybody!
For every character your browser encounters it looks for a matching glyph in the current font. If the font doesn't have that glyph it looks for any fallback fonts to see if they have that glyph. Ultimately every browser has a core set of default fonts that are the ultimate fallback. When you specify the font Bliss but use Arabic characters you are probably just seeing your browser's fallback fonts.
PDFs don't work that way. If you say something is using font XYZ then it will try to render it using that font or fail.
The easiest way probably is to just add a font to your CSS that supports those characters.
.myclass{font-family: blissregular, Arial}
If that doesn't work you might need to inject the fonts manually. (Actually, I'm not 100% certain the iText support #font-face, either.) iText has a helper class that can figure things out for you that Bruno talks about it here but unfortunately the C# link isn't working anymore. It's very simple, you just create an instance of the FontSelector class, call AddFont in the order that you want characters to be looked up up in and then pass a string to the Process() method which spits back a Phrase that you can add. Below is basic sample code that shows this off. I apologize for my sample text, I'm English-native so I just searched for something to use, I hope I didn't mangle it or get it backwards.
You'll need to jump through a couple of extra hoops when processing the HTML but you should be able to work it out, hopefully.
//Sample string. I apologize, this is from a Google search so I hope it isn't backward
var testString = "يوم الاثنين \"monday\" in Arabic";
var outputFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Test.pdf");
//Standard PDF setup
using (var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (var doc = new Document()) {
using (var writer = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
//This is a font that I know *does not* support Arabic characters, substitute with your own font if you don't have it
var gishaFontPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "gisha.ttf");
var gishaBaseFont = BaseFont.CreateFont(gishaFontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var gishaFont = new iTextSharp.text.Font(gishaBaseFont, 20);
//Add our test string using just a normal font, this *will not* display the Arabic characters
doc.Add(new Phrase(testString, gishaFont));
//This is a font that I know *does* support Arabic characters
var arialFontPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Fonts), "ARIALUNI.TTF");
var arialBaseFont = BaseFont.CreateFont(arialFontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
var arialFont = new iTextSharp.text.Font(arialBaseFont, 20);
//Create our font selector specifying our most specific font first
var Sel = new FontSelector();
Sel.AddFont(gishaFont);
Sel.AddFont(arialFont);
//Have the font selector process our text into a series of chunks wrapped in a phrase
var newPhrase = Sel.Process(testString);
//Add the phrase, this will display both characters
doc.Add(newPhrase);
//Clean up
doc.Close();
}
}
}

Resources