I'm applying header on a pdf/a document
I embed my font in document, no problem if I have hundreds of page, in pdf created I see just one font embedded in document properties.
Now I worked on adding an header using canvas as seen in many examples.
At first it throw error because it says font must be embedded.
When I embed the font it works, but in document properties I see the font repeated for every page.
So the document kb size grows a lot.
I want font embedded just one time.
Spring boot, but i think it does not matter.
The code of header:
#Slf4j
public class Header implements IEventHandler {
private IFontProviderService fontProviderService;
private String logoPath;
private String header;
private List<String> subHeaders;
public Header(IFontProviderService fontProviderService, String logoPath, String header, List<String> subHeaders) {
this.fontProviderService = fontProviderService;
this.header = header;
this.subHeaders = subHeaders;
this.logoPath = logoPath;
}
#Override
public void handleEvent(Event event) {
try {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
PdfDictionary pdfObject = page.getPdfObject();
PdfCanvas headerPdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
Rectangle headerRect = new Rectangle(35, 740, 495, 96);
Canvas headerCanvas = new Canvas(headerPdfCanvas, headerRect);
headerCanvas.setFont(fontProviderService.getDefaultPdfFont());
headerCanvas.enableAutoTagging(page);
CreateHeaderContent(headerCanvas);
headerCanvas.close();
} catch (Exception e) {
log.error("Error in header settings.", e);
}
}
private void CreateHeaderContent(Canvas canvas) throws MalformedURLException {
Table table = new Table(UnitValue.createPercentArray(new float[] { 80, 20 }));
table.setWidth(UnitValue.createPercentValue(100));
Cell cell1 = new Cell().add(new Paragraph(header).setBold().setFontSize(11).setTextAlignment(TextAlignment.LEFT));
for (int i = 0; i < subHeaders.size(); i++) {
cell1.add(new Paragraph(subHeaders.get(i)).setFontSize(8).setTextAlignment(TextAlignment.LEFT));
}
cell1.setBorder(Border.NO_BORDER);
table.addCell(cell1);
ImageData imageData = ImageDataFactory.create(logoPath);
Image image = new Image(imageData);
image.getAccessibilityProperties().setAlternateDescription("...");
Cell cell2 = new Cell().add(image.setTextAlignment(TextAlignment.RIGHT));
cell2.setBorder(Border.NO_BORDER);
cell2.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(cell2);
canvas.add(table);
}
}
#Slf4j
#Service
public class FontProviderService implements IFontProviderService {
#Value("${pdf.resources.external.path}")
private String staticResourcesPath;
#Override
public FontProvider getFontProvider() throws IOException {
FontProvider fontProvider = new FontProvider("DMSans-Regular");
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-Regular.ttf"));
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-Bold.ttf"));
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-Italic.ttf"));
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-BoldItalic.ttf"));
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-Medium.ttf"));
fontProvider.addFont(FontProgramFactory.createFont(staticResourcesPath + "pdf/fonts/DMSans-MediumItalic.ttf"));
return fontProvider;
}
#Override
public PdfFont getDefaultPdfFont() throws IOException {
String defaultFontFamily = this.getFontProvider().getDefaultFontFamily();
Collection<FontInfo> fonts = this.getFontProvider().getFontSet().getFonts();
FontInfo fontInfo = fonts.stream().filter(f -> f.getFontName().equals(defaultFontFamily)).findFirst().get();
PdfFont pdfFont = this.getFontProvider().getPdfFont(fontInfo);
return pdfFont;
}
}
...Spring had something to do with it in some way ...at least in the manner i wrote the service...
Well... Actually in my case the problem was just how I used the service sprint to retrieve the fontProvider and the font.
I'm passing to my handler the entire fontProviderService:
public Header(IFontProviderService fontProviderService, String logoPath, String header, List<String> subHeaders)
and calling every time:
headerCanvas.setFont(fontProviderService.getDefaultPdfFont());
That's equal to create every time a new provider:
FontProvider fontProvider = new FontProvider("DMSans-Regular");
The point to focus is that the FontProvider object and the PdfFont objects must be always the same
So modified my Handler like this:
#Slf4j
public class Header implements IEventHandler {
private FontProvider fontProvider;
private PdfFont pdfFont;
private String logoPath;
private String header;
private List<String> subHeaders;
public Header(FontProvider fontProvider, PdfFont pdfFont, String logoPath, String header, List<String> subHeaders) {
this.fontProvider = fontProvider;
this.pdfFont = pdfFont;
this.header = header;
this.subHeaders = subHeaders;
this.logoPath = logoPath;
}
#Override
public void handleEvent(Event event) {
try {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
PdfDictionary pdfObject = page.getPdfObject();
PdfCanvas headerPdfCanvas = new PdfCanvas(page.newContentStreamBefore(), page.getResources(), pdf);
Rectangle headerRect = new Rectangle(35, 740, 495, 96);
Canvas headerCanvas = new Canvas(headerPdfCanvas, headerRect);
headerCanvas.setFontProvider(fontProvider);
headerCanvas.setFont(pdfFont);
headerCanvas.enableAutoTagging(page);
CreateHeaderContent(headerCanvas);
headerCanvas.close();
} catch (Exception e) {
log.error("Error in header settings.", e);
}
}
private void CreateHeaderContent(Canvas canvas) throws MalformedURLException {
Table table = new Table(UnitValue.createPercentArray(new float[] { 80, 20 }));
table.setWidth(UnitValue.createPercentValue(100));
Cell cell1 = new Cell().add(new Paragraph(header).setBold().setFontSize(11).setTextAlignment(TextAlignment.LEFT));
for (int i = 0; i < subHeaders.size(); i++) {
cell1.add(new Paragraph(subHeaders.get(i)).setFontSize(8).setTextAlignment(TextAlignment.LEFT));
}
cell1.setBorder(Border.NO_BORDER);
table.addCell(cell1);
ImageData imageData = ImageDataFactory.create(logoPath);
Image image = new Image(imageData);
image.getAccessibilityProperties().setAlternateDescription("...");
Cell cell2 = new Cell().add(image.setTextAlignment(TextAlignment.RIGHT));
cell2.setBorder(Border.NO_BORDER);
cell2.setVerticalAlignment(VerticalAlignment.MIDDLE);
table.addCell(cell2);
canvas.add(table);
}
}
Just for complete, I removed the getDefaultFont from Service and this is an extract of the pdf creator calling the Handler:
FontProvider fontProvider = fontProviderService.getFontProvider();
String defaultFontFamily = fontProvider.getDefaultFontFamily();
Collection<FontInfo> fonts = fontProvider.getFontSet().getFonts();
FontInfo fontInfo = fonts.stream().filter(f -> f.getFontName().equals(defaultFontFamily)).findFirst().get();
PdfFont defaultPdfFont = fontProvider.getPdfFont(fontInfo);
...
converterProperties.setFontProvider(fontProvider);
Header headerHandler = new Header(fontProvider, defaultPdfFont, staticResourcesPath + "....png", "...", "...");
pdf.addEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
Related
Good morning
I try to create a .docx documento using docx4j.
In the document I need to insert the footer only in the first page.
This is my code
private WordprocessingMLPackage wordMLPackage;
private ObjectFactory factory;
private FooterPart footerPart;
private Ftr footer;
public void creaDocumentoConFooterImmagine() throws Exception {
wordMLPackage = WordprocessingMLPackage.createPackage();
factory = Context.getWmlObjectFactory();
Relationship relationship = this.createFooterPart();
this.createFooterReference(relationship);
wordMLPackage.getMainDocumentPart().addParagraphOfText("Hello Word!");
URL logo = getClass().getClassLoader().getResource("Footer.jpg");
InputStream is = logo.openStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] byteChunk = new byte[4096]; // Or whatever size you want to read in at a time.
int n;
while ( (n = is.read(byteChunk)) > 0 ) {
baos.write(byteChunk, 0, n);
}
this.addImageInline(baos.toByteArray());
addPageBreak();
wordMLPackage.getMainDocumentPart().addParagraphOfText("This is page 2!");
File exportFile = new File("C:\\footerConImmagine.docx");
wordMLPackage.save(exportFile);
}
private void addImageInline(byte[] byteArray) throws Exception {
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, footerPart, byteArray);
int docPrId = 1;
int cNvPrId = 2;
Inline inLine = imagePart.createImageInline("Filename hint", "Alternative text", docPrId, cNvPrId, false);
if (footer != null) {
this.addInlineImageToFooter(inLine);
}
}
private void addInlineImageToFooter(Inline inLine) {
// Now add the in-line image to a paragraph
ObjectFactory factory2 = new ObjectFactory();
P paragraph2 = factory2.createP();
R run = factory.createR();
paragraph2.getContent().add(run);
Drawing drawing = factory.createDrawing();
run.getContent().add(drawing);
drawing.getAnchorOrInline().add(inLine);
footer.getContent().add(paragraph2);
}
private void createFooterReference(Relationship relationship) {
List<SectionWrapper> sections = wordMLPackage.getDocumentModel().getSections();
SectPr sectionProperties = sections.get(sections.size() - 1).getSectPr();
// There is always a section wrapper, but it might not contain a sectPr
if (sectionProperties == null) {
sectionProperties = factory.createSectPr();
wordMLPackage.getMainDocumentPart().addObject(sectionProperties);
sections.get(0).setSectPr(sectionProperties);
}
FooterReference footerReference = factory.createFooterReference();
footerReference.setId(relationship.getId());
footerReference.setType(HdrFtrRef.FIRST);
sectionProperties.getEGHdrFtrReferences().add(footerReference);
}
private Relationship createFooterPart() throws InvalidFormatException {
footerPart = new FooterPart();
footerPart.setPackage(wordMLPackage);
footerPart.setJaxbElement(this.createFooter("Text"));
return wordMLPackage.getMainDocumentPart().addTargetPart(footerPart);
}
//inserisco il testo del footer
private Ftr createFooter(String content) {
footer = factory.createFtr();
P paragraph = factory.createP();
R run = factory.createR();
Text text = new Text();
text.setValue(content);
run.getContent().add(text);
paragraph.getContent().add(run);
footer.getContent().add(paragraph);
return footer;
}
/**
* Adds a page break to the document.
*/
private void addPageBreak() {
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
Br breakObj = new Br();
breakObj.setType(STBrType.PAGE);
P paragraph = factory.createP();
paragraph.getContent().add(breakObj);
documentPart.getJaxbElement().getBody().getContent().add(paragraph);
}
If I set
footerReference.setType(HdrFtrRef.DEFAULT);
the footer is created properly, so the code seems correct.
I use this version of docx4j library: 6.1.2
How can I debug the problem?
Is there same example in the documentation of the library?
Thanks
Regards
I have simple piece of code that writes a PDF sometime this PDF will contain RTL languages like Hebrew or Arabic.
I was able to manipulate the text and mirror it using Bidi (Ibm lib)
But the text is still running in reverse
In English it would be something like:
instead of:
The quick
brown fox
jumps over
the lazy dog
It appears as:
the lazy dog
jumps over
brown fox
The quick
Complete code:
#Test
public void generatePdf() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
String dest = "c:\\temp\\" + formatter.format(Calendar.getInstance().getTime()) + ".pdf";
String fontPath = "C:\\Windows\\Fonts\\ARIALUNI.TTF";
FontProgramFactory.registerFont(fontPath, "arialUnicode");
OutputStream pdfFile = null;
Document doc = null;
try {
ByteArrayOutputStream output = new ByteArrayOutputStream();
PdfFont PdfFont = PdfFontFactory.createRegisteredFont("arialUnicode", PdfEncodings.IDENTITY_H, true);
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(output));
pdfDoc.setDefaultPageSize(PageSize.A4);
pdfDoc.addFont(PdfFont);
doc = new Document(pdfDoc);
doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
String txt = "בתשרי נתן הדקל פרי שחום נחמד בחשוון ירד יורה ועל גגי רקד בכסלו נרקיס הופיע בטבת ברד ובשבט חמה הפציעה ליום אחד. 1234 באדר עלה ניחוח מן הפרדסים בניסן הונפו בכוח כל החרמשים";
Bidi bidi = new Bidi();
bidi.setPara(txt, Bidi.RTL, null);
String mirrTxt = bidi.writeReordered(Bidi.DO_MIRRORING);
Paragraph paragraph1 = new Paragraph(mirrTxt)
.setFont(PdfFont)
.setFontSize(9)
.setTextAlignment(TextAlignment.CENTER)
.setHeight(200)
.setWidth(70);
paragraph1.setBorder(new SolidBorder(3));
doc.add(paragraph1);
Paragraph paragraph2 = new Paragraph(txt)
.setFont(PdfFont)
.setFontSize(9)
.setTextAlignment(TextAlignment.CENTER)
.setHeight(200)
.setWidth(70);
paragraph2.setBorder(new SolidBorder(3));
doc.add(paragraph2);
doc.close();
doc.flush();
pdfFile = new FileOutputStream(dest);
pdfFile.write(output.toByteArray());
ProcessBuilder b = new ProcessBuilder("cmd.exe","/C","explorer " + dest);
b.start();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {pdfFile.close();} catch (IOException e) {e.printStackTrace();}
}
}
The only solution that I have found with iText7 and IBM ICU4J without any other third party libraries is to first render the lines and then mirror them one by one. This requires a helper class LineMirroring and it's not precisely the most elegant solution, but will produce the output that you expect.
Lines mirroring class:
public class LineMirroring {
private final PageSize pageSize;
private final String fontName;
private final int fontSize;
public LineMirroring(PageSize pageSize, String fontName, int fontSize) {
this.pageSize = pageSize;
this.fontName = fontName;
this.fontSize = fontSize;
}
public String mirrorParagraph(String input, int height, int width, Border border) {
final StringBuilder mirrored = new StringBuilder();
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
PdfFont font = PdfFontFactory.createRegisteredFont(fontName, PdfEncodings.IDENTITY_H, true);
final PdfWriter writer = new PdfWriter(output);
final PdfDocument pdfDoc = new PdfDocument(writer);
pdfDoc.setDefaultPageSize(pageSize);
pdfDoc.addFont(font);
final Document doc = new Document(pdfDoc);
doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
final LineTrackingParagraph paragraph = new LineTrackingParagraph(input);
paragraph.setFont(font)
.setFontSize(fontSize)
.setTextAlignment(TextAlignment.RIGHT)
.setHeight(height)
.setWidth(width)
.setBorder(border);
LineTrackingParagraphRenderer renderer = new LineTrackingParagraphRenderer(paragraph);
doc.add(paragraph);
Bidi bidi;
for (LineRenderer lr : paragraph.getWrittenLines()) {
bidi = new Bidi(((TextRenderer) lr.getChildRenderers().get(0)).getText().toString(), Bidi.RTL);
mirrored.append(bidi.writeReordered(Bidi.DO_MIRRORING));
}
doc.close();
pdfDoc.close();
writer.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
return mirrored.toString();
}
private class LineTrackingParagraph extends Paragraph {
private List<LineRenderer> lines;
public LineTrackingParagraph(String text) {
super(text);
}
public void addWrittenLines(List<LineRenderer> lines) {
this.lines = lines;
}
public List<LineRenderer> getWrittenLines() {
return lines;
}
#Override
protected IRenderer makeNewRenderer() {
return new LineTrackingParagraphRenderer(this);
}
}
private class LineTrackingParagraphRenderer extends ParagraphRenderer {
public LineTrackingParagraphRenderer(LineTrackingParagraph modelElement) {
super(modelElement);
}
#Override
public void drawChildren(DrawContext drawContext) {
((LineTrackingParagraph)modelElement).addWrittenLines(lines);
super.drawChildren(drawContext);
}
#Override
public IRenderer getNextRenderer() {
return new LineTrackingParagraphRenderer((LineTrackingParagraph) modelElement);
}
}
}
Minimal JUnit Test:
public class Itext7HebrewTest {
#Test
public void generatePdf() {
final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
final String dest = "F:\\Temp\\" + formatter.format(Calendar.getInstance().getTime()) + ".pdf";
final String fontPath = "C:\\Windows\\Fonts\\ARIALUNI.TTF";
final String fontName = "arialUnicode";
FontProgramFactory.registerFont(fontPath, "arialUnicode");
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
PdfFont arial = PdfFontFactory.createRegisteredFont(fontName, PdfEncodings.IDENTITY_H, true);
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(output));
pdfDoc.setDefaultPageSize(PageSize.A4);
pdfDoc.addFont(arial);
LineMirroring mirroring = new LineMirroring(pdfDoc.getDefaultPageSize(), fontName,9);
Document doc = new Document(pdfDoc);
doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
final String txt = "בתשרי נתן הדקל פרי שחום נחמד בחשוון ירד יורה ועל גגי רקד בכסלו נרקיס הופיע בטבת ברד ובשבט חמה הפציעה ליום אחד. 1234 באדר עלה ניחוח מן הפרדסים בניסן הונפו בכוח כל החרמשים";
final int height = 200;
final int width = 70;
final Border border = new SolidBorder(3);
Paragraph paragraph1 = new Paragraph(mirroring.mirrorParagraph(txt, height, width, border));
paragraph1.setFont(arial)
.setFontSize(9)
.setTextAlignment(TextAlignment.RIGHT)
.setHeight(height)
.setWidth(width)
.setBorder(border);
doc.add(paragraph1);
doc.close();
doc.flush();
try (FileOutputStream pdfFile = new FileOutputStream(dest)) {
pdfFile.write(output.toByteArray());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
I have created a upload button, or upload buttons with Vaadin 14. Works like a charm. Perfect. But how do I access the images I uploaded? I have tried to read the tutorials on Vaadin's web page, but they only show the example I have post below. Not how to access the picture. I want to get all the pixels in a matrix form and turn them all into 0..255 gray scale.
Question:
Do you know what method to use to get the images, when I have upload or upload the pictures with this code?
#Data
public class PictureUpload {
private Upload upload;
public PictureUpload() {
// Add picture uploader
upload = new Upload();
addPictureUploader();
}
private void addPictureUploader() {
Div output = new Div();
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
upload.setReceiver(buffer);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
Component component = createComponent(event.getMIMEType(), event.getFileName(), buffer.getInputStream(event.getFileName()));
showOutput(event.getFileName(), component, output);
});
}
private Component createComponent(String mimeType, String fileName, InputStream stream) {
if (mimeType.startsWith("text")) {
return createTextComponent(stream);
} else if (mimeType.startsWith("image")) {
Image image = new Image();
try {
byte[] bytes = IOUtils.toByteArray(stream);
image.getElement().setAttribute("src", new StreamResource(fileName, () -> new ByteArrayInputStream(bytes)));
try (ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(bytes))) {
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
image.setWidth(reader.getWidth(0) + "px");
image.setHeight(reader.getHeight(0) + "px");
} finally {
reader.dispose();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
Div content = new Div();
String text = String.format("Mime type: '%s'\nSHA-256 hash: '%s'", mimeType, MessageDigestUtil.sha256(stream.toString()));
content.setText(text);
return content;
}
private Component createTextComponent(InputStream stream) {
String text;
try {
text = IOUtils.toString(stream, StandardCharsets.UTF_8);
} catch (IOException e) {
text = "exception reading stream";
}
return new Text(text);
}
private void showOutput(String text, Component content, HasComponents outputContainer) {
HtmlComponent p = new HtmlComponent(Tag.P);
p.getElement().setText(text);
outputContainer.add(p);
outputContainer.add(content);
}
}
Update:
I did some test with Mr. Lund's example code below in the comments. It seems that I have trouble to show a picture with this code:
#Data
public class LoadExportTemplate {
private VerticalLayout subjectCounterExportButtonUploaders;
public LoadExportTemplate() {
subjectCounterExportButtonUploaders = new VerticalLayout();
Upload pictureUpload = new PictureUpload().getUpload();
Div output = new PictureUpload().getOutput();
subjectCounterExportButtonUploaders.add(pictureUpload, output);
}
}
Where I insert the subjectCounterExportButtonUploaders with this MainView code. I can't see the picture when I upload it.
#Route("")
#Viewport("width=device-width, minimum-scale=1, initial-scale=1, user-scalable=yes, viewport-fit=cover")
#PreserveOnRefresh
public class MainView extends AppLayout {
/**
*
*/
private static final long serialVersionUID = 1L;
public MainView() {
// Get the components
VerticalLayout buildPredictValidateTemplate = new BuildPredictValidateTemplate().getBuildButtonPredictButtonValidateButtonTextArea();
VerticalLayout subjectCounterExportButtonUpload = new LoadExportTemplate().getSubjectCounterExportButtonUploaders();
// Create logo and drawer
Image barImage = new Image("img/barImage.png", "Fisherfaces Logo");
barImage.setHeight("55px");
addToNavbar(new DrawerToggle(), barImage);
// Create tabs and add listeners to them
Tab buildPredictValidate = new Tab("Build & Predict & Validate");
buildPredictValidate.getElement().addEventListener("click", e -> {
getContent().getChildren().forEach(component -> {
boolean visible = component.equals(buildPredictValidateTemplate);
component.setVisible(visible);
});
});
Tab loadExport = new Tab("Load & Export");
loadExport.getElement().addEventListener("click", e -> {
// Walk around from the bug
getContent().getChildren().forEach(component -> {
boolean visible = component.equals(subjectCounterExportButtonUpload);
component.setVisible(visible);
});
});
// Set the contents
setContent(new Div(buildPredictValidateTemplate, subjectCounterExportButtonUpload));
subjectCounterExportButtonUpload.setVisible(false);
// Add them and place them as vertical
Tabs tabs = new Tabs(buildPredictValidate, loadExport);
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
}
}
But this example works. Here I can see the picture when I upload it.
#Route(value = UploadView.ROUTE)
#PageTitle(UploadView.TITLE)
public class UploadView extends AppLayout{
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String ROUTE = "upload";
public static final String TITLE = "Upload";
public UploadView() {
PictureUpload pictureUpload = new PictureUpload();
VerticalLayout vl = new VerticalLayout();
vl.add(pictureUpload.getUpload(),pictureUpload.getOutput());
setContent(vl);
}
}
Do you know why?
In the comments you clarified that all you want is to get the byte[] of the image after the upload. Here is how you could do that.
Variant 1: MultiFileMemoryBuffer
MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
upload.setReceiver(buffer);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
byte[] imageBytes = IOUtils.toByteArray(buffer.getInputStream(event.getFileName()));
});
Variant 2: be your own Receiver interface
public class UploadView implements Receiver {
private FastByteArrayOutputStream outputStream;
private Upload upload;
private Button actualUploadButton;
public UploadView(){
upload = new Upload(this);
upload.setAcceptedFileTypes("image/jpeg", "image/png", "image/gif");
upload.addSucceededListener(event -> {
// uploaded file is now in outputStream
byte[] newImageBytes = outputStream.toByteArray();
Notification.show("We have now got the uploaded images bytearray!");
});
upload.setMaxFiles(10);
actualUploadButton = new Button(getTranslation("upload-image"), VaadinIcon.UPLOAD.create());
actualUploadButton.setWidth("100%");
upload.setUploadButton(actualUploadButton);
add(upload);
}
#Override
public OutputStream receiveUpload(String s, String s1) {
return outputStream = new FastByteArrayOutputStream();
}
}
I need to create a pdf file from plain text files. I supposed that the simplest method would be read these files and print them to a PDF printer.
My problem is that if I print to a pdf printer, the result will be an empty pdf file. If I print to Microsoft XPS Document Writer, the file is created in plain text format, not in oxps format.
I would be satisfied with a two or three step solution. (Eg. converting to xps first then to pdf using ghostscript, or something similar).
I have tried a couple of pdf printers such as: CutePDF, Microsoft PDF writer, Bullzip PDF. The result is the same for each one.
The environment is Java 1.7/1.8 Win10
private void print() {
try {
DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
PrintRequestAttributeSet patts = new HashPrintRequestAttributeSet();
PrintService[] ps = PrintServiceLookup.lookupPrintServices(flavor, patts);
if (ps.length == 0) {
throw new IllegalStateException("No Printer found");
}
System.out.println("Available printers: " + Arrays.asList(ps));
PrintService myService = null;
for (PrintService printService : ps) {
if (printService.getName().equals("Microsoft XPS Document Writer")) { //
myService = printService;
break;
}
}
if (myService == null) {
throw new IllegalStateException("Printer not found");
}
myService.getSupportedDocFlavors();
DocPrintJob job = myService.createPrintJob();
FileInputStream fis1 = new FileInputStream("o:\\k\\t1.txt");
Doc pdfDoc = new SimpleDoc(fis1, DocFlavor.INPUT_STREAM.AUTOSENSE, null);
HashPrintRequestAttributeSet pr = new HashPrintRequestAttributeSet();
pr.add(OrientationRequested.PORTRAIT);
pr.add(new Copies(1));
pr.add(MediaSizeName.ISO_A4);
PrintJobWatcher pjw = new PrintJobWatcher(job);
job.print(pdfDoc, pr);
pjw.waitForDone();
fis1.close();
} catch (PrintException ex) {
Logger.getLogger(Docparser.class.getName()).log(Level.SEVERE, null, ex);
} catch (Exception ex) {
Logger.getLogger(Docparser.class.getName()).log(Level.SEVERE, null, ex);
}
}
class PrintJobWatcher {
boolean done = false;
PrintJobWatcher(DocPrintJob job) {
job.addPrintJobListener(new PrintJobAdapter() {
public void printJobCanceled(PrintJobEvent pje) {
allDone();
}
public void printJobCompleted(PrintJobEvent pje) {
allDone();
}
public void printJobFailed(PrintJobEvent pje) {
allDone();
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
allDone();
}
void allDone() {
synchronized (PrintJobWatcher.this) {
done = true;
System.out.println("Printing done ...");
PrintJobWatcher.this.notify();
}
}
});
}
public synchronized void waitForDone() {
try {
while (!done) {
wait();
}
} catch (InterruptedException e) {
}
}
}
If you can install LibreOffice, it is possible to use the Java UNO API to do this.
There is a similar example here which will load and save a file: Java Convert Word to PDF with UNO. This could be used to convert your text file to PDF.
Alternatively, you could take the text file and send it directly to the printer using the same API.
The following JARs give access to the UNO API. Ensure these are in your class path:
[Libre Office Dir]/URE/java/juh.jar
[Libre Office Dir]/URE/java/jurt.jar
[Libre Office Dir]/URE/java/ridl.jar
[Libre Office Dir]/program/classes/unoil.jar
[Libre Office Dir]/program
The following code will then take your sourceFile and print to the printer named "Local Printer 1".
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import com.sun.star.beans.PropertyValue;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.view.XPrintable;
public class DirectPrintTest
{
public static void main(String args[])
{
// set to the correct name of your printers
String printer = "Local Printer 1";// "Microsoft Print to PDF";
File sourceFile = new File("c:/projects/WelcomeTemplate.doc");
if (!sourceFile.canRead()) {
throw new RuntimeException("Can't read:" + sourceFile.getPath());
}
com.sun.star.uno.XComponentContext xContext = null;
try {
// get the remote office component context
xContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
System.out.println("Connected to a running office ...");
// get the remote office service manager
com.sun.star.lang.XMultiComponentFactory xMCF = xContext
.getServiceManager();
Object oDesktop = xMCF.createInstanceWithContext(
"com.sun.star.frame.Desktop", xContext);
com.sun.star.frame.XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime
.queryInterface(com.sun.star.frame.XComponentLoader.class,
oDesktop);
StringBuffer sUrl = new StringBuffer("file:///");
sUrl.append(sourceFile.getCanonicalPath().replace('\\', '/'));
List<PropertyValue> loadPropsList = new ArrayList<PropertyValue>();
PropertyValue pv = new PropertyValue();
pv.Name = "Hidden";
pv.Value = Boolean.TRUE;
loadPropsList.add(pv);
PropertyValue[] loadProps = new PropertyValue[loadPropsList.size()];
loadPropsList.toArray(loadProps);
// Load a Writer document, which will be automatically displayed
com.sun.star.lang.XComponent xComp = xCompLoader
.loadComponentFromURL(sUrl.toString(), "_blank", 0,
loadProps);
// Querying for the interface XPrintable on the loaded document
com.sun.star.view.XPrintable xPrintable = (XPrintable) UnoRuntime
.queryInterface(com.sun.star.view.XPrintable.class, xComp);
// Setting the property "Name" for the favoured printer (name of
// IP address)
com.sun.star.beans.PropertyValue propertyValue[] = new com.sun.star.beans.PropertyValue[2];
propertyValue[0] = new com.sun.star.beans.PropertyValue();
propertyValue[0].Name = "Name";
propertyValue[0].Value = printer;
// Setting the name of the printer
xPrintable.setPrinter(propertyValue);
propertyValue[0] = new com.sun.star.beans.PropertyValue();
propertyValue[0].Name = "Wait";
propertyValue[0].Value = Boolean.TRUE;
// Printing the loaded document
System.out.println("sending print");
xPrintable.print(propertyValue);
System.out.println("closing doc");
((com.sun.star.util.XCloseable) UnoRuntime.queryInterface(
com.sun.star.util.XCloseable.class, xPrintable))
.close(true);
System.out.println("closed");
System.exit(0);
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
}
Thank you for all. After two days struggling with various type of printers (I gave a chance to CUPS PDF printer too but I could not make it to print in landscape mode) I ended up using the Apache PDFbox.
It's only a POC solution but works and fits to my needs. I hope it will be useful for somebody.
( cleanTextContent() method removes some ESC control characters from the line to be printed. )
public void txt2pdf() {
float POINTS_PER_INCH = 72;
float POINTS_PER_MM = 1 / (10 * 2.54f) * POINTS_PER_INCH;
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:m.ss");
PDDocument doc = null;
try {
doc = new PDDocument();
PDPage page = new PDPage(new PDRectangle(297 * POINTS_PER_MM, 210 * POINTS_PER_MM));
doc.addPage(page);
PDPageContentStream content = new PDPageContentStream(doc, page);
//PDFont pdfFont = PDType1Font.HELVETICA;
PDFont pdfFont = PDTrueTypeFont.loadTTF(doc, new File("c:\\Windows\\Fonts\\lucon.ttf"));
float fontSize = 10;
float leading = 1.1f * fontSize;
PDRectangle mediabox = page.getMediaBox();
float margin = 20;
float startX = mediabox.getLowerLeftX() + margin;
float startY = mediabox.getUpperRightY() - margin;
content.setFont(pdfFont, fontSize);
content.beginText();
content.setLeading(leading);
content.newLineAtOffset(startX, startY);
BufferedReader fis1 = new BufferedReader(new InputStreamReader(new FileInputStream("o:\\k\\t1.txt"), "cp852"));
String inString;
//content.setRenderingMode(RenderingMode.FILL_STROKE);
float currentY = startY + 60;
float hitOsszesenOffset = 0;
int pageNumber = 1;
while ((inString = fis1.readLine()) != null) {
currentY -= leading;
if (currentY <= margin) {
content.newLineAtOffset(0, (mediabox.getLowerLeftX()-35));
content.showText("Date Generated: " + dateFormat.format(new Date()));
content.newLineAtOffset((mediabox.getUpperRightX() / 2), (mediabox.getLowerLeftX()));
content.showText(String.valueOf(pageNumber++)+" lap");
content.endText();
float yCordinate = currentY+30;
float sX = mediabox.getLowerLeftY()+ 35;
float endX = mediabox.getUpperRightX() - 35;
content.moveTo(sX, yCordinate);
content.lineTo(endX, yCordinate);
content.stroke();
content.close();
PDPage new_Page = new PDPage(new PDRectangle(297 * POINTS_PER_MM, 210 * POINTS_PER_MM));
doc.addPage(new_Page);
content = new PDPageContentStream(doc, new_Page);
content.beginText();
content.setFont(pdfFont, fontSize);
content.newLineAtOffset(startX, startY);
currentY = startY;
}
String ss = new String(inString.getBytes(), "UTF8");
ss = cleanTextContent(ss);
if (!ss.isEmpty()) {
if (ss.contains("JAN") || ss.contains("SUMMARY")) {
content.setRenderingMode(RenderingMode.FILL_STROKE);
}
content.newLineAtOffset(0, -leading);
content.showText(ss);
}
content.setRenderingMode(RenderingMode.FILL);
}
content.newLineAtOffset((mediabox.getUpperRightX() / 2), (mediabox.getLowerLeftY()));
content.showText(String.valueOf(pageNumber++));
content.endText();
fis1.close();
content.close();
doc.save("o:\\k\\t1.pdf");
} catch (IOException ex) {
Logger.getLogger(Document_Creation.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (doc != null) {
try {
doc.close();
} catch (IOException ex) {
Logger.getLogger(Document_Creation.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
I have to generate a pdf file depending on some input .Each time the code runs , the input length may vary , so how can I add pages to the document dynamically depending on my input content .
public class pdfproject
{
static int lineno=768;
public static void main (String[] args) throws Exception
{
PDDocument doc= new PDDocument();
PDPage page = new PDPage();
doc.addPage(page);
PDPageContentStream cos = new PDPageContentStream(doc, page);
for(int i=0;i<2000;i++)
{
renderText("hello"+i,cos,60);
}
cos.close();
doc.save("test.pdf");
doc.close();
}
static void renderText(String Info,PDPageContentStream cos,int marginwidth) throws Exception
{
lineno-=12;
System.out.print("lineno="+lineno);
PDFont fontPlain = PDType1Font.HELVETICA;
cos.beginText();
cos.setFont(fontPlain, 10);
cos.moveTextPositionByAmount(marginwidth,lineno);
cos.drawString(Info);
cos.endText();
}
}
How do i ensure that the content is rendered on the next page by adding a new page dynamically when there is no space on the current page ?
Pdfbox does not include any automatic layouting support. Thus, you have to keep track of how full a page is, and you have to close the current page, create a new one, reset fill indicators, etc
This obviously should not be done in static members in some project class but instead in some dedicated class and its instance members. E.g.
public class PdfRenderingSimple implements AutoCloseable
{
//
// rendering
//
public void renderText(String Info, int marginwidth) throws IOException
{
if (content == null || textRenderingLineY < 12)
newPage();
textRenderingLineY-=12;
System.out.print("lineno=" + textRenderingLineY);
PDFont fontPlain = PDType1Font.HELVETICA;
content.beginText();
content.setFont(fontPlain, 10);
content.moveTextPositionByAmount(marginwidth, textRenderingLineY);
content.drawString(Info);
content.endText();
}
//
// constructor
//
public PdfRenderingSimple(PDDocument doc)
{
this.doc = doc;
}
//
// AutoCloseable implementation
//
/**
* Closes the current page
*/
#Override
public void close() throws IOException
{
if (content != null)
{
content.close();
content = null;
}
}
//
// helper methods
//
void newPage() throws IOException
{
close();
PDPage page = new PDPage();
doc.addPage(page);
content = new PDPageContentStream(doc, page);
content.setNonStrokingColor(Color.BLACK);
textRenderingLineY = 768;
}
//
// members
//
final PDDocument doc;
private PDPageContentStream content = null;
private int textRenderingLineY = 0;
}
(PdfRenderingSimple.java)
You can use it like this
PDDocument doc = new PDDocument();
PdfRenderingSimple renderer = new PdfRenderingSimple(doc);
for (int i = 0; i < 2000; i++)
{
renderer.renderText("hello" + i, 60);
}
renderer.close();
doc.save(new File("renderSimple.pdf"));
doc.close();
(RenderSimple.java)
For more specialized rendering support you will implement improved rendering classes, e.g. PdfRenderingEndorsementAlternative.java from this answer.