How can close PDF file if it is open? - java

I can create a PDF file with iText library in Java. This works, but now I have this problem, I execute the method, then I have a PDF file, its name is file.pdf and it is ok. Now I re-call the function to create the PDF file, its name is file.pdf but now, if the file is just open, I have an error.
FileNotFoundException:Impossible to access at file
And is ok this, so I want that if the file is open, from code, close the file then recreate the file and open it.
This is my code to create a PDF file:
public static void printFile(String nomeFolder, String nomeFile,List<Articoli> listaArticoli, boolean aprire)throws DocumentException{
String folderName = DateUtil.getDataGiornaliera();
nomeFolder = (new StringBuilder()).append(nomeFolder).append(nomeFile+"_"+folderName).append(".pdf").toString();
File f = new File(nomeFolder);
try {
OutputStream os = new FileOutputStream(f);
Document doc = new Document(PageSize.A4.rotate(), -65F, -65F, 85F, 40F);
PdfWriter docWriter = PdfWriter.getInstance(doc, os);
EndPageFoglioFatturaFatt hp2 = new EndPageFoglioFatturaFatt(nomeFolder, "Img/ineco1.jpg",folderName);
docWriter.setPageEvent(hp2);
FooterDocumenti hp = new FooterDocumenti(nomeFolder, "Img/ineco1.jpg",folderName);
docWriter.setPageEvent(hp);
doc.open();
float[] colonne = {0.7f,1.5f,4.5f,0.5f,0.5f,1.5f,1.5f,1.5f};
PdfPTable table = new PdfPTable(colonne);
table.setHeaderRows(1);
String[] intestazioni = {"C.ART","C.BARRE", "NOME ARTICOLO","IVA(%)", "Q.TA",
"PR.VENDITA", "ULT.PR.VENDITA", "ULT.DATA ACQUISTO"};
PdfPCell cell = new PdfPCell();
for(int i = 0; i< intestazioni.length; i++){
cell = new PdfPCell(new Paragraph(intestazioni[i], FontFactory.getFont("Century Gothic", 8F)));
cell.setGrayFill(0.9F);
cell.setUseAscender(true);
cell.setHorizontalAlignment(1);
cell.setVerticalAlignment(5);
cell.setBorderWidth(0.5F);
cell.setFixedHeight(15F);
table.addCell(cell);
}
//Vector v = db.eseguiQueryTuttiArticoli("SELECT ARTICOLIDETT.CodArticolo,NomeArticolo,Iva, Quantita,PrezzoAttuale, PrezzoRivenditore, PrezzoIngrosso, Soglia FROM Articolidett,Articoliquantita WHERE ARTICOLIDETT.CODARTICOLO = ARTICOLIQUANTITA.CODARTICOLO ORDER BY NOMEARTICOLO");
for (Articoli articoli : listaArticoli) {
cell = new PdfPCell(new Paragraph(articoli.getCodArticoloString(), FontFactory.getFont("Century Gothic", 10F)));
cell.setVerticalAlignment(5);
cell.setHorizontalAlignment(0);
cell.setColspan(0);
cell.setBorderWidth(0.5F);
table.addCell(cell);
....
....
CODE TO BUILD A FILE
.....
.....
}
doc.add(table);
doc.close();
os.close();
} catch (FileNotFoundException e) {
log.logStackTrace(e);
VisualMessageStampe.getErroreFileAperto();
}
catch(IOException exp)
{
log.logStackTrace(exp);
}
catch(DocumentException exp2)
{
log.logStackTrace(exp2);
}
if(aprire)
{
if(Desktop.isDesktopSupported())
{
try
{
Desktop.getDesktop().open(f.getCanonicalFile());
}
catch(IOException ex)
{
log.logStackTrace(ex);
}
} else
{
VisualMessageStampe.getErroreAcrobatInesistente();
}
}
}
How can I fixed my problem?

You cannot open an OutputStream into a file opened in external application (Adobe Reader or stuff). Some things you could do instead:
Create new filename for each iteration (creating tempfiles is cheap)
Check if file exists before you go and overwrite. If exists create a suffix (_1, _2, ...) and check that does not exist.
Alert user once you see that message to "please close PDF file before creating new"
Something like this might help:
protected File getFile(String nomeFile, String nomeFolder) {
String folderName = DateUtil.getDataGiornaliera();
nomeFolder = (new StringBuilder()).append(nomeFolder).append(nomeFile+"_"+folderName).append(".pdf").toString();
File f = new File(nomeFolder);
int suffix = 1;
while(f.exists()) {
nomeFolder = (new StringBuilder()).append(nomeFolder).append(nomeFile+"_"+folderName+"_"+(suffix++)).append(".pdf").toString();
f = new File(nomeFolder);
}
return f;
}

Related

Java Apache POI: insert an image "infront the text"

I have a placeholder image in my docx file and I want to replace it with new image. The problem is - the placeholder image has an attribute "in front of text", but the new image has not. As a result the alignment breaks. Here is my code snippet and the docx with placeholder and the resulting docx.
.......
replaceImage(doc, "Рисунок 1", qr, 50, 50);
ByteArrayOutputStream out = new ByteArrayOutputStream();
doc.write(out);
out.close();
return out.toByteArray();
}
}
public XWPFDocument replaceImage(XWPFDocument document, String imageOldName, byte[] newImage, int newImageWidth, int newImageHeight) throws Exception {
try {
int imageParagraphPos = -1;
XWPFParagraph imageParagraph = null;
List<IBodyElement> documentElements = document.getBodyElements();
for (IBodyElement documentElement : documentElements) {
imageParagraphPos++;
if (documentElement instanceof XWPFParagraph) {
imageParagraph = (XWPFParagraph) documentElement;
if (imageParagraph.getCTP() != null && imageParagraph.getCTP().toString().trim().contains(imageOldName)) {
break;
}
}
}
if (imageParagraph == null) {
throw new Exception("Unable to replace image data due to the exception:\n"
+ "'" + imageOldName + "' not found in in document.");
}
ParagraphAlignment oldImageAlignment = imageParagraph.getAlignment();
// remove old image
boolean isDeleted = document.removeBodyElement(imageParagraphPos);
// now add new image
XWPFParagraph newImageParagraph = document.createParagraph();
XWPFRun newImageRun = newImageParagraph.createRun();
newImageParagraph.setAlignment(oldImageAlignment);
try (InputStream is = new ByteArrayInputStream(newImage)) {
newImageRun.addPicture(is, XWPFDocument.PICTURE_TYPE_JPEG, "qr",
Units.toEMU(newImageWidth), Units.toEMU(newImageHeight));
}
// set new image at the old image position
document.setParagraph(newImageParagraph, imageParagraphPos);
// NOW REMOVE REDUNDANT IMAGE FORM THE END OF DOCUMENT
document.removeBodyElement(document.getBodyElements().size() - 1);
return document;
} catch (Exception e) {
throw new Exception("Unable to replace image '" + imageOldName + "' due to the exception:\n" + e);
}
}
The image with placeholder:
enter image description here
The resulting image:
enter image description here
To replace picture templates in Microsoft Word there is no need to delete them.
The storage is as so:
The embedded media is stored as binary file. This is the picture data (XWPFPictureData). In the document a picture element (XWPFPicture) links to that picture data.
The XWPFPicture has settings for position, size and text flow. These dont need to be changed.
The changing is needed in XWPFPictureData. There one can replace the old binary content with the new.
So the need is to find the XWPFPicture in the document. There is a non visual picture name stored while inserting the picture in the document. So if one knows that name, then this could be a criteriea to find the picture.
If found one can get the XWPFPictureData from found XWPFPicture. There is method XWPFPicture.getPictureDatato do so. Then one can replace the old binary content of XWPFPictureData with the new. XWPFPictureData is a package part. So it has PackagePart.getOutputStream to get an output stream to write to.
Following complete example shows that all.
The source.docx needs to have an embedded picture named "QRTemplate.jpg". This is the name of the source file used while inserting the picture into Word document using Word GUI. And there needs to be a file QR.jpg which contains the new content.
The result.docx then has all pictures named "QRTemplate.jpg" replaced with the content of the given file QR.jpg.
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
public class WordReplacePictureData {
static XWPFPicture getPictureByName(XWPFRun run, String pictureName) {
if (pictureName == null) return null;
for (XWPFPicture picture : run.getEmbeddedPictures()) {
String nonVisualPictureName = picture.getCTPicture().getNvPicPr().getCNvPr().getName();
if (pictureName.equals(nonVisualPictureName)) {
return picture;
}
}
return null;
}
static void replacePictureData(XWPFPictureData source, String pictureResultPath) {
try ( FileInputStream in = new FileInputStream(pictureResultPath);
OutputStream out = source.getPackagePart().getOutputStream();
) {
byte[] buffer = new byte[2048];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
static void replacePicture(XWPFRun run, String pictureName, String pictureResultPath) {
XWPFPicture picture = getPictureByName(run, pictureName);
if (picture != null) {
XWPFPictureData source = picture.getPictureData();
replacePictureData(source, pictureResultPath);
}
}
public static void main(String[] args) throws Exception {
String templatePath = "./source.docx";
String resultPath = "./result.docx";
String pictureTemplateName = "QRTemplate.jpg";
String pictureResultPath = "./QR.jpg";
try ( XWPFDocument document = new XWPFDocument(new FileInputStream(templatePath));
FileOutputStream out = new FileOutputStream(resultPath);
) {
for (IBodyElement bodyElement : document.getBodyElements()) {
if (bodyElement instanceof XWPFParagraph) {
XWPFParagraph paragraph = (XWPFParagraph)bodyElement;
for (XWPFRun run : paragraph.getRuns()) {
replacePicture(run, pictureTemplateName, pictureResultPath);
}
}
}
document.write(out);
}
}
}
I have a dirty workaround. Since the text block on the right side of the image is static, I replaced the text with screen-shot on the original docx. And now, when the placeholder image been substituted by the new image, everything is rendered as expected.

how to pass a file path to PdfReader of iText

im using iText to get content of a pdf like this :
try {
String parsedText="";
File file = new File(getApplicationContext().getFilesDir(), "test.pdf");
PdfReader reader = new PdfReader(String.valueOf(file));
int n = reader.getNumberOfPages();
for (int i = 0; i <n ; i++) {
parsedText = parsedText+ PdfTextExtractor.getTextFromPage(reader, i+1).trim()+"\n"; //Extracting the content from the different pages
}
reader.close();
} catch (Exception e) {
Log.d("heh", String.valueOf(e));
}
but it returns the error:
/data/user/0/com.clementine.story_project/files/test.pdf not found as file or resource.
what am i doing wrong?
PdfReader doesn't accept file object, but it accept InputStream. So you can use the below code
Path path = file.toPath();
if(Files.exists(path)) {
PdfReader reader = new PdfReader(Files.newInputStream(path));
//other operations
}
Also, added a file exists condition before calling the stream.

Java - Read excel, modify then save to a new file

I have it currently working so that my application is generating the content, then saving the information into an excel file, this is working as expected using the below code
public void writeExcel(ClassManager cm, String fn, ErrorManager em) throws FileNotFoundException, IOException {
// Get classes
classes = cm.getClasses();
String fileName = (!"".equals(fn)) ? fn : "temp.xlsx";
// Create Rows
setupRows();
File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + fileName;
FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
the setupRow function calls several other functions, all setup the same as below
public void setupRowTemplateName() {
int start = 2;
Row row = sheet.createRow(1);
for (int i = 0; i < classes.size(); i++) {
// Get class and template details
Classes c = classes.get(i);
Template t = c.getTemplate();
// Create cell
Cell cell = row.createCell(start);
// Set contents
if(t != null) {
cell.setCellValue(t.getName());
}
start++;
}
}
I'm trying to adjust the saving so that it takes an excel file, adds the information to that, then saves as a new file (i.e: Take file "Codes Template.xlsx", add data, save as another filename.
So far I have
public void writeExcelReplace(ClassManager cm, String fn, ErrorManager em) throws FileNotFoundException, IOException {
File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocationOpen = path.substring(0, path.length() - 1) + "Codes Template.xlsx";
FileInputStream inputStream = new FileInputStream(new File(fileLocationOpen));
workbook = WorkbookFactory.create(inputStream);
sheet = workbook.getSheetAt(0);
// Get classes
classes = cm.getClasses();
String fileName = (!"".equals(fn)) ? fn : "temp.xlsx";
// Create Rows
setupRows();
String fileLocation = path.substring(0, path.length() - 1) + fileName;
inputStream.close();
FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
outputStream.close();
workbook.close();
}
This is taking the content from the "template" file and saving it to the new file, but none of the content from setupRows is being added

Internal links are not working on merged PDF files

I am currently modifying the logic for generating a PDF report, using itext package (itext-2.1.7.jar). The report is generated first, then - table of contents (TOC) and then TOC is inserted into the report file, using PdfStamper and it's method - replacePage:
PdfStamper stamper = new PdfStamper(new PdfReader(finalFile.getAbsolutePath()),
new FileOutputStream(reportFile));
stamper.replacePage(new PdfReader(tocFile.getAbsolutePath()), 1, 2);
However, I wanted TOC to also have internal links to point to the right chapter. Using replacePage() method, unfortunately, removes all links and annotations, so I tried another way. I've used a method I've found to merge the report file and the TOC file. It did the trick, meaning that the links were now preserved, but they don't seem to work, the user can click them, but nothing happens. I've placed internal links on other places in the report file, for testing purposes, and they seem to work, but they don't work when placed on the actual TOC. TOC is generated separately, here's how I've created the links (addLeadingDots is a local method, not pertinent to the problem):
Chunk anchor = new Chunk(idx + ". " + chapterName + getLeadingDots(chapterName, pageNumber) + " " + pageNumber, MainReport.FONT12);
String anchorLocation = idx+chapterName.toUpperCase().replaceAll("\\s","");
anchor.setLocalGoto(anchorLocation);
line = new Paragraph();
line.add(anchor);
line.setLeading(6);
table.addCell(line);
And this is how I've created anchor destinations on the chapters in the report file:
Chunk target = new Chunk(title.toUpperCase(), font);
String anchorDestination = title.toUpperCase().replace(".", "").replaceAll("\\s","");
target.setLocalDestination(anchorDestination);
Paragraph p = new Paragraph(target);
p.setAlignment(Paragraph.ALIGN_CENTER);
doc.add(p);
Finally, here's the method that supposed to merge report file and the TOC:
public static void mergePDFs(String originalFilePath, String fileToInsertPath, String outputFile, int location) {
PdfReader originalFileReader = null;
try {
originalFileReader = new PdfReader(originalFilePath);
} catch (IOException ex) {
System.out.println("ITextHelper.addPDFToPDF(): can't read original file: " + ex);
}
PdfReader fileToAddReader = null;
try {
fileToAddReader = new PdfReader(fileToInsertPath);
} catch (IOException ex) {
System.out.println("ITextHelper.addPDFToPDF(): can't read fileToInsert: " + ex);
}
if (originalFileReader != null && fileToAddReader != null) {
int numberOfOriginalPages = originalFileReader.getNumberOfPages();
Document document = new Document();
PdfCopy copy = null;
try {
copy = new PdfCopy(document, new FileOutputStream(outputFile));
document.open();
for (int i = 1; i <= numberOfOriginalPages; i++) {
if (i == location) {
for (int j = 1; j <= fileToAddReader.getNumberOfPages(); j++) {
copy.addPage(copy.getImportedPage(fileToAddReader, j));
}
}
copy.addPage(copy.getImportedPage(originalFileReader, i));
}
document.close();
} catch (DocumentException | FileNotFoundException ex) {
m_logger.error("ITextHelper.addPDFToPDF(): can't read output location: " + ex);
} catch (IOException ex) {
m_logger.error(Level.SEVERE, ex);
}
}
}
So, the main question is, what happens to the links, after both pdf documents are merged and how to make them work? I'm not too experienced with itext, so any help is appreciated.
Thanks for your help

How do I add standalone="no" TO A FILE using JDOM?

I found here how I can override the print-out of the XML document to my Eclipse console so that it includes standalone = "no", but how do I write standalone = "no" to a file? I have tried writing the same document to a file, and it still will not print standalone = "no". In other words, when I try writing to a file, the overridden method does not work.
Is there some other method that I should override when writing to a file? What is the issue here?
private static void writeXML() {
try {
Document doc = new Document();
Element theRoot = new Element("tvshows");
doc.setRootElement(theRoot);
Element show = new Element("show");
Element name = new Element("name");
name.setAttribute("show_id", "show_001");
name.addContent(new Text("Life on Mars"));
Element network = new Element("network");
network.setAttribute("country", "US");
network.addContent(new Text("ABC"));
show.addContent(name);
show.addContent(network);
theRoot.addContent(show);
//-----------------------------
Element show2 = new Element("show");
Element name2 = new Element("name");
name2.setAttribute("show_id", "show_002");
name2.addContent(new Text("Life on Mars"));
Element network2 = new Element("network");
network2.setAttribute("country", "UK");
network2.addContent(new Text("BBC"));
show2.addContent(name2);
show2.addContent(network2);
theRoot.addContent(show2);
XMLOutputter xmlOutput = new XMLOutputter(Format.getPrettyFormat(), XMLOUTPUT);
//xmlOutput.output(doc, System.out);
xmlOutput.output(doc, new FileOutputStream(new File("./src/jdomMade.xml")));
System.out.println("The file has been written");
}
catch (Exception ex){
ex.printStackTrace();
}
}
public static final XMLOutputProcessor XMLOUTPUT = new AbstractXMLOutputProcessor() {
#Override
protected void printDeclaration(final Writer out, final FormatStack fstack) throws IOException {
write(out, "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?> ");
write(out, fstack.getLineSeparator());
}
};
Your code lies ;-)
xmlOutput.output(doc, new FileOutputStream(new File("./src/jdomMade.xml")));
System.out.println("The file has been written");
The println says the file has been written, but it has not.
The File is only written when the file is flushed, and closed. You do not do that.
You should add a try-with-resources to your code:
try (FileOutputStream fos = new FileOutputStream(new File("./src/jdomMade.xml"))) {
xmlOutput.output(doc, fos);
}
System.out.println("The file has been written");

Categories

Resources