If i use
PdfContentByte cb = writer.getDirectContent();
cb.setColorFill(new CMYKColor(c, m, y, k));
it's straightforward. However i have some Swing components, that draw self in Graphics2D, it is very convince to use something like that:
PdfContentByte cb = writer.getDirectContent();
Graphics2D g2 cb.createGraphics(w, h);
mySwingComponent.paint(g2);
g2.dispose();
It works fine, but the colors are translated form java's sRGB to CMYK by iText. I want to draw direct with CMYK colors. I am trying to do it so in my Swing component
MySwingComponent extends JComponenet {
void paint(Graphics2D g2) {
g.setColor(new com.lowagie.text.pdf.CMYKColor(0, 0, 0, 1));
}
}
Unfortunately it just does not work. Is there some way exactly to specify which CMYK color will be painted?
P.S. Background of my problem is that if i draw something in garyscale, then in Adobe Illustrator in PDF color is not just (0, 0, 0, 0.4), but like (0.1, 0.15, 0.2, 0.4f).
UPD: I have solution now:
Just using
g2.setPaint(new CMYKColor(1f, 0.0f, 0.0f, 0.0f));
in your paint(Graphics2D g2)
will force iText to produce CMYK Pdf
I had your exact problem. I messed around with the API but finally had to look at the source code. I came up with two solutions.
The first solution is to modify the source code to fit your needs (after all, isn't that the definition of free software?). The source code can be extracted from the itextpdf-5.1.3-sources.jar file (or whatever version of the library you have). The line causing the CMYK/RGB issue is line 1650 of the PdfGraphics2D.java file (com/itextpdf/text/pdf/PdfGraphics2D.java). You should see a line that says:
cb.setColorFill(new BaseColor(color));
If you want a quick and dirty fix, simply change that line to:
cb.setColorFill(new CMYKColor(0f, 0f, 0f, 1f));
This, of course, limits you to one color, but now that you know which line is handling the actual color, you can modify the class and add some functionality/state (if you need it). You'll need to add
import com.itextpdf.text.pdf.CMYKColor;
to the top of the file as well. N.B. Line 1650 handles fills. If you're doing strokes, simply modify the same thing in the else statement (it should be clear when you look at the file).
Compile the source:
javac -cp path/to/itextpdf-5.1.3.jar path/to/PdfGraphics2D.java
Change to the root of the itextpdf-5.1.3-sources folder and update the jar:
jar uf path/to/itextpdf-5.1.3.jar com/itextpdf/text/pdf/PdfGraphics2D.class
And that's it! Your PDF file will now render the color using the CMYK value you specified. This is great for something simple, but if you need more functionality, you will have to modify the PdfGraphics2D class some more. I was personally using this to draw CMYK black fonts using the drawGlyphVector method.
Second solution:
If the first solution doesn't work for you, you can always edit/parse the PostScript directly. In your method that is creating the PDF, add the line Document.compress = false; after you instantiate the PdfWriter. Now you can view the PDF file in a text editor. Search around and you'll find some lines like
0 0 0 1 k or 0 0 1 rg These lines are setting colors (CMYK black and RGB black, respectively). Lowercase letters after the color values (which are floats, it seems) mean fill and uppercase is stroke. So 0 0 0 1 K would be a CMYK black stroke and so forth.
You could read the PDF in line by line and basically do a "search and replace" (in Java, programmatically, of course) for lines ending in "rg". Hope that makes sense. Not terribly fast, since this requires an extra disk read and write...
Hope that helps.
Related
I created a Python code that prints a text on an image using PIL library, the code makes it perfectly, but there is one problem ...
I use white image in PNG format and blue text, the text is an email, the code prints the mail perfectly in the picture, but it is not quite right that text, ie not seen the letters perfectly as It would for example if you write to the Windows Paint, being that Paint is the most basic, yet the text printed PIL is not exactly equal to that prints the Windows Paint, Paint windows is of better quality, if We see this picture:
http://www.subeimagenes.com/img/texto-1414832.png
we see that the above text is written with PIL, while the text below is written with Paint and while very little noticeable difference, I would like to make it exactly like Windows Paint, and the truth is not the same .. . I used to be different and the same source code and no case! until I use the quality property with a value of 100 and yet the text above it shows you do not have as much quality as the text below, if you look carefully, you will see that it is as I say, the quality is not the same, the quality of PIL text used to print text that is of lower quality than the paint.
What's more ... it seems that used to be another source ... which is exactly the same, the truth is I do not like and I wonder if there is any way that the text prints have better quality or PIL is best defined as The Paint.
This is the code that I have currently:
imagen = Image.open("img.png")
img = imagen.resize((175, 60))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("Verdana.ttf", 15)
draw.text((10, 4),"mimail#hotmail.com",(0,79,255),font=font)
img.save('texto.png', format='PNG', subsampling=0, quality=100)
Thank you!! :-)
You can try to render your image at a multiple of the size you require, then resize it with filter=Image.ANTIALIAS.
Here is an example using a resize factor of 2:
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
imageSize = (400,100) # 2x size of the image you originally wanted.
img = Image.new("RGB", imageSize, "white")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("Verdana.ttf", 15 * 2) # 2x of the font you wanted.
draw.text((10, 4),"mimail#hotmail.com",(0,79,255), font=font)
# downsample with Antialias by 2
img.thumbnail( (imageSize[0]/2, imageSize[1]/2), Image.ANTIALIAS)
img.save('texto.png')
When using the graphics object in the paint() method of a Java Applet,
Does anyone know how to use a method on the graphics object whereby it will return the name of the color being used?
After using g.setColor(Color.red);
Then drawing a rectangle
Ive tried using g.getColor().toString();
But this only returns a string like this: "java.awt.Applet[r:255 g:0 b:0]"
Im looking to get back "Red" if its possible
It should be possible to do something like this if you really want to. I would start by converting the color from RGB to HSV. Then partition the hues into regions. Usually red is at 0 degrees, followed by yellow at 60, green at 120, cyan at 180, blue at 240, to magenta or purple at 300 degrees, then back to red. You can use the saturation to tell if the value is grayscale or not. The value can tell you "bright", "regular" or "dark". You might want to special-case some values, such as those in the orange/brown range. And some have special names, like "light unsaturated red" is pink.
For what it's worth, I've posted an Objective-C version here. It should be fairly easy to convert to Java possibly using the wikipedia article linked above.
I'm building an app which among other things allows the user to insert a text into a PDF, using a layer.
The position of the text in the PDF page can be set using the app, which renders the PDF using ICEPdf inside a JPanel. After selecting the position and the size of the layer, the app renders it to the PDF using iText (v. 5.3.2).
The problem I'm facing is that the font rendering from Swing is sightly different from the final result in the PDF.
Here are some screen-shots, both using the Helvetica plain font inside the same bounding box:
Rendering a text with Swing:
protected void paintComponent(Graphics g){
//for each line...
g.drawString(text, b0, b1);
//b0 and b1 are computed from the selected bounding box for the text
}
I have this:
Rendering a text with iText:
PdfTemplate t; //PdfTemplate is created elsewhere
ColumnText ct = new ColumnText(t);
ct.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct.setSpaceCharRatio(1);
ct.setSimpleColumn(new Phrase(text, font), b0, b1, b3, b4, font.getSize(), Element.ALIGN_BOTTOM);
//b0, b1, b2 and b3 are the bounding box of the text
ct.go();
I have this:
So the question is: what can be done to make Swing and iText render fonts exactly the same way? I can tweak Swing or iText, so no matter what code is modified, I need a truly WYSIWYG experience for the user.
I tried with other fonts and types, but still there are some differences between them. I think I'm missing some configuration.
Thanks.
Edit:
Font in Java is measured in Pixels, but iText measures in Points, and we know there are 72 points per inch, and for a standard windows machine there are 96 pixels per inch / dpi.
First we need to find the difference between a point and a pixel:
difference = 72 / dpi
0.75 = 72 / 96
Next we can multiply the Java font size with the difference to get the iText font size, if the java font size is 16, then the iText font size should be 12 when used with 96dpi.
iTextFontSize = difference x javaFontSize
12 = 0.75 x 16
On a windows machine 96dpi is often the norm, but remember that is not always the case, you should work it out for each different machine.
Original Post
I believe the difference is caused by rendering hints.
Solution 1:
The best way to do it would be to draw everything on a buffered image. Then the buffered image is drawn to the swing component and the exact same buffered image is drawn to the PDF as well, that way there should be no difference between them.
Alternate Idea:
Another idea that may not work as well, but will work better with your existing code is to draw the contents of the swing component directly to a buffered image then draw the buffered image to the PDF.
The following is a quick example that will draw the contents of a JPanel to a buffered image with a few different rendering hints. (Change the hints to suit your swing component)
public BufferedImage createImage(JPanel panel)
{
BufferedImage swingComponent = new BufferedImage(
panel.getHeight(), panel.getWidth(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g = swingComponent.createGraphics();
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.dispose();
return swingComponent; //print this to your PDF
}
So the question is: what can be done to make Swing and iText render fonts exactly the same way?
Exactly the same? Very little. Presuming that you supply the same font characteristics to both, there may still be differences introduced in rendering.
PDF files (or really, the text phrases) hold font information—family, size, style, etc.—but it is your PDF reader that renders the text to your device. Depending on what program you use, it can use the platform's renderer or it can choose one of its own.
AFAIK, Java Swing uses its own font rendering engine, as distinct from the underlying platform's renderer. This makes it look more consistent across platforms, but also makes it very unlikely that text will be rendered the same way any other program would.
Knowing that, your options are limited:
Use a PDF reader that also uses Swing font rendering. That's a fairly limiting solution.
Use your platform's rendering engine to draw into Swing. That sounds like iffy work, and also like something SWT would have solved. Maybe you could embed an SWT component?
I'm trying to print Arabic in some PDF documents using the Java code found here :
http://www.java2s.com/Code/Java/PDF-RTF/ArabicTextinPDF.htm
The example works great, except that the text comes out backwards. For example, changing the example slightly :
String txt = "\u0623\u0628\u062c\u062f\u064a\u0629 \u0639\u0631\u0628\u064a\u0629";
System.out.println(txt);
g2.drawString(txt, 100, 30);
What is printed on the screen are the same characters but in the opposite direction, compared to the PDF. The console output is correct, the PDF is not.
I don't want to simply reverse the characters because otherwise I would lose bi-directional support ...
Thanks much
IIRC, iText supports Arabic shaping at a highler level than drawString. Lets see here...
Ah! ColumnText.showTextAligned(PdfContentByte canvas, int alignment, Phrase phrase, float x, float y, float rotation, int runDirection, int arabicOptions)
Alignment is one of Element.ALIGN_*. Run direction is one of PdfWriter.RUN_DIRECTION_*. Arabic options are bit flags, ColumnText.AR_*
That should do the trick, with one caveat: I'm not sure that it'll handle multiple directions in the same phrase. Your test string has CJKV, Arabic, and Latin characters, so there should be two direction changes.
Good luck.
Figured it out, here is the complete process :
document.open();
java.awt.Font font = new java.awt.Font("times", 0, 30);
PdfContentByte cb = writer.getDirectContent();
java.awt.Graphics2D g2 = cb.createGraphicsShapes(PageSize.A4.width(), PageSize.A4.height());
g2.setFont(font);
String txt = "日本人 أبجدية عربية Dès Noël où";
System.out.println(txt);
java.awt.font.FontRenderContext frc = g2.getFontRenderContext();
java.awt.font.TextLayout layout = new java.awt.font.TextLayout(txt, font, frc);
layout.draw(g2, 15, 55);
g2.dispose();
document.close();
You'll notice it does multiple languages with bi-directional support. Only thing is it's impossible to copy/paste the resulting PDF text, as it is an image. I can live with that.
Unicode Arabic (or anything else) is always in logical order in a Java program. Some PDFs are made in visual order, though this is quite rare in the modern world. The program you cite might be a hack that ends up with PDF's that work, sort of, for some purposes.
If I were you, I'd start by examining some PDF's produced in Arabic by some modern tool.
This sort of 'graphics' approach to PDF construction seems risky to me at best.
Exposition:
I'm writting an OpenGL app in Java via JOGL. The built in fonts with GLUT are very basic. I want to be able to take a Java Font, render all the characters in it to a 2D array of bytes (a greyscale image representing the characters), which I can then load as a texture in OpenGL.
Problem:
I can load the textures in OpenGL; I can use JOGL. My only problem is going from the "Font java cn read" --> "2D greyscale image of all the characters step". What functions / libraries should I be using?
I'm not sure I quite understand what you're looking for. I think what you want is some code that will generate grayscale bitmap images of a given size for every glyph in a font.
There isn't a way (that I am aware of anyway) to get all the glyphs a font supports (oddly, you can get the number of glyphs... so yeah, I may just be missing something, bah). However, you can get glyph metrics for given characters quite easily.
Something along these lines should work for you.
HashMap<int[], Rectangle2D> generateGlyphs(int fontSize, String characters, Font font){
HashMap<int[], Rectangle2D> ret = new HashMap<int[], Rectangle>();
FontRenderContext rendCont = new FontRenderContext(null, true, true);
for(int i = 0; i < characters.length; i++){
Rectangle2D bounds = font.getStringBounds(characters.substring(i, 1), rendCont);
BufferedImage bi = new BufferedImage((int)bounds.getWidth(), (int)bounds.getHeight(), BufferedImage.TYPE_INT_GRAY);
Graphics g = bi.getGraphcs();
g.setFont(font);
g.drawString(characters.substring(i, 1), 0, (int)bounds.getHeight());
ret.put(bi.getData().getPixels(0, 0, (int)bounds.getWidth(), (int)bounds.getHeight()), bounds);
}
return ret;
}
Note that I'm clipping rather than rounding in some places, which could potentially be an issue.
Possible I'm missing something, but can java.awt not do most of this for you?
create a new BufferedImage
get its Graphics2D (image.getGraphics)
paint the text to the image
get the Raster (getData) from the buffered image.
dispose of the Graphics2D context when done.
Processing can render fonts in OpenGL, and it uses it's own in house open source class PFont to "generate grayscale bitmap images of a given size for every glyph in a font," as Kevin put it. I recommend you look at the source, which is here.