Choosing a FontProviderImp in iTextSharp - itext

I am using XMLWorker for parsing html. I have been having some issues with the fonts I define in the styles. For example, something simple as this:
<span style="font-family: Garamond">Foo Garamond</span>
wasn't not working.
I was using this as my css applier:
CssAppliers ca = new CssAppliersImpl();
In order to check if it was a problem with the encoding of the html, or any other issue..., I did my own implementation of the IFontProvider:
class MyFontProvider : IFontProvider
{
public bool IsRegistered(string fontname)
{
return false;
}
public Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color)
{
var font = FontFactory.GetFont(fontname, encoding, embedded, size, style, color);
return new Font(font);
}
}
Then, this:
CssAppliers ca = new CssAppliersImpl(new MyFontProvider());
Great!!!, that works fine!!!, also if I passed to the constructor this:
CssAppliers ca = new CssAppliersImpl(new XMLWorkerFontProvider());
also works.
So, it is obvious that the default implementation of the font provider is not working. I defined it as this:
CssAppliers ca = new CssAppliersImpl();
or
CssAppliers ca = new CssAppliersImpl(new FontFactoryImp());
, and neither worked.
My questions are:
What possible explanation has this?
Differences between XMLWorkerFontProvider and FontFactoryImp implementations

FontFactoryImp is part of iText/iTextSharp core. It provides access to the required core 14 fonts and allows you to optionally register additional font files and give them nice names. But unless you manually register a font file it will just return the "default" font.
XMLWorkerFontProvider is part of XMLWorker and is actually a subclass of FontFactoryImp. The biggest difference between the two is that if you use the empty constructor on XMLWorkerFontProvider it actually calls base.RegisterDirectories() which registeres every font in the system font folder. Depending on the number of fonts you have this could be expensive which is why the default version doesn't do it.

Related

How can I get text value of TMPro Text without markup tags in Unity?

I am trying to get text value in TMPro Text component without markup tags but haven't found any solutions.
Say, <b><color=red>Hello </color><b> world is the value in TMPro Text, and I just want Hello world in c# script.
Bear in mind that tag <b> and color will change, so I would love to remove tags dynamically, meaning I would like not to replacing each tag by text.replace("<b>", "") kind of things.
Does anyone know how to do it?
I dont know about the option of using HTML on tmp but you can attach the text to your script by create a new variable like that:
[SerializeField] TMP_Text textVar;
then you can drag you tmp game object to the component that include this script
and the you can change the text like that:
textVar.text = "what ever";
or get text like that:
string textString = textVar.text;
for the color you can use
Color color = textVar.color;
You can use TMP_Text.GetParsedText () to get the text after it has been parsed and rich text tags removed.
Alternatively you can also use regular expressions to search a string for rich text tags, and remove them while preserving the rest of the string.
using System.Text.RegularExpressions;
public static string GetString (string str)
{
Regex rich = new Regex (#"<[^>]*>");
if (rich.IsMatch (str))
{
str = rich.Replace (str, string.Empty);
}
return str;
}

Proper way to implement custom Css attribute with Itext and html2Pdf

I'm using Itext 7 and their html2Pdf lib.
Is there a way to implement for example cmyk colors.
.wootWorkingCMYK-color{
color: cmyk( 1 , 0.69 , 0.08 , 0.54);
}
I know the itext core part pretty good, looking for away to use the html2Pdf side. I'm aware of the CssApplierFactory but this seems to be to far up the chain.
Well, of course there is a way of processing custom CSS properties like cmyk colors, but unfortunately the code would be quite bulky and you will need to write quite some code for different cases. I will show how to apply custom color for font, but e.g. for backgrounds, borders or other cases you will need to write separate code in a similar way. Reason behind it is that iText layout structure, although designed with HTML/CSS in mind, is not 100% similar and has some differences you have to code around.
Having that said, if you can fork, build and use your custom version from sources, this is the way I would advice to go. Although it has drawbacks like having to rebase to get updates, the solution would be simpler and more generic. To do that, search for usages of CssUtils.parseRgbaColor in pdfHTML module, and you will find that it is used in BackgroundApplierUtil, BorderStyleApplierUtil, FontStyleApplierUtil, OutlineApplierUtil. There you will find code like
if (!CssConstants.TRANSPARENT.equals(cssColorPropValue)) {
float[] rgbaColor = CssUtils.parseRgbaColor(cssColorPropValue);
Color color = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
float opacity = rgbaColor[3];
transparentColor = new TransparentColor(color, opacity);
} else {
transparentColor = new TransparentColor(ColorConstants.BLACK, 0f);
}
Which I belive you can tweak to process cmyk as well, knowing that you know core part pretty well.
Now, the solution without custom pdfHTML version is to indeed start with implementing ICssApplierFactory, or subclassing default implementation DefaultCssApplierFactory. We are mostly interested in customizing implementation of SpanTagCssApplier and BlockCssApplier, but you can consult with DefaultTagCssApplierMapping to get the full list of appliers and cases they are used in, so that you can decide which of them you want to process in your code.
I will show you how to add support for custom color space for font color in the two main applier classes I mentioned and you can work from there.
private static class CustomCssApplierFactory implements ICssApplierFactory {
private static final ICssApplierFactory DEFAULT_FACTORY = new DefaultCssApplierFactory();
#Override
public ICssApplier getCssApplier(IElementNode tag) {
ICssApplier defaultApplier = DEFAULT_FACTORY.getCssApplier(tag);
if (defaultApplier instanceof SpanTagCssApplier) {
return new CustomSpanTagCssApplier();
} else if (defaultApplier instanceof BlockCssApplier) {
return new CustomBlockCssApplier();
} else {
return defaultApplier;
}
}
}
private static class CustomSpanTagCssApplier extends SpanTagCssApplier {
#Override
protected void applyChildElementStyles(IPropertyContainer element, Map<String, String> css, ProcessorContext context, IStylesContainer stylesContainer) {
super.applyChildElementStyles(element, css, context, stylesContainer);
String color = css.get("color2");
if (color != null) {
color = color.trim();
if (color.startsWith("cmyk")) {
element.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
}
}
}
}
private static class CustomBlockCssApplier extends BlockCssApplier {
#Override
public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker) {
super.apply(context, stylesContainer, tagWorker);
IPropertyContainer container = tagWorker.getElementResult();
if (container != null) {
String color = stylesContainer.getStyles().get("color2");
if (color != null) {
color = color.trim();
if (color.startsWith("cmyk")) {
container.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
}
}
}
}
}
// You might want a safer implementation with better handling of corner cases
private static DeviceCmyk parseCmykColor(String color) {
final String delim = "cmyk(), \t\r\n\f";
StringTokenizer tok = new StringTokenizer(color, delim);
float[] res = new float[]{0, 0, 0, 0};
for (int k = 0; k < 3; ++k) {
if (tok.hasMoreTokens()) {
res[k] = Float.parseFloat(tok.nextToken());
}
}
return new DeviceCmyk(res[0], res[1], res[2], res[3]);
}
Having that custom code, you should configure the ConverterProperties accordingly and pass it to HtmlConverter:
ConverterProperties properties = new ConverterProperties();
properties.setCssApplierFactory(new CustomCssApplierFactory());
HtmlConverter.convertToPdf(..., properties);
You might have noticed that I used color2 instead of color, and this is for a reason. pdfHTML has a mechanism of CSS property validation (as browsers do as well), to discard invalid CSS properties when calculating effective properties for an element. Unfortunately, there is no mechanism of customizing this validation logic currently and of course it treats cmyk colors as invalid declarations at the moment. Thus, if you really want to have custom color property, you will have to preprocess your HTML and replace declarations like color: cmyk... to color2: cmyk.. or whatever the property name you might want to use.
As I mentioned at the start of the answer, my recommendation is to build your own custom version :)

iTextSharp XMLWorkerHelper Font Size

I'm need to set the font size for the iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml() method.
Or set the document default font side. but I can't seem to find the methods in Document object :/
using (var stringReader = new StringReader(tcTopic.Body))
{
iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(
pdfWriter, doc, stringReader
);
}
Setting the font-size in the HTML content that is being parsed through solved my issue.

Embedding font using itext 5 for PDF/UA compliance

We are currently building a proof of concept to generate PDF/UA compliant PDF from from a CSS and html (xhtml) file using xslt. We are able tag the PDF and add the appropriate metadata information.
The last major issue we are unable to solve is embedding a standard PDF font zapfdinbats, which our accessibility assessment tool complains about - using PAC 2.0 along with adobe DC built in checker.
As you can see from the image below the other fonts we are using seems automatically get embedded using the xmlworker from our CSS.
I have also tried finding the font as indicated and found one, however, it doesn't seem to be the correct one.
Here is a sample of our code
private static ReturnValue CreateFromHtml(string html)
{
ReturnValue Result = new ReturnValue();
var stream = new MemoryStream();
using (var doc = new Document(PageSize.LETTER))
{
using (var ms = new MemoryStream())
{
using (var writer = PdfWriter.GetInstance(doc, ms))
{
writer.CloseStream = false;
writer.SetPdfVersion(PdfWriter.PDF_VERSION_1_7);
//TAGGED PDFVERSION_1_7
//Make document tagged
writer.SetTagged();
//===============
//PDF/UA
//Set document metadata
writer.ViewerPreferences = PdfWriter.DisplayDocTitle;
doc.AddLanguage("en-US");
doc.AddTitle("document title");
writer.CreateXmpMetadata();
doc.Open();
var embedfont = HttpContext.Current.Server.MapPath("~/scripts/ZapfDingbats.ttf");
var fontProv = new XMLWorkerFontProvider();
fontProv.DefaultEncoding = "UTF-8";
fontProv.Register(embedfont);
//Testing zapfDingbats font
Font font = FontFactory.GetFont(embedfont, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Paragraph p1 = new Paragraph("Testing of Fonts", font);
doc.Add(p1);
//end font processing
var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
tagProcessors.RemoveProcessor(HTML.Tag.IMG);
tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor());
var cssFiles = new CssFilesImpl();
cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
var cssResolver = new StyleAttrCSSResolver(cssFiles);
var charset = Encoding.UTF8;
var context = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
context.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors);
var htmlPipeline = new HtmlPipeline(context, new PdfWriterPipeline(doc, writer));
var cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(cssPipeline, true);
var xmlParser = new XMLParser(true, worker, charset);
using (var sr = new StringReader(html))
{
xmlParser.Parse(sr);
doc.Close();
ms.Position = 0;
ms.CopyTo(stream);
stream.Position = 0;
}
}
}
}
// get bytes from stream
Result.Data = stream.ToArray();
// success
Result.Success = true;
return Result;
}
Maybe there is something in the CSS we need to do (our CSS is quite large f
iText only ships with the Adobe Font Metrics (AFM) file of Zapfdingbats. This means that you can't embed that font unless you provide the corresponding PostScript Font Binary (PFB) file. This PFB file can't be shipped with iText because iText doesn't have a license to do so.
The first step to solve this, is to:
purchase a Zapfdingbats license so that you get the PFB (If I recall correctly, it's a font owned by Adobe), or
use an alternative font when you want to insert special characters (check boxes, phone symbols,...) into your text (e.g. purchase a license for the AdobePiStd font that was used as a substitution font and use that font instead of Zapfdingbats).
In your case, you provided a font ZapfDingbats.ttf which you register with the XMLWorkerFontProvider. When you register this font, it can be recognized through an alias. If ZapfDingbats.ttf isn't picked up by XML Worker, there is probably a mismatch between the name of the font used in the PDF and the alias that was used when ZapfDingbats.ttf was registered.
What is the font name used for ZapfDingbats in the CSS? You should register ZapfDingbats using that name as alias.

Increased line height for Consolas font in Eclipse

Many people are using Consolas for their primary programming font but unfortunately there is no way to change line height in Eclipse so it looks kinda ugly as it is shown below:
I was wondering if there is anyone who solved this by adding some extra space between lines or simply changing the font itself which has longer height now.
It would be nice to share it with us here on Stackoverflow.
There are some topics I've found while searching for this but none of them were what I am looking for:
How can I change line height / line spacing in Eclipse?
https://stackoverflow.com/questions/15153938/improved-line-spacing-for-eclipse?lq=1
and so on...
Some of them designed their own fonts (such as Meslo Font) by modifying the existing ones so it would be nice if you could share your modified Consolas font.
As mentioned in one of the answers you reference the underlying StyledText control does have a setLineSpacing method, but the existing editors do not use it.
The CSS styling code in Eclipse 4.3 does provide a way to access this but it requires writing a plugin to extend the CSS in order to do so.
The plugin.xml for the plugin would look like this:
<plugin>
<extension
point="org.eclipse.e4.ui.css.core.elementProvider">
<provider
class="linespacing.LineSpacingElementProvider">
<widget
class="org.eclipse.swt.custom.StyledText"></widget>
</provider>
</extension>
<extension
point="org.eclipse.e4.ui.css.core.propertyHandler">
<handler
adapter="linespacing.StyledTextElement"
composite="false"
handler="linespacing.LineSpacingPropertyHandler">
<property-name
name="line-spacing">
</property-name>
</handler>
</extension>
</plugin>
which declares a CSS element provider LineSpacingElementProvider which would be:
public class LineSpacingElementProvider implements IElementProvider
{
#Override
public Element getElement(final Object element, final CSSEngine engine)
{
if (element instanceof StyledText)
return new StyledTextElement((StyledText)element, engine);
return null;
}
}
The StyledTextElement this provides is just:
public class StyledTextElement extends ControlElement
{
public StyledTextElement(StyledText control, CSSEngine theEngine)
{
super(control, theEngine);
}
}
The second declaration in the plugin.xml is a CSS property handler for a property called line-spacing
public class LineSpacingPropertyHandler extends AbstractCSSPropertySWTHandler implements ICSSPropertyHandler
{
#Override
protected void applyCSSProperty(Control control, String property, CSSValue value, String pseudo, CSSEngine engine) throws Exception
{
if (!(control instanceof StyledText))
return;
StyledText text = (StyledText)control;
if ("line-spacing".equals(property))
{
int pixelValue = (int)((CSSPrimitiveValue)value).getFloatValue(CSSPrimitiveValue.CSS_PX);
text.setLineSpacing(pixelValue);
}
}
#Override
protected String retrieveCSSProperty(Control control, String property, String pseudo, CSSEngine engine) throws Exception
{
return null;
}
}
With a plugin containing this installed you can then modify one of the existing CSS style sheets to contain:
StyledText {
line-spacing: 2px;
}
You better choose different fonts. Don't just stick to things. Try new things and accept them. :D I was also using Consolas. But now I am using Courier New and they are pretty fine. If you have 21" or larger display you can use Courier New at 12 or 14 size. Once you use this you will get used to it as you are with Consolas now :P
You could try Fira Mono. See some screenshots here. Small sizes look good too.