I am using pdfbox 1.8 and I am trying to fill a pdf form with chinese character but all I got is strange characters. I got a ttc file (uming.ttc) and using font forge I exported ttf file (right now I am tryng to use only one of the exported fonts).
Loading of the fonts is done using
InputStream is = ..
PDTrueTypeFont font = PDTrueTypeFont.loadTTF(doc, is);
and I am writing the pdf field using the following code (that I found here in stackoverflow but currently I can't found it)
protected void setPDFFieldAndFont(String fieldName, String keyFontName, Object... values) {
try {
PDField pdField = pdfForm.getField(fieldName);
if (pdField == null) {
return;
}
// append fields to create a new textfield
Filler filler = new Filler();
filler.append(values);
String textFieldString = filler.toString();
String fontName = key2FontName.get(keyFontName);
COSDictionary dict = pdField.getDictionary();
COSString defaultAppearance = (COSString) dict
.getDictionaryObject(COSName.DA);
if (defaultAppearance != null)
{
dict.setString(COSName.DA, "/" + fontName + " 11 Tf");
}
if (pdField instanceof PDTextbox)
{
PDTextbox textbox = new PDTextbox(pdfForm, dict);
//PDTextbox textbox = (PDTextbox) pdField;
textbox.setValue(textFieldString);
}
} catch (IOException e) {
throw new IllegalStateException("Invalid field name: " + fieldName, e);
}
}
I have read that pdfbox2.0 supports unicode do I need to use this new version ?
Using font-forge I have seen that my ttf font has encoding ISO-10646-1.
Thanks for any help
EDITED
As asked by Tilman Hausherr I tried EmbeddedFonts.java and it works fine but I am filling the form in a different way. I created a main sample:
public static void main(String[] args) throws IOException {
String pdfform = "D:\\form.pdf";
PDDocument doc = PDDocument.load(new File(pdfform));
PDType0Font font = PDType0Font.load(doc, new File("D:\\fonts\\UMingCN.ttf"));
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
PDResources res = acroForm.getDefaultResources();
if (res == null){
res = new PDResources();
}
COSName fontName = res.add(font);
acroForm.setDefaultResources(res);
PDField pdField = acroForm.getField("personalInformation_fullName");
if (pdField == null) {
return;
}
COSDictionary dict = pdField.getCOSObject();
COSString defaultAppearance = (COSString) dict.getDictionaryObject(COSName.DA);
if (defaultAppearance != null)
{
dict.setString(COSName.DA, "/" + fontName.getName() + " 11 Tf");
}
if (pdField instanceof PDTextField)
{
PDTextField textbox = new PDTextField(acroForm);
textbox.getCOSObject().addAll(dict);
textbox.setValue("保保保");
}
doc.save("example2.pdf");
doc.close();
}
but it does not fill anything. In debug the code goes to textbox.setValue but the pdfform saved does not have the value set in the pdf.
Probably I am missing something ..
Thanks again
I solved the issues with PdfBox and chinese (japanese, korean, and any other font) by turning text into image, like this
void writeLine(String text, int x, int y, int width, int height,
Font font, Color color, PDPageContentStream contentStream, PDDocument document) throws IOException {
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream()
) {
int scale = 2;
BufferedImage img = new BufferedImage(width * scale, height * scale, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
g2d.setColor(color);
g2d.scale(scale,scale);
g2d.drawString(text, 0, g2d.getFontMetrics().getAscent());
g2d.dispose();
ImageIO.write(img, "png", baos);
baos.flush();
baos.close();
contentStream.drawImage(PDImageXObject.createFromByteArray(
document,baos.toByteArray(), ""), x, y, width, height);
}
}
Related
I'm trying to find an image that I create previously inside an empty template with this function that insert text on it receiving color, content and font and return the path of generate image:
the template
public String insertTextOnBlanck(String colorLetter,String text,Font font) {
//path is a private varibable initialized with the constructor
File blankFile = new File("images/dinamic/"+path);
BufferedImage image = null;
String exit_path = null;
try {
image = ImageIO.read(blankFile);
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
Graphics2D g2 = image.createGraphics();
FontMetrics metrics = g2.getFontMetrics(font);
BufferedImage resizeImage = resizeImage(image,type, text,metrics);
image.flush();
int w = resizeImage.getWidth();
int h = resizeImage.getHeight();
g2 = resizeImage.createGraphics();
g2.setColor(Color.decode(colorLetter));
g2.setFont(font);
// Get the FontMetrics
int x = (w - metrics.stringWidth(text)) / 2;
int y = (metrics.getAscent() + (h - (metrics.getAscent() + metrics.getDescent())) / 2);
g2.setBackground(Color.decode("#d1e8f8"));
g2.drawString(text, x, y);
g2.dispose();
//create image with text
exit_path = "images/dinamic/changed_"+path;
File file = new File(exit_path);
ImageIO.write(resizeImage, "png", file);
resizeImage.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return exit_path;
}
and this works the fist time when i call this other function
public void dinamicClick(String path,String input,String fontLetter,String colorLetter, int fontType,int size) throws FindFailed {
DinamicImg DimImg = new DinamicImg();
DimImg.setPath(path);
String modPath = DimImg.insertTextOnBlanck(
colorLetter,
input,//Inventario de recurso
new Font(fontLetter,fontType, size)
);
Iterator<Match> myIt = s.findAll(modPath);
while (myIt.hasNext()) {
Location loc = myIt.next().getTarget();
s.click(loc);
}
myIt.remove();
removeFile(modPath);
}
the removeFile function is:
private void removeFile(String toRemove) {
File file = new File(toRemove);
if(file.delete()){
System.out.println(file.getName() + " is deleted!");
}else{
System.out.println("Delete operation is failed.");
}
}
The result:
but next calls dont work at all, just when i change the name of exit path, so i thought was a cache problem but adding ImageIO.setUseCache(false); at start of "insertTextOnBlanck" function still doesn`t work. Im out of ideas please help, thanks.
I resolve it , with the libary org.sikuli.script.ImagePath you ve to reset the paths of the internal cache of SikuliX with ImagePath.reset().
I have problem to load image by file name by using method Toolkit.getDefaultToolkit().getImage(filename); MediaTracker return false which means there is no image loaded isn't? How to solve this problem? Thanks in advance. Below is my code:
String name = "example.jpg";
File inputFile = new File(UPLOAD_DIRECTORY + File.separator + name);
BufferedImage thumbImage = getThumbnail(name, 200, 120, 0, name);
File outputfile = new File(UPLOAD_DIRECTORY + File.separator + "2"+name);
ImageIO.write(thumbImage, "jpg", outputfile);
getThumbnail method :
private static BufferedImage getThumbnail(String filename, int thumbWidth, int thumbHeight, int quality, String outFileName)
throws InterruptedException, FileNotFoundException, IOException {
//load image from filename
Image image = Toolkit.getDefaultToolkit().getImage(filename);
MediaTracker mediaTracker = new MediaTracker(new Container());
mediaTracker.addImage(image, 0);
mediaTracker.waitForID(0);
// use this to test for errors at this point:
System.out.println(mediaTracker.isErrorAny());
//determine thumbnail size from WIDTH and HEIGHT
double thumbRatio = (double)thumbWidth / (double)thumbHeight;
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
double imageRatio = (double)imageWidth / (double) imageHeight;
if (thumbRatio < imageRatio){
thumbHeight = (int)(thumbWidth / imageRatio);
} else{
thumbWidth = (int)(thumbHeight * imageRatio);
}
//draw original image to thumbnail image object and
//scale it to the new size
BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
//save thumbnail image to outFileName
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outFileName));
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);
quality = Math.max(0, Math.min(quality, 100));
param.setQuality((float)quality / 100.0f, false);
encoder.setJPEGEncodeParam(param);
encoder.encode(thumbImage);
out.close();
return thumbImage;
}
Shouldn't
BufferedImage thumbImage = getThumbnail(name, 200, 120, 0, name);
be
BufferedImage thumbImage = getThumbnail(UPLOAD_DIRECTORY + File.separator + name, 200, 120, 0, name);
?
Image img = Toolkit.getDefaultToolkit().getImage(URL or file path);
The Toolkit is a class in the java.awt package that provides various resources and tools for the display system. One of the Toolkit methods is getImage() that functions much like the getImage() method in the Applet class. It is overloaded to take either a String filename parameter specifying the location of the image file or a URL parameter identifying the image file.
Before calling getImage(), one must have a reference to the Toolkit instance in use. The static method Toolkit.getDefaultToolkit() returns a reference to that Toolkit.
I am making a survey using Java and would like to have a printable version also. However, some of questions fall outside of the viewable area (they are in a JScrollPane). Below is the code I have for printing but it only prints the viewable part of the JFrame. Please could someone help?
private void printFrame(){
PrinterJob printerJob = PrinterJob.getPrinterJob();
printerJob.setPrintable(this);
// pop up a dialog box for the end user to fine tune the options.
if ( printerJob.printDialog() )
{
try
{
// render the component onto the printer or print queue.
printerJob.print();
}
catch ( PrinterException e )
{
System.out.println( "Error printing: " + e );
}
}
}
public int print( Graphics gr, PageFormat pageFormat, int pageIndex ){
if ( pageIndex > 0 )
{
return Printable.NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D)gr;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
double xScale = 0.33;
double yScale = 0.33;
g2d.scale(xScale, yScale);
paint(g2d);
return Printable.PAGE_EXISTS;
}
Thanks in advance,
D
Thanks, Arthur.
I now have it working with:
public void PrintFrameToPDF(File file) {
try {
Document d = new Document();
PdfWriter writer = PdfWriter.getInstance(d, new FileOutputStream(file));
d.open();
PdfContentByte cb = writer.getDirectContent();
PdfTemplate template = cb.createTemplate(PageSize.A4.getWidth(),PageSize.A4.getHeight());
cb.addTemplate(template, 0, 0);
Graphics2D g2d = template.createGraphics(PageSize.A4.getWidth(),PageSize.A4.getHeight());
g2d.scale(0.4, 0.4);
for(int i=0; i< this.getContentPane().getComponents().length; i++){
Component c = this.getContentPane().getComponent(i);
if(c instanceof JLabel || c instanceof JScrollPane){
g2d.translate(c.getBounds().x,c.getBounds().y);
if(c instanceof JScrollPane){c.setBounds(0,0,(int)PageSize.A4.getWidth()*2,(int)PageSize.A4.getHeight()*2);}
c.paintAll(g2d);
c.addNotify();
}
}
g2d.dispose();
d.close();
} catch (Exception e) {
System.out.println("ERROR: " + e.toString());
}
}
If anyone has optimisations for the above, I'd love to hear from you. Thanks for the help!
D
One PDF library can be found at http://itextpdf.com/ .
I have a bunch of .jpg images and I want to print them (on paper with ink), at a fixed size (in cm).
Let's say image1.png is 400x600 pixels and I want to print it at 300 dpi.
I've tried using PrinterJob and Printable implementation, but it seems I can't specify DPI.
Here is the code snippets:
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(new PrintableDeck(cardDB));
PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
attr.add(new MediaPrintableArea(8,21,210-16,296-42,MediaPrintableArea.MM));
attr.add(MediaSizeName.ISO_A4);
attr.add(new Copies(1));
attr.add(OrientationRequested.PORTRAIT);
attr.add(PrintQuality.HIGH);
//attr.add(Fidelity.FIDELITY_TRUE);
job.print(attr);
and
public class PrintableDeck implements Printable {
BufferedImage image;
public PrintableDeck(DB cardDB){
// This load an image into 'image'
BufferedImage image = cardDB.getCard(5462).getBufferedImage();
}
public int print(Graphics graphics, PageFormat pf, int page)
throws PrinterException{
if(page>0){
return NO_SUCH_PAGE;
}
Graphics2D g2 = (Graphics2D) graphics;
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
double pageHeight = pf.getImageableHeight();
double pageWidth = pf.getImageableWidth();
// This print ONLY ~596x842, as if page is 72 DPI
System.out.println("Imageable WH: "+pageWidth+" x "+pageHeight);
// This print correctly 400x600
System.out.println("Image: "+images.get(0).getWidth(null)+" x "+images.get(0).getHeight(null));
g2.drawImage(image, 0, 0, null);
g2.dispose();
return PAGE_EXISTS;
}
}
As you can see above, I have PageFormat.getImageableHeight() ~ 842 and PageFormat.getImageableWidth() ~ 595. If page would be 300 DPI, I expected these values to be much higher, about 3000 x 2500.
What I am missing?
Thank you so much.
Java sets the image's DPI to the default java 72dpi if there is no previously a defined DPI in the image's meta data, so it was better than scalling your image to its dimensions in the java 72dpi default resolution, it is better to add your 300dpi resolution to your image meta data, thus, it would be adjusted in the better resolution in the right printable area dimensions, and that is besides setting printer resolution, media size, and media printable area attributes, You may set the dpi to your saved image with such method in http://www.javased.com/?post=321736 :
private void saveGridImage(File output,BufferedImage gridImage) throws IOException {
output.delete();
final String formatName = "png";
for (Iterator<ImageWriter> iw = ImageIO.getImageWritersByFormatName(formatName); iw.hasNext();) {
ImageWriter writer = iw.next();
ImageWriteParam writeParam = writer.getDefaultWriteParam();
ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam);
if (metadata.isReadOnly() || !metadata.isStandardMetadataFormatSupported()) {
continue;
}
setDPI(metadata);
final ImageOutputStream stream = ImageIO.createImageOutputStream(output);
try {
writer.setOutput(stream);
writer.write(metadata, new IIOImage(gridImage, null, metadata), writeParam);
} finally {
stream.close();
}
break;
}
}
private void setDPI(IIOMetadata metadata) throws IIOInvalidTreeException {
double INCH_2_CM = 2.54;
// for PMG, it's dots per millimeter
double dotsPerMilli = 1.0 * DPI / 10 / INCH_2_CM;
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
horiz.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
vert.setAttribute("value", Double.toString(dotsPerMilli));
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
dim.appendChild(horiz);
dim.appendChild(vert);
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
root.appendChild(dim);
metadata.mergeTree("javax_imageio_1.0", root);
}
Then add printing attributes such :
attr.add(new PrinterResolution(300, 300, PrinterResolution.DPI));
attr.add(new MediaPrintableArea(8,21,210-16,296-42,MediaPrintableArea.MM));
attr.add(MediaSizeName.ISO_A4);
To have better quality of image's view and resolution.
here's my code, note I am using Scalr.
private String autoResizeImage(String image, int width, int dpi, String prefix) throws IllegalArgumentException, ImagingOpException, IOException {
File file = new File(image);
BufferedImage img = ImageIO.read(file);
BufferedImage result = Scalr.resize(img, Scalr.Method.SPEED, Scalr.Mode.FIT_TO_WIDTH, width, Scalr.OP_ANTIALIAS);
File outputfile = new File(prefix);
PNGEncodeParam penc = PNGEncodeParam.getDefaultEncodeParam(result);
double meter2inchRatio = 1d / 0.0254d;
int dim = (int) (dpi * meter2inchRatio) + 1;
penc.setPhysicalDimension(dim, dim, 1);
// resize orginal image
JAI.create("filestore", result, outputfile.getAbsolutePath(), "PNG", penc);
return outputfile.getAbsolutePath();
}
I have a text file, and I need to print it to a specific network printer. I know the name of the printer.
Until now I have made a Printable class to print my file (ticket).
public class TicketPrintPage implements Printable {
private File ticket;
public TicketPrintPage(File f) {
ticket = f;
}
public int print(Graphics g, PageFormat pf, int pageIndex) throws PrinterException {
int interline = 12;
Graphics2D g2 = (Graphics2D) g;
g2.setFont(new Font("CourierThai", Font.PLAIN, 10));
int x = (int) pf.getImageableX();
int y = (int) pf.getImageableY();
try {
FileReader fr = new FileReader(ticket);
BufferedReader br = new BufferedReader(fr);
String s;
while ((s = br.readLine()) != null) {
y += interline;
g2.drawString(s, x, y);
}
} catch (IOException e) {
throw new PrinterException("File to print does not exist (" + ticket.getAbsolutePath() +") !");
}
return Printable.PAGE_EXISTS;
}
}
I call this TicketPrintPage this way :
public void printTicketFile(File ticket, int orientation) throws PrinterException {
if (!ticket.exists()) {
throw new PrinterException("Ticket to print does not exist (" + ticket.getAbsolutePath() + ") !");
}
PrinterJob pjob = PrinterJob.getPrinterJob();
// get printer using PrintServiceLookup.lookupPrintServices(null, null) and looking at the name
pjob.setPrintService(getPrintService());
// job title
pjob.setJobName(ticket.getName());
// page fomat
PageFormat pf = pjob.defaultPage();
// landscape or portrait
pf.setOrientation(orientation);
// Paper properties
Paper a4Paper = new Paper();
double paperWidth = 8.26;
double paperHeight = 11.69;
double margin = 16;
a4Paper.setSize(paperWidth * 72.0, paperHeight * 72.0);
a4Paper.setImageableArea(
margin,
//0,
margin,
//0,
a4Paper.getWidth()- 2 * margin,
//a4Paper.getWidth(),
a4Paper.getHeight()- 2 * margin
//a4Paper.getHeight()
); // no margin = no scaling
pf.setPaper(a4Paper);
// Custom class that defines how to layout file text
TicketPrintPage pages = new TicketPrintPage(ticket);
// adding the page to a book
Book book = new Book();
book.append(pages, pf);
// Adding the book to a printjob
pjob.setPageable(book);
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
// No jobsheet (banner page, the page with user name, job name, date and whatnot)
pras.add(JobSheets.NONE);
// Printing
pjob.print(pras);
}
It works not so bad but :
- I doesn't work for more than one page of text (found some algorithms for that but well)
- I can't get to know when the printer is done printing, and if I try printing two or more tickets in a row the printer will return a Printer not ready message.
So the question again is : Isn't there a simple way to print a text file to a printer ?
JTextComponent#print should do the trick:
JTextPane jtp = new JTextPane();
jtp.setBackground(Color.white);
jtp.setText("text to print");
boolean show = true;
try {
jtp.print(null, null, show, null, null, show);
} catch (java.awt.print.PrinterException ex) {
ex.printStackTrace();
}
in this manner you can quickly print out even nice formatted text - just create a StyledDocument and attach it to JTextPane before printing.
I'm not sure if this solves your problem but I use the following to print a text file
FileInputStream textStream;
textStream = new FileInputStream(FILE_NAME);
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc mydoc = new SimpleDoc(textStream, flavor, null);
PrintService[] services = PrintServiceLookup.lookupPrintServices(
flavor, aset);
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
if(services.length == 0) {
if(defaultService == null) {
//no printer found
} else {
//print using default
DocPrintJob job = defaultService.createPrintJob();
job.print(mydoc, aset);
}
} else {
//built in UI for printing you may not use this
PrintService service = ServiceUI.printDialog(null, 200, 200, services, defaultService, flavor, aset);
if (service != null)
{
DocPrintJob job = service.createPrintJob();
job.print(mydoc, aset);
}
}
You may not need the ServiceUI, but I think you could use PrintService[] services to get a list of printers available for printing. And using an input stream and the Doc class you can print a file to a printer.