Flying Saucer: set custom DPI for output PDF - pdf-generation

I'm using Flying Saucer for HTML to PDF conversion. I need to produce an output PDF with 600dpi in Letter size. How can I achieve this?

There are four different factors at play, and they are all interrelated:
Target Page Metrics
You want the page metrics to be correct, so that when you ask Flying Saucer to produce a "letter" size page, the resulting PDF will show up in Acrobat as measuring 8.5" x 11". You configure the page size directly in FS by specifying the page-size property in your CSS, as obourgain noted in the other answer: #page { size: letter; }
Resolution
You want the final output to be suitable for printing on some printer at a certain XXX dpi. This is all well and good, but remember that PDF is (mostly) a vector format. I didn't check the spec, but as far as I know, the PDF file/page don't "have" resolution because they are vector-based. That having been said, things placed inside the page have an effective resolution, so we'll need your desired XXX dpi number to calculate the numbers below.
Dots per point
In the FlyingSaucer (and Java) world, a point is always a constant 1/72 of an inch. Period. So we can calculate the dots-per-point value by taking the desired resolution and dividing by the size of a point. For example, if you want 300 dpi output:
dots-per-point = 300 dpi / 72 ppi = 300 dots/inch / 72 points/inch = 300/72 dots/point = 4.1666 dots/point
Dots per pixel
This is not a magic number and this value is directly related to the dots-per-point number, as well as the expected resolution of the graphical images that you are trying to feed into FlyingSaucer. More specifically, given a graphic image that is X x Y pixels in dimensions, you need to decide how big you want that to render in your PDF. If you are using an image that was prepared for screen (web) use, you probably are starting out at the standard 96 pixels/inch (so a 96 x 96 px image would render as a one-inch square on the PDF output).
So we can easily calculate dots-per-pixel as follows, again assuming we wanted 300 dpi output:
dots-per-pixel = dots-per-inch (dots) / pixels-per-inch (pixels)
dots-per-pixel = 300 dots/inch / 96 pixels/inch = 3.125 dots/pixel
If you go this approach, your images will be sized correctly, but they won't be the 300 dpi print quality that you're looking for. That's because your images were not of high enough resolution to begin with. More on that in a minute.
Getting it all set up
If you just call SharedContext#setDPI directly as suggested in one of the other answers, you'll likely get the wrong results. This is because it doesn't make logical sense to change the dots-per-point without also changing the resolution (dots-per-inch). The ITextRenderer constructor makes a fixed call to setDPI(72*dotsPerPoint), and when it goes to create a new page, it also uses the dotsPerPoint value set by the constructor to calculate the correct page width in points. If you have changed the resolution under its nose by calling setDPI, you'll end up with the wrong page size.
The correct way is to create a new ITextRenderer object using the values we calculated above. If we wanted 300 dpi output and we had 96 ppi images to feed it, we would call:
ITextRenderer renderer = new ITextRenderer(4.1666f, 3);
Note that the dots-per-pixel parameter only accepts integers, so we're rounding 3.125 to the closest integer above. However...it's truly the ratio between the two numbers that seems to be important, so to make the last argument an integer, we can multiply both numbers by 8 (the lowest integer multiplier that yields an integer), which gives 33.3333 and exactly 25. This also is my guess for the origin of the magic "20" number in the Flying Saucer sources.
Check your output
By this point, your output PDF should look pretty much the same as it did when you started (assuming that you were previously using the default 96 ppi configuration of Flying Saucer). But now we know the parameters that we need to tune to make everything work.
To get high-quality output, you need high quality input
So we've verified that the above parameters work for our purposes, but our images are still a lowly 96 ppi. If we want to print this stuff at high resolution, all you need to do is swap out the images for 300 ppi versions, change the constructor parameters, and then you're done, right?
Maybe. Let's work through the numbers:
Your expected output resolution (300 dpi) does not change, so dots-per-point is still 4.1666. But your input images are now at 300 ppi, so your dots-per-pixel = 300 dots/inch / 300 pixels/inch = 1 dot/pixel. So you'll now call the constructor like this:
ITextRenderer renderer = new ITextRenderer(4.1666f, 1);
Once you do this, your new 300 px x 300 px image will end up as 1" square on the PDF, which is exactly the print quality you wanted.
But wait! All of my text got really small too!
Flying Saucer uses the dots-per-pixel measurement to convert a number of things, not just images. In particular, if you have specified anything in your stylesheets that uses pixels, the dots-per-pixel measurement will have an impact on their sizes too.
If you have stylesheet rules like font-size: 10px; then increasing the dots-per-pixel supplied to the constructor will make that text smaller, which is probably also not what you want. After all, you should be able to increase the resolution of the images in your PDF while leaving your text in the same size and place.
The answer is to convert everything in your stylesheet to use points. (Or inches. At least something other than pixels!) If you started out with the default Flying Saucer settings (meaning pixels are 96 ppi), you simply need to convert all of your "px" measurements into points. Since 72 points = 1 inch, you would change "px" to "pt" and multiply the value by 72/96.
For example, the font-size: 10px; above would become font-size: 7.5pt;. If you want true consistency with what you had before, everything in your CSS that mentions "px" (as well as any inline styles) must be changed into "pt" with the the same conversion too.
Once you have made this change, your text and other layout will be consistent, and if you decide that you need 600 dpi output later, you can just adjust your images and change the constructor argument, but the rest of the layout will still remain constant. Done!

You can set the letter size with the CSS page size property in your HTML document:
#page {
size: letter;
}
You can change the dpi of the document using the following ITextRenderer constructor :
public ITextRenderer(float dotsPerPoint, int dotsPerPixel)
I don't understand what those values really represent, but default values are dotsPerPoint = 20f * 4f / 3f and dotsPerPixel = 20, and it will output a 96dpi document.
To get 600dpi, you can use dotsPerPoint = 500f / 3f and dotsPerPixel = 20.
Looking at the code of ITextRenderer, the final dpi is given by the formula: dpi = dotsPerPoint * 72 / dotsPerPixel.

A simpler answer for setting the DPI when using Flying Saucer:
renderer.getSharedContext().setDPI(600);
As with obourgain's answer, to be used in conjuction with the #page { size:letter; } CSS.
Source

Related

How to calculate size of Windows bitmap font using FreeType

The Problem
I am loading the classic serife.fon file from Microsoft Windows using FreeType.
Here is how I set the size:
FT_Set_Pixel_Sizes(face, 0, fontHeight);
I use 0 for the fontWidth so that it will be auto-calculated based on the height.
How do I find the correct value for fontHeight such that the resulting font will be exactly 9 pixels tall?
Notes
Using trial and error, I know that the correct value is 32 - but I don't understand why.
I am not sure how relevant this is for bitmap fonts, but according to the docs:
pixel_size = point_size * resolution / 72
Substituting in the values:
point_size = 32
resolution = 96 (from FT_Get_WinFNT_Header)
gives:
pixel_size = 42.6666666
This is a long way from our target height of 9!
The docs do go on to say:
pixel_size computed in the above formula does not directly relate to the size of characters on the screen. It simply is the size of the EM square if it was to be displayed. Each font designer is free to place its glyphs as it pleases him within the square.
But again, I am not sure if this is relevant for bitmap fonts.
fon files are exe files with a fnt payload, where the fnt payload can be a vector or raster font. If this is a raster font (which is most likely) then the dfPixHeight value in the fnt header will tell you what size it's meant to be, which is exposed by FreeType2 as the pixel_height field of the FT_WinFNT_Header.
(And of course, note that using any size other than "the actual raster-size of the FNT" is going to lead to hilarious headaches because bitmap scaling is the kind of madness that's so bad, OpenType instead went with "just embed as many bitmaps as you need, at however many sizes you need, because that's the only way your bitmaps are going to look good")
The FNT-specific FT2 documentation can be found over on https://www.freetype.org/freetype2/docs/reference/ft2-winfnt_fonts.html but you may need to read it in conjunction with https://jeffpar.github.io/kbarchive/kb/065/Q65123 (or https://web.archive.org/web/20120215123301/http://support.microsoft.com/kb/65123) to find any further mappings that you might need between names/fields as defined in the FNT spec and FT2's naming conventions.

I don't understand TYPO3's image management, Images are not properly sized

I am new in TYPO3, and I am trying something simple, add an image.
Iam doing the following:
I added Content Element "Text & Images"
In the tab "Images" i uploaded an image 1920 x 262
Save
The image loaded is the resolution 600 x 81, i don't understan why.
In the properties i try set 1920 in the field width but same.
In the future i want to know how establish the srcset but first the simple.
(sorry my english)
Sorry to confuse you but there are some rules applied to the maximum size which date back to those days where 600 was already quite large.
the following typoscript constants are relevant:
styles.content {
maxW = 600
maxWInText = 300
}
Depending on the selected value of the field Position and Alignment, one of those 2 applies. So If e.g. "in text, right" is selected, the maximum width is 300.
As a solution you can override the constants to same values which fit more properly.
Most people don't use the default content elements anymore and create custom ones using extensions like mask or dce or without any 3rd party code.

ZPL - How to format a Code 93 barcode (^BA) to fit the label

I'm using the ZPL - Zebra Programming Language to format a Code 93 barcode ^BA to reside within a label.
I know I can set the default module width using ^BY. My problem is that ^BY1 makes the barcode to small to read and ^BY2 makes it too large for the label.
This is the code:
^FO15,110^BY2,3,35^BAN,35,N^FD001EC0A688E2^FS
I wish I could use decimal values with ^BY but that doesn't seem to be possible.
Some barcodes as Code 128 ^BC have a mode parameter to pack the bar code better based on the data but ^BA doesn't have that.
I saw that some barcodes as QR (^BQ) do have a magnification factor parameter but that's also missing for ^BA.
Are there any other ways to set the width with smaller steps than ^BY?
The label is 38 mm wide and 19 mm tall and the DPI is 203 (8 dots/mm) and the data is always 12 hexadecimal characters [0-9 and A-F].
^BY does allow decimals in the second parameter (2.0 to 3.0) but that only applies to variable-ratio barcodes and code-93 is fixed-ratio.
The problem is that you need to think in terms of dots. Setting the narrow-bar width to 2 (as in ^BY2) means that the wide bar is then 4 or 6 dots (^BY2,2 or ^BY2,3) so the physical result is that the data content is always going to be (3 bars + 3 spaces)*datalength which translates to a particular number of dots.
The dot pitch is commonly 203dpi but 300dpi are available (you don't say which model you are using.) The barcode width when printed thus depends dirctly onthe amount of data and barcode type you are using. It's not like laser-printers where 1200dpi is common - the dots are six times bigger.
So - you'd need to say how wide you can handle, which model you are using and what your data characteristics are (your sample shows 12-character hexadecimal - are you using full ASCII or could you adjust and use numeric-only?) Are you stuck on code-93 or will some other encoding be OK?
Have you tried ^BY2,2? That will use a smaller ratio, but larger base.
If you want a more detailed answer you will need to provide: DPI, print width and max amount of data you are trying to encode.

Embedding matlab plot in pdf for printing: Sizes

I'm currently creating my figures in matlab to embed themvia latex into a pdf for later printing. I save the figures and save them via the script export_fig! Now I wonder which is the best way to go:
Which size of the matlab figure window to chose
Which -m option to take for the script? It will change the resolution and the size of the image...
I'm wondering about those points in regards to the following two points:
When chosing the figure-size bigger, there are more tickmarks shown and the single point markers are better visible
When using a small figure and using a big -m option, I still have only some tickmarks
When I generate a image which is quite huge (e.g. resolution 300 and still 2000*2000px) and than embed it into the document: Does this than look ugly? Will this be embedded in a nice scaling mode or is it the same ugliness as if you upload a 1000*1000px image onto a homepage and embed it via the widht and height tags in html -> the browser displays it quite ugly because the browser doesn't do a real resize. So it looks unsharp and ugly.
Thanks in advance!
The MATLAB plots are internally described as vector graphics, and PDF files are also described using vector graphics. Rendering the plot to a raster format is a bad idea, because you end up having to choose resolution and end up with bigger files.
Just save the plot to EPS format, which can be directly embedded into a PDF file using latex. I usually save my MATLAB plots for publication using:
saveas(gcf, 'plot.eps', 'epsc');
and embed them directly into my latex file using:
\includegraphics[width=0.7\linewidth]{plot.eps}
Then, you only need to choose the proportion of the line the image is to take (in this case, 70%).
Edit: IrfanView and others (XnView) don't display EPS very well. You can open them in Adobe Illustrator to get a better preview of what it looks like. I always insert my plots this way and they always look exactly the same in the PDF as in MATLAB.
One bonus you also get with EPS is that you can actually specify a font size so that the text is readable even when you resize the image in the document.
As for the number of ticks, you can look at the axes properties in the MATLAB documentation. In particular, the XTick and YTick properties are very useful manually controlling how many ticks appear no matter what the window resolution is.
Edit (again): If you render the image to a raster format (such as PNG), it is preferable to choose the exact same resolution as the one used in the document. Rendering a large image (by using a big window size) and making it small in the PDF will yield bad results mainly because the size of the text will scale directly with the size of the image. Rendering a small image will obviously make for a very bad effect because of stretching.
That is why you should use a vector image format. However, the default MATLAB settings for figures produce some of the same problems as raster images: text size is not specified as a font size and the number of ticks varies with the window size.
To produce optimal plots in the final render, follow the given steps:
Set the figure's font size to a decent setting (e.g. 11pt)
Render the plot
Decide on number of ticks to get a good effect and set the ticks manually
Render the image to color EPS
In MATLAB code, this should look somewhat like the following:
function [] = nice_figure ( render )
%
% invisible figure, good for batch renders.
f = figure('Visible', 'Off');
% make plots look nice in output PDF.
set(f, ...
'DefaultAxesFontSize', 11, ...
'DefaultAxesLineWidth', 0.7, ...
'DefaultLineLineWidth', 0.8, ...
'DefaultPatchLineWidth', 0.7);
% actual plot to render.
a = axes('Parent', f);
% show whatever it is we need to show.
render(a);
% save file.
saveas(f, 'plot.eps', 'epsc');
% collect garbarge.
close(f);
end
Then, you can draw some fancy plot using:
function [] = some_line_plot ( a )
%
% render data.
x = -3 : 0.001 : +3;
y = expm1(x) - x - x.^2;
plot(a, x, y, 'g:');
title('f(x)=e^x-1-x-x^2');
xlabel('x');
ylabel('f(x)');
% force use of 'n' ticks.
n = 5;
xlimit = get(a, 'XLim');
ylimit = get(a, 'YLim');
xticks = linspace(xlimit(1), xlimit(2), n);
yticks = linspace(ylimit(1), ylimit(2), n);
set(a, 'XTick', xticks);
set(a, 'YTick', yticks);
end
And render the final output using:
nice_figure(#some_line_plot);
With such code, you don't need to worry about the window size at all. Notice that I haven't even showed the window for you to play with its size. Using this code, I always get beautiful output and small EPS and PDF file sizes (much smaller than when using PNG).
The only thing this solution does not address is adding more ticks when the plot is made larger in the latex code, but that can't be done anyways.

setting density upon image read with RMagick

I am attempting to use RMagick to convert an SVG to a PNG of a different size.
When I read in the SVG with Magick::Image.read('drawing.svg') and write it out to drawing.png (the equivalent of just running convert drawing.svg drawing.png from the command line), the size is 744x1052.
Let's suppose I want the PNG to be twice as large as it is by default. You can't just read it in, resize it, then write it out, as that first rasterizes the SVG and then scales that image to be twice as large, losing quality and the entire benefit of using a vector graphic in the first place. So instead, if I understand correctly, you're supposed to set the image's density upon read.
image = Magick::Image.read('drawing.svg'){self.density = 144}.first
But image.density still reports the density as "72x72", and if I write out the image it has the same size as before, 744x1052. It doesn't seem to matter how I specify the density upon read. With 144, "144", 144.0, "144.0", "144x144", and "144.0x144.0", it always comes back "72x72".
Running convert -density 144 drawing.svg drawing.png from the command line works as expected and generates a PNG that's twice as large as before, 2104x1488.
I'm using OS X 10.6.7, ImageMagick 6.7.0-0 (installed via MacPorts), RMagick 2.13.1, and Ruby 1.9.2p180. When I put my code into the context of a little Sinatra webapp on Heroku, it has the same incorrect behavior, so the issue does not seem to lie with OS X or MacPorts.
Density is about resolution (i.e. dots per inch), not the rendered size. From the fine manual:
The vertical and horizontal resolution in pixels of the image. The default is "72x72".
I think you're looking for resize or resize!:
Changes the size of the receiver to the specified dimensions.
You can specify the new size in two ways. Either specify the new width and height explicitly, or specify a scale factor, a number that represents the percentage change.
So this will work:
Magick::Image.read('drawing.svg').first.resize(2).write('drawing.png')
Or this:
img = Magick::Image.read('drawing.svg').first
img.resize!(2)
img.write('drawing.png')
I don't know why convert behaves differently than the library, there could be other default settings in play that have different defaults in the library or maybe -density does more than set the density.
If resize isn't doing the trick for you (and, based on your comments, it is happening too late to be of use), you can try setting the size parameter in the block:
img = Magick::Image.read('drawing.svg'){ |opts| opts.size = '2104x1488' }.first
Of course, you have to know how big the SVG is before hand. You're supposed to be able to specify things like 200%x200% for the geometry but read always ignores the flag on the Magick::Geometry when I try it.

Resources