How to use the 'page' property in iText / pdfHtml? - java

I'm using the #page rule to set specific options for pages.
I just found out that you can also define different properties for different pages by naming them.
That would be quite useful, but it doesn't seem to work.
Although I can see that iText correctly interprets my named page and stores the name (I can tell, by monitoring CssPageSelectorParser and CssPageTypeSelectorItem), it seems to ignore the page property though, that is used to select which page to use.
Something like this should work, but it doesn't.
#page narrow {
size: 9cm 18cm;
}
#page rotated {
size: landscape;
}
div {
page: narrow;
}
table {
page: rotated;
}
Is there any way of getting this to work or does this feature simply not work?
Cheers,
--Zuzu_Typ--

Related

OpenHtmlToPdf results in Error when using PDF/A conformance

I am facing an issue, while creating a PDF using OpenHtmlToPdf. Creating a normal PDF works fine, but once PDF/A conformance is enabled, the application exits with a NullPointerException.
The PDF i am trying to create has to be PDF/A conform. However, without the conformance, the resulting pdf does not contain the fonts.
The process of creating a PDF starts with an HTML template, i process using Thymeleaf in Spring Boot. The rendered PDF is at last returned as a ByteArray and return by a controller as a Blob-Download. This part is working fine. The code generating the PDF looks something like this:
val model: Model = modelFactory.buildModel(id)
val context = Context(model.locale)
val outputStream = ByteArrayOutputStream()
val builder = PdfRendererBuilder()
val conformance = PdfRendererBuilder.PdfAConformance.NONE
context.setVariable("model", model)
// Other variables
val htmlContent: String = templateEngine.process("content", context)
builder.useFastMode().usePdfAConformance(conformance)
.withHtmlContent(htmlContent, "")
.usePdfVersion(if (conformance.part == 1) 1.4f else 1.5f)
.toStream(outputStream)
.useFont({ ClassPathResource("fonts/first-font.ttf").inputStream }, "first-font")
.useFont({ ClassPathResource("fonts/second-font.ttf").inputStream }, "second-font")
.useFont({ ClassPathResource("fonts/third-font.ttf").inputStream }, "third-font")
.useFont({ ClassPathResource("fonts/fourth-font.ttf").inputStream }, "fourth-font")
.run()
return outputStream.toByteArray()
The code has been slightly altered, but the logic is kept the same.
The html contains css, which includes the fonts like this:
#page {
size: a4;
#bottom-center {
font-size: 8pt;
border-top: 1px solid black;
content: 'Generated on [[${formatters.formatDateTime(model.generatedAt)}]]';
font-family: "first-font"; /* Font provided in code */
}
// ...
}
html {
font-size: 9pt;
font-family: "second-font"; /* Font provided in code */
}
// ...
With PdfAConformance.NONE, everything works fine and the PDF is rendered as expected.
However, once i change it to any PDF/A conformance, it no longer works. There is a very long list of logs to System.err, containing the following two lines. Repeated over and over again.
com.openhtmltopdf.exception WARNING:: Font metrics not available. Probably a bug.
com.openhtmltopdf.render WARNING:: Font is null.
And finally, the process ends with the following three info logs and NullPointerException
com.openhtmltopdf.general INFO:: Using fast-mode renderer. Prepare to fly.
com.openhtmltopdf.general INFO:: Specified fonts don't contain a space character!
com.openhtmltopdf.general INFO:: Specified fonts don't contain a space character!
java.lang.NullPointerException
at org.apache.pdfbox.pdmodel.PDPageContentStream.setFont(PDPageContentStream.java:409)
at com.openhtmltopdf.pdfboxout.PdfContentStreamAdapter.setFont(PdfContentStreamAdapter.java:262)
at com.openhtmltopdf.pdfboxout.PdfBoxFastOutputDevice.drawStringFast(PdfBoxFastOutputDevice.java:462)
at com.openhtmltopdf.pdfboxout.PdfBoxFastOutputDevice.drawString(PdfBoxFastOutputDevice.java:408)
at com.openhtmltopdf.pdfboxout.PdfBoxTextRenderer.drawString(PdfBoxTextRenderer.java:51)
at com.openhtmltopdf.render.AbstractOutputDevice.drawText(AbstractOutputDevice.java:107)
at com.openhtmltopdf.render.InlineText.paint(InlineText.java:171)
at com.openhtmltopdf.render.InlineLayoutBox.paintInline(InlineLayoutBox.java:279)
at com.openhtmltopdf.render.simplepainter.SimplePainter.paintInlineContent(SimplePainter.java:170)
at com.openhtmltopdf.render.simplepainter.SimplePainter.paintLayer(SimplePainter.java:72)
at com.openhtmltopdf.render.PageBox.paintMarginAreas(PageBox.java:430)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.paintPageFast(PdfBoxRenderer.java:886)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.writePDFFast(PdfBoxRenderer.java:619)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.createPdfFast(PdfBoxRenderer.java:554)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.createPDF(PdfBoxRenderer.java:472)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.createPDF(PdfBoxRenderer.java:409)
at com.openhtmltopdf.pdfboxout.PdfBoxRenderer.createPDF(PdfBoxRenderer.java:391)
at com.openhtmltopdf.pdfboxout.PdfRendererBuilder.run(PdfRendererBuilder.java:42)
....
This Exception is thrown within Apache PdfBox and i cannot control the input values, hence this appears to be an issue within OpenHtmlToPdf and not another duplicate of "What is a NullPointerException, and how do I fix it?". This is also the case, because nothing is allowed to be null in this Kotlin code.
This Exception is thrown after calling run on the Builder.
I have tried a lot of possible combinations using the conformance. All 3 PDF/A conformance settings, in combination with and without the fast mode, because this post suggested it might be an issue. I made sure to [...] [use] a name that is not sans-serif, serif or monospace as this question might have suggested. Also, adding the "-fs-font-subset: complete-font", as well as the url additionally in the css entries did not help, as it apparently did in this question. If possible, i want to include the fonts in code not in css, since resolving those urls was tricky and finicky in the past. I also made sure that the fonts are not broken, by trying out different ttfs and all i tried resulted in said NullPointerException.
However, those answers and all other answers to issues on Github as well as here did not help me in my case. I am lost.
Is there anything i am missing? Do i have to do something different to get PDF/A conformance?

vaadin legacy-styles.css doesn't load in IE8

I am using vaadin to create a web app. I want to import legacy-styles.css into my styles.css
my styles.css is as follow:
#import "../reindeer/legacy-styles.css";
.v-app {
background: yellow;
}
Then use morderniz to targer IE8
Element head = response.getDocument().head();
Element meta = head.appendElement("meta");
meta.attr("name", "viewport");
meta.attr("content", "width=device-width, initial-scale=1, maximum-scale=1");
// Meta tag to force IE8 to standard mode
String ie8Meta = "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">";
head.prepend(ie8Meta);
// some other stuffs ...
// Adding modernizr library to target ie8
// http://modernizr.com/docs/
String modernizr = "<script type=\"text/javascript\" src=\"//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js\"></script>";
head.prepend(modernizr);
Strangely, the legacy-styles loaded properly in IE10. Then legacy-styles.css doesn't load in IE8
The error reported is
com.vaadin.client.VConsole
SEVERE: CSS files may have not loaded properly.
I have tried to rearrange moderniz.js (using append instead of prepend) but didn't work
Before we dig into the problem at hand, using #import is a super bad idea. While it is a convenient thing to do for you, it means that every single user that comes to your site will have to download a file (the document itself), in order to download another file (the one containing the #import string) just to download yet another file. In addition to DNS resolution and tcp handshakes, you are looking at possibly up to a dozen round trips between your server and their computer just to get this one single document.
It would be much better to use a css precompiler, such as sass or less, and concatenating the older file with the new one into a single, compressed, file.
Next, modernizr shouldn't be used to target IE8, or any browser for that matter. That is actually completely against the purpose of Modernizr - which specializes in feature detection, rather than browser detection. That means that rather than saying you want to "target IE8", you would think more along the lines of wanting to "target browsers lacking feature X" (svg, geolocation, rounded corners, etc).
That being said, there are a number of reasons to specifically target versions of internet explorer, but modernizr is not the way to do it. The more correct way to do this would be using IE's conditional classes
<!--[if IE 8]>
//IE specific stlyes here
<![endif]-->
Nothing you have shown has anything to do with IE specific code, and since modernizr doesn't add any features itself, there it isn't really clear why IE 10 would do anything different at all.

sencha GXT css classes

i'm having problems with styling grid in gxt, the thing is that the elements in the grid get (i don't know how exactly) css class named ".GKA1XC4LIC" and this class overrides the settings, provided by my own css class (in my own css file). However some properties (like font-size) i'm able to change with my class (i mean my css file is being loaded).
i guess this .GKA1XC4LIC class is generated somewhere i don't know where. Why it is done this way? Am i doing this completely wrong?
i set class name like this:
codeColumnConfig.setColumnTextClassName("smk-grid-text");
thanks
I assume you are using GXT3. You said some properties are set by changing the css. That is because the GXT3 has not set them and so they work.
To do use the GXT3 Appearnces correctly, it may be best to see this section Styling a GXT 3 application in the migration guide. It's about the middle of the page.
It explains the two ways to modify the Appearance pattern that GXT3 uses.
via configuration (in the GWT module XML file)
via constructor arguments
There is another explanation in the Sencha docs for Appearances
That said, that is pretty involved depending on how much you need to change things.
To do it quickly, I sometimes use a cell to render it how I need:
For example to render a cell in a grid a particular way I would do
ColumnConfig<Users, String> userCol = new ColumnConfig<SelectUserDialog.Users, String>(selectUserProperties.userName(), 240);
AbstractCell<String> c2 = new AbstractCell<String>() {
#Override public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
value = "<div style=\"font-size:2.5EM; line-height : 30px; height=40px\" >" + value + "</div>";
sb.appendHtmlConstant(value);
}
};
userCol.setCell(c2);
If you are not using ColumnConfig already, you may need to see ValueProvider and ProperyAccess

Java Servlet as a HTTP Proxy

I have read hundreds of SO Posts and studied several Java HTTP-Proxy Sources available... but I could not find a solution for my Problem.
I wrote a WebApp that proxies Http-Requests. The WebApp is working, but links and referrers become broken because the "Root" of the proxied page points to the root of my server and not to the path of my proxyservlet..
To make it more clear:
My ProxyServlet gets a Request "http://myserver.com/proxy/ProxyServlet?foo=bar"
The ProxyServlet now fetches the pagecontent from ServerX (e.g. "http://original.com/test.html")
The content of the page is delivered to the browser by just reading and writing from one stream to the other and copying the headers.
The browser displays the page, the URL, that the browser shows is the original request ("http://myserver.com/proxy/ProxyServlet?foo=bar"), but all relative links now point to
"http://myserver.com/XXX.html" instead of "http://myserver.com/proxy/ProxyServlet/XXX.html"
Is there a response-header where I can change the "path" so that relative links correctly point to my ProxyServlet?
(Rewriting the page-content and replacing links would be too difficult, because the page contains relatively addressed elements such as javascript code and other active content...)
(Changing the mapping for my Servlet to "/*" is also not possible... it must be accessed via this path...)
You are inventing a "reverse proxy", and miss the "URL rewriting" feature...
Off the top of my search results, here's an open source proxy servlet that does this:
http://j2ep.sourceforge.net/docs/rewrite.html
Also you should know there is probably something wrong with the system architecture if you have to do this. Dropping in a standalone proxy like Apache, nginex, Varnish should always be an option, as you will HAVE to add one (or more!) as you start scaling.
It sounds like the page you're proxying in is using absolute links, e.g. <a href="/XXX.html"> which means "no matter where this link is found, look for it relative to the document root". If you have control of it, the best thing is for the proxy target to be more lenient in it's linking, and instead use <a href="XXX.html">. If you can't do that, then you need to re-write these URLs, some example code, using JSoup:
Document doc = Jsoup.parse(rawBody, getDisplayUrl());
for(Element cssALink : doc.select("link[rel=stylesheet],a[href]"))
{
cssALink.attr("href", cssALink.absUrl("href"));
}
for(Element imgJsLink : doc.select("script[src],img[src]"))
{
imgJsLink.attr("src", imgJsLink.absUrl("src"));
}
return doc.toString();

best way to externalize HTML in GWT apps?

What's the best way to externalize large quantities of HTML in a GWT app? We have a rather complicated GWT app of about 30 "pages"; each page has a sort of guide at the bottom that is several paragraphs of HTML markup. I'd like to externalize the HTML so that it can remain as "unescaped" as possible.
I know and understand how to use property files in GWT; that's certainly better than embedding the content in Java classes, but still kind of ugly for HTML (you need to backslashify everything, as well as escape quotes, etc.)
Normally this is the kind of thing you would put in a JSP, but I don't see any equivalent to that in GWT. I'm considering just writing a widget that will simply fetch the content from html files on the server and then add the text to an HTML widget. But it seems there ought to be a simpler way.
I've used ClientBundle in a similar setting. I've created a package my.resources and put my HTML document and the following class there:
package my.resources;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.TextResource;
public interface MyHtmlResources extends ClientBundle {
public static final MyHtmlResources INSTANCE = GWT.create(MyHtmlResources.class);
#Source("intro.html")
public TextResource getIntroHtml();
}
Then I get the content of that file by calling the following from my GWT client code:
HTML htmlPanel = new HTML();
String html = MyHtmlResources.INSTANCE.getIntroHtml().getText();
htmlPanel.setHTML(html);
See http://code.google.com/webtoolkit/doc/latest/DevGuideClientBundle.html for further information.
You can use some templating mechanism. Try FreeMarker or Velocity templates. You'll be having your HTML in files that will be retrieved by templating libraries. These files can be named with proper extensions, e.g. .html, .css, .js obsearvable on their own.
I'd say you load the external html through a Frame.
Frame frame = new Frame();
frame.setUrl(GWT.getModuleBase() + getCurrentPageHelp());
add(frame);
You can arrange some convention or lookup for the getCurrentPageHelp() to return the appropriate path (eg: /manuals/myPage/help.html)
Here's an example of frame in action.
In GWT 2.0, you can do this using the UiBinder.
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'>
<div>
Hello, <span ui:field='nameSpan’/>, this is just good ‘ol HTML.
</div>
</ui:UiBinder>
These files are kept separate from your Java code and can be edited as HTML. They are also provide integration with GWT widgets, so that you can easily access elements within the HTML from your GWT code.
GWT 2.0, when released, should have a ClientBundle, which probably tackles this need.
You could try implementing a Generator to load external HTML from a file at compile time and build a class that emits it. There doesn't seem to be too much help online for creating generators but here's a post to the GWT group that might get you started: GWT group on groups.google.com.
I was doing similar research and, so far, I see that the best way to approach this problem is via the DeclarativeUI or UriBind. Unfortunately it still in incubator, so we need to work around the problem.
I solve it in couple of different ways:
Active overlay, i.e.: you create your standard HTML/CSS and inject the GET code via <script> tag. Everywhere you need to access an element from GWT code you write something like this:
RootPanel.get("element-name").setVisible(false);
You write your code 100% GWT and then, if a big HTML chunk is needed, you bring it to the client either via IFRAME or via AJAX and then inject it via HTML panel like this:
String html = "<div id='one' "
+ "style='border:3px dotted blue;'>"
+ "</div><div id='two' "
+ "style='border:3px dotted green;'"
+ "></div>";
HTMLPanel panel = new HTMLPanel(html);
panel.setSize("200px", "120px");
panel.addStyleName("demo-panel");
panel.add(new Button("Do Nothing"), "one");
panel.add(new TextBox(), "two");
RootPanel.get("demo").add(panel);
Why not to use good-old IFRAME? Just create an iFrame where you wish to put a hint and change its location when GWT 'page' changes.
Advantages:
Hits are stored in separate maintainable HTML files of any structure
AJAX-style loading with no coding at all on server side
If needed, application could still interact with loaded info
Disadvantages:
Each hint file should have link to shared CSS for common look-and-feel
Hard to internationalize
To make this approach a bit better, you might handle loading errors and redirect to default language/topic on 404 errors. So, search priority will be like that:
Current topic for current language
Current topic for default language
Default topic for current language
Default error page
I think it's quite easy to create such GWT component to incorporate iFrame interactions
The GWT Portlets framework (http://code.google.com/p/gwtportlets/) includes a WebAppContentPortlet. This serves up any content from your web app (static HTML, JSPs etc.). You can put it on a page with additional functionality in other Portlets and everything is fetched with a single async call when the page loads.
Have a look at the source for WebAppContentPortlet and WebAppContentDataProvider to see how it is done or try using the framework itself. Here are the relevant bits of source:
WebAppContentPortlet (client side)
((HasHTML)getWidget()).setHTML(html == null ? "<i>Web App Content</i>" : html);
WebAppContentDataProvider (server side):
HttpServletRequest servletRequest = req.getServletRequest();
String path = f.path.startsWith("/") ? f.path : "/" + f.path;
RequestDispatcher rd = servletRequest.getRequestDispatcher(path);
BufferedResponse res = new BufferedResponse(req.getServletResponse());
try {
rd.include(servletRequest, res);
res.getWriter().flush();
f.html = new String(res.toByteArray(), res.getCharacterEncoding());
} catch (Exception e) {
log.error("Error including '" + path + "': " + e, e);
f.html = "Error including '" + path +
"'<br>(see server log for details)";
}
You can use servlets with jsps for the html parts of the page and still include the javascript needed to run the gwt app on the page.
I'm not sure I understand your question, but I'm going to assume you've factored out this common summary into it's own widget. If so, the problem is that you don't like the ugly way of embedding HTML into the Java code.
GWT 2.0 has UiBinder, which allows you to define the GUI in raw HTMLish template, and you can inject values into the template from the Java world. Read through the dev guide and it gives a pretty good outline.
Take a look at
http://code.google.com/intl/es-ES/webtoolkit/doc/latest/DevGuideClientBundle.html
You can try GWT App with html templates generated and binded on run-time, no compiling-time.
Not knowing GWT, but can't you define and anchor div tag in your app html then perform a get against the HTML files that you need, and append to the div? How different would this be from a micro-template?
UPDATE:
I just found this nice jQuery plugin in an answer to another StackOverflow question.

Categories

Resources